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
Cyclone DDS调优
**问题:**尽管使用可靠的设置并通过有线网络传输,Cyclone DDS无法可靠地传递大消息。
这个问题应该会很快得到解决。在那之前,我们提出了以下解决方案(使用`此测试程序 <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配置文件<https://github.com/jacobperron/pc_pipe/blob/master/etc/ROS2TEST_QOS_PROFILES.xml>`_ ,同时增加 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配置文件<https://github.com/jacobperron/pc_pipe/blob/master/etc/ROS2TEST_QOS_PROFILES.xml>`_,*不*调整``rmem_max``。
ROS2TEST_QOS_PROFILES.xml文件是使用RTI的文档`配置流控制器<https://community.rti.com/forum-topic/transfering-large-data-over-dds>`_进行配置的。它包含了慢速、中速和快速的流控制器(在Connext QoS配置文件链接中可见)。
中等流量控制器在我们的案例中产生了最好的结果。然而,控制器仍然需要根据它们所操作的特定机器/网络/环境进行调整。Connext流量控制器可以用来调整带宽及其发送数据的攻击性,尽管一旦超过特定设置的带宽,性能就会开始下降。