VLink 2.0.0
A high-performance communication middleware
Loading...
Searching...
No Matches
故障排查手册 · Troubleshooting

按"症状 → 可能原因 → 如何确认 → 如何处置"结构组织。搜索关键词请用浏览器 Ctrl+F。

万能第一步:vlink-check diag。它会一次性跑 40+ 项自检(见 §1)。

找不到你的问题? 直接跳到 §24 按错误字符串速查。

目录:

  1. 先跑 vlink-check diag
  2. 构建期问题
  3. 启动期问题
  4. 通信建立不起来 / 收不到数据
  5. 性能问题(延迟抖、丢样本、CPU 高)
  6. SHM / Iceoryx 专属
  7. DDS 专属
  8. Bag 录制回放
  9. C API / Python / 跨语言
  10. CLI 工具异常
  11. 还没排出来?
  12. 每个 CLI 工具错误目录
  13. 每个 Transport 专属 init 错误
  14. 运行时异常分类速查
  15. Discovery 深入
  16. 平台专属陷阱
  17. QoS + 安全兼容性
  18. 容器 / K8s / VPN 部署
  19. 插件加载失败
  20. Bag 损坏 / 恢复
  21. 日志调优
  22. 版本 / ABI 不匹配
  23. 性能反模式 & 调试技巧
  24. 按错误字符串速查(Reverse Lookup)

1. 先跑 vlink-check diag

诊断命令会按顺序检查(源代码:cli/check/check.cc)。按分组整理如下:

分组 自检项 失败时候的大致含义
构建 / 主机 Check vlink version... / Check platform info... / Check hostname... / Check machine id... / Check cpu cores... 用于问题上报时收集的基础身份信息
IP / DDS Check available IP addresses... 机器上只有 lo 或无 IP,所有跨机 transport 都不会工作
IP / DDS Check VLink DDS IP available... VLINK_DDS_IP 设置了但不在本机 IP 列表里
IP / DDS Check VLink DDS interface... VLINK_DDS_IP 对应的网卡找不到
IP / DDS Check VLink DDS interface MTU... 网卡 MTU < 1500:大报文会被分片甚至丢弃
IP / DDS Check VLink multicast address... 路由表里没有 239.255.0.100 —— 服务发现会失败
IP / DDS Check DDS multicast address... DDS 默认组播 239.255.0.1 未配通
IP / DDS Check VLINK_DDS_DOMAIN range... 域 ID 超出 [0,232],多数 DDS 栈会拒绝
内核 / 网络 Check net.core.rmem_max/wmem_max... UDP 收/发缓冲太小:高码率 DDS/Zenoh 会丢样本
内核 / 网络 Check rp_filter... rp_filter=1 会静默丢弃异步网卡的多播回包
进程限额 Check RLIMIT_NOFILE... 文件描述符上限太低:DDS 会开不出足够 socket
进程限额 Check RLIMIT_MEMLOCK... 锁页内存太小:SHM 零拷贝池会分配失败
文件系统 Check available space for log dir... 日志盘不足(建议 >1 GB 余量)
文件系统 Check log dir writable... 日志目录不可写(权限 / 只读挂载)
文件系统 Check /dev/shm space... 共享内存池空间不足:SHM/shm2 / iceoryx 无法创建段
文件系统 Check VLINK_PLUGIN_DIR / PROTO_DIR / FBS_DIR 环境变量指向的目录不存在或不是目录
文件系统 Check VLINK_QOS_CONFIG / FASTDDS_QOS_FILE / CYCLONEDDS_URI QoS / 后端配置文件路径无效
文件系统 Check VLINK_LOG_LEVEL value... 日志级别不在 [0,6] 范围(含 6=Off),会回退默认值
运行时健康 Check cpu usage... 当前负载过高(>90% 触发 FAIL);后续测量不准
运行时健康 Check memory usage... 内存紧张(>90% 触发 FAIL);SHM 分配可能失败
运行时健康 Check singleton lock... 单例锁目录存在争用,可能有残留进程或权限问题
运行时健康 Check time sync daemon... 没有 chrony/ntpd/systemd-timesyncd:bag 时间戳会乱序
运行时健康 Check iox-roudi running... RouDi 未运行,shm:// 透明传输会失败
进程 Check proxy/bag/dump/eproto/efbs running... 相关 CLI 是否已运行;排查重复启动或互相抢资源
进程 Check monitor/viewer/player/analyzer running... 同上
进程 Check bench/webviz running... 基准与网页可视化工具是否已运行
进程 Check others running... 通过 vlink-list -nc 统计当前是否还有 vlink 用户进程

看到 FAILED 行的 [DETAIL] 列:直接给出了失败原因字串,参考下面各节处理。

vlink-check diag 新增参数:

  • -s / --summary:执行完毕后打印 PASSED / WARNING / FAILED 统计,便于 CI 汇总;
  • -f <substring> / --filter <substring>:只跑标题包含子串的诊断项,例如 -f dds 只关心 DDS 相关检查;
  • -a / --all:附加打印所有 VLINK_ENABLE_* 编译选项状态。

vlink-check env 会把 cli/check/check.cc 内显式列出的那组 VLINK_* 环境变量逐条打印出来(是否已设置、当前值),并在末尾输出汇总行。清单项按编译时模块开关动态裁剪:未启用 VLINK_SUPPORT_ZENOH / VLINK_SUPPORT_SHM2 / VLINK_SUPPORT_MQTT / VLINK_SUPPORT_DDS* / VLINK_SUPPORT_SOMEIP / VLINK_SUPPORT_INTRA 等模块时,相关 env 段会自动隐藏;未启用 VLINK_ENABLE_CLI_BENCHVLINK_BENCH_* 也会隐藏。完整清单仍以 doc/21-environment-vars.md 为准。可用 -p <prefix> 按前缀过滤,例如 vlink-check env -p VLINK_ZENOH_ 只看 Zenoh 专属变量。-b/--available 只显示已设置项。

