A high-throughput and memory-efficient inference and serving engine for LLMs
Mirrored from https://github.com/tduncan-lum/Nvidia-Optimization-Stack---VLLM.git
Synced Nov 7, 16:30 UTC
[Bugfix] Fix MessageQueue connect_ip for cross-node data parallelism (#35429)
Signed-off-by: Lu Fang <fanglu@fb.com> Co-authored-by: Lu Fang <30275821+houseroad@users.noreply.github.com>
Lucia Fang committed
Feb 26, 2026 at 14:08 UTC
0f2f24c8b205b5bf2dadacf1f95f1ad9f7de73e0
2 files changed
+93
-1
tests/distributed/test_mq_connect_ip.py
new
+79
@@ -0,0 +1,79 @@
1
+# SPDX-License-Identifier: Apache-2.0
2
+# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3
+"""
4
+Test that MessageQueue uses the local node's IP for binding,
5
+not a remote master_addr. This validates the fix for cross-node
6
+data-parallel where each DP group leader must bind to its own IP.
7
+
8
+The bug: multiproc_executor used `parallel_config.master_addr` as
9
+`connect_ip` for every DP group's MessageQueue. For DP groups whose
10
+leader is NOT on the master node, binding to master_addr fails with
11
+"Cannot assign requested address".
12
+
13
+The fix: use `get_ip()` (local node IP) instead of `master_addr`.
14
+"""
15
+
16
+import pytest
17
+import zmq
18
+
19
+from vllm.distributed.device_communicators.shm_broadcast import MessageQueue
20
+from vllm.utils.network_utils import get_ip
21
+
22
+
23
+def test_mq_bind_with_local_ip():
24
+ """MessageQueue with remote readers should successfully bind
25
+ when connect_ip is the local node's IP."""
26
+ # n_reader=2, n_local_reader=1 means 1 remote reader,
27
+ # which triggers the remote ZMQ socket bind.
28
+ mq = MessageQueue(
29
+ n_reader=2,
30
+ n_local_reader=1,
31
+ connect_ip=get_ip(),
32
+ )
33
+ handle = mq.export_handle()
34
+ assert handle.remote_subscribe_addr is not None
35
+ # The bound address should contain our local IP
36
+ local_ip = get_ip()
37
+ assert (
38
+ local_ip in handle.remote_subscribe_addr
39
+ or f"[{local_ip}]" in handle.remote_subscribe_addr
40
+ )
41
+ del mq
42
+
43
+
44
+def test_mq_bind_with_non_local_ip_fails():
45
+ """MessageQueue should fail to bind when connect_ip is a
46
+ non-local IP address (simulating the bug where master_addr
47
+ from a different node was used)."""
48
+ # Use a non-local IP that we definitely can't bind to.
49
+ # 198.51.100.1 is from TEST-NET-2 (RFC 5737), never locally assigned.
50
+ non_local_ip = "198.51.100.1"
51
+ with pytest.raises(zmq.error.ZMQError, match="Cannot assign requested address"):
52
+ MessageQueue(
53
+ n_reader=2,
54
+ n_local_reader=1,
55
+ connect_ip=non_local_ip,
56
+ )
57
+
58
+
59
+def test_mq_bind_defaults_to_local_ip():
60
+ """When connect_ip is None, MessageQueue should auto-detect
61
+ the local IP and bind successfully."""
62
+ mq = MessageQueue(
63
+ n_reader=2,
64
+ n_local_reader=1,
65
+ connect_ip=None, # should fallback to get_ip()
66
+ )
67
+ handle = mq.export_handle()
68
+ assert handle.remote_subscribe_addr is not None
69
+ del mq
70
+
71
+
72
+if __name__ == "__main__":
73
+ test_mq_bind_with_local_ip()
74
+ print("PASSED: test_mq_bind_with_local_ip")
75
+ test_mq_bind_with_non_local_ip_fails()
76
+ print("PASSED: test_mq_bind_with_non_local_ip_fails")
77
+ test_mq_bind_defaults_to_local_ip()
78
+ print("PASSED: test_mq_bind_defaults_to_local_ip")
79
+ print("\nAll tests passed!")
vllm/v1/executor/multiproc_executor.py
+14
-1
@@ -44,6 +44,7 @@ from vllm.logger import init_logger
44
from vllm.tracing import instrument, maybe_init_worker_tracer
45
from vllm.utils.network_utils import (
46
get_distributed_init_method,
47
+ get_ip,
48
get_loopback_ip,
49
get_open_port,
50
)
@@ -128,11 +129,23 @@ class MultiprocExecutor(Executor):
129
# For leader node within each dp rank,
130
# each dp will have its own leader multiproc executor.
131
max_chunk_bytes = envs.VLLM_MQ_MAX_CHUNK_BYTES_MB * 1024 * 1024
132
+ mq_connect_ip = get_ip()
133
+ logger.info(
134
+ "DP group leader: node_rank=%d, node_rank_within_dp=%d, "
135
+ "master_addr=%s, mq_connect_ip=%s (local), "
136
+ "world_size=%d, local_world_size=%d",
137
+ self.parallel_config.node_rank,
138
+ self.parallel_config.node_rank_within_dp,
139
+ self.parallel_config.master_addr,
140
+ mq_connect_ip,
141
+ self.world_size,
142
+ self.local_world_size,
143
+ )
144
self.rpc_broadcast_mq = MessageQueue(
145
self.world_size,
146
self.local_world_size,
147
max_chunk_bytes=max_chunk_bytes,
135
- connect_ip=self.parallel_config.master_addr,
148
+ connect_ip=mq_connect_ip,
149
)
150
scheduler_output_handle = self.rpc_broadcast_mq.export_handle()
151
# Create workers