恒美微站
首页
关于我们
建站服务
主题模板
案例展示
资讯中心
联系我们
开源DDS三强对比:Fast DDS、Cyclone DDS与OpenDDS选型指南
首页
资讯中心
/
开源DDS三强对比:Fast DDS、Cyclone DDS与OpenDDS选型指南
开源DDS三强对比:Fast DDS、Cyclone DDS与OpenDDS选型指南
发布时间:2026/9/8 3:10:58
我在分布式机器人项目里接触 DDS 的时间不短了。从最早跟着 ROS 2 默认配置走到后来因为现场节点互相发现不了被迫去翻协议栈源码这段弯路让我对开源 DDS 实现的价值和差距有了比较直观的认识。DDS也就是 Data Distribution Service是一套面向分布式实时系统的数据分发标准它规定了数据如何发布、订阅、被发现以及如何按 QoS 策略保障通信质量。而在开源世界里目前工程里提到频率最高、也最能打的三套实现分别是以 eProsima 团队为主导的 Fast DDS、隶属于 Eclipse 基金会的 Cyclone DDS以及由 OCIObject Computing, Inc.维护的 OpenDDS。这篇内容不是想把 OMG 标准文档复述一遍而是想围绕我实际拆解、压测、选型过程中积累的经验把这三套开源 DDS 实现各自的定位、优势、短板以及真正落地时怎么选讲清楚。1. 同一个 DDS 标准三种不同的工程哲学1.1 DDS 标准究竟规范了什么我早期用 DDS 时有个误区以为只要装了一个厂商的 SDK就算用了 DDS。后来才发现OMG 的 DDS 规范是一套标准而实现是可以自主选择的。整个标准体系里最核心的有几块DCPSData-Centric Publish-Subscribe定义了 API、主题、数据类型和 QoS 策略的模型DDSI-RTPS 定义了基于 UDP/IP 的线协议Wire Protocol这是不同实现能够互通的基础再往上还有 DDS Security 和 DDS-XTypes分别解决安全通信和类型系统演进的问题。这里有一个关键结论只要两个实现都遵循 DDS 标准理论上同一份数据从 Fast DDS 发出来Cyclone DDS 可以正常收到。这也是很多项目愿意在架构层面引入 DDS 的根本原因——它给了你替换实现的自由。但“理论上互通”和“工程上好用”之间差距非常大。对比这三家真正要看的是标准没有约束的部分默认配置下谁更稳、异常场景下谁更容易排查、资源受限时谁能跑起来。1.2 Fast DDS在 ROS 2 的战场上快速成熟Fast DDS 的前身是 Fast RTPS由 eProsima 团队开发几乎和 ROS 2 的时间线完全重合。从 ROS 2 早期的 Ardent 到 Foxy、Galactic、HumbleFast DDS 很长一段时间都是 ROS 2 的默认 RMWRMW 是 ROS 2 对 DDS 实现的抽象层大量工业机器人、无人车、商用产品把它带到了生产环境所以它经受的真实场景考验是最密集的。Fast DDS 的优势可以用一个“全”字概括。传输层方面它同时支持 UDPv4、TCPv4 和 SharedMemory功能方面它对 QoS、DDS Security、XTypes 的支持都相当完整工程工具链也比较成熟用 fastddsgen 生成现代 C 代码很顺手官方文档和示例数量在三者里是最多的。遇到编译问题、连接问题基本都能在 GitHub Issues 或 ROS Answers 里找到类似案例。但它也有典型的“瑞士军刀”代价配置项极多内部线程数量高默认行为下内存占用相对偏高。尤其在新手手里很容易陷入“默认配置跑起来了但性能一般想调优又不知道该动哪个参数”的尴尬状态。我们团队在早期的项目里吃过这个亏后面我会展开说。1.3 Cyclone DDS用最小的内核撬动高性能Cyclone DDS 是 Eclipse 基金会下的项目核心代码主要由并入 ZettaScale 的前 TwinOaks 团队成员开发。它和 Fast DDS 最大的不同在于实现语言和工程哲学Cyclone DDS 用 C 写了一个非常紧凑的核心再在这个核心之上提供 C、C、Python、Rust 等多种语言绑定。依赖少、编译快、模块边界清楚这是它一上来就给人留下的好印象。Cyclone DDS 在第三方独立评测里很长一段时间都保持着更低的端到端延迟和更好的吞吐表现尤其在默认配置下优势明显。这背后其实没有魔法主要归功于更高效的事件循环、对缓存和内存访问路径的精细控制以及相对克制的线程模型。对于资源受限的嵌入式设备这三点的收益是实打实的。从 ROS 2 的演进也能看出趋势从 Iron 版本开始Cyclone DDS 正式成为 ROS 2 的默认 RMW。这个决定并不是因为 Fast DDS 不好而是在大规模节点、多机协同的场景下Cyclone DDS 的默认表现更加稳定、更容易预测。这一点对在实际项目中做选型的人非常关键。1.4 OpenDDS更保守、更老派的标准守护者OpenDDS 的历史比前两者都要长由 OCI 公司持续维护了二十年左右。它在一套名为 ACE/TAO 的经典 C 框架基础上发展而来在航空、国防、电网、轨道交通等对稳定性和标准合规要求极高的行业里占有率很高。这类客户看重的是长期验证过的可靠性和对 DDS 标准的完整覆盖而不是追新功能。OpenDDS 的成熟度毋庸置疑但它也有明显的“时代包袱”。构建依赖 ACE/TAO 这套相对厚重的框架代码生成链路比较复杂用 opendds_idl 加 tao_idl 配合对现代 CMake 项目来说不算友好。如果你的项目没有历史包袱也不是为了满足特定行业的合规审查我通常不会首推 OpenDDS。但反过来如果客户明确要求 DDS Security 审计、要求严格的标准一致性那 OpenDDS 反而是更稳妥的选择。1.5 基础信息速览维度Fast DDSCyclone DDSOpenDDS维护组织eProsimaEclipse 基金会项目OCI核心语言CCC许可证Apache-2.0EPL-2.0 / EDLApache-2.0依赖 ACE/TAO 需单独评估代码生成工具fastddsgenidlc / cyclonedds 系列opendds_idl tao_idl典型应用领域ROS 2、工业机器人、自动驾驶ROS 2、高性能分布式、嵌入式航空、国防、传统关键系统资源占用趋势功能全、默认占用偏高精简、低占用中等偏重这张表只能帮你建立第一印象。真正做选型时还得往下看关键维度。2. 从“能跑”到“好用”对比的关键维度2.1 QoS 完整度与可配置性DDS 之所以比普通消息队列灵活核心就在于 QoS 策略。可靠性、历史数据保留、生命周期、分区、所有权、截止时间等等每一个策略都直接决定通信行为。三套实现都实现了 OMG 标准里的大部分 QoS 策略但在暴露方式和易用性上有明显差异。Fast DDS 几乎把所有东西都暴露给了用户通过 XML profile 或者 C API 可以精细控制传输、发现、资源限制。好处是上限高坏处是学习曲线陡。Cyclone DDS 也支持 XML/YAML 配置但默认值明显更“开箱即用”。它更倾向于让用户只关心业务而不是一开始就去调线程数和缓存池。OpenDDS 的配置能力同样很强但文档风格偏传统很多参数的解释停留在“标准原文”级别实际项目里需要有一定经验才能用好。提示不要迷信“哪个功能多就选哪个”。大多数项目用到的 QoS 策略不超过十个真正影响体验的是默认值是否合理以及出问题时配置是否容易理解。2.2 发现机制最多坑的地方分布式系统里面“节点互相发现不了”是我遇到最多的问题没有之一。DDS 默认使用 RTPS Simple Discovery大致流程是节点启动后在局域网里通过组播发送 SPDP 宣告自己的存在然后通过 SEDP 交换端点信息最终建立发布订阅关系。这套机制本身很优雅但在真实网络环境里组播被禁、多网卡绑定错、防火墙拦截、路由器隔离等情况都会让发现失败。三套实现在发现机制上都有自己的优化和扩展。Fast DDS 提供了 Discovery Server 的集中发现模式适合设备数量多、网络拓扑复杂的场景。Cyclone DDS 对组播发现做了比较多细节优化同时允许通过配置文件指定网卡接口排查问题相对直观。OpenDDS 除了支持 RTPS 发现还保留了传统的 InfoRepo 集中发现方式适合历史系统对接。这里我要强调一句很多团队把发现失败归咎于“DDS 不稳定”实际上往往是部署层面的问题。后面第 5 节我会专门写排查清单。2.3 传输层与共享内存不同 DDS 实现的传输层设计直接决定了同机通信和跨机通信的性能差异。Fast DDS 自带 SharedMemory 传输同机多进程场景下可以避免走网络协议栈吞吐提升非常明显。Cyclone DDS 早期主要依赖 UDP后来也对共享内存做了支持但在某些版本和使用场景下配置路径不如 Fast DDS 顺手。OpenDDS 则有 TCP、UDP、组播、共享内存等全套传输插件灵活性不差。在实际项目里我建议把“同机通信占比高不高”作为选型考量因素。如果你的系统是多个进程跑在同一台工控机上并且进程间有大流量数据交换那么共享内存传输的成熟度就很重要。反之如果系统是典型的车端、机端多设备组网UDP 组播就足够了不必为共享内存额外付出配置成本。2.4 类型系统与代码生成DDS 通过 IDL 定义数据类型三套实现都支持 IDL 到目标语言代码的生成。我们常用的定义大概是这样的module demo { struct ImuData { long device_id; float accel_x; float accel_y; float accel_z; unsigned long seq; }; };Fast DDS 的 fastddsgen 生成代码风格现代对 C11 以上支持好生成的类型可以直接在 ROS 2 节点里复用。Cyclone DDS 的 idlc 生成的代码更轻量配合它的 C 核心使用体验很干净。OpenDDS 因为要用 opendds_idl 加 tao_idl 两步生成链路长初次使用很容易被工具链劝退。需要特别提醒的是自定义类型的互通问题。RTPS 线协议虽然统一但类型信息是否完整传递、XTypes 类型兼容性检查是否严格不同实现之间是有差异的。实际测试中三套实现用同一个简单 IDL 可以实现互通但遇到复杂的嵌套类型、动态类型或者枚举变更时就必须提前做互通性测试。这个点常常被忽略等到系统联调阶段再暴露就会很被动。3. 亲测流程一套可复现的对比方法3.1 准备环境与编译安装我的对比环境是两台 Ubuntu 22.04 的 x86 工控机通过一台千兆交换机直连关闭了防火墙防止干扰。每套 DDS 都从源码编译避免发行版仓库版本不一致带来的误差。Fast DDS 的源码编译相对直接git clone https://github.com/eProsima/Fast-DDS.git cd Fast-DDS mkdir build cd build cmake -DCMAKE_BUILD_TYPERelease -DBUILD_TESTINGOFF .. cmake --build . --target installCyclone DDS 也很简单git clone https://github.com/eclipse-cyclonedds/cyclonedds.git cd cyclonedds mkdir build cd build cmake -DCMAKE_BUILD_TYPERelease -DBUILD_TESTINGOFF .. cmake --build . --target installOpenDDS 建议直接看官方文档的 Quick Start因为它依赖 ACE/TAO这里不展开命令。编译过程中最容易踩的坑是系统缺少 OpenSSL 或 Bison 相关依赖建议先把 libssl-dev、bison、flex 装齐了再开始。3.2 写一个最小收发程序测试互通用上面的 ImuData 定义分别用三套工具的 IDL 编译器生成代码实现一个最简单的发布者和订阅者。测试时我会开四个终端终端 1Fast DDS 发布者终端 2Cyclone DDS 订阅者终端 3Cyclone DDS 发布者终端 4OpenDDS 订阅者只要两两配合能正常收到数据就说明 RTPS 层的互通没有问题。这一步看起来简单却是评估实现兼容性最直接的手段。根据我的实测最简单的内建类型结构体在三个实现之间互通基本没有障碍。但一旦启用 DDS Security 或者复杂类型就需要双方同时配置对应的安全插件和类型信息策略工作量和风险都会上升。注意不同实现之间的互通测试一定要放在选型初期做不要等到系统设计完了再验证。一旦发现互通问题更换实现的代价会呈几何级增长。3.3 性能测试工具与方法性能测试我没有用太复杂的工具Cyclone DDS 自带的 ddsperf 就够用。一个终端跑回显模式另一个终端用指定频率发布消息ddsperf latency ddsperf pub -i 1000Fast DDS 方面eProsima 提供了 fastdds 命令行工具和性能测试示例可以在源码的 examples 目录里找到。OpenDDS 也带了一套 PerformanceTests但历史包袱重配置稍微繁琐。实测下来我的结论是默认参数下Cyclone DDS 的延迟抖动量明显更小内存占用也更低Fast DDS 经过调优后可以达到很不错的效果但需要你真正理解它的线程模型和缓存参数。这里我不给具体数字因为性能数字与硬件、系统内核、网络驱动关系太大网上的基准数据只能作为粗略参考。真正可靠的做法是拿自己的场景、自己的消息大小、自己的频率去复测。3.4 简单的诊断技巧测试过程中最容易遇到的是“程序启动了但就是收不到消息”。先别急着换实现或者怀疑代码按顺序排查先看两台机器能不能互相 ping 通再用 tcpdump 抓包看有没有 UDP 组播包发出然后用实现自带的诊断工具查看 participant 是否被发现最后才对比 QoS 和类型名是否一致。Cyclone DDS 可以在配置里开启调试日志export CYCLONEDDS_URIfile:///path/to/cyclonedds.xml配置文件里把 Tracing 的 Verbosity 开到 config 级别就能看到 participant 和 endpoint 的匹配情况。这个能力在排查多机通信问题时非常省时间。4. 在 ROS 2 和嵌入式项目里怎么做选型4.1 ROS 2 的 RMW 切换一个接口换多种实现ROS 2 抽象出了 RMW 层目的就是让你可以方便地切换 DDS 实现。日常开发中只需要设置环境变量export RMW_IMPLEMENTATIONrmw_cyclonedds_cpp ros2 run demo_nodes_cpp talker前提是你已经安装了对应的 RMW 包sudo apt install ros-$ROS_DISTRO-rmw-cyclonedds-cpp sudo apt install ros-$ROS_DISTRO-rmw-fastrtps-cpp这里有个实际经验不同 RMW 之间切换后ROS 2 的话题名称、服务名称都要重新发现之前缓存的节点信息可能干扰新实现。切换后最好先重启所有节点必要时清一下共享内存目录比如 /dev/shm 下的相关文件避免残留数据导致问题。4.2 资源受限设备上的取舍如果目标平台是 512MB 内存的 ARM 工控板或者对启动时间有严格要求的车载设备Cyclone DDS 通常比 Fast DDS 更友好。它的依赖少交叉编译简单运行时内存占用低线程数也少。Fast DDS 在没有精简配置的情况下默认建线程的数量会明显更多内存分配也更激进。但这不代表 Fast DDS 不能做嵌入式。eProsima 本身就提供面向嵌入式场景的配置指导只是你需要花时间裁剪 XML 配置。裁剪的核心思路是限制 discovery 的参与者数量、关闭不需要的传输层、指定线程池大小、调整缓存区上限。这套活做下来对团队的 DDS 理解水平要求比较高。4.3 我的选型决策流程我现在面对一个新项目并不会立刻定 DDS 实现而是按流程走一遍先确认项目是否必须用 DDS。如果只是单机内进程通信用共享内存加自定义协议可能更简单如果有严格的多机分布式、动态发现、QoS 要求再上 DDS 不迟。然后看生态。如果项目基于 ROS 2优先跟随官方默认或经过大规模验证的实现除非有明确痛点。团队里有 ROS 2 经验的人越多越适合先沿用默认 RMW遇到性能瓶颈再切换。再看场景特征。延迟敏感、消息频率高的小数据包场景我会优先验证 Cyclone DDS功能全面、需要充分定制的复杂系统Fast DDS 更合适如果客户是航空、电力这类有合规要求的行业OpenDDS 的完整性和历史背书是加分项。最后做一个简单决策表项目特征推荐方向理由ROS 2 全栈、团队新手多跟随发行版默认 RMW社区资料最多踩坑成本最低延迟敏感、高频小消息Cyclone DDS默认性能好内存和线程开销低多机大规模、复杂网络拓扑Fast DDS Discovery Server集中发现模式更可控航空、国防等合规场景OpenDDS标准完整度高长期验证充分多厂商异构设备互联根据互通测试结果确定必须提前验证 RTPS 互操作性这张表只是一个起点真正落地前还是要用第 3 节的方法做一轮实测。5. 常见问题速查与避坑清单5.1 节点互相发现不了这是我在群里被问得最多的问题。原因通常集中在四类domain ID 不一致、网卡绑定错误、组播被禁止、防火墙拦截。排查时先用 ros2 doctor 看当前环境的 RMW 和网络配置再确认所有节点的 ROS_DOMAIN_ID 是否一致。多网卡设备上还要在 DDS 配置里锁定要使用的网卡接口否则节点可能通过错误的网卡发送组播包。5.2 不同实现之间互通失败Fast DDS 和 Cyclone DDS 互相通信失败最常见的原因是 QoS 不匹配。比如发布者用的是 BEST_EFFORT订阅者配置成了 RELIABLE有些实现会直接拒绝建立连接。还有类型名不一致的问题跨实现时对类型名的校验更严格错一个字母都会导致匹配失败。建议在项目里制定统一的 QoS 模板并让所有团队共用同一份 IDL 文件。从源头避免类型和策略的漂移。5.3 内存和线程持续增长如果程序长期运行后内存缓慢增长先看是不是 discovery 不停触发重连。节点频繁启停、网络抖动都会导致 DDS 内部维护大量连接信息。可以尝试限制 discovery 相关配置把无效连接的超时时间调短。另外Fast DDS 在默认配置下会创建较多线程资源紧张时注意通过 XML 限制线程池和缓存池大小。5.4 性能达不到文档数据网上很多性能测试数据都是“最优配置下的极限值”例如关闭可靠性、禁用安全插件、使用共享内存传输、绑核、设置实时优先级等。咱们实际项目里的数据达不到这些值不代表实现有问题。优先检查 QoS 是否用了可靠模式可靠模式的吞吐和延迟天然比尽力而为模式差不少。再检查是否开启了 DDS Security加解密开销会明显影响性能。最后才需要怀疑实现本身。5.5 一张问题速查表现象可能根因排查与解决办法节点互相看不见网卡绑定错误、组播禁止、domain ID 不一致ros2 doctor、tcpdump 抓包、配置网卡接口跨实现收不到数据QoS 不匹配、类型名不一致统一 QoS 模板、统一 IDL、开启调试日志内存缓慢增长discovery 重连、缓存未释放调短连接超时、限制缓存池延迟明显偏高RELIABLE 模式、Security 开销改用 BEST_EFFORT、关闭非必要安全插件线程数过多默认线程池配置宽松通过 XML 限制线程数、减少传输层最后再说几句实在话接触 DDS 这几年我最大的体会是不要小看默认实现带来的生态惯性也不要因为一两次性能问题就急着换实现。“默认”意味着社区踩坑最多、公开资料最多很多奇怪问题都能搜到答案但当你真遇到连接不稳定、资源占用过高等实实在在的瓶颈时换一个实现可能立竿见影因为实现之间的工程取舍差距是真实存在的。我现在做一个新项目都会预留出半天时间把候选 DDS 实现放到真实网络和真实消息负载下跑一轮互通测试和性能测试再拍板。这个成本相比上线后再抓包排错真的划算太多。希望这篇对比能帮你少走一点弯路。