vlink-check test 分两段:

  • Part 1 在 intra:// 上跑 Event / Method / Field 三种 paradigm 的最小往返(对应 Publisher/SubscriberClient/ServerSetter/Getter)。
  • Part 2 按 VLINK_SUPPORT_* 宏遍历当前构建进产物的所有传输后端(intra / shm / shm2 / dds / ddsc / ddsr / ddst / zenoh / someip / mqtt / fdbus / qnx),每个后端跑一次同进程 Publisher/Subscriber 往返;需要外部依赖的后端(如 shm:// 经由 vlink::ShmConf::has_roudi_running() 探测 RouDi、someip:// 需要 VLINK_SOMEIP_CFG)在前置条件不满足时直接跳过(WARNING),**不会**真去调用可能 std::terminate 的底层栈。

退出码 = FAILED 的子测试数;WARNING 只告警、不计入。


2. 构建期问题

2.1 编译时 static_assert: is_supported(type) / kUnknownType

**原因**:你给 Publisher<T> / Subscriber<T> 等传了一个 Serializer 不认识的类型。

**如何确认**:看看 T 是否满足 06-serialization.md 14 种触发条件中的某一个。

**修复**:

  • POD:确保 std::is_trivial_v<T> && std::is_standard_layout_v<T> 都是 true(不能带虚函数、不能有非 trivial 的成员)
  • Protobuf:用 message 类型,确保有 SerializeToArray() / ParseFromArray()
  • FlatBuffers:用 object-API(继承 flatbuffers::NativeTable)或 builder 模式
  • 自定义:实现 operator>>(Bytes&)operator<<(const Bytes&) 让它匹配 kCustomType

2.2 Could not find package vlink::<module>

**原因**:你 find_package(vlink REQUIRED COMPONENTS shm dds) 但 VLink 构建时 SKIP_SHM=ON 或依赖缺失导致该 module 没编出来。

**确认**:跑 vlink-info -lENABLE_SHM / ENABLE_DDS 等开关是否 ON。

**修复**:重新构建 VLink 时显式 -DSKIP_SHM=OFF,或在你的项目里改用 find_package(vlink REQUIRED COMPONENTS all) 自动适配当前安装。

2.3 找不到 iceoryx_posh / fastdds / 其它 third-party

**原因**:Conan 或系统包管理没装上这些依赖。

**修复**:用 Conan:conan install . --build=missing。或参考 01-build.md 逐个装。

2.4 Protobuf 版本冲突

**症状**:link error: multiple definition of google::protobuf::...

**原因**:libprotobuf-lite 与 libprotobuf 混用;或 VLink 用系统 protobuf、你的项目用 vendor protobuf。

**修复**:两边统一。查 pkg-config --modversion protobufgrep 'find_package(Protobuf' /path/to/YourCMake.txt

2.5 -Wconversion / -Werror 开着的时候 VLink 头报一堆 warning

**原因**:VLink 头大量使用 int64_tsize_t 互转;对 -Wconversion 严苛的项目会爆。

**修复**:在 link 到 VLink 的 target 上临时 target_compile_options(... PRIVATE -Wno-conversion) 屏蔽该警告源。

2.6 clang-tidy 报一堆 readability-identifier-naming 在 VLink 头

**原因**:你在项目里开了全局 clang-tidy,但它把 VLink 头的 kCamelCase 判为违规。

**修复**:.clang-tidyHeaderFilterRegex 只限你自己的代码,排除 VLink 安装路径(/usr/local/include/vlink/.*)。

2.7 undefined reference to vlink::...

**原因**:链接时缺 vlink::vlink 基础库,或只链了 module 没链 core。

**修复**:

target_link_libraries(app PRIVATE vlink::vlink vlink::shm vlink::dds)
# ^^^^^^^^^^^^^^^
# 必须!modules 依赖 core

3. 启动期问题

3.1 构造 Publisher 直接抛异常(vlink::Exception::RuntimeError

**常见根因**(源:src/impl/url_parser.cc):

  • URL 格式错误 —— 具体错误消息见 §19 和 §24 速查:
    • "The URL transport prefix cannot be empty." → URL 不含 xxx://
    • "Invalid character found in the URL transport prefix." → scheme 含非法字符
    • "A path is required on a hierarchical URL, even an empty path." → 少了 path 部分
    • "Bad key in the query string!" → query 里写错参数名
  • 指定的 transport module 未编进这次构建(例如用 ddsr://SKIP_DDSR=ON)—— 运行时由 url.cc"Unsupported plugin module"
  • DDS domain 冲突、多播端口被占用、或 Iceoryx RouDi 还没起

**确认**:

# 开启详细日志
export VLINK_LOG_LEVEL=0
./your_app 2>&1 | head -50

**修复**:按日志指示排查;或用 InitType::kWithoutInit 延迟 init、在外层捕获异常后重试。

3.2 进程一启动就挂死(没日志、没报错)

**常见根因**:

  • shm:// 但 SHM 守护进程没起(见 §6)
  • 多播网卡绑错:Linux 上路由默认走 eth0,但服务发现想走 eth1
  • 使用了 kWithInit 的 Server/Client 且构造函数里阻塞等待连接
  • Iceoryx RouDi 在运行但 mempool 耗尽(loan() 返回并阻塞)

**确认**:

strace -f -p <pid> # 看是否卡在 recvfrom / sem_wait
ls /dev/shm/ # 看有无 iceoryx* 段
ps aux | grep -E "iox-roudi|vlink-proxy"

**修复**:

  • **首选**:起 vlink-proxy -c(内嵌 iox-roudi + 针对 VLink 载荷分级的 chunk 内存池:默认 -l 2 Middle = 7 档 / -l 3 High = 8 档 / -l 1 Low = 6 档;自带远程监控能力)—— 详见 §6.1
  • 绑定网卡:export VLINK_INTRA_BIND=eth0;或直接在 URL 写 shm://iface=eth0/topic
  • 改用 InitType::kWithoutInit + 显式 init() + 超时控制

3.3 Failed to load plugin / Unsupported plugin module

**源码引用**:src/impl/url.cc:295src/base/plugin.cc:162-287

**原因**:VLINK_URL_PLUGINSVLINK_PLUGIN_DIR 指向的 .so 找不到 / ABI 不匹配 / 不是 VLink 插件。

**修复**:检查文件存在;ldd plugin.so 看依赖;插件符号必须用 VLINK_PLUGIN_EXPORT 宏导出。完整插件错误见 §19。

3.4 Program has started.(vlink-proxy 拒绝启动)

**源码**:proxy/proxy.cc:109

**原因**:本机已有 vlink-proxy 在跑(同 domain id)。

**修复**:ps aux | grep vlink-proxy;找到旧实例 kill 掉,或改用不同的 -d 域。


4. 通信建立不起来 / 收不到数据

4.1 pub.has_subscribers() 永远为 false

检查清单**(从最常见排起):

  1. URL 是否**完全一致**?shm://a/bshm://a/b?qos=sensor **不是同一个 endpoint**(domain 可能变)
  2. vlink-list -n 能否看到两端都在?两端是否看对方?
  3. Domain 是否一致?两端 URL 的 ?domain=XVLINK_DDS_DOMAIN 一致?
  4. 安全模式是否匹配?一端 kWithSecurity、另一端 kWithoutSecurity —— **不通

  1. Serializer 类型是否匹配?一端用 Protobuf、另一端用 FlatBuffers —— 即使消息在线上看起来相似也匹配不上
  2. 多播路由:vlink-check diag 中的 "VLink multicast address" 必须 PASSED

4.2 跨机器看不到对方

**高频根因**:

  • 防火墙挡了 UDP(Linux 上 sudo ufw status;关:sudo ufw disable;或精准开放 239.255.0.0/24)
  • 多播未启用:ip link show eth0 | grep MULTICAST 应该有 MULTICAST
  • 容器网络:Docker --net=host 下 OK,bridge 下多播默认不通
  • VPN / 跨子网:DDS 不路由 UDP 多播;跨 NAT 场景可用 zenoh://(内置 NAT 穿透),或在局域网两端各配置静态单播对端 IP(VLINK_DDS_PEER / dds_implpeer_ip

**修复**:

# 临时验证多播可达
iperf -s -u -B 239.255.0.100 -i 1 # 接收端
iperf -c 239.255.0.100 -u -T 1 -t 3 # 发送端

4.3 订阅回调偶尔少触发

**看两点**:

  • QoS History depth:设置太小(如 KeepLast(1))对突发流量会丢;kSensor 默认 20
  • set_latency_and_lost_enabled(true) 后查 get_lost().lost —— 明确告诉你丢了几条

4.4 SecurityPublisherSecuritySubscriber 连通但乱码

**原因**:密钥不一致;或一端设了 set_security_key 另一端设了 set_security_callbacks

**修复**:两端用完全相同的配置。并检查 OpenSSL 版本是否匹配(不同 OpenSSL 的 PKCS7 填充细节不完全相同,但 VLink 统一用 EVP API,一般没事)。

4.5 Server::listen 被调用了两次

**原因**:同一 Server 对 listen / listen_for_reply 多次注册,后者覆盖前者。

**修复**:一个 Server 只注册一个 callback;需要多条逻辑在 callback 里分发。


5. 性能问题(延迟抖、丢样本、CPU 高)

5.1 P99 延迟明显高于 P50

**做法**:

# 1) 用 vlink-bench 基准对比
vlink-bench run --preset quick --report terminal
# 2) 订阅端开启延迟统计
sub.set_latency_and_lost_enabled(true);
VLOG_I("latency=", sub.get_latency(), " us");

**可能原因**:

  • CPU 没 isolcpu / governor 不是 performance
  • MessageLoop 被阻塞任务挡住(避免在回调里做重活;用 ThreadPool 转出去)
  • History::kKeepAll 让 Reliable 重传无限等待
  • NUMA 错位:pub/sub 在不同 NUMA node,memcpy 穿桥延迟高
  • 中断亲和性:网卡 IRQ 没 pin 到专用核

5.2 吞吐上不去

  • 检 QoS:Reliability=Reliable + PublishMode=Sync 会序列化到单一网络栈栏;改 ASync
  • 大消息:用 zerocopyloan()),别让序列化层 memcpy
  • DDS:检查 block_time 是否太长(默认 100 ms);VLINK_DDS_BUF 调高 socket buffer
  • MTU:大消息分片多 → 调 VLINK_DDS_MTU 或开 Reliable+Heartbeat 延长

5.3 CPU 占用异常高

  • 关掉调试日志:export VLINK_LOG_LEVEL=3(Warn)或更高
  • 关闭剖析器:export VLINK_PROFILER_ENABLE=0
  • vlink-monitor 看哪个 endpoint 的 cpu_usage 最高
  • 序列化类型走 kStreamType(文本)性能远差于 kStandardType(二进制)或 kBytesType(直通)

5.4 延迟统计本身带来抖动

set_latency_and_lost_enabled(true) 需要每条消息附带时间戳并在订阅端做计算。生产环境建议关掉,只在调试时开。


6. SHM / Iceoryx 专属

6.1 shm:// endpoint 报错启动不了

**原因**:SHM 后端依赖一个共享内存守护进程(Iceoryx RouDi)提前启动。如果该进程没起,所有 shm:// 端点都会构造失败。

✅ 首选修复:vlink-proxy -c

VLink 自带的 vlink-proxy 工具在带 -c 时,会在自己进程里**内嵌启动 iox-roudi**,按 -l 选择分级 chunk 预分配内存池:默认 -l 2(Middle,7 档,等价 proxy/etc/proxy_roudi.toml);点云/重载场景可切到 -l 3(High,8 档,等价 proxy_roudi_large.toml);嵌入式轻量端侧 -l 1(Low,6 档,等价 proxy_roudi_small.toml)。下表展示 High 档(-l 3)的内存池布局:

Chunk 容量 预分配个数 适配的典型载荷
1 KB 10000 控制指令 / 心跳 / 小型状态消息
16 KB 1000 小型结构化消息 / 配置
128 KB 500 IMU / GPS / CAN 批次 / 压缩后小帧
1 MB 200 普通图像帧 / 压缩点云切片
3 MB 100 高分辨率图像
6 MB 50 多相机帧 / 中型点云
13 MB 30 大尺寸点云 / 稀疏张量
24 MB 20 超大负载 / 原始图像批

核心思路:**小 chunk 多、大 chunk 少**,既覆盖控制指令到原始点云的全量程载荷,又不会让少量大消息把小消息路径的 chunk 抢空。绝大多数 VLink 应用无需自己配 iox-roudi:

# 最省心的一行:-c 使用内置默认配置(推荐)
vlink-proxy -c
# 指定自定义 iox-roudi TOML 配置
vlink-proxy -c /path/to/custom_roudi.toml
# -l 选内存策略:1=Low / 2=Middle(默认)/ 3=High
vlink-proxy -c -l 3
# -m on/off 控制 Iceoryx 监控
vlink-proxy -c -m off
# 验证
ls /dev/shm | grep iox # 应能看到 iceoryx* 段

vlink-proxy 同时提供跨机器/远程拓扑可视化能力(详见 16-proxy.md),一个进程就把"SHM 守护 + 远程监控"都带起来。

⚠️ 备选:独立跑 iox-roudi

仅当你有明确的部署限制(例如不能运行 vlink-proxy)时才需要这样做:

iox-roudi -c /path/to/iceoryx_config.toml &

需要自己维护 iox-roudi 配置文件;默认内存池往往太小不够 VLink 大消息用,**建议直接复制** proxy/etc/proxy_roudi_large.toml 作为起点。

6.2 loan() 返回空 / 报 Failed to loan buffer, size: ...

**源码**:modules/shm/shm_factory.cc:640, 677, 832, 887, 1028, 1068

**原因**:共享内存池配置不够大,或你一直 loan 但忘了 publish(泄露)。

**修复**:

  • vlink-proxy -c -l 3(High 内存策略,最大档位)
  • 或者 vlink-proxy -c /path/to/your.toml 自定义更大的 mempool
  • 检查每次 loan() 后是否都有对应 publish() 或显式 return_loan()
  • set_manual_unloan(true) 时一定要在回调里显式 sub.return_loan(b)(由订阅端归还,Bytes 自身没有该方法)

6.3 Shm roudi is not supported. 错误

**源码**:modules/shm/shm_factory.cc:363

**原因**:代码路径里错误地假设可以用外部 RouDi;实际 VLink 的 shm module 只支持"代码侧 init_runtime 连到已经运行的 iox-roudi"。

**修复**:确保 RouDi(最好是 vlink-proxy -c 内嵌的那个)已在跑;业务进程里不要调 init_roudi

6.4 shm2://shm:// 能否混用

**不能**。Iceoryx v1 和 v2 是完全独立的共享内存域。两端必须统一用同一个版本。 注意:vlink-proxy -c 内嵌的是 Iceoryx v1(对应 shm://);shm2:// 无需守护进程(Iceoryx2 无中心 daemon)。

6.5 ShmConf: Input string length is too long.

**源码**:modules/shm/shm_conf.cc:60

**原因**:URL path 或 service name 超过 128 字符上限(Iceoryx 硬限制)。

**修复**:缩短路径;用 hash 替代长路径名。

6.6 shm:// 同机多个应用启动时随机出错

**原因**:RouDi 的 segment 名字与 app 名字关联;如果两个 app 叫同样名字会冲突。

**修复**:每个进程用不同的 process_name(通过 ShmConf::init_runtime(name)),或确保 argv[0] 唯一。


7. DDS 专属

7.1 dds://ddsc:// 能互通吗

**RTPS wire 协议层互通**(FastDDS 和 CycloneDDS 都符合 OMG RTPS),但要保证:

  • Domain ID 一致
  • QoS 兼容(Reliability、Durability 方向正确)
  • VLink 的 topic 命名要一致(URL path → DDS topic name 映射)

7.2 Multiple nodes with same DDS participant name

**原因**:VLink 为每个进程起一个 DDS Participant,但某些场景(同进程起多个 Publisher/Subscriber)共享同一个 Participant。正常。

7.3 DDS Security(RTPS SECURE)与 VLink Security

两者是正交的:**VLink Security 在 serializer 层加密 payload**,**DDS Security 在 RTPS 层加密报文**。可同时开启,但处理成本叠加。

7.4 kCdrType 的"安全例外"

dds:// + kCdrType 跳过 VLink 的序列化层,直接交由 DDS 做 CDR 编码 —— 这意味着 **VLink 的 kWithSecurity 模板也对这条路径无效**。代码会在构造时直接打印 "Cdr type does not support security." 并退化为明文。如需加密,要么改走 Protobuf 等,要么开 DDS Security。

7.5 Topic ... has no registered typesupport.

**源码**:modules/dds/dds_factory.cc:188

**原因**:你用了 CDR 类型但没 register_type() 注册到 DDS。

**修复**:在 SchemaPlugin 中 register schema,或直接用 Protobuf/FlatBuffers 让 VLink 自动处理。

7.6 ssl.* properties are set but CycloneDDS was built without DDS_HAS_SSL support.

**源码**:modules/ddsc/ddsc_factory.cc:488

**原因**:你的 CycloneDDS 包编译时没带 OpenSSL。

**修复**:换个带 SSL 的 CycloneDDS 发行版;或者 unset VLINK_SSL_* 先跑起来。

7.7 RTI Connext(ddsr://)报 DDS_DomainParticipantFactory_create_participant failed.

**源码**:modules/ddsr/ddsr_proxy.cc:57

**原因**:RTI license 过期、domain ID 不合法、NDDSHOME 没设、网络初始化失败。

**修复**:先确认 RTI 环境(rtiddspingpub 能否跑起来);再回到 VLink。

7.8 TravoDDS(ddst://)上 CDR 完全被禁

**源码**:所有 modules/ddst/ddst_*_impl.cc 都有 "Cdr type does not support security."

**结论**:ddst:// + security 组合下不要用 CDR 类型。FlatBuffers / Protobuf 都可。


8. Bag 录制回放

8.1 .vdb 打不开 / 损坏(Database version is incompatible.

**源码**:src/extension/database_reader.cc:1714

**原因**:

  • 录制时用的 VLink 版本太新,当前读取端太旧
  • 或 bag 文件在 writer 还未落盘前 kill -9 导致 SQLite 头损坏

**修复**:

  • vlink-bag check file.vdb 检查完整性
  • vlink-bag fix old.vdb(可选 -y/--rebuild 进入重建模式,原地写入;无 -o 选项)尝试修复损坏段落
  • 升级 VLink 到与录制端相同/更高的版本

8.2 MCAP 文件打不开(Mcap version is incompatible.

**源码**:src/extension/mcap_reader.cc:842

**原因**:MCAP 规范升级;你的 VLink 太旧。

**修复**:升级 VLink;或用 Foxglove Studio 之类的第三方工具直接读(因为 .vcap 就是 MCAP)。

8.3 回放速率跟不上原始速率

  • -r 0.5 放慢;用 -r 2.0 加速
  • 解码开销大(Protobuf 大消息):先 vlink-bag clone <src> <dst>(省略 -p,即不开压缩)得到无压缩版本再回放
  • IO 瓶颈:NVMe → HDD 差一个数量级;存档用 HDD 没问题,回放建议放 SSD

8.4 split_by_sizesplit_by_time 能同时使用吗

可以;任一条件触发都会切。时间单位是**毫秒**。

8.5 VCAP(<tt>.vcap)与 MCAP 标准兼容吗

—— .vcap 内部就是 MCAP。可以用 Foxglove 直接打开,也可以 vlink-bag2mcap 转一步(主要是改扩展名和补 schema 注册)。

8.6 Cache size is full, waiting to consume. 刷屏

**源码**:src/extension/bag_reader_processor.cc:96

**原因**:回放端消费速度跟不上读取速度;缓冲环已满。

**修复**:降低 -r 速率;或下调 QoS history depth(因为回调占用时间太长)。

8.7 The number of messages has reached the upper limit

**源码**:src/extension/database_writer.cc:1351-1353

**原因**:达到 max_row_count(需先 enable_limit=true);writer 按策略丢旧数据或丢新数据。

**修复**:加大 max_row_count,或启用 split_by_size / split_by_time 让文件自动切分,而不是丢数据。

8.8 The compile macro VLINK_ENABLE_SQLITE is not turned on.

**源码**:src/extension/database_writer.cc:317database_reader.cc:155

**原因**:VLink 构建时 ENABLE_SQLITE=OFF,<tt>.vdb 读写不可用。

**修复**:重新构建时打开 -DENABLE_SQLITE=ON;或只用 .vcap/MCAP。


9. C API / Python / 跨语言

9.1 VLINK_RET_RUNTIME_ERROR 是什么意思

c_api.h:153 定义:C++ 构造或初始化过程中抛出了异常。 常见触发:

  • URL 格式错(VLINK_RET_INVALID_ERROR 单独用于空指针/坏 handle)
  • Transport module 运行时初始化失败(例如 DDS 域启动失败)

**调试**:临时把 VLINK_LOG_LEVEL=0 看 C++ 层的异常 what() 信息。

9.2 Python 侧 ImportError: cannot import _vlink_nanobind

  • 先确认装了 ENABLE_PYTHON_API=ON 构建出的 _vlink_nanobind.so
  • LD_LIBRARY_PATH 包含安装目录的 lib/python
  • Python 版本需与构建时一致(nanobind 是 ABI 强绑定)

9.3 VLINK_RET_MEMORY_ERROR 是什么

vlink_get() 之类:调用者给的 buffer 太小。先 vlink_get(..., NULL, &size) 查需要多少,再 allocate 重试。

9.4 VLINK_RET_TRANSFER_ERROR

publish / listen / invoke 操作失败。对 publisher:多数情况是没有订阅者(先 vlink_has_subscribers 检查)或者 transport 层 send 失败(网络/shm 问题)。

9.5 C API handle 用完忘了销毁,进程退出时卡住

**原因**:vlink_destroy_* 没调用;析构时 C++ 端试图等待 deinit,但 handle 已 leak。

**修复**:每个 vlink_create_* 必须有对应的 vlink_destroy_*;放入 RAII wrapper / finally 块。


10. CLI 工具异常

10.1 vlink-list 看不到任何节点

→ 跑 vlink-check diag。十有八九是 "VLink multicast address" FAILED(路由表没有 239.255.0.100)。

**临时 workaround**(Linux):

sudo ip route add 239.255.0.100/32 dev eth0

10.2 vlink-eproto subMust set proto dir

  • -d /path/to/protos 指定 proto 目录
  • export VLINK_PROTO_DIR=/path/to/protos
  • 或注册 VLINK_SCHEMA_PLUGIN(schema 插件 — 见 19-extensions.md

10.3 vlink-monitor TUI 花屏

终端不支持某些控制序列。用 TERM=xterm-256color;或关闭分页 --no-pagervlink-bench 里也一样)。

10.4 vlink-bench run 的某些 case 被 SKIPPED

这是设计:intra:// + mode=process 会自动跳(跨进程 intra 无意义);quick 预设也会做分层抽样。加 --verbose 看每个被跳过的原因。

10.5 vlink-bag recordSync mode and task depth cannot be set at the same time

**源码**:cli/bag/bag.cc:2825

**原因**:-s/--sync_mode--max_task_depth 冲突(sync 不需要队列)。

**修复**:二选一。


11. 还没排出来?

  1. 收集:vlink-info -l 输出 + vlink-check diag 全文 + 一段有 VLINK_LOG_LEVEL=0 的日志
  2. 精简复现:最小 pub/sub 双端程序 + URL
  3. 到项目 issue 里提交,标签 triage

12. 每个 CLI 工具错误目录

以下所有错误都是 CLI 工具 std::cerr 直接输出的 —— grep 你看到的字串可以精确定位到源码行。

12.1 vlink-bagcli/bag/bag.cc

错误字串 常见原因
The target file not exists. 1146+ 指定的 bag 文件不存在 / 路径错
Invalid time (input error). 1176+ --start / --duration 时间戳格式错
Invalid time (duration error). 1242+ duration ≤ 0
Invalid datatime. / Invalid systime. 1182+ 时区 / 格式不支持
Can't find any urls to play. 1357 bag 元数据缺失或空 URL 列表
The source file is same as target file. 1598 clone/merge 时源 = 目标
Tag name can not be empty. 2289 tag 子命令缺名字
Sync mode and task depth cannot be set at the same time cli/bag/bag.cc --sync_mode 校验段 -s--max_task_depth 冲突
Sync mode and memory size cannot be set at the same time 同上 -s--max_memory_size 冲突
You cannot use diff time formats at the same time cli/bag/bag.cc 时间参数互斥校验段 -b 用了多个冲突格式
BagWriter force to quit. 785 收到 SIGINT 或 OOM,writer 被强制终止
Failed to load plugin (...) 1255 schema 插件缺失(见 §19)
filesystem_error 回溯 多处 权限 / 磁盘满 / 路径不存在

12.2 vlink-checkcli/check/check.cc

参见 §1 的自检表 + 每项 FAILED 原因:

  • Empty IP address → 机器无网卡或全部 down
  • Only find lo → 物理网卡未启用
  • VLINK_DDS_IP is empty → 你没设这个变量(WARN)
  • <ip> is invalid → 你设的 VLINK_DDS_IP 不在本机 IP 列表
  • Cannot find 239.255.0.100 / Cannot find 239.255.0.1 → 路由表缺多播项
  • Unsupported command: ip route → 系统没有 ip 命令(古老发行版)
  • List running failed → 无权限读 /proc 或 ps 不可用

12.3 vlink-dumpcli/dump/dump.cc

错误 说明
[url] cannot be empty. 必须传 URL(位置参数)
CSV/JSON mode requires -c to specify fields. CSV/JSON 输出必须 -c field1,field2,...
Expression (-x) requires -c to specify fields as variables. 用表达式必须先声明变量
Expression support requires exprtk library. 该 VLink 构建没带 exprtk
native [--native] is only valid without bag_file [-f] --native-f 互斥
begin_time [-b] is only valid with bag_file [-f] -b 只对离线 bag 有效
Unknown type: ... -f 输出格式不认识
Failed to compile expression: ... -x 表达式语法错
Warning: No proto_dir or fbs_dir set, only zerocopy types will work. 忘了设 -d--fbs_dir

12.4 vlink-eproto / vlink-efbscli/eproto/eproto.cc, efbs/efbs.cc

共享的错误:

  • Cannot pub intra url. → intra:// 不能跨进程 pub
  • Url is empty. / ser_type and encoding do not match.
  • Must set proto dir [-d], set env 'VLINK_PROTO_DIR', or load VLINK_SCHEMA_PLUGIN.
  • Proto txt file does not exist. / load_text_for_file failed.
  • Blob content must be hex bytes.
  • Cannot find proto. / Cannot find ser.
  • Create root msg failed.
  • JSON mode is not supported for zerocopy message types.
  • Unsupported schema_type for eproto sub: ...

12.5 vlink-info

  • Cannot find options for path [...]vlink-options.txt 不在默认搜索路径
  • Cannot open options for path [...] → 文件存在但无读权限

12.6 vlink-proxyproxy/proxy.cc

  • Invalid domain id. (L137) → -d 超出 0–255(vlink-proxy 自身校验范围;注意 vlink-check diag 针对 VLINK_DDS_DOMAIN 另外限制在 0–232)
  • Invalid input for [-m, --iox_monitoring]. (L157) → -m 只接受 on/off
  • RouDi for shm is not supported. (L165) → SHM direct 模式要求内嵌 RouDi;确保 -c 已给
  • Program has started. (L109) → 本机已有一个 proxy 实例
  • -x/--max_packet_size 设成 0 后所有非空消息被丢弃 → 过滤逻辑 if (bytes.size() > real_max_packet_size) return;proxy_server.cc:1215)没有 0 = unlimited 的特判;CLI 默认是 4.0 MiB,若需放行大包请显式设置足够大的 MiB 值(例如 -x 64)。头文件注释中写的 "0 = unlimited" 与当前实现不符

12.7 ProxyAPI 嵌入(proxy/proxy_api/proxy_api.cc

  • ProxyApi: Non-controller nodes cannot send control. (L241)
  • ProxyApi: Non-controller nodes cannot send data. (L273)
  • ProxyApi: send_data requires url, ser, and a known schema. (L280)
  • ProxyApi: send_data metadata does not match direct publisher. (L302)

13. 每个 Transport 专属 init 错误

13.1 intra://

  • IntraFactory: Intra does not support setting thread count. — 别给 intra pool 设 set_thread_count()
  • IntraConf: Unknown node type, cannot parse protocol. — URL path 为空
  • Two identical service requests. — 同一进程里对同一 intra:// URL 起了两个 Server

13.2 shm:// / shm2://

见 §6。额外:

  • ShmConf: Wait mode must be Event(Pub/Sub). (shm_conf.cc:108) — shm 的 RPC 不支持阻塞等待
  • Shm2Factory: Bad event service name: ... / Failed to open or create event service '...' — iceoryx2 服务名非法或冲突
  • Shm2Factory: Failed to init config. — iceoryx2 TOML 加载失败
  • Shm2Factory: Failure in WaitSet::wait_and_process, ret=... result=... — 事件循环层失败

13.3 dds:// (Fast-DDS)

  • DdsConf: Invalid qos name: '...' (reserved or already registered). — qos profile 名冲突
  • DdsConf: Unknown node type, cannot parse protocol. — URL path 错
  • DdsFactory: Topic ... has no registered typesupport. — schema 没注册
  • DdsFactory: Topic ... does not support BuiltIn::Raw. — 当前 Fast-DDS 包不支持 raw 类型
  • DdsFactory: Method conf topic error. / ... req and resp cannot be equal. — RPC topic 规划错

13.4 ddsc:// (CycloneDDS)

  • 多数类似 dds,额外:
  • DdscFactory: Failed to take data.dds_take() 返回失败
  • DdscFactory: ssl.* properties are set but CycloneDDS was built without DDS_HAS_SSL support. — CycloneDDS 包不带 TLS

13.5 ddsr:// (RTI Connext)

  • DDS_DomainParticipantFactory_create_participant failed. — 多半 license / network 错
  • DDS_DomainParticipant_create_topic failed. — topic 已存在或命名冲突
  • 完整错误链在 modules/ddsr/ddsr_proxy.cc:57-254

13.6 ddst:// (TravoDDS)

  • DdstConf: Invalid qos name: '...' (reserved). — qos 名非法
  • DdstFactory: Method conf topic error. — RPC 路径错
  • DdstFactory: Failed to write data, does not support ptr type. — CDR ptr 不被支持
  • Cdr type does not support security. — 所有 6 种原语都会打(见 §17)

13.7 zenoh://

  • ZenohFactory: Failed to invoke [zc_init_log_from_env_or].
  • ZenohFactory: Failed to invoke [z_config_default].
  • ZenohFactory: Found invalid qos. — qos 配置非法
  • ZenohFactory: Failed to invoke server [z_view_keyexpr_from_str]. / [z_declare_queryable].

配置可通过 VLINK_ZENOH_CONFIG=<json5>(zenoh-c 仅接受 JSON5 配置)、VLINK_ZENOH_MODE=router|peer|clientVLINK_ZENOH_PEER=<endpoint> 等调节。

13.8 someip:// (vsomeip3)

  • SomeipFactory: Someip does not support zero thread count.set_thread_count(0) 非法
  • SomeipFactory: Failed to init app. — vsomeip 应用名非法或 JSON config 缺失
  • Two identical service requests. — 同一 service+instance+method 注册多次

**env**:VLINK_SOMEIP_CFG 指定 vsomeip JSON 路径。

13.9 mqtt://

  • MqttFactory: Failed to invoke [MQTTClient_create], rc=...
  • MqttFactory: Failed to invoke [MQTTClient_connect], broker=... rc=...
  • MqttFactory: Failed to subscribe to topic '...', rc=...

rc 的含义见 Paho MQTT C 文档(-1 = no connect,-2 = connect refused,等)。

13.10 fdbus://

  • FdbusFactory: Fdbus does not support zero thread count.
  • FdbusFactory: Server bind failed. — FDBus 名称服务未运行或该名字已被占

13.11 qnx://

  • QnxFactory: Qnx does not support zero thread count.
  • QnxFactory: Server name_attach failed. — 服务名冲突
  • QnxFactory: Server MsgReceive failed. — 通道异常
  • QnxFactory: Client MsgSend failed. — 服务端挂了 / 不可达
  • QnxFactory: Client name_attach failed. — 客户端注册失败

14. 运行时异常分类速查

14.1 Publisher 热路径

错误 位置 诊断
Failed to loan buffer, size: ... shm_factory.cc:640+ SHM pool 耗尽(见 §6.2
Failed to send, error: ... shm_factory.cc:667+ IPC channel 断 / 订阅端死
write_data() type mismatch, expected raw bytes but received ptr type. dds_factory.cc:446 你发了原生对象进 raw-bytes topic
write_cdr_data() type mismatch, expected ptr type but received raw bytes. dds_factory.cc:464 你发了 bytes 进 CDR topic
McapWriter: Writer is not open. mcap_writer.cc:675 bag writer 还没 init

14.2 Subscriber 热路径

  • Failed to take sample, error: ... (shm_factory.cc:1248) — ring buffer 损坏或空
  • DdscFactory: Failed to take data. — CycloneDDS 读失败(QoS 不匹配最常见)
  • DatabaseReader: Is busy. (database_reader.cc:*) — 并发读 VDB(不支持)

14.3 Server / Client 热路径

  • QnxFactory: Server name_attach failed. — 名字冲突
  • FdbusFactory: Server bind failed. — 同上
  • DdsServer: Cannot find request id. — 收到陌生 req_id 的 reply(协议乱)
  • Cdr type does not support security. — 12 处都会打,见 §17

14.4 Setter / Getter

  • Bytes: Cannot shrink_to on non-owned Bytes. — 对 shallow_copy / loan buf 改尺寸
  • Bytes: Cannot resize on non-owned Bytes. — 同上
  • Bytes: Cannot deep copy self. / Cannot shallow copy self. — 自复制
  • Bytes: Cannot move self. — 自移动

14.5 Bag 内部(VDB + MCAP)

  • DatabaseWriter: Sqlite not open. — 底层 DB 未初始化 / 被删
  • DatabaseReader: Invalid start_timestamp.begin_time 超出 bag 时间段
  • DatabaseReader: Cannot find any data for play. — 过滤后结果为空
  • DatabaseReader: Incomplete data detected. — bag 文件被截断
  • McapWriter: Compress is not supported without cache_size > 0. — MCAP 压缩需 buffering

14.6 Base 组件

  • Timer: Callback is null for call_once. / Callback is not set. — 启动定时器前没注册 cb
  • Timer: MessageLoop is null. / is not attached. — 没 attach 到 loop 就 start
  • WheelTimer: Timeout too large (rounds overflow). — 超出 wheel 可表达范围;改普通 Timer
  • WheelTimer: Failed to allocate a unique key. — 并发冲突;重试或减压

15. Discovery 深入

**Discovery 地址**:239.255.0.100 UDP 多播(src/extension/discovery_reporter.cc)。

15.1 Failed to set multicast interface to loopback. (discovery_reporter.cc:202)

  • 内核不允许绑 loopback multicast(容器 / 某些 seccomp 配置)
  • 修复:检查 /proc/sys/net/ipv4/conf/lo/mc_forwarding;或启用 VLINK_DISCOVER_NATIVE=1 切到单机走别的路径

15.2 Failed to set multicast, please add address [...] to target device... (discovery_viewer.cc:560-570)

  • 路由表没有 239.255.0.100 的出口
  • 修复:sudo ip route add 239.255.0.100/32 dev eth0(持久化改 /etc/network/interfaces 或 NetworkManager)

15.3 Global discovery reporter is disabled. (discovery_reporter.cc:122)

  • VLINK_DISCOVER_DISABLE=1 被设上了
  • 修复:unset VLINK_DISCOVER_DISABLE 或显式设为 0

15.4 Url is too long [...] / Ser type is too long [...]

**源码**:discovery_reporter.cc:302, 307

**原因**:URL 或 ser_type 超过 256 字符(Discovery 消息内 buffer 上限)。

**修复**:缩短 URL;用 hash 替代长路径名。

15.5 DiscoveryViewer 拿不到 cpu_usage

  • VLINK_PROFILER_ENABLE=0 把剖析器关了
  • 修复:打开剖析器或接受 cpu_usage=0

16. 平台专属陷阱

16.1 Windows 相关(#ifdef _WIN32

  • SysSharemem: CreateFileMapping failed. — 权限 / quota / 名字冲突
  • SysSharemem: MapViewOfFile failed. — 32-bit 进程 VA 耗尽;换 64-bit
  • SysSemaphore: CreateSemaphore failed. / WaitForSingleObjectEx failed. / ReleaseSemaphore failed. — 命名信号量或 kernel 对象异常
  • Process: MultiByteToWideChar failed — UTF-8 命令含非法字节序列
  • 多播路由用 route print(不是 ip route
  • 服务发现的多播路径与 Linux 不完全一致;如 netstat -an | findstr 239.255

16.2 macOS(#ifdef __APPLE__

  • SysSemaphore: dispatch_semaphore_create failed. / dispatch_semaphore_wait timeout or failed. — macOS 用 GCD 语义
  • Multicast 路由用 netstat -rn
  • **shm:// 不可用**:macOS 不支持 Iceoryx RouDi 的某些 POSIX 特性 → 改用 dds:// / intra://

16.3 Linux / POSIX

  • SysSharemem: shm_open is not supported on this platform. — 裁剪内核
  • SysSharemem: ftruncate failed./dev/shm 不足或 tmpfs 配额
  • SysSharemem: mmap failed. — VA 耗尽 / 32-bit
  • SysSemaphore: sem_open failed. / sem_close / sem_unlink — 检查 /dev/shm/sem.*

16.4 Android

  • shm:// (Iceoryx v1) **不可用**(Android 不支持 RouDi daemon) → 改 shm2://(Iceoryx2 无 daemon)、intra://dds://fdbus://
  • 日志后端默认 native(logcat)
  • NDK >= r25

16.5 QNX

  • 有专用 qnx:// transport(见 §13.11)
  • shm:// 可用但配置细节不同;需自己维护 RouDi
  • 日志后端默认 native(slog2)

17. QoS + 安全兼容性

17.1 CDR + Security 全面不兼容

**出处**:12 处源码显式打印 "Cdr type does not support security."

  • modules/ddst/ddst_publisher_impl.cc:60
  • modules/ddst/ddst_subscriber_impl.cc:105
  • modules/ddst/ddst_client_impl.cc:134
  • modules/ddst/ddst_server_impl.cc:108
  • modules/ddst/ddst_setter_impl.cc:36
  • modules/ddst/ddst_getter_impl.cc:105
  • modules/dds/dds_publisher_impl.cc:60
  • modules/dds/dds_subscriber_impl.cc:152
  • modules/dds/dds_client_impl.cc:169
  • modules/dds/dds_server_impl.cc:161
  • modules/dds/dds_setter_impl.cc:36
  • modules/dds/dds_getter_impl.cc:152

**原因**:CDR 编码路径直接交 DDS 管理,绕过 VLink 的加解密流程。

**修复**:换 Protobuf / FlatBuffers / Bytes;或启用 DDS-Security(RTPS 层加密)。

17.2 QoS 预设 vs 自定义 Qos

  • 传入 URL 的 ?qos=xxx 要小写(kSensorsensor
  • 自定义 Qos 必须 valid = true 才生效
  • KeepAll 的 depth 参数是**忽略的**(只对 KeepLast 有效)

17.3 DdscFactory: ssl.* properties are set but CycloneDDS was built without DDS_HAS_SSL support.

**源码**:modules/ddsc/ddsc_factory.cc:488

**修复**:

  • 改用支持 TLS 的 CycloneDDS 构建
  • 或 unset VLINK_SSL_* 跑明文

18. 容器 / K8s / VPN 部署

18.1 Docker 网络模式

模式 UDP 多播 适用
--net=host **推荐**,与宿主机共享 stack
--net=bridge(默认) ❌(除非额外配置) 不推荐用 dds:// / intra:跨容器用 host 或 overlay
--net=container:other 取决于 other

**修复**:启动容器时加 --net=host;或改用 unicast(VLINK_DDS_PEER=<ip>)。

18.2 Kubernetes / Service Mesh

  • Pod-to-pod 多播默认禁。方案:
    • 用 hostNetwork: true(生产不推荐)
    • 改 unicast peer 列表(VLINK_DDS_PEER=10.0.0.1,10.0.0.2
    • zenoh:// + Zenoh router pod 做中继
  • env 注入:ConfigMap / Secret(VLINK_* 变量从 env 读)

18.3 VPN / 跨子网

  • DDS / VLink 多播不路由到另一个子网;用 ddsr://zenoh://、或自己搭 multicast relay
  • vlink-proxy 可以跨子网桥接:一端起 vlink-proxy -b <subnetA>,另一端起 vlink-proxy -p <subnetB>

18.4 Docker /dev/shm 太小

容器默认 /dev/shm 只有 64 MB;iceoryx 用完就失败。

**修复**:docker run --shm-size=2g ... 或挂载 tmpfs。


19. 插件加载失败

**源码**:src/base/plugin.cc:114-287

错误 说明
Plugin: Plugin id is empty. 114, 221 VLINK_PLUGIN_REGISTER_BY_ID 没带 id
Plugin: Lib name is empty. 122 Plugin::load 第一个参数空
Plugin: Already loaded (...) 131 同一 lib 加载两次
Plugin: Cannot find plugin (...) 162 dlopen/LoadLibrary 失败;ldd 看依赖
Plugin: Cannot find symbol function to create (...) 182 插件没导出 create_* 入口
Plugin: Failed to create handle (...) 191 插件的 create 返回 nullptr
Plugin: Failed to load plugin (...): ... 212 create 过程中抛异常
Plugin: Not loaded (...) 228 destroy 之前没 load 成功
Plugin: Cannot find symbol function to destroy (...) 255 插件没导出 destroy
Plugin: Failed to destroy handle (...) 262 destroy 抛异常
Plugin: Plugin id mismatch: expected '...', got '...' 280 lib 内部的 PLUGIN_ID 不对
Plugin: Version mismatch: local X.Y, required X.Z. 287 ABI 版本不兼容

**通用排查**:

ldd plugin.so # Linux 依赖检查
nm -D plugin.so | grep create # 看导出符号
export VLINK_LOG_LEVEL=0 && ./app # 看 plugin.cc 的详细日志

20. Bag 损坏 / 恢复

20.1 流程

vlink-bag check broken.vdb # 快速检测
↓ FAILED
vlink-bag reindex broken.vdb # 重建索引(结构损坏但数据完好时)
↓ still bad
vlink-bag fix broken.vdb # 原地修复(跳过损坏段落)
vlink-bag fix broken.vdb -y # 重建模式(-y/--rebuild,破坏性更大)

20.2 常见错误消息

错误 可做的
DatabaseReader: Database version is incompatible. database_reader.cc:1714 换回录制端相同版本
DatabaseReader: Incomplete data detected. database_reader.cc:348 vlink-bag fix
DatabaseReader: Invalid start_timestamp. database_reader.cc:1743 -b 超出 bag 时间段
DatabaseReader: Database accuracy is not supported. database_reader.cc:1756 VDB 精度版本差太多
McapReader: Mcap version is incompatible. mcap_reader.cc:842 升级 VLink
McapReader: DB list is empty. mcap_reader.cc:1314 MCAP 头损坏
McapReader: JSON parse error, ... mcap_reader.cc:1430 metadata JSON 坏

20.3 Kill -9 防护

录制时尽量不要直接 kill -9 —— 这会让 SQLite 的 WAL 文件处于不一致状态。优雅退出用 SIGINTSIGTERM(VLink 会 graceful drain)。


21. 日志调优

21.1 级别

env 默认
VLINK_LOG_LEVEL kWarn(3) 0=Trace / 1=Debug / 2=Info / 3=Warn / 4=Error / 5=Fatal / 6=Off
VLINK_LOG_CONSOLE_LEVEL 继承 只控制 stdout/stderr
VLINK_LOG_FILE_LEVEL 继承 只控制文件 sink

21.2 日志文件轮转

export VLINK_LOG_DIR=/var/log/vlink
export VLINK_LOG_MAX_SIZE=$((100*1024*1024)) # 100 MB
export VLINK_LOG_MAX_COUNT=10 # 保留 10 份
export VLINK_LOG_FLUSH_DELAY=1000 # 1 秒刷一次

21.3 线上不要 TRACE/DEBUG

VLOG_T / VLOG_D 在 Release 构建下被编译消除(零指令),**前提是** VLINK_LOG_LEVEL 宏在编译时就设了。运行时设置只影响不被消除的那部分。

21.4 backtrace 辅助调试

vlink::Logger::enable_backtrace(50); // 常态下缓存最近 50 条(含 T/D)
// 业务出错时:
vlink::Logger::dump_backtrace(); // 一次性输出全部

21.5 自定义日志 sink(插件)

VLINK_LOG_PLUGIN=/path/to/libmylogger.so;实现 LoggerPluginInterface。见 19-extensions.md


22. 版本 / ABI 不匹配

22.1 Plugin 版本

  • Plugin: Version mismatch: local X.Y, required X.Z. → plugin 要求的主/次版本不是当前 VLink 的版本
  • Major 必须严格相同;Minor 向下兼容(plugin.cc:285-289,条件 target_major != local_major || target_minor > local_minor
  • 修复:重新编译 plugin 对齐 VLink 版本

22.2 Bag 版本

  • 录制端 / 读取端 VLink 版本差距过大,可能出现 DatabaseReader: Database version is incompatible.McapReader: Mcap version is incompatible.
  • 修复:升级 reader;或在录制端省略 -p/--compress 录无压缩版本以减少版本敏感性

22.3 Python 绑定 ABI

_vlink_nanobind.so 对 Python 次版本敏感(3.10 != 3.11 的 nanobind ABI);对 VLink C++ 侧 ABI 也敏感。

**修复**:重新 pip install 或重新构建 Python API。

22.4 VLINK_VERSION 检查

运行时:

vlink-info # 版本 / Git tag / commit id
vlink-info -l | grep ENABLE # 当前构建开启了哪些特性

代码里:

static_assert(VLINK_VERSION_CHECK(2, 0, 0), "需要 VLink ≥ 2.0.0");
#define VLINK_VERSION_CHECK(major, minor, patch)
Encodes a version triple into a single 24-bit integer for comparison.
Definition version.h:165

23. 性能反模式 & 调试技巧

23.1 热路径里的代码气味

  • Subscriber::listen 回调里:文件 IO / 上锁 / new/delete / std::regex / stringstream / JSON 序列化 → **所有这些都是坑**。把重活转到 ThreadPool
  • 每个消息都 std::shared_ptr 分配 → 用 ObjectPool
  • 对 POD struct 用 kStreamType 强行文本化 → 用 kStandardType(memcpy)
  • History::kKeepAll + 突发高频 → reliable 重传会堆积

23.2 常见"静默"警告(运行时打 WARN 但不崩)

  • WheelTimer: Timer is already running. — 重复 start
  • BagReaderProcessor: Cache size is full, waiting to consume. — 回放太慢(源:src/extension/bag_reader_processor.cc
  • McapWriter: Compress is not supported without cache_size > 0. — MCAP 压缩要 buffer
  • DiscoveryReporter: Url is too long — URL > 256 字符被截断

23.3 性能调试黄金三步

# 1. 基线
vlink-bench run --preset quick --report terminal
# 2. 订阅端统计
sub.set_latency_and_lost_enabled(true);
# 3. CPU 剖析(本进程每个 endpoint)
VLINK_PROFILER_ENABLE=1 ./my_app
vlink-monitor # 在另一个终端看 cpu_usage 列

23.4 SHM 状态速查

# Linux
ls -la /dev/shm/iceoryx_* # 段名
ipcs -m # SysV shm
lsof /dev/shm/* | head # 谁在用
# Windows
# 看 ProgramData\iceoryx*,或用 Windows Resource Monitor

23.5 DDS 状态速查

  • Fast-DDS:fastdds discovery(需要 Fast-DDS tools)
  • CycloneDDS:cyclonedds inspect
  • RTI Connext:rtiddspingpub

24. 按错误字符串速查(Reverse Lookup)

遇到的字符串 去哪看 一句话
The URL transport prefix cannot be empty. §3.1 URL 不含 xxx://
Bad key in the query string! §3.1 URL ? 后面的 key 打错
Unsupported plugin module, libname: ... §3.3 / §19 transport 没编进或 plugin 不存在
Cdr type does not support security. §17.1 CDR + kWithSecurity 不兼容
Topic ... has no registered typesupport. §13.3 DDS schema 没注册
Failed to loan buffer, size: ... §6.2 SHM mempool 不够大
Shm roudi is not supported. §6.3 RouDi 模式错
Database version is incompatible. §8.1 bag 版本错位
Mcap version is incompatible. §8.2 MCAP 版本错位
Must set proto dir [-d], ... §10.2 动态 proto 没 schema 目录
Plugin: Version mismatch: local X.Y, required X.Z. §22.1 plugin ABI 不对
Cache size is full, waiting to consume. §8.6 回放消费跟不上
DiscoveryReporter: Failed to set multicast ... §15.1 多播接口配置问题
Invalid domain id. §12.6 vlink-proxy -d 参数超出 0–255
VLINK_RET_RUNTIME_ERROR §9.1 C++ 构造时抛异常
VLINK_RET_MEMORY_ERROR §9.3 调用方 buffer 太小
VLINK_RET_TRANSFER_ERROR §9.4 send/recv/invoke 失败
write_data() type mismatch, expected raw bytes but received ptr type. §14.1 用错类型发 DDS
BagWriter force to quit. §12.1 writer 被强制终止
The number of messages has reached the upper limit... §8.7 bag 达到 max_row_count
ShmConf: Input string length is too long. §6.5 URL path > 128
Url is too long [...] / Ser type is too long [...] §15.4 Discovery buffer 256 上限

找不到?去 §11 还没排出来? 走最后一步。