Skip to content

systemd 显示 active,为什么数据链仍然是死的

systemctl is-active 返回 active,只说明 systemd 认为主进程还活着。它不证明相机已经出帧、Unix socket 正在提供数据、下游完成握手,更不证明 topic 达到目标频率。

这次故障里,上游相机服务一直是 active,下游视觉服务却无限重连。真正的问题藏在两组看似合法、组合后却不可能工作的配置里。

现场症状

系统启动后:

  • 相机服务为 active (running)
  • 下游进程也没有立即退出;
  • 客户端日志持续显示 socket reconnect;
  • 预期的图像输入始终没有建立;
  • IMU 等其他接口仍然正常,容易让人误判为“偶发启动顺序问题”。

第一反应通常是增加 RestartSec、延长启动延迟或让客户端无限重试。但这些操作只会延后暴露根因。

错误判断:把进程存活当成服务可用

systemd 默认关注的是进程生命周期。对于 Type=simple 服务,只要进程成功启动且没有退出,unit 就可以进入 active 状态。

业务 readiness 是另一回事。相机流水线至少要满足:

  1. 设备已经成功打开;
  2. 必需的硬件处理链已经创建;
  3. 目标输出模式确实启用;
  4. socket 或输出端口完成监听;
  5. 下游能收到格式、尺寸和时间戳都正确的数据。

缺少任何一步,进程都可能仍然活着。

证据链:不要先改重试次数

排查顺序应该从 producer 到 consumer:

1. 核对最终生效配置

这次配置允许“启用下游 DMA-BUF consumer”,同时“关闭生成完整 atlas 所必需的硬件处理”。两个开关单独看都合法,组合起来却意味着 consumer 永远等不到目标输出。

如果配置系统只校验字段类型,不校验跨字段约束,故障就会被推迟到 runtime。

2. 检查 producer 是否真的创建输出

不要只看服务日志里的“started”。需要确认:输出 socket 是否创建、类型是否正确、owner/mode 是否符合预期、producer 是否真的进入 publish loop。

3. 检查 consumer 重连的相对时序

记录 producer 启动、socket listen、首帧、consumer connect、首个有效数据之间的单调时间。这样才能区分“启动较慢”和“永远不会 ready”。

4. 最后看业务输出

对于 ROS 或流式系统,至少检查 topic 是否存在、频率是否达到合同、时间戳是否推进、序列号是否连续。服务 active 不能替代这些证据。

根因与修复

根因是缺少配置级 capability gate。修复后,在服务真正启动硬件链之前就验证:

text
enable_direct_consumer = true
  ⇒ enable_required_transform = true
  ⇒ output_layout = full_atlas

不满足时立即失败,并输出可读的配置错误,不能让下游进入无限重连。

socket 清理也必须谨慎。启动时不能对一个可配置路径无条件 unlink,需要先检查文件类型、owner 和当前是否存在活跃 listener,避免删除了不属于本服务的对象。

怎样建立真正的 readiness

有条件时可以使用 Type=notify,由进程在完成设备初始化、输出端建立和首轮自检后发送 READY=1。但这仍只是进程内部 readiness,外部 health check 还应补充:

  • 输出端口或 socket 可连接;
  • 首帧在超时内到达;
  • topic/rate 位于允许范围;
  • 关键时间戳和 sequence 持续推进;
  • consumer 重连次数没有持续增长。

修复后的验收

验收不应该只写“服务已恢复”。更可靠的记录是:

text
T0      systemd 启动 producer
T0+Δ1   设备与硬件处理链 ready
T0+Δ2   socket 开始监听
T0+Δ3   consumer 连接成功
T0+Δ4   首个有效 frame 到达
steady  topic/rate/sequence 持续满足合同

同时还要测试两条失败路径:配置组合非法时必须启动失败;producer 重启后 consumer 必须能够重新建立连接,并且不会读到旧 socket 或旧 buffer。

结论

active 是 liveness,不是 readiness,更不是数据面健康。涉及相机、NPU、VINS、串口或网络流时,完成线必须延伸到真实输出、频率、时间戳和重连行为。

参考:READY=1 的语义见 sd-daemon 官方接口说明