DDS 調校資訊
本頁面提供一些參數調校的指引,這些調校是針對在實際情況中於 Linux 上使用各種 DDS 實作時所遇到的問題。我們在 Linux 上或使用某個供應商時發現的問題,也可能發生在其他未在此記錄的平台和供應商上。
以下建議是調校的起點;它們在特定系統和環境中有效,但調校可能因多種因素而異。在除錯時,您可能需要根據訊息大小、網路拓撲等因素來增加或減少數值。
重要的是要認識到,調校參數可能會消耗資源,並可能影響系統中超出預期改進範圍的部分。對於每個案例,應權衡提升可靠性的好處與其帶來的任何不利影響。
跨供應商調校
問題: 透過有損(通常是 WiFi)連線傳送資料時,若某些 IP 片段被丟棄,可能會導致接收端的內核緩衝區被填滿。
當一個 UDP 封包缺少至少一個 IP 片段時,其餘已接收的片段會填滿內核緩衝區。預設情況下,Linux 內核在嘗試重組封包片段 30 秒後會逾時。由於此時內核緩衝區已滿(預設大小為 256KB),無法再接收新的片段,因此連線會看似「掛起」很長一段時間。
此問題在所有 DDS 供應商中普遍存在,因此解決方案涉及調整內核參數。
解決方案: 使用盡力而為(best-effort)的 QoS 設定,而非可靠(reliable)模式。
盡力而為設定可減少網路流量,因為 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
Fast RTPS 調校
問題: Fast RTPS 在透過 WiFi 運作時,會以大量資料或快速發布的資料淹沒網路。
請參閱 跨供應商調校 下的解決方案。
Cyclone DDS 調校
問題: Cyclone DDS 即使使用可靠設定並透過有線網路傳輸,仍無法可靠地傳遞大型訊息。
此問題應 很快會被解決。在此之前,我們提出了以下解決方案(使用 此測試程式 進行除錯):
解決方案: 增加 Linux 內核的最大接收緩衝區大小和 Cyclone 使用的最小 socket 接收緩衝區大小。
解決 9MB 訊息的調整:
透過執行以下指令設定最大接收緩衝區大小 rmem_max:
$ sudo sysctl -w net.core.rmem_max=2147483647
或者透過編輯 /etc/sysctl.d/10-cyclone-max.conf 檔案將其永久設定為包含以下內容:
net.core.rmem_max=2147483647
接下來,若要設定 Cyclone 請求的最小 socket 接收緩衝區大小,請編寫一個供 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 乙太網路連接),結果沒有訊息丟失,平均訊息傳遞時間分別為 700 毫秒和 371 毫秒。
在未組態內核 rmem_max 的情況下,相同的 Connext QoS 設定檔需要長達 12 秒才能完成資料傳遞。然而,它至少總能完成傳遞。
解決方案: 使用 Connext QoS 設定檔,*無需*調整 rmem_max。
ROS2TEST_QOS_PROFILES.xml 檔案是使用 RTI 關於 設定流量控制器 的文件進行配置的。它包含慢速、中速和快速流量控制器(請參閱 Connext QoS 設定檔連結)。
中速流量控制器在我們的情況下產生了最佳結果。然而,控制器仍需要根據其運行的特定機器/網路/環境進行調校。Connext 流量控制器可用於調整頻寬及其發送資料的積極程度,但一旦超過特定設定的頻寬,效能就會開始下降。