Swift使用SwiftyZeroMQ发布首条消息后无法识别新订阅者求助
问题现象
- 基于Swift实现的ZeroMQ发布端,发出首条消息后,后续新接入的订阅端无法正常建立订阅连接,没法实现多订阅端随时接入、断开并稳定收流的需求
- 目前的场景验证结果:只有当订阅端在发布端发送首条消息前完成连接,或是先接好所有订阅端再启动发布应用,才能正常收消息。相同逻辑用Python实现的发布端没有任何启动顺序要求,IP、端口、主题、消息格式等配置已经全部排查确认没问题,跨语言组合的测试结果也排除了跨栈协议兼容的问题
- 全程没有显性报错:不按指定顺序启动时,订阅端的轮询器完全不触发;按顺序启动时,轮询器可以正常触发、正常收消息
- 已完成的全组合测试:
- 同设备Swift发布端到Swift订阅端:只有按指定启动顺序才能正常工作
- 跨设备Swift发布端到Swift订阅端:只有按指定启动顺序才能正常工作
- Swift发布端到Python3订阅端:只有按指定启动顺序才能正常工作
- Python3发布端到Swift订阅端:不受启动顺序影响,工作正常
- Python3发布端到Python3订阅端:不受启动顺序影响,工作正常
问题根因
结合ZeroMQ PUB/SUB的原生运行机制,对照测试结果可以确定,问题出在Swift发布端的socket配置上:
- 现有代码里设置的发送缓冲区只有4096字节,同时在初始化阶段就把linger设成了0,两个配置叠在一起,直接把ZeroMQ PUB socket默认的新连接握手缓冲机制给破坏了
- ZeroMQ原生的PUB socket本来会对新接入的SUB连接做短暂的状态保留,等SUB把自己要订阅的主题发过来,完成双向握手之后,再开始推送对应消息,不会一上来就把新连接当成未准备好的连接直接丢弃。但当发送缓冲区被设到极小值,又开了零滞留模式,PUB端在首条消息发出去之后,缓冲区被占满,新连上来的SUB还没来得及发送订阅主题,PUB端就直接丢弃了这些新连接的后续推送权限,和现在观测到的异常现象完全匹配
可落地解决方法
- 调整发布端的socket初始化参数
- 移除过小的发送缓冲区配置,如果确实需要自定义缓冲区大小,建议设置到256KB(262144字节)以上,和ZeroMQ默认的缓冲能力对齐
- 不要在socket初始化阶段直接设置
setLinger(0),只在主动关闭socket的环节再配置这个参数,避免运行期的连接缓冲机制被提前关闭 - 补充配置PUB socket的握手间隔参数,给新接入的SUB预留足够的握手时间,确保新连接能完成订阅规则的双向同步
- 优化发布端的消息推送逻辑
- 在常规业务消息之外,每间隔100ms到500ms推送一条固定主题的轻量心跳探测消息,不依赖业务消息驱动连接状态更新,确保新接入的SUB在完成订阅设置后,能快速收到探测消息激活连接
验证测试方案
- 启动Swift发布端,持续发送10条以上业务消息后,再启动Python/Swift订阅端,观察是否能正常接收后续的持续推送
- 模拟运行过程中订阅端随机断开、随机接入的场景,观察所有连接的订阅端是否能无延迟稳定收流
- 对比调整参数前后,不同启动顺序下的连接稳定性,确认是否完全消除启动顺序依赖
内容的提问来源于stack exchange,提问作者Andreas Gising
相关产品推荐
相关产品推荐

