ZeroMQ 4.3.5 部署指南
ZeroMQ(libzmq)4.3.5 部署指南:单机库安装、zmq_proxy broker 源码部署与 systemd 托管、Docker Compose 三服务编排(中转+发布+订阅)三种形态 0 到 1 全流程,含连通验证、运维动作与常见问题,全部命令逐条实测(2026-10-20)。
ZeroMQ 4.3.5 部署指南
目标:把 ZeroMQ(libzmq 4.3.5)从「一个库」部署为「可用的消息基础设施」,覆盖三种落地形态——单机库安装、单机中转(zmq_proxy broker + systemd 托管)、Docker Compose 三服务编排(中转 + 发布 + 订阅),每种形态均给出完整部署步骤与逐命令实测回显。全部实测在 Ubuntu 22.04.5 LTS (x86_64) 完成,实测日期 2026-10-20。
一、环境信息
- 操作系统:Ubuntu 22.04.5 LTS(jammy),x86_64(
cat /etc/os-release实测:PRETTY_NAME="Ubuntu 22.04.5 LTS") - 组件版本:libzmq 4.3.5(官方最新稳定版,2023-10-09 发布,Releases Atom 源实查,查询日期 2026-10-20)
- 编译工具链:gcc (Ubuntu 11.4.0-1ubuntu1~22.04.3) 11.4.0、GNU Make 4.3
- Compose 形态运行时:python:3.12-slim + pyzmq 27.2.0(wheel 内置 libzmq 4.3.5,与基准版本一致,实测确认见 6.1 节)
- 编排网络:自定义 bridge
10.89.58.0/24(网段选取避开宿主机已占用网段) - 宿主端口:8145(XSUB/发布侧)、8146(XPUB/订阅侧),均为空闲端口实测占用
- 源码包:zeromq-4.3.5.tar.gz(2.5 MB,sha256
6653ef5910f17954861fe72332e68b03ca6e4d9c7160eb3a8de5a5a913bfab43,实测)
二、部署形态与方案选型
ZeroMQ 是消息库而非消息服务器:make install 之后系统里只有 libzmq.so 这一个共享库,没有守护进程、没有配置文件、没有管理端口。「部署 ZeroMQ」要解决的是两件事:① 把库装好;② 把使用这个库的应用进程跑起来。当应用需要「多对多」的消息交换时,再补一个极简中转进程(zmq_proxy broker)。
三种部署形态对照:
| 形态 | 组成 | 进程数 | 适用场景 |
|---|---|---|---|
| 单机直连 | libzmq 库 + 应用进程 | 仅应用自身 | 进程内/进程间通信(inproc/ipc),端点直连 |
| 单机中转 | libzmq 库 + broker(zmq_proxy)+ systemd 托管 + 应用进程 | 应用 N 个 + broker 1 个 | 需要中心交换点的发布订阅(XPUB/XSUB)或请求应答中转 |
| Compose 编排 | 编排文件 + 三个服务(broker/pub/sub) | 3 个服务实例 | 快速搭建可迁移的演示/开发/边缘环境,与宿主机解耦 |
选型建议:纯进程间通信选单机直连;生产级中心交换点选单机中转(进程模型最简、systemd 托管成熟);需要环境隔离与一键迁移(演示、开发联调、边缘盒子)选 Compose 编排。本文第四、五节展开单机两条线,第六节展开 Compose 编排(该节为容器化部署形态,行文按编排语境描述)。
三、前置条件
- 一台 Ubuntu 22.04 服务器,root 或 sudo 权限;
- 方案所需基础软件:编译线需要
build-essential、pkg-config、wget;Compose 线需要已安装 Docker 与 Docker Compose 插件(docker compose version可确认); - 网络可达 GitHub Releases(下载源码包约 2.5 MB;受限网络请配置
http_proxy/https_proxy后重试,实测直连失败经代理下载成功); - 端口规划:broker 默认占用 5555/5556(容器内)并映射到宿主 8145/8146,部署前确认端口未被占用:
ss -ltn | grep -E '5555|5556|8145|8146'应无输出。
四、单机部署形态:编译安装 libzmq 4.3.5(0→1)
本节把库从零装好,是后面两种形态的共同底座。完整编译细节与排障实录另见《Ubuntu 22.04 安装 ZeroMQ 4.3.5 指南》,此处保留完整可执行主线。
4.1 安装编译依赖
apt-get update
apt-get install -y build-essential wget pkg-config
实测回显(输出节选,实测末尾):
Processing triggers for ca-certificates (20260601~22.04.1) ...
Updating certificates in /etc/ssl/certs...
0 added, 0 removed; done.
Running hooks in /etc/ca-certificates/update.d...
done.
4.2 下载源码包并校验
cd /usr/local/src
wget https://github.com/zeromq/libzmq/releases/download/v4.3.5/zeromq-4.3.5.tar.gz
sha256sum zeromq-4.3.5.tar.gz
实测回显:
6653ef5910f17954861fe72332e68b03ca6e4d9c7160eb3a8de5a5a913bfab43 zeromq-4.3.5.tar.gz
4.3 配置、编译、安装
tar xf zeromq-4.3.5.tar.gz
cd zeromq-4.3.5
./configure --prefix=/usr/local
make -j$(nproc)
make install
ldconfig
实测回显(configure 关键行节选):
configure: Using 'epoll' I/O thread polling system with CLOEXEC
configure: Using built-in SHA1
configure: Using mtree implementation to manage subscriptions
configure: Building stable and legacy API (no draft API)
config.status: creating src/platform.hpp
config.status: creating src/libzmq.pc
💡 说明:默认构建使用 epoll I/O 多路复用与内置 tweetnacl 密码实现;若需标准 libsodium 支持 CURVE 加密,改为
./configure --prefix=/usr/local --with-libsodium(需先apt-get install libsodium-dev,且必须在全新解压目录执行,详见《Ubuntu 22.04 安装 ZeroMQ 4.3.5 指南》5.7 节与 FAQ)。
4.4 安装验证
pkg-config --modversion libzmq
ls -l /usr/local/lib/libzmq.so.5*
python3 -c "import zmq; print(zmq.zmq_version())"
实测回显:
4.3.5
lrwxrwxrwx 1 root root 15 Oct 19 18:10 /usr/local/lib/libzmq.so.5 -> libzmq.so.5.2.5
-rwxr-xr-x 1 root root 14150720 Oct 19 18:10 /usr/local/lib/libzmq.so.5.2.5
4.3.5
验证通过:pkg-config 元数据、动态库文件、Python 运行时加载版本均为 4.3.5(Python 验证依赖 python3-zmq 包,如未安装可执行 apt-get install -y python3-zmq,其运行时会自动优先加载 /usr/local/lib 下的 4.3.5)。
五、单机中转部署:zmq_proxy broker + systemd 托管
需要「多发布者 → 多订阅者」的中心交换点时,用官方 zmq_proxy() 构件写一个约 30 行的中转程序:前端 XSUB 收发布者连接(5555),后端 XPUB 供订阅者连接(5556),进程内无限转发。本节将其编译、托管为 systemd 服务并做连通性与运维动作实测。
5.1 部署 broker 程序
写入源码并编译安装到 /usr/local/bin:
mkdir -p /opt/zmq-proxy
cat > /opt/zmq-proxy/broker.c <<'EOF'
#include <zmq.h>
#include <stdio.h>
int main(void)
{
void *ctx = zmq_ctx_new();
void *xsub = zmq_socket(ctx, ZMQ_XSUB);
void *xpub = zmq_socket(ctx, ZMQ_XPUB);
if (zmq_bind(xsub, "tcp://0.0.0.0:5555") != 0) {
fprintf(stderr, "bind XSUB 5555 failed: %s\n", zmq_strerror(zmq_errno()));
return 1;
}
if (zmq_bind(xpub, "tcp://0.0.0.0:5556") != 0) {
fprintf(stderr, "bind XPUB 5556 failed: %s\n", zmq_strerror(zmq_errno()));
return 1;
}
printf("zmq-proxy: XSUB tcp://0.0.0.0:5555 XPUB tcp://0.0.0.0:5556\n");
fflush(stdout);
zmq_proxy(xsub, xpub, NULL);
zmq_close(xsub);
zmq_close(xpub);
zmq_ctx_term(ctx);
return 0;
}
EOF
gcc -O2 -o /usr/local/bin/zmq-proxy /opt/zmq-proxy/broker.c $(pkg-config --cflags --libs libzmq)
ldd /usr/local/bin/zmq-proxy | grep zmq
实测回显:
libzmq.so.5 => /usr/local/lib/libzmq.so.5 (0x000070a81bb5c000)
ldd 确认 broker 链接的正是 4.4 节安装的 /usr/local/lib/libzmq.so.5。
5.2 systemd 服务托管
写入单元文件 /etc/systemd/system/zeromq-proxy.service:
[Unit]
Description=ZeroMQ proxy broker (XSUB 5555 / XPUB 5556)
After=network.target
[Service]
Type=simple
ExecStart=/usr/local/bin/zmq-proxy
Restart=on-failure
RestartSec=3
User=nobody
[Install]
WantedBy=multi-user.target
💡 技术拓展:进程托管方式对比——
方式 特点 适用场景 systemd 服务 原生托管、开机自启、崩溃自动拉起、journald 日志 服务器常驻进程(本文采用) supervisor 配置简单、跨发行版一致 已有 supervisor 体系的环境 nohup/后台脚本 零依赖 临时验证 本文因目标是生产常驻且宿主为标准 Ubuntu,采用 systemd。
启用并启动服务:
systemctl daemon-reload
systemctl enable zeromq-proxy
systemctl start zeromq-proxy
systemctl is-active zeromq-proxy
ss -ltn | grep -E ':5555|:5556'
实测回显:
Created symlink /etc/systemd/system/multi-user.target.wants/zeromq-proxy.service → /etc/systemd/system/zeromq-proxy.service.
active
LISTEN 0 100 0.0.0.0:5555 0.0.0.0:*
LISTEN 0 100 0.0.0.0:5556 0.0.0.0:*
验证通过:服务 active,5555(XSUB)与 5556(XPUB)双双进入 LISTEN。查看服务日志确认启动横幅:
journalctl -u zeromq-proxy --no-pager | tail -3
实测回显:
Oct 19 18:12:28 e9eb393be32c systemd[1]: /etc/systemd/system/zeromq-proxy.service:10: Special user nobody configured, this is not safe!
Oct 19 18:12:28 e9eb393be32c systemd[1]: Started ZeroMQ proxy broker (XSUB 5555 / XPUB 5556).
Oct 19 18:12:28 e9eb393be32c zmq-proxy[9148]: zmq-proxy: XSUB tcp://0.0.0.0:5555 XPUB tcp://0.0.0.0:5556
⚠️ 注意:第一行是 systemd 对
User=nobody的安全告警(实测原文)。生产环境建议创建专用系统用户运行 broker:useradd -r -s /usr/sbin/nologin zmqproxy,并把单元中User=nobody改为User=zmqproxy后systemctl daemon-reload && systemctl restart zeromq-proxy。
5.3 客户端连通验证
用 Python 绑定(pyzmq)做一次「发布 → 中转 → 订阅」全链路验证:
# broker_client_test.py —— 经 broker 的 PUB/SUB 全链路自测
import time
import zmq
ctx = zmq.Context.instance()
pub = ctx.socket(zmq.PUB)
pub.connect("tcp://127.0.0.1:5555") # 发布者连 broker 的 XSUB 前端
sub = ctx.socket(zmq.SUB)
sub.connect("tcp://127.0.0.1:5556") # 订阅者连 broker 的 XPUB 后端
sub.setsockopt_string(zmq.SUBSCRIBE, "")
time.sleep(0.5) # 等待订阅关系经 broker 建立
for i in range(3):
pub.send_string("sys %d" % i)
time.sleep(0.1)
time.sleep(0.2)
print([sub.recv_string() for _ in range(3)])
实测回显:
['sys 0', 'sys 1', 'sys 2']
验证通过:发布者与订阅者互不直连,消息经 broker 完成交换。
5.4 日常运维动作(实测)
systemctl restart zeromq-proxy
systemctl is-active zeromq-proxy
systemctl stop zeromq-proxy
systemctl is-active zeromq-proxy
ss -ltn | grep ':5555'
实测回显:
active
inactive
restart 后回到 active(ZeroMQ 端点会自动重连 broker,业务代码无需改动);stop 后状态 inactive,且 5555 端口监听消失(ss | grep 无输出)。如需恢复服务再执行 systemctl start zeromq-proxy。
六、Docker Compose 编排部署形态
本节用 Docker Compose 把「中转 + 发布 + 订阅」编排为三个服务,形成一套可整体迁移的环境。镜像层面 libzmq 官方没有发布任何 Docker 镜像,因此采用通用运行时镜像 + 语言绑定:python:3.12-slim 安装 pyzmq 绑定——pyzmq 27.2.0 的 wheel 内置 libzmq 4.3.5,与本文基准版本严格一致(下一节实测核对)。
6.1 镜像选型说明与版本核对
先确认 pyzmq 最新稳定版及其内置 libzmq 版本:
docker run --rm python:3.12-slim sh -c 'pip install -q pyzmq==27.2.0; python -c "import zmq; print(\"libzmq:\", zmq.zmq_version(), \" pyzmq:\", zmq.pyzmq_version())"'
实测回显:
libzmq: 4.3.5 pyzmq: 27.2.0
镜像选型结论:以 python:3.12-slim 为基座、pip install pyzmq==27.2.0 固定绑定版本,运行时 libzmq 即 4.3.5,无需单独编译安装库文件。
6.2 部署步骤
项目目录结构:
/opt/data/quzuo/tmp/zeromq/compose/
├── Dockerfile
├── docker-compose.yml
└── app/
├── broker.py # 中转服务:zmq.proxy(XSUB, XPUB)
├── pub.py # 发布服务:每秒发一条 hello N
└── sub.py # 订阅服务:打印收到的消息
Dockerfile:
FROM python:3.12-slim
RUN pip install --no-cache-dir pyzmq==27.2.0
WORKDIR /app
COPY app/broker.py app/pub.py app/sub.py /app/
app/broker.py:
import zmq
def main():
ctx = zmq.Context.instance()
xsub = ctx.socket(zmq.XSUB)
xsub.bind("tcp://0.0.0.0:5555")
xpub = ctx.socket(zmq.XPUB)
xpub.bind("tcp://0.0.0.0:5556")
print("broker: XSUB tcp://0.0.0.0:5555 XPUB tcp://0.0.0.0:5556", flush=True)
zmq.proxy(xsub, xpub)
if __name__ == "__main__":
main()
app/pub.py:
import os
import time
import zmq
BROKER = os.environ.get("ZMQ_BROKER", "zmq-proxy")
INTERVAL = float(os.environ.get("ZMQ_INTERVAL", "1"))
def main():
ctx = zmq.Context.instance()
pub = ctx.socket(zmq.PUB)
pub.connect("tcp://%s:5555" % BROKER)
n = 0
while True:
pub.send_string("hello %d" % n)
n += 1
time.sleep(INTERVAL)
if __name__ == "__main__":
main()
app/sub.py:
import os
import zmq
BROKER = os.environ.get("ZMQ_BROKER", "zmq-proxy")
def main():
ctx = zmq.Context.instance()
sub = ctx.socket(zmq.SUB)
sub.connect("tcp://%s:5556" % BROKER)
sub.setsockopt_string(zmq.SUBSCRIBE, "")
print("sub connected, waiting...", flush=True)
while True:
print("recv:", sub.recv_string(), flush=True)
if __name__ == "__main__":
main()
docker-compose.yml(显式指定独立网段,避免与宿主上其他编排项目的网段冲突;container_name 命名遵循「产品-版本-用途」):
services:
zmq-proxy:
build: .
container_name: zmq-4-3-5-proxy
hostname: zmq-proxy
command: ["python", "/app/broker.py"]
ports:
- "8145:5555"
- "8146:5556"
networks:
- zmq-net
restart: unless-stopped
zmq-pub:
build: .
container_name: zmq-4-3-5-pub
hostname: zmq-pub
command: ["python", "/app/pub.py"]
environment:
ZMQ_BROKER: zmq-proxy
ZMQ_INTERVAL: "1"
depends_on:
- zmq-proxy
networks:
- zmq-net
restart: unless-stopped
zmq-sub:
build: .
container_name: zmq-4-3-5-sub
hostname: zmq-sub
command: ["python", "/app/sub.py"]
environment:
ZMQ_BROKER: zmq-proxy
depends_on:
- zmq-proxy
networks:
- zmq-net
restart: unless-stopped
networks:
zmq-net:
driver: bridge
ipam:
config:
- subnet: 10.89.58.0/24
💡 说明:
zmq-pub/zmq-sub通过服务名zmq-proxy直连 broker——Compose 网络内置 DNS 按服务名/主机名解析,broker 的服务名同时是它的稳定地址;三个服务同属zmq-net自定义网络。网段10.89.58.0/24为部署前核查宿主已占用网段后选取的空闲槽位。
构建并启动(首次构建需拉取 python:3.12-slim 并安装 pyzmq,约 1 分钟):
docker compose -p zeromq up -d --build
实测回显(输出节选,实测末尾):
Image compose-zmq-proxy Built
Image compose-zmq-pub Built
Image compose-zmq-sub Built
Container zmq-4-3-5-proxy Started
Container zmq-4-3-5-pub Started
Container zmq-4-3-5-sub Started
6.3 部署验证
服务状态:
docker compose -p zeromq ps --format 'table {{.Name}}\t{{.Status}}'
实测回显:
NAME STATUS
zmq-4-3-5-proxy Up 8 seconds
zmq-4-3-5-pub Up 8 seconds
zmq-4-3-5-sub Up 8 seconds
订阅端日志(消息已从 pub 经 broker 流转到 sub):
docker compose -p zeromq logs zmq-sub | tail -6
实测回显:
zmq-4-3-5-sub | recv: hello 3
zmq-4-3-5-sub | recv: hello 4
zmq-4-3-5-sub | recv: hello 5
zmq-4-3-5-sub | recv: hello 6
zmq-4-3-5-sub | recv: hello 7
zmq-4-3-5-sub | recv: hello 8
broker 启动横幅:
docker compose -p zeromq logs zmq-proxy | head -3
实测回显:
zmq-4-3-5-proxy | broker: XSUB tcp://0.0.0.0:5555 XPUB tcp://0.0.0.0:5556
宿主端口监听与网络拓扑:
ss -ltn | grep -E '8145|8146'
docker network inspect zeromq_zmq-net --format '{{(index .IPAM.Config 0).Subnet}}'
docker ps --filter name=zmq-4-3-5 --format '{{.Names}}' | while read c; do docker inspect $c --format '{{.Name}} {{range $k,$v := .NetworkSettings.Networks}}{{$k}}={{$v.IPAddress}} {{end}}'; done
实测回显:
LISTEN 0 4096 0.0.0.0:8145 0.0.0.0:*
LISTEN 0 4096 0.0.0.0:8146 0.0.0.0:*
LISTEN 0 4096 [::]:8145 [::]:*
LISTEN 0 4096 [::]:8146 [::]:*
10.89.58.0/24
/zmq-4-3-5-proxy zeromq_zmq-net=10.89.58.2
/zmq-4-3-5-pub zeromq_zmq-net=10.89.58.3
/zmq-4-3-5-sub zeromq_zmq-net=10.89.58.4
验证通过:宿主 8145/8146 映射 broker 的 XSUB/XPUB;三个服务位于 10.89.58.0/24 自定义网络(.2/.3/.4),发布-中转-订阅全链路有真实消息流转。
6.4 环境变量表
Compose 服务可调环境变量(由 6.2 节应用脚本定义,均有默认值):
| 环境变量 | 所属服务 | 默认值 | 说明 |
|---|---|---|---|
| ZMQ_BROKER | zmq-pub / zmq-sub | zmq-proxy | broker 服务地址(Compose 网络内用服务名;跨机部署改填 broker 所在主机 IP/域名) |
| ZMQ_INTERVAL | zmq-pub | 1 | 发布间隔(秒),调小可增大消息速率 |
libzmq 本身无运行时环境变量,其行为由 socket 选项控制,见第七节。
6.5 数据持久化说明
ZeroMQ 是纯内存消息库:broker 只做转发、不落盘、无存储目录,三个服务均无状态,不需要数据卷。唯一值得持久化的是日志(默认走 Docker 日志驱动,docker compose logs 即可读取);若需文件日志,为 broker 服务追加:
volumes:
- ./logs:/app/logs
⚠️ 注意:不要把「持久化消息」的预期带入本形态——broker 进程重启期间未投递的 PUB 消息即丢失,这是 ZeroMQ 的设计语义(见 7.1 节 LINGER/HWM)。
6.6 等价 docker run 命令
不使用编排文件时,等价的裸命令序列(网络、构建、三服务逐个拉起):
docker network create --driver bridge --subnet 10.89.58.0/24 zeromq-net
docker build -t zeromq-app:4.3.5 .
docker run -d --name zmq-4-3-5-proxy --hostname zmq-proxy --network zeromq-net -p 8145:5555 -p 8146:5556 zeromq-app:4.3.5 python /app/broker.py
docker run -d --name zmq-4-3-5-pub --hostname zmq-pub --network zeromq-net -e ZMQ_BROKER=zmq-proxy -e ZMQ_INTERVAL=1 zeromq-app:4.3.5 python /app/pub.py
docker run -d --name zmq-4-3-5-sub --hostname zmq-sub --network zeromq-net -e ZMQ_BROKER=zmq-proxy zeromq-app:4.3.5 python /app/sub.py
6.7 常用运维命令
docker compose -p zeromq ps # 查看服务状态
docker compose -p zeromq logs -f zmq-sub # 跟踪订阅端消息流
docker compose -p zeromq restart zmq-proxy # 重启 broker(pub/sub 自动重连)
docker compose -p zeromq stop # 停止全部服务(保留容器)
docker compose -p zeromq up -d # 再次拉起
docker compose -p zeromq down # 删除容器与网络(保留镜像)
docker compose -p zeromq up -d --build # 改代码后重建镜像并滚动更新
其中 restart zmq-proxy 演示 broker 重启后的自愈能力:ZeroMQ 端点按 ZMQ_RECONNECT_IVL(默认 100ms,见 7.1 节)自动重连,pub/sub 无需任何操作即恢复收发。
七、配置参数说明
ZeroMQ 没有 broker 配置文件,一切「配置」都发生在两个层面:socket 选项(代码内设置)与端点 URL(bind/connect 参数)。部署视角最常用的 socket 选项如下(默认值逐一取自 libzmq 4.3.5 源码 src/options.cpp 实查):
7.1 常用 socket 选项
| 选项 | 默认值 | 说明 |
|---|---|---|
| ZMQ_SNDHWM / ZMQ_RCVHWM | 1000 / 1000 | 发/收方向高水位:队列积压超过阈值后,PUB/SUB 类模式开始丢弃消息,REQ/REP 类模式阻塞发送 |
| ZMQ_LINGER | -1 | 套接字关闭后未发完消息的滞留时间(毫秒);-1 表示无限等待,0 表示立即丢弃,建议显式设为有限值(如 1000) |
| ZMQ_RECONNECT_IVL | 100 | 断线重连基础间隔(毫秒),broker 重启后端点约 100ms 内自动重连 |
| ZMQ_RECONNECT_IVL_MAX | 0 | 重连最大间隔(毫秒),0 表示退避间隔不增长 |
| ZMQ_MAXMSGSIZE | -1 | 单条消息大小上限,-1 表示不限制;暴露公网时建议设置 |
| ZMQ_IMMEDIATE | 0 | 1 = 连接未完成前不允许消息排队,避免首批发消息「黑洞」 |
| ZMQ_TCP_KEEPALIVE | -1 | TCP keepalive 开关,-1 表示沿用系统默认 |
| ZMQ_SUBSCRIBE / ZMQ_UNSUBSCRIBE | 无 | SUB 套接字专用:按消息前缀订阅/退订主题 |
💡 技术拓展:消息积压策略不止「丢」一种,ZeroMQ 按 socket 类型在 HWM 触发后的行为不同——PUB/SUB、PUSH/PULL 采用「丢新消息」(partially:到达阈值后拒绝新消息),REQ/REP、DEALER 采用「阻塞发送」。高吞吐广播场景要接受丢弃语义,可靠投递场景需要业务层加确认机制或改用支持持久化的中间件。
7.2 端点 URL 与绑定约定
| 端点 | 示例 | 用途 |
|---|---|---|
| tcp 通配绑定 | tcp://*:5555 | broker/服务端监听所有网卡 |
| tcp 定向连接 | tcp://zmq-proxy:5555 | 客户端连接服务端(Compose 内服务名 / 生产内网主机名 / IP) |
| ipc | ipc:///tmp/zmq-demo.ipc | 同机进程间通信(自动创建 socket 文件,注意清理与权限) |
| inproc | inproc://pipeline | 同进程线程间通信(需共享同一 Context) |
八、常见问题(FAQ)
Q1:docker compose up 报 invalid pool request: Pool overlaps with other one on this address space?
实测踩坑:compose 文件指定的 10.89.57.0/24 与宿主上其他编排项目的网络重叠,网络创建失败且首个服务卡在 Creating。解决:先用 docker network inspect <网络名> --format '{{(index .IPAM.Config 0).Subnet}}' 逐一盘点已占用网段,选一个空闲槽位写入 compose 的 ipam.config.subnet 后重新 up(本文由 57 段改用 58 段后成功)。
Q2:compose 项目与其他项目的容器互相干扰(up 时出现 orphan 警告)?
在同名目录运行 compose 会默认生成同名项目(目录名即项目名),与其他项目撞名导致 Found orphan containers 警告与资源混淆。解决:所有 compose 命令显式带独立项目名 -p zeromq(本文所有命令已如此)。
Q3:订阅端一条消息都收不到?
最常见原因是「慢加入者」:PUB 端先启动发送、SUB 端后建立订阅关系,早期消息被丢弃。解决:订阅端先 setsockopt_string(zmq.SUBSCRIBE, ...)、connect 后留出几百毫秒(本文脚本 time.sleep(0.5))再让发布端开跑;生产上建议用 XPUB 的订阅事件或业务层握手对齐。
Q4:broker 端口绑定失败(Address already in use)?
用 ss -ltnp | grep -E '5555|5556' 找到占用进程;本部署约定 5555/5556 仅在编排网络内部使用、宿主侧统一映射 8145/8146,若宿主侧端口冲突,改 compose 端口映射左侧为其他空闲端口(如 8147/8148)并同步防火墙策略。
Q5:systemd 日志出现 Special user nobody configured, this is not safe!?
这是对 User=nobody 的常规安全提示(5.2 节实测原文),服务仍正常运行。生产环境按 5.2 节建议改为专用系统用户即可消除。
Q6:broker 重启后消息会丢吗? 会。ZeroMQ 全内存、无持久化,PUB 模式下 broker 重启窗口内发布的消息不会补投(PUB 本身也是「丢弃语义」)。要求不丢消息时:改用 REQ/REP + 业务层重试,或换用支持持久化的消息中间件。
九、参考链接
- libzmq Releases:https://github.com/zeromq/libzmq/releases
- zmq_proxy 官方 API 文档:https://libzmq.readthedocs.io/en/latest/zmq_proxy.html
- socket 选项官方文档(zmq_setsockopt):https://libzmq.readthedocs.io/en/latest/zmq_setsockopt.html
- ZeroMQ 官方 Guide(broker/代理模式章节):https://zguide.zeromq.org/docs/chapter2/#The-Dynamic-Discovery-Problem
- pyzmq 文档:https://pyzmq.readthedocs.io/
- 本平台《ZeroMQ 4.3.5 介绍与选型指南》:《ZeroMQ 4.3.5 介绍与选型指南》
- 本平台《Ubuntu 22.04 安装 ZeroMQ 4.3.5 指南》:《Ubuntu 22.04 安装 ZeroMQ 4.3.5 指南》