4. QoS策略(上):可靠性、持久性、历史记录
各位同学,今天我们聊聊DDS里最核心的三个QoS策略。说实话,这三个策略要是搞不明白,后面做项目肯定要踩坑。我自己带团队的时候,发现80%的通信问题都出在这三个策略的配置上。
4.1 可靠性(RELIABILITY)——消息到底能不能丢?
先问大家一个问题:你的系统允许丢消息吗?
如果答案是「绝对不能丢」,那你就得用 RELIABLE 模式。如果偶尔丢几条无所谓,那就用 BEST_EFFORT。
我个人习惯把可靠性策略比作快递服务:
- BEST_EFFORT 就像普通快递——丢了不赔,但速度快
- RELIABLE 就像顺丰保价——必须送到,但可能慢一点
我在项目中遇到过这样一个案例:一个自动驾驶的感知模块,用BEST_EFFORT发障碍物信息。结果有一次丢包了,控制模块没收到障碍物数据,差点出事。嗯,从那以后,所有安全相关的topic我都强制用RELIABLE。
核心要点:
- RELIABLE:发送方会重传,直到接收方确认收到
- BEST_EFFORT:发完就不管了,适合传感器数据、日志等
代码配置示例:
// 创建QoS对象
QosPolicy qos = QosPolicy.createDefault();
// 设置为可靠模式
qos.setReliability(ReliabilityKind.RELIABLE);
// 或者设置为尽力而为
qos.setReliability(ReliabilityKind.BEST_EFFORT);
注意:RELIABLE模式会占用更多内存和带宽。我曾经有个项目,所有topic都用RELIABLE,结果内存爆了。后来把高频传感器数据改成BEST_EFFORT,问题就解决了。
4.2 持久性(DURABILITY)——晚来的订阅者怎么办?
这个策略解决的是「后来者」的问题。你想想看,一个订阅者晚到了,它还能不能看到之前发布的数据?
持久性策略有四种:
| 策略 | 含义 | 适用场景 |
|---|---|---|
| VOLATILE | 不保存历史数据 | 实时数据,如传感器值 |
| TRANSIENT_LOCAL | 保存在发布者内存中 | 配置参数、静态信息 |
| TRANSIENT | 保存在持久化服务中 | 需要跨进程共享的数据 |
| PERSISTENT | 保存在磁盘上 | 关键配置,重启后仍需保留 |
我建议你记住一个原则:持久性越强,代价越大。PERSISTENT虽然最安全,但读写磁盘很慢。我在做车载诊断系统时,就把故障码用PERSISTENT存着,这样车重启后还能查到历史故障。
我的经验:大多数场景用TRANSIENT_LOCAL就够了。只有需要跨ECU持久化的数据,才考虑TRANSIENT或PERSISTENT。
4.3 历史记录(HISTORY)——保留多少条旧数据?
历史记录策略和持久性策略是搭配使用的。它决定了「要保留多少条历史数据」。
有两种模式:
- KEEP_LAST:只保留最近N条数据
- KEEP_ALL:保留所有数据,直到资源耗尽
代码示例:
// 保留最近10条数据
qos.setHistory(HistoryKind.KEEP_LAST, 10);
// 保留所有数据
qos.setHistory(HistoryKind.KEEP_ALL);
避坑指南:我曾经用KEEP_ALL配合RELIABLE,结果数据量太大,内存直接爆了。后来改成KEEP_LAST + depth=100,问题就解决了。记住:KEEP_ALL要慎用,除非你确定数据量很小。
4.4 三个策略的联动关系
这三个策略不是孤立的,它们会互相影响。我画了一张图来说明:
说白了,这三个策略的配置要一起考虑。我一般这样配:
- 实时控制信号:RELIABLE + VOLATILE + KEEP_LAST(1)
- 传感器数据:BEST_EFFORT + VOLATILE + KEEP_LAST(10)
- 配置参数:RELIABLE + TRANSIENT_LOCAL + KEEP_LAST(5)
总结一下:
- 可靠性:保证消息送达
- 持久性:保证后来者能看到历史
- 历史记录:控制保留多少历史
这三个策略是DDS的基石。搞懂了它们,你就掌握了DDS通信的核心。