systemd启动OpenSplice发布端无法发布数据问题排查
问题概述
部署在Ubuntu 20.04上的systemd托管OpenSplice发布端存在以下固定异常:
- 开机由systemd自动拉起时,无法正常发布数据,OpenSplice日志无任何报错
- 命令行手动启动,或开机后手动重启systemd服务,发布端功能完全正常
已完成的排查项: - 跨机器部署的发布、订阅端QoS配置完全匹配
- 网络内无其他DDS参与者冲突,所有机器重启验证、调整重启顺序均无法解决问题
- 2022年9月16日补充验证:普通UDP协议编写的发布程序存在完全相同的异常,确认问题与systemd启动顺序、依赖配置相关;将服务启动时机调整到用户登录前,异常仍未解决
现有配置
systemd服务单元文件
[Unit] Description=Publisher Process Documentation= After=network.target StartLimitIntervalSec=0 [Service] Type=simple WorkingDirectory=/opt/publisher/bin ExecStart=/opt/publisher/bin/publisher.sh Restart=always RestartSec=2 [Install] WantedBy=multi-user.target
原始启动脚本publisher.sh
#!/bin/bash cd /opt/publisher/bin source bashrc_local # 程序崩溃后自动拉起保活 while true; do ./publisher sleep 15 done
当前临时规避方案
通过先启动无关进程等待30秒再拉起正式服务绕过问题:
#!/bin/bash cd /opt/publisher/bin source bashrc_local timeout 30 ./remote_processor killall remote_processor # 程序崩溃后自动拉起保活 while true; do ./publisher sleep 15 done
根因说明
问题核心是network.target的语义不符合常规预期:Ubuntu 20.04的systemd中,network.target仅代表网络管理服务的启动流程已触发,完全不代表物理网卡链路up、IP地址分配完成、路由表生效、网络接口初始化完成。
开机阶段systemd并行启动服务的速度远快于网络栈就绪速度,此时启动的DDS/普通UDP程序会绑定到未就绪的网络接口,后续网络栈就绪后,程序默认不会重新探测网络接口状态,直接导致数据发送失败,且这类底层套接字绑定异常通常不会输出到应用层日志。手动重启服务时网络早已完全就绪,因此功能正常。
调整服务到用户登录前启动不生效的原因是,多数场景下(尤其是DHCP动态分配IP的环境)用户登录触发时机早于网络完全就绪的时间点,单纯切换启动target无法精准匹配网络可用的时机。
根本解决方法
方案1:修正systemd服务依赖,对齐网络就绪判定标准
替换原有服务单元中错误的network.target依赖,改为等待网络完全就绪的target,修改后的服务文件如下:
[Unit] Description=Publisher Process Documentation= After=network-online.target Wants=network-online.target StartLimitIntervalSec=0 [Service] Type=simple WorkingDirectory=/opt/publisher/bin ExecStart=/opt/publisher/bin/publisher.sh Restart=always RestartSec=2 [Install] WantedBy=multi-user.target
执行对应命令启用网络等待服务,否则network-online.target不会主动阻塞等待网络就绪:
# 若使用NetworkManager管理网络(Ubuntu桌面版默认) systemctl enable --now NetworkManager-wait-online.service # 若使用systemd-networkd管理网络(Ubuntu Server精简配置默认) # systemctl enable --now systemd-networkd-wait-online.service
提示:静态IP场景下可修改对应wait-online服务的超时参数,将默认2分钟超时调整为30秒,避免不必要的开机等待。
方案2:启动脚本内置网络探测逻辑(推荐,无全局副作用)
如果不想修改全局网络等待配置、延长整体开机时间,可以直接在启动脚本中增加业务侧的网络就绪判定,确认满足业务通信条件后再启动发布程序,替换原有publisher.sh内容如下:
#!/bin/bash cd /opt/publisher/bin source bashrc_local # 网络就绪探测,将eth0替换为实际承载业务流量的网卡名 while true; do # 检查网卡已分配非回环IP ip addr show eth0 | grep -w 'inet' | grep -v '127.0.0.1' >/dev/null 2>&1 IP_OK=$? # 检查对应网卡已配置默认路由 ip route show default | grep -w 'eth0' >/dev/null 2>&1 ROUTE_OK=$? if [ $IP_OK -eq 0 ] && [ $ROUTE_OK -eq 0 ]; then break fi sleep 2 done # 原有保活逻辑 while true; do ./publisher sleep 15 done
该方案完全匹配业务实际需要的网络条件,不依赖systemd的target判定逻辑,也不会影响其他开机服务的启动速度。
方案3:OpenSplice侧配置接口自动重探测(DDS场景加固)
针对OpenSplice场景可额外增加配置,让服务运行过程中自动感知网络接口变化,彻底规避启动时网络未就绪的影响。在OpenSplice配置文件的NetworkService段增加如下配置:
<NetworkService> <!-- 保留原有其他配置 --> <Interface> <AutoDetectInterface>true</AutoDetectInterface> <InterfaceRefreshInterval>10</InterfaceRefreshInterval> </Interface> </NetworkService>
配置后OpenSplice每10秒检查一次网络接口状态,链路恢复、IP变化后会自动重新绑定网卡,不需要重启服务。
内容的提问来源于stack exchange,提问作者Damian Dixon

