Eclipse Cyclone DDS 是OMG DDS 规范的一个非常高效和强大的开源实现。Cyclone DDS 是完全开放开发的 Eclipse IoT 项目(参见eclipse-cyclone-dds ),其采用者名单正在不断增加(如果您是其中之一,请添加您的徽标)。它是机器人操作系统ROS 2的一级中间件。
什么是 DDS?
DDS 是分布式系统中保守得最好的秘密,它存在的时间比大多数发布订阅消息系统要长得多,而且仍然比其中许多系统更胜一筹。DDS 用于各种各样的系统,包括空中交通管制、喷气发动机测试、铁路控制、医疗系统、海军指挥和控制、智能温室等等。简而言之,它在航空航天和国防领域已经很成熟,但不再局限于此。而且它很容易使用!
类型通常在 IDL 中定义,并使用 Cyclone 中包含的 IDL 编译器进行预处理,但我们的Python 绑定允许您动态定义数据类型:
from dataclasses import dataclass
from cyclonedds.domain import DomainParticipant
from cyclonedds.core import Qos, Policy
from cyclonedds.pub import DataWriter
from cyclonedds.sub import DataReader
from cyclonedds.topic import Topic
from cyclonedds.idl import IdlStruct
from cyclonedds.idl.annotations import key
from time import sleep
import numpy as np
try:
from names import get_full_name
name = get_full_name()
except:
import os
name = f"{os.getpid()}"
# C, C++ require using IDL, Python doesn't
@dataclass
class Chatter(IdlStruct, typename="Chatter"):
name: str
key("name")
message: str
count: int
rng = np.random.default_rng()
dp = DomainParticipant()
tp = Topic(dp, "Hello", Chatter, qos=Qos(Policy.Reliability.Reliable(0)))
dw = DataWriter(dp, tp)
dr = DataReader(dp, tp)
count = 0
while True:
sample = Chatter(name=name, message="Hello, World!", count=count)
count = count + 1
print("Writing ", sample)
dw.write(sample)
for sample in dr.take(10):
print("Read ", sample)
sleep(rng.exponential())
如今,DDS 在机器人和自动驾驶汽车中也很受欢迎,因为它们确实依赖于高吞吐量、低延迟的控制系统,而不会通过在中间使用消息代理引入单点故障。事实上,它是迄今为止 ROS 2 中最常用和默认的中间件选择。它用于在组件之间传输命令、传感器数据甚至视频和点云。
OMG DDS 规范涵盖了使用发布-订阅消息构建系统所需的一切。它们定义了一个结构类型系统,允许在读取器和写入器之间自动进行字节序转换和类型检查。此类型系统还支持类型演变。可互操作的网络协议和标准 C++ API 使构建集成多个 DDS 实现的系统变得容易。零配置发现也包含在标准中,并得到所有实现的支持。
DDS 实际上带来了更多:发布-订阅消息传递是对“普通”网络的一个很好的抽象,但普通的发布-订阅不会影响人们对系统的看法。真正改变分布式系统观点的一个非常强大的架构是“共享数据空间”,它本身是一个古老的想法,实际上只是一个分布式数据库。大多数共享数据空间设计在实时控制系统中都失败了,因为它们提供了强大的一致性保证,但牺牲了太多的性能和灵活性。DDS的最终一致性共享数据空间在帮助构建需要满足许多“功能”的系统方面非常成功:可靠性、可维护性、可扩展性、可升级性……说实话,这就是它被发明的原因,而发布-订阅消息传递只是一种实现技术。
Cyclone DDS 旨在全面覆盖规格,目前已涵盖了大部分规格。参考各个 OMG 规格,可获得以下内容:
- DCPS基本规范
- 零配置发现(如果多播有效)
- 发布/订阅消息
- 可配置订阅者的数据存储
- 许多 QoS 设置——活跃度监控、截止期限、历史数据......
- 覆盖范围包括最低限度、所有权和(部分)内容配置文件
- DDS 安全——提供身份验证、访问控制和加密
- DDS C++ API
- DDS XTypes - 结构类型系统(这里有一些注意事项)
- DDSI-RTPS——可互操作的网络协议
Cyclone DDS 中的网络堆栈已经以各种形式存在了十多年,并且已经在许多系统中证明了自己,包括大型、高可用性系统和需要与其他实现互操作性的系统。
该存储库提供了 Cyclone DDS 的核心,包括其 C API、OMG C++和Python语言绑定(位于兄弟存储库中)。
请参阅路线图以获得即将推出的功能的高级概述。
入门
构建 Eclipse Cyclone DDS
为了构建 Cyclone DDS,您需要一台 Linux、Mac 或 Windows 10 机器(或者,有一些注意事项,需要一台 *BSD、QNX、OpenIndiana 或 Solaris 2.6 机器),并且在主机上安装以下软件:
- C 编译器(最常见的是 Linux 上的 GCC、Windows 上的 Visual Studio、macOS 上的 Xcode);
- 可选的GIT版本控制系统;
- CMake,版本 3.16 或更高版本;
- 可选的OpenSSL,我们推荐使用完全修补和支持的版本,但 1.1.1 仍然可以使用;
- 可选的Eclipse Iceoryx版本 2.0 用于共享内存和零拷贝支持;
- 可选的Bison解析器生成器。缓存的源已签入存储库。
如果您想试用一下解析器,则需要安装 bison 解析器生成器。在 Ubuntu 上apt install bison
应该可以完成安装。在 Windows 上,安装 chocolateychoco install winflexbison3
应该会很有帮助。在 macOS 上,brew install bison
这是最简单的。
要获取 Eclipse Cyclone DDS,请执行以下操作
<span style="background-color:var(--bgColor-muted, var(--color-canvas-subtle))"><span style="color:#1f2328"><span style="color:var(--fgColor-default, var(--color-fg-default))"><span style="background-color:var(--bgColor-muted, var(--color-canvas-subtle))"><code>$ git clone https://github.com/eclipse-cyclonedds/cyclonedds.git
$ cd cyclonedds
$ mkdir build
</code></span></span></span></span>
根据您是否想使用 Cyclone DDS 开发应用程序或为其做出贡献,您可以遵循不同的程序:
构建配置
除了标准选项之外,还使用 CMake 定义指定了一些配置选项,例如CMAKE_BUILD_TYPE
:
-DBUILD_EXAMPLES=ON
:构建所包含的示例-DBUILD_TESTING=ON
:构建测试套件(强制从库中导出所有符号)-DBUILD_IDLC=NO
:禁用 IDL 编译器的构建(影响示例、测试和构建ddsperf
)-DBUILD_DDSPERF=NO
:禁用构建ddsperf绩效衡量工具-DENABLE_SSL=NO
:不查找 OpenSSL,删除 TLS/TCP 支持并避免构建实现身份验证和加密的插件(AUTO
如果发现 OpenSSL,则默认启用它们)-DENABLE_ICEORYX=NO
:不寻找 Iceoryx 禁用构建 PSMX Iceoryx 插件(AUTO
如果找到 Iceoryx,则默认启用它)-DENABLE_SECURITY=NO
:不在核心代码中构建安全接口和挂钩,也不在插件中构建安全接口和挂钩(可以在没有 OpenSSL 的情况下启用安全性,在这种情况下,您只需要在其他地方找到插件)-DENABLE_LIFESPAN=NO
:排除对有限寿命 QoS 的支持-DENABLE_DEADLINE_MISSED=NO
:排除对有限期限 QoS 设置的支持-DENABLE_TYPELIB=NO
-DENABLE_TYPE_DISCOVERY=NO
:要排除对类型库的支持,还需要使用和禁用类型和主题发现-DENABLE_TOPIC_DISCOVERY=NO
-DENABLE_TYPE_DISCOVERY=NO
:要排除对类型发现和检查类型兼容性(实际上大多数 XTypes)的支持,还需要使用禁用主题发现-DENABLE_TOPIC_DISCOVERY=NO
-DENABLE_TOPIC_DISCOVERY=NO
:排除对主题发现的支持-DENABLE_SOURCE_SPECIFIC_MULTICAST=NO
:禁用对源特定多播的支持(禁用此功能-DENABLE_IPV6=NO
可能需要 QNX 构建)-DENABLE_IPV6=NO
:禁用 ipv6 支持(禁用此功能-DENABLE_SOURCE_SPECIFIC_MULTICAST=NO
可能需要 QNX 构建)-DBUILD_IDLC_XTESTS=NO
:包括一组针对 IDL 编译器的测试,这些测试使用 C 后端在(测试)运行时编译 idl 文件,并使用 C 编译器为生成的类型构建测试应用程序,执行该应用程序以进行实际测试(Windows 上不支持)-DENABLE_QOS_PROVIDER=NO
:禁用对 qos 提供商的支持
对于应用程序开发人员
要构建和安装使用 Cyclone DDS 开发自己的应用程序所需的库,只需几个简单的步骤。Linux 和 macOS 与 Windows 之间存在一些细微的差异。对于 Linux 或 macOS:
$ cd build
$ cmake -DCMAKE_INSTALL_PREFIX=<install-location> ..
$ cmake --build .
对于 Windows:
$ cd build
$ cmake -G "<generator-name>" -DCMAKE_INSTALL_PREFIX=<install-location> ..
$ cmake --build .
您应该将 替换<install-location>
为要安装 Cyclone DDS 的目录以及CMake生成器<generator-name>
提供的生成构建文件的方法之一。例如,“Visual Studio 15 2017 Win64”将使用 Visual Studio 2017 进行 64 位构建。
要在成功构建后安装它,请执行以下操作:
$ cmake --build . --target install
它将所有内容复制到:
<install-location>/lib
<install-location>/bin
<install-location>/include/ddsc
<install-location>/share/CycloneDDS
根据安装位置,您可能需要管理员权限。
此时您已准备好在自己的项目中使用 Eclipse Cyclone DDS。
请注意,默认构建类型是包含调试信息的发布构建 (RelWithDebInfo),这通常是应用程序使用起来最方便的构建类型,因为它兼具性能和调试功能。如果您想要使用调试或纯发布构建,请进行CMAKE_BUILD_TYPE
相应设置。
为 Eclipse Cyclone DDS 做出贡献
我们非常欢迎对项目的所有贡献,无论是问题、示例、错误修复、文档增强或改进,还是其他任何内容。考虑贡献代码时,最好知道 Azure 管道的构建配置存在于存储库中,并且有一个使用简单测试框架和 CTest 构建的测试套件,如果需要,可以在本地构建。要构建它,请BUILD_TESTING
在配置时将 cmake 变量设置为 on,例如:
$ cd build
$ cmake -DCMAKE_BUILD_TYPE=Debug -DBUILD_TESTING=ON ..
$ cmake --build .
$ ctest
文档
文档仍然相当有限,部分内容仍然只能以文本文件的形式在docs
目录中找到。此 README 通常已过时,文档状态正在慢慢改善,因此绝对值得一看。
构建并运行往返示例
我们将向您展示如何构建和运行用于测量延迟的示例程序。示例是在构建 Cyclone DDS 时自动构建的,因此您无需遵循这些步骤即可运行该程序,它仅用于说明该过程。
$ mkdir roundtrip
$ cd roundtrip
$ cmake <install-location>/share/CycloneDDS/examples/roundtrip
$ cmake --build .
在一个终端上启动将响应 ping 的应用程序:
$ ./RoundtripPong
在另一个终端上,启动将发送 ping 的应用程序:
$ ./RoundtripPing 0 0 0
# payloadSize: 0 | numSamples: 0 | timeOut: 0
# Waiting for startup jitter to stabilise
# Warm up complete.
# Latency measurements (in us)
# Latency [us] Write-access time [us] Read-access time [us]
# Seconds Count median min 99% max Count median min Count median min
1 28065 17 16 23 87 28065 8 6 28065 1 0
2 28115 17 16 23 46 28115 8 6 28115 1 0
3 28381 17 16 22 46 28381 8 6 28381 1 0
4 27928 17 16 24 127 27928 8 6 27928 1 0
5 28427 17 16 20 47 28427 8 6 28427 1 0
6 27685 17 16 26 51 27685 8 6 27685 1 0
7 28391 17 16 23 47 28391 8 6 28391 1 0
8 27938 17 16 24 63 27938 8 6 27938 1 0
9 28242 17 16 24 132 28242 8 6 28242 1 0
10 28075 17 16 23 46 28075 8 6 28075 1 0
上述数字是在 2018 年 12 月 12 日在运行 4.2 GHz Intel Core i7 的 Mac 上测得的。从这些数字中您可以看到往返非常稳定,并且在此硬件上最小延迟现在降至 17 微秒(以前为 25 微秒)。
表现
对于非常小的样本,可靠的消息吞吐量超过 1MS/s,对于 100 字节样本,大约是 GbE 的 90%,当使用ddsperf在两个运行 Ubuntu 16.04 的 Intel(R) Xeon(R) CPU E3-1270 V2 @ 3.50GHz(2012 年的硬件......)之间测量时,延迟约为 30us,在 Ubuntu 18.04 上使用 gcc 7.4.0 构建的可执行文件用于默认(即“RelWithDebInfo”)构建。
这是在订阅者处于监听模式时,使用异步传输进行吞吐量测试的结果。配置是略微调整的开箱即用配置:增加了最大消息大小和片段大小,并增加了写入器端可靠性窗口的高水位标记。有关详细信息,请参阅脚本目录、 环境详细信息以及图表所依据的吞吐量和延迟数据。这些还包括 CPU 使用率(吞吐量和延迟)和内存使用率。
运行时配置
开箱即用的配置通常应该没问题,但可以通过创建具有所需设置的 XML 文件并定义CYCLONEDDS_URI
指向该文件的选项来调整许多选项。例如(在 Linux 上):
$ cat cyclonedds.xml
<?xml version="1.0" encoding="UTF-8" ?>
<CycloneDDS xmlns="https://cdds.io/config" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="https://cdds.io/config https://raw.githubusercontent.com/eclipse-cyclonedds/cyclonedds/master/etc/cyclonedds.xsd">
<Domain Id="any">
<General>
<Interfaces>
<NetworkInterface autodetermine="true" priority="default" multicast="default" />
</Interfaces>
<AllowMulticast>default</AllowMulticast>
<MaxMessageSize>65500B</MaxMessageSize>
</General>
<Discovery>
<EnableTopicDiscoveryEndpoints>true</EnableTopicDiscoveryEndpoints>
</Discovery>
<Internal>
<Watermarks>
<WhcHigh>500kB</WhcHigh>
</Watermarks>
</Internal>
<Tracing>
<Verbosity>config</Verbosity>
<OutputFile>cdds.log.${CYCLONEDDS_PID}</OutputFile>
</Tracing>
</Domain>
</CycloneDDS>
$ export CYCLONEDDS_URI=file://$PWD/cyclonedds.xml
(在 Windows 上,必须使用set CYCLONEDDS_URI=file://...
。)
这个例子说明了一些事情:
Interfaces
可用于覆盖默认选择的接口。成员包括NetworkInterface[@autodetermine]
告诉 Cyclone DDS 自动选择它认为最佳的接口。NetworkInterface[@name]
指定要选择的接口的名称(上面未显示,自动确定的替代方法)。NetworkInterface[@address]
指定要选择的接口的 ipv4/ipv6 地址(上面未显示,自动确定的替代方法)。NetworkInterface[@multicast]
指定是否应在此接口上使用多播。默认值“default”表示 Cyclone DDS 将检查 OS 报告的接口标志,并在支持多播的情况下启用多播。使用“true”可忽略 OS 报告的内容并启用它,使用“false”可始终禁用此接口上的多播。NetworkInterface[@priority]
指定接口的优先级。默认值(default
)表示0
普通接口的优先级,以及2
环回接口的优先级。
AllowMulticast
配置使用多播的情况。如果所选接口不支持多播,则显然不会使用多播 (false
);但如果支持多播,则网络适配器的类型将决定默认值。对于有线网络,它将使用多播进行初始发现以及当数据需要发送到多个对等点时传输数据 (true
)。在 WiFi 网络上,它将仅将其用于初始发现 (spdp
),因为 WiFi 上的多播非常不可靠。EnableTopicDiscoveryEndpoints
打开主题发现(假设它在编译时启用),它默认是禁用的,因为它在许多系统中不被使用并且在发现流量中带来大量开销。Verbosity
允许控制跟踪,“config”将配置转储到跟踪输出(默认为“cyclonedds.log”,但此处附加了进程 ID)。使用哪个接口、使用哪些多播设置等都在跟踪中。将详细程度设置为“最精细”可提供有关内部工作方式的更多输出,并且还有其他各种级别。MaxMessageSize
控制 RTPS 消息的最大大小(基本上是 UDP 有效负载的大小)。这些较大的值通常比环回接口上的(当前)默认值更能提高性能。WhcHigh
确定发送方何时等待读取方的确认,因为它缓冲了太多未确认的数据。有一些自动调整,(当前)默认值有点小,无法获得真正高的吞吐量。
您可以在此处找到有关配置 Cyclone DDS 的背景信息,并可查看设置列表。
本文来源:GitHub - eclipse-cyclonedds/cyclonedds: Eclipse Cyclone DDS project