DDS调优指南
本页提供了一些关于参数调整的指导,这些参数调整被发现可以解决在实际情况下在Linux上使用各种DDS实现时所面临的问题。我们在Linux上或使用一个供应商时发现的问题可能会发生在其他平台和此处未记录的供应商身上。
以下建议是调整的起点; 它们适用于特定的系统和环境,但调整可能因多种因素而异。在调试时,您可能需要增加或减少与消息大小、网络拓扑等因素相关的值。 [待校准@6023]
重要的是要认识到,优化参数可能会给重新源文件带来代价,并且可能会影响系统的某些部分,超出预期的改进范围。提高可靠性的好处应该与每个个案的任何不利因素相权衡。 [待校准@6024]
跨供应商调整
Issue问题: when当一些IP片段被丢弃时,通过有损 (通常是WiFi) 连接发送数据会变得有问题,这可能导致接收端的内核缓冲区变满。 [待校准@6026]
当UDP数据包缺少至少一个IP片段时,其余接收到的片段会填满内核缓冲区。默认情况下,linux内核将在尝试重组数据包片段30秒后超时。因为内核缓冲区已满此时 (默认大小是256KB),无新片段可以进来,所以连接看似 "hang" 长时间。 [待校准@6027]
此问题在所有DDS供应商中都是通用的,因此解决方案涉及调整内核参数。 [待校准@6028]
Solution解决方案: Use使用尽力而为的QoS设置,而不是可靠的。 [待校准@6029]
尽力而为的设置减少了网络流量,因为DDS的实施不需要产生可靠通讯的开销,如果发布者要求对发送给订阅者的消息进行确认,并且必须重新发送未正确接收的样本。 [待校准@6030]
但是,如果用于IP片段的内核缓冲区已满,则症状仍然相同 (阻塞30秒)。这个解决方案应该在不需要调整参数的情况下改善问题。 [待校准@6031]
解决方案: 减少 ipfrag_time
参数的值。 [小鱼@6032]
[需手动修复的语法]``net.ipv4.ipfrag_time / /proc/sys/net/ipv4/ipfrag_time`` (默认30秒): 将IP片段保存在内存中的时间 (以秒为单位)。 [待校准@6033]
例如,通过运行以下命令将值减小到3s: [待校准@6034]
sudo sysctl net.ipv4.ipfrag_time=3
减小此参数的值还会减少未收到片段的时间窗口。对于所有传入的片段,该参数是全局的,因此需要为每个环境考虑降低其值的可行性。 [待校准@6035]
解决方案: 增加 ipfrag_high_thresh
参数的值。 [小鱼@6036]
[需手动修复的语法]``net.ipv4.ipfrag_high_thresh / /proc/sys/net/ipv4/ipfrag_high_thresh`` (默认值: 262144字节): 用于重新组装IP片段的最大内存。 [待校准@6037]
例如,通过运行以下命令将值增加到128mb: [待校准@6038]
sudo sysctl net.ipv4.ipfrag_high_thresh=134217728 # (128 MB)
显著增加此参数的值是为了确保缓冲区永远不会完全满。然而,假设每个UDP数据包缺少一个片段,该值可能必须非常高才能保存在 ipfrag_time
时间窗内收到的所有数据。 [待校准@6039]
Issue问题: Sending使用非原始类型的大型可变大小数组发送自定义消息会导致较高的序列化/反序列化开销和CPU负载。这可能会导致出版商停滞不前,因为在 publish()
和工具 (如 ros2 topic hz
) 上花费的时间过长,无法报告收到消息的实际频率。请注意,例如 builtin_interfaces/Time
也被视为非原始类型,将产生更高的序列化开销。由于增加的序列化开销,当天真地将自定义消息类型从ROS 1过渡到ROS 2时,可以观察到严重的性能下降。 [待校准@6040]
Workaround解决方法: Use使用多个原语数组而不是单个自定义类型数组,或者像在 PointCloud2
消息中那样打包到字节数组中。例如,将 FooArray
信息定义为: [待校准@6041]
Foo[] my_large_array
with Foo
is defined as:
uint64 foo_1
uint32 foo_2
相反,将 FooArray
定义为: [待校准@6043]
uint64[] foo_1_array
uint32[] foo_2_array
快速RTPS调整 [待校准@6044]
Issue问题: Fast通过WiFi运行时,快速RTPS会向网络注入大量数据或快速发布的数据。 [待校准@6045]
见 Cross-vendor tuning 下的解决方案。 [待校准@6046]
CycloneDDS调谐 [待校准@6047]
Issue问题: 尽管使用了可靠的设置并通过有线网络传输,但CycloneDDS无法可靠地传递大消息。 [待校准@6048]
这个问题应该是 addressed soon 。在此之前,我们提出了以下解决方案 (使用 this test program 调试): [待校准@6049]
Solution解决方案: Increase增加linux内核接收缓冲区的最大大小和Cyclone使用的最小套接字接收缓冲区大小。 [待校准@6050]
为解决9MB消息而进行的调整: [小鱼@6051]
通过运行以下命令设置最大接收缓冲区大小 rmem_max
: [待校准@6052]
sudo sysctl -w net.core.rmem_max=2147483647
或者通过将 /etc/sysctl.d/10-cyclone-max.conf
文件编辑为包含以下内容来永久设置它: [待校准@6053]
net.core.rmem_max=2147483647
接下来,要设置Cyclone请求的最小套接字接收缓冲区大小,请编写一个配置文件供Cyclone在启动时使用,如下所示: [待校准@6054]
<?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>
<MinimumSocketReceiveBufferSize>10MB</MinimumSocketReceiveBufferSize>
</Internal>
</Domain>
</CycloneDDS>
然后,无论何时运行节点,都要设置以下环境变量: [待校准@6055]
CYCLONEDDS_URI=file:///absolute/path/to/config_file.xml
RTI Connext调谐 [待校准@6056]
Issue问题: con尽管使用了可靠的设置并通过有线网络传输,但Connext无法可靠地传递大消息。 [待校准@6057]
解决方案: 此 Connext QoS 配置文件 ,同时增加 rmem_max
参数。 [小鱼@6058]
通过运行以下命令设置最大接收缓冲区大小 rmem_max
: [待校准@6052]
sudo sysctl -w net.core.rmem_max=4194304
通过在linux内核中将 net.core.rmem_max
调整到4mb,QoS配置文件可以产生真正可靠的行为。 [待校准@6059]
这种配置已被证明可以通过SHMEM | UDPv4可靠地传递消息,并且仅在一台计算机上使用UDPv4。还使用4MB和20MB的 rmem_max
测试了多机配置 (两台机器连接1Gbps以太网),无丢弃消息,平均消息传递时间分别为700毫秒和371毫秒。 [待校准@6060]
在不配置内核的 rmem_max
的情况下,相同的Connext QoS配置文件最多需要12秒才能传送数据。然而,它总是至少设法完成交付。 [待校准@6061]
Solution: Use the Connext QoS profile without adjusting rmem_max
.
Ros2test_qos_profile.Xml文件是使用RTI关于 configuring flow controllers 的文档配置的。它有慢、中、快流量控制器 (见Connext QoS配置文件链接)。 [待校准@6063]
介质流量控制器为我们的案例产生了最好的结果。然而,控制器仍然需要根据他们正在操作的特定机器/网络/环境进行调整。Connext流量控制器可用于调整带宽及其发送数据的侵略性,尽管一旦通过特定设置的带宽,性能将开始下降。 [待校准@6064]