DDS 调整信息

本页提供了一些参数调整指南,这些指南旨在解决在实际情况下使用 Linux 上的各种 DDS 实现时遇到的问题。 我们在 Linux 上或使用某个供应商时发现的问题可能会出现在其他未在此处记录的平台和供应商上。

以下建议是调整的起点;它们适用于特定的系统和环境,但调整可能会因多种因素而异。 您可能需要在调试时根据消息大小、网络拓扑等因素增加或减少值。

重要的是要认识到调整参数可能会消耗资源,并且可能会影响系统的部分内容,超出预期的改进范围。 应权衡提高可靠性的好处与每种情况下的任何不利之处。

跨供应商调整

问题: 当某些 IP 片段被丢弃时,通过有损连接(通常是 WiFi)发送数据会变得有问题,这可能会导致接收端的内核缓冲区变满。

当 UDP 数据包缺少至少一个 IP 片段时,其余接收的片段会填满内核缓冲区。 默认情况下,Linux 内核将在尝试重新组合数据包片段 30 秒后超时。 由于此时内核缓冲区已满(默认大小为 256KB),因此无法输入任何新片段,因此连接似乎会长时间“挂起”。

此问题在所有 DDS 供应商中都很常见,因此解决方案涉及调整内核参数。

解决方案: 使用尽力而为的 QoS 设置而不是可靠设置。

尽力而为的设置减少了网络流量,因为 DDS 实现不必承担可靠通信的开销,在可靠通信中,发布者需要确认发送给订阅者的消息,并且必须重新发送未正确接收的样本。

但是,如果 IP 片段的内核缓冲区已满,症状仍然相同(阻塞 30 秒)。 此解决方案应该可以在一定程度上改善问题,而无需调整参数。

解决方案: 降低 ipfrag_time 参数的值。

``net.ipv4.ipfrag_time / /proc/sys/net/ipv4/ipfrag_time``(默认 30 秒): 以秒为单位将 IP 片段保留在内存中。

例如,通过运行以下命令将值降低到 3 秒:

sudo sysctl net.ipv4.ipfrag_time=3

降低此参数的值也会减少未收到任何片段的时间窗口。 此参数对所有传入片段都是全局的,因此需要考虑针对每个环境降低其值的可行性。

解决方案: 增加 ipfrag_high_thresh 参数的值。

``net.ipv4.ipfrag_high_thresh / /proc/sys/net/ipv4/ipfrag_high_thresh``(默认值:262144 字节): 用于重组 IP 片段的最大内存。

通过运行以下命令将该值增加到 128MB,例如:

sudo sysctl net.ipv4.ipfrag_high_thresh=134217728     # (128 MB)

大幅增加此参数的值是为了确保缓冲区永远不会完全填满。 但是,假设每个 UDP 数据包缺少一个片段,则该值可能必须非常高才能保存“ipfrag_time”时间窗口内收到的所有数据。

问题: 发送带有大型可变大小非原始类型的数组的自定义消息会导致高序列化/反序列化开销和 CPU 负载。 这可能会导致发布者因在“publish()”上花费过多时间而停滞,并且“ros2 topic hz”等工具未报告收到消息的实际频率。 请注意,例如“builtin_interfaces/Time”也被视为非原始类型,并将产生更高的序列化开销。 由于序列化开销增加,当将自定义消息类型从 ROS 1 简单转换到 ROS 2 时,可能会出现严重的性能下降。

解决方法: 使用多个原语数组而不是单个自定义类型数组,或者像在“PointCloud2”消息中那样打包到字节数组中。 例如,不要将“FooArray”消息定义为:

Foo[] my_large_array

其中 Foo 定义为:

uint64 foo_1
uint32 foo_2

相反,将“FooArray”定义为:

uint64[] foo_1_array
uint32[] foo_2_array

快速调整

问题: 通过 WiFi 操作时,快速 RTPS 会用大量数据或快速发布的数据淹没网络。

请参阅 跨供应商调优 下的解决方案。

Cyclone DDS 调优

问题: 尽管使用可靠的设置并通过有线网络传输,Cyclone DDS 仍无法可靠地传递大量消息。

此问题应很快得到解决 <https://github.com/eclipse-cyclonedds/cyclonedds/issues/484>`_。 在此之前,我们提出了以下解决方案(使用`此测试程序 <https://github.com/jacobperron/pc_pipe>`_ 进行调试):

解决方案: 增加 Cyclone 使用的最大 Linux 内核接收缓冲区大小和最小套接字接收缓冲区大小。

调整以解决 9MB 消息的问题:

通过运行以下命令设置最大接收缓冲区大小“rmem_max”:

sudo sysctl -w net.core.rmem_max=2147483647

或者通过编辑“/etc/sysctl.d/10-cyclone-max.conf”文件来永久设置它,使其包含:

net.core.rmem_max=2147483647

接下来,为了设置 Cyclone 请求的最小套接字接收缓冲区大小,请写出 Cyclone 在启动时使用的配置文件,如下所示:

<?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">
        <Internal>
            <SocketReceiveBufferSize min="10MB"/>
        </Internal>
    </Domain>
</CycloneDDS>

然后,无论何时运行节点,请设置以下环境变量:

CYCLONEDDS_URI=file:///absolute/path/to/config_file.xml

RTI Connext 调整

问题 :尽管使用可靠的设置并通过有线网络传输,Connext 仍无法可靠地传递大消息。

解决方案 :此 Connext QoS 配置文件,以及增加 rmem_max 参数。

通过运行以下命令设置最大接收缓冲区大小 rmem_max

sudo sysctl -w net.core.rmem_max=4194304

通过在 Linux 内核中将“net.core.rmem_max”调整为 4MB,QoS 配置文件可以产生真正可靠的行为。

事实证明,此配置可以通过 SHMEM|UDPv4 可靠地传递消息,并且在单台机器上仅使用 UDPv4。 还测试了多台机器配置,其中“rmem_max”为 4MB 和 20MB(两台机器通过 1Gbps 以太网连接),没有丢失消息,平均消息传递时间分别为 700ms 和 371ms。

如果不配置内核的“rmem_max”,相同的 Connext QoS 配置文件最多需要 12 秒才能传递数据。 但是,它至少总是能够完成传递。

解决方案: 使用 Connext QoS 配置文件 *无需*调整 rmem_max

ROS2TEST_QOS_PROFILES.xml 文件是使用 RTI 关于``配置流量控制器 <https://community.rti.com/forum-topic/transfering-large-data-over-dds>`_ 的文档配置的。它具有慢速、中速和快速流量控制器(见 Connext QoS 配置文件链接)。

中等流量控制器在我们的案例中产生了最佳结果。 但是,控制器仍然需要针对其所运行的特定机器/网络/环境进行调整。 Connext 流量控制器可用于调整带宽及其发送数据的积极性,但一旦超过特定设置的带宽,性能就会开始下降。