DDS(Data Distribution Service,数据分发服务)是一套由对象管理组织(OMG)制定和维护的以数据为中心的发布-订阅(Publish-Subscribe)通信中间件协议与API标准。它旨在为分布式实时系统提供低延迟、高可靠性、高可扩展性和强动态性的数据通信能力,广泛应用于国防、航空航天、工业自动化、机器人(如ROS 2)、自动驾驶和物联网等领域 。

1. DDS 核心架构与设计哲学

DDS的核心设计哲学是以数据为中心(Data-Centric)。与传统的以消息或通道为中心的中间件不同,DDS构建了一个虚拟的全局数据空间(Global Data Space)。应用程序无需知道数据的生产者和消费者是谁,也无需管理点对点的连接,只需关注其感兴趣的数据(Topic),并向数据空间声明读写意图即可。这种设计极大地降低了分布式系统的耦合度和复杂度 。

DDS架构通常分为四层,以FastDDS为例 :

  1. 应用层:提供用户友好的API。
  2. DDS层:实现以数据为中心的模型,管理域(Domain)、主题(Topic)、发布者(Publisher)、订阅者(Subscriber)等核心实体。
  3. RTPS层:实现实时发布订阅协议(Real-Time Publish-Subscribe Protocol),这是确保不同DDS供应商实现之间互操作性的关键。
  4. 传输层:支持多种传输协议,包括UDPv4/v6、TCPv4/v6、共享内存(SHM)等。

2. DDS 核心概念详解

核心概念 定义与作用 关键特性与说明
域(Domain) 一个独立的虚拟通信平面,由唯一的DomainId标识。不同域内的参与者完全隔离,无法通信。 类似于虚拟局域网(VLAN),允许在同一物理网络上运行多个独立的DDS系统 。
域参与者(DomainParticipant) 应用程序加入一个DDS域的入口点。一个应用程序可以创建多个参与者加入不同的域。 作为工厂,用于创建发布者、订阅者、主题等实体 。
主题(Topic) 全局数据空间中数据的唯一标识符和类型定义。是连接数据生产者(DataWriter)和消费者(DataReader)的纽带。 由名称(TopicName)和数据类型(Type)共同定义。发布和订阅必须基于相同的主题才能匹配 。
发布者(Publisher) 负责管理一个或多个DataWriter,是数据写入的容器。 一个发布者可以管理多个不同主题的DataWriter 。
订阅者(Subscriber) 负责管理一个或多个DataReader,是数据读取的容器。 一个订阅者可以管理多个不同主题的DataReader 。
数据写入者(DataWriter) 绑定到特定Topic的实体,应用程序通过它将数据样本(Sample)写入全局数据空间。 每个DataWriter与一个Topic严格绑定 。
数据读取者(DataReader) 绑定到特定Topic的实体,应用程序通过它从全局数据空间读取数据样本。 每个DataReader与一个Topic严格绑定 。
实例(Instance)与键(Key) 在定义数据结构时,可以使用@key标记一个或多个字段作为。拥有相同键值的数据样本属于同一个实例 DDS可以独立管理每个实例的生命周期(注册、注销、处置),这对于表示不断更新的实体状态(如设备ID、航班号)非常高效 。
服务质量(QoS) 一组策略的集合,用于精确控制DDS通信的各个方面,如可靠性、持久性、截止时间、资源限制等。 QoS是DDS强大灵活性的根源,允许针对不同数据流进行细粒度行为定制 。

3. 服务质量(QoS)策略详解

QoS策略是DDS协议的灵魂,它使得DDS能够适应从尽力而为的传感器数据流到强实时的控制指令等多样化场景。以下是一些关键策略:

QoS 策略 功能描述 可配置参数与选项
可靠性(Reliability) 控制数据传输的可靠性。 BEST_EFFORT(尽力而为,低延迟,可能丢包)或 RELIABLE(可靠传输,保证送达,可能重传)。
持久性(Durability) 控制新加入的订阅者是否能收到在其加入之前已发布的历史数据。 VOLATILE(不保留)、TRANSIENT_LOCAL(在发布者内存中保留)、TRANSIENT(持久化到磁盘)。
历史(History) 控制为DataWriter或DataReader缓存的数据样本数量。 KEEP_LAST(保留最新的N条)或 KEEP_ALL(保留所有)。
截止时间(Deadline) 定义DataReader期望接收数据更新的最大时间间隔。 设置时间周期。如果超时未收到新数据,会触发监听器(Listener)。
活跃度(Liveliness) 定义如何判断一个发布者是否“存活”。用于检测节点故障。 三种模式:AUTOMATIC(由底层基础设施自动声明)、MANUAL_BY_PARTICIPANTMANUAL_BY_TOPIC,并需设置租约期限(Lease Duration)。
生命周期(Lifespan) 定义数据样本的有效期,过期的数据不会被投递。 设置时间周期 。
资源限制(ResourceLimits) 限制为Topic、DataWriter/DataReader分配的资源(如最大样本数、实例数)。 防止因数据生产过快导致内存耗尽 。
分区(Partition) 在同一个Domain内提供额外的逻辑隔离层。Publisher和Subscriber必须在匹配的分区内才能通信。 通过字符串名称列表定义分区,支持通配符匹配 。

QoS兼容性与匹配:DDS的发布-订阅匹配是基于Topic和QoS的双重匹配。只有当DataWriter和DataReader的Topic名称、数据类型以及关键的QoS策略(如可靠性、持久性、分区等)相互兼容时,它们之间才会建立连接并开始传输数据 。

4. RTPS协议与动态发现

RTPS(Real-Time Publish-Subscribe)协议是DDS标准的网络互通部分,它定义了在IP网络上传输DDS数据的标准线缆协议(Wire Protocol)。其核心机制是动态发现(Discovery),该过程完全去中心化,无需配置服务器 。

  1. 参与者发现协议(PDP):当DomainParticipant启动时,会通过用户数据报协议(通常是UDP多播或单播)发送声明消息,以发现同一Domain内的其他Participant。
  2. 端点发现协议(EDP):在Participant之间建立联系后,它们会交换各自拥有的DataWriter和DataReader的详细信息,包括其关联的Topic和QoS。
  3. 匹配与建立连接:根据交换的信息,DDS中间件在兼容的DataWriter和DataReader之间建立逻辑连接。这个过程是完全自动的,应用程序无需干预。
  4. 存活维护:通过定期的心跳(Heartbeat)和应答(AckNack)消息来维护连接状态,并实现可靠传输中的数据确认与重传(当使用RELIABLE QoS时)。

5. DDS 通信模式与传输协议

DDS支持多种通信模式以满足不同需求:

  • 发布-订阅(核心模式):一对多、多对多的异步数据分发。
  • 请求-回复(通过DDS-RPC):在标准的发布-订阅模型之上,OMG还定义了DDS-RPC规范,用于实现同步的请求-响应模式,类似于传统的RPC,但继承了DDS的QoS和发现机制 。

在传输层面,DDS实现(如FastDDS)通常支持:

  • UDP/IP:默认且最常用的协议,特别适合对延迟敏感的应用。RTPS over UDP可以通过应用层机制实现可靠传输。
  • TCP/IP:在需要穿越严格防火墙或与仅支持TCP的系统集成时使用。
  • 共享内存(SHM):用于同一台主机上进程间的极高性能通信,实现零拷贝数据传输 。
  • 用户自定义传输:允许开发者集成特殊的传输方式(如RDMA、共享内存的扩展等)。

6. DDS 安全机制

DDS安全(DDS-Security)规范提供了一套完整的安全框架,主要包括:

  • 身份认证(Authentication):验证DomainParticipant的身份。
  • 访问控制(Access Control):基于策略控制哪些Participant可以发布/订阅特定Topic,以及可以执行哪些操作(如写、读)。
  • 加密(Encryption):对网络传输中的数据载荷进行加密,保证机密性。
  • 日志(Logging):记录安全相关事件。
    这些安全策略同样通过可插拔的插件和QoS进行配置,实现了安全性与通信功能的解耦 。

7. 示例:一个简单的DDS数据定义与发布/订阅流程

// 1. 定义数据类型 (使用IDL或直接在代码中定义)
// 假设有一个名为“Temperature”的Topic,其数据类型如下:
struct Temperature {
    @key string<256> sensor_id; // 使用sensor_id作为键(Key)
    float value;
    long timestamp;
};

// 2. 发布者 (Publisher) 端代码框架
// 创建DomainParticipant (domain_id=0)
DomainParticipant* participant = DomainParticipantFactory::create_participant(0);
// 注册Temperature类型
TypeSupport type(new TemperaturePubSubType());
type.register_type(participant);
// 创建Topic “RoomTemp”
Topic* topic = participant->create_topic("RoomTemp", "Temperature", TOPIC_QOS_DEFAULT);
// 创建Publisher
Publisher* publisher = participant->create_publisher(PUBLISHER_QOS_DEFAULT);
// 创建DataWriter,并配置QoS(例如,可靠传输)
DataWriterQos writer_qos;
writer_qos.reliability().kind = RELIABLE_RELIABILITY_QOS;
DataWriter* writer = publisher->create_datawriter(topic, writer_qos);
// 写入数据
Temperature sample;
sample.sensor_id("sensor_1");
sample.value(25.5);
sample.timestamp(get_current_time());
writer->write(&sample);

// 3. 订阅者 (Subscriber) 端代码框架
// 创建DomainParticipant (domain_id=0,必须与发布者相同)
DomainParticipant* participant_sub = ...;
// 注册类型、创建Topic(名称和类型必须匹配)
Topic* topic_sub = participant_sub->create_topic("RoomTemp", "Temperature", TOPIC_QOS_DEFAULT);
// 创建Subscriber
Subscriber* subscriber = participant_sub->create_subscriber(SUBSCRIBER_QOS_DEFAULT);
// 创建DataReader,并配置匹配的QoS(必须也是RELIABLE)
DataReaderQos reader_qos;
reader_qos.reliability().kind = RELIABLE_RELIABILITY_QOS;
DataReader* reader = subscriber->create_datareader(topic_sub, reader_qos);
// 设置监听器(Listener)或通过轮询方式读取数据

注释:以上代码为概念性示例,展示了DDS编程的基本流程。实际开发中需根据具体DDS实现库(如FastDDS、OpenDDS、RTI Connext DDS)的API进行调整。关键点在于Topic匹配和QoS(如可靠性)的兼容性配置 。

8. DDS 的优势与适用场景

优势

  • 以数据为中心:简化架构,降低耦合。
  • 丰富的QoS:提供细粒度的通信行为控制。
  • 动态发现:系统可动态扩展,即插即用。
  • 高性能与实时性:针对低延迟、高吞吐量优化。
  • 强可靠性:通过QoS保证关键数据必达。
  • 标准化与互操作性:基于RTPS协议,不同厂商的实现可以互通 。

适用场景

  • 分布式实时系统:如航空航天电子系统、工业自动化控制。
  • 机器人系统:ROS 2默认使用DDS作为中间件。
  • 自动驾驶:车辆内部各传感器、控制器、决策模块间的高速数据交换。
  • 物联网(IoT)边缘计算:设备间高效、可靠的数据分发。
  • 金融交易系统:对延迟和可靠性有极致要求的场景。

总结:DDS协议是一套功能极其丰富、设计精巧的分布式通信标准。它通过以数据为中心的模型、强大的QoS策略集和去中心化的动态发现机制,为构建复杂、可靠、实时的分布式系统提供了坚实的基础设施。理解其核心概念、QoS模型和RTPS发现机制,是有效使用DDS的关键 。


参考来源

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