DPDK based Open vSwitch熱升級設計與實現

語言: CN / TW / HK

本文是由位元組跳動系統部 STE 團隊出品的文章。

系統級服務的無擾動升級(non distruptive upgrade,下文簡稱為熱升級)對服務的快速迭代開發有非常重要的意義。虛擬交換機(vSwitch)作為虛擬網路的入口,需求多變,但頻繁升級斷網會影響虛機上執行的業務。此外,一般每臺宿主機上只有一個虛擬交換機,在架構上也不好做主備。因此熱升級技術對 vSwitch 的快速迭代至關重要。

本文介紹了我們在 DPDK based Open vSwtich(下簡稱 ovs-dpdk)上的熱更新技術的實踐,希望和業界同行共同探討。

現狀

  1. Open vSwitch(下簡稱 ovs)已有的“熱升級”方案基本是為 ovs-kernel 而實現的。在 ovs-kernel 中,vswitchd 程序是慢路徑,kernel 模組是快速路徑。升級 vswitchd 程序時可不替換 kernel 模組,讓大部分流量經過 kernel 中 flow cache 轉發,減少網路擾動。升級 kernel 模組則可能會有較長的斷網風險。這塊的詳細資訊可以參考連結: http://docs.openvswitch.org/en/latest/intro/install/general/?highlight=hot%20upgrade#hot-upgrading
  2. ovs-dpdk 中,快速路徑和慢速路徑都整合在 vswitchd 程序中,如果簡單的重啟 vswtichd,由於 DPDK 的初始化(主要是大頁初始化,1G 大頁耗時約 600ms)、網絡卡的初始化(實測 Mellanox CX5 驅動初始化耗時接近 1s)都比較耗時,因此會有秒級斷網。
  3. 為了實現快速的迭代開發,降低升級導致的斷網帶來的業務擾動,需要開發 ovs-dpdk 的熱升級特性。

方案與折衷

實現熱更新有很多實現方式:

  • 外掛式升級(形象的說就是熱補丁):將主要的包處理邏輯變成動態連結庫,通過熱載入外掛的方式,避免耗時的 dpdk 初始化和網絡卡初始化。(DPDK 主從模式也可被認為是這種方式的變體)

    • 優點:常規升級斷網時間非常小,可以做到納秒級。
    • 缺點:框架升級和外掛升級成為了兩種升級,框架和外掛之間必然有相互呼叫的 API 和共享資料結構,開發人員需要保持框架和外掛之間的 ABI(Application Binary Interface)一致。一個簡單的例子是流表的結構體可能會在框架和外掛之間共享,如果升級修改了流表的結構體,框架也需要升級,否則會因為不一致而導致記憶體錯誤。
  • 雙程序升級(形象的說就是熱替換):通過硬體資源冗餘,讓新老 ovs 在升級中並存,老的 ovs 繼續進行轉發,使得流量不會斷,新的 ovs 完成初始化之後,接管流量。

    • 優點:新舊 ovs 是兩個程序,不需要做任何相容,只需要遵守新舊程序之間的資訊同步的通訊協議即可。
    • 缺點:需要資源冗餘,需要網絡卡和記憶體冗餘以同時滿足新舊 ovs 的升級需求(2x 記憶體加 2x VF),斷網時間也會更長一些

業界一般採用雙程序實現熱升級,這種方式的覆蓋面更廣,工程實現上相對來說也更容易一些。下圖描述了雙程序熱升級的一般流程。

OVS 熱更新的工作原理並不複雜,就是實現上需要考慮不少瑣碎的工程細節。主要通過程式碼上精細的控制使得升級斷網時間較小。

二段式設計

我們把熱升級的整個流程分成兩個階段(二段式),這裡的設計有點借鑑虛擬機器進行熱遷移的過程。在第一階段,網路的轉發服務不會停止,並且一旦升級出現故障,整個系統是可以自動回滾的。只有到達第二階段,網路會出現斷網。在第二階段,如果出現問題,只能斷網重啟服務,系統不再具有回滾能力。在實現上,我們給 ovs 開啟了一個 JSON-RPC 服務用於熱升級。當 ovs 程序啟動時,會自動檢測是否有老程序的存在。如果存在,則主動通過 JSON-RPC 發起熱升級請求。接收到熱升級請求的 ovs 程序則開啟兩階段升級:

  • 第一階段:

    • 老 ovs 程序釋放各種獨佔資源:比如 ovsdb 的資料庫鎖,pid 檔案改名,unixctl server path 等資源。此時老 ovs 不能通過 ovsdb 獲取最新配置,但是 PMD 執行緒依舊執行,轉發並未停止。
    • 釋放資源之後,新老程序開始進行狀態同步,主要是一些 OVS 的 megaflow 同步,網路 tap 裝置的 fd 同步等。
    • 同時,老的 ovs 會將所有的 OpenFlow 規則進行備份。
    • 這一切完成之後,老程序會返回 JSON-RPC 的請求的響應。如果上述過程無問題,則返回成功,升級繼續。否則返回失敗,新程序會退出,升級失敗。同時老程序會狀態回滾,將之前釋放的資源又重新申請回來,回到正常的工作狀態。
    • 新程序獲得各種狀態資訊,開始正常初始化。包括 DPDK 初始化記憶體,ovs 從 ovsdb 中獲取網橋、網絡卡等各種配置開始初始化等。在這個過程中,如果出現異常,新程序 crash,會導致 JSON-RPC 這個 unix socket 連線中斷。一旦老程序檢測到這個連線中斷,就認為新程序初始化失敗,自動回滾。
    • 新程序載入之前備份的 OpenFlow 規則。這之間的 OpenFlow 規則變更,會由 local controller 記錄並下發。
    • 新程序發起第二階段 JSON-RPC 請求。
  • 第二階段:

    • 老程序退出。
    • 新程序開啟 pmd 執行緒開始轉發。
    • 升級結束。

下圖簡單的描述了升級時序圖:

由升級時序圖可以看出,熱升級第一階段裡新 ovs 程序完成了最耗時的初始化工作,同時老 ovs 程序一直在進行轉發,並沒有斷網。斷網只是在第二階段老 ovs 退出和新 ovs 啟動 PMD 執行緒之間發生。

在升級過程中,我們利用了 MLNX 網絡卡一個特性:同一個網絡卡裝置可以被兩個獨立的 dpdk 程序同時開啟,並且流量會被同時映象到兩個程序中去。如果使用其他的網絡卡,可以通過多 VF 配合流表規則切換的方法達到同樣效果。這裡就不再展開敘述了。

斷網時間評估

我們考察了兩種虛擬網絡卡後端的斷網時間:

  1. 採用 representer + VF 的方式,
  2. 採用 vhost-user + virtio 的方式。

測試方法

兩臺宿主機上兩臺虛機互相 ping,使用ping -i 0.01。兩次 ping 之間相隔 10ms,最後統計在升級中,ping 包未回的數量即表示升級斷網時間。 iperf -i 1測試,觀察 TCP 吞吐是否會受到影響。

representer + VF 方式

ping 測試

10 次試驗結果如下:

1524 packets transmitted, 1524 received, +36 duplicates, 0% packet loss, time 16747ms
623 packets transmitted, 622 received, +29 duplicates, 0% packet loss, time 6830ms
662 packets transmitted, 662 received, +30 duplicates, 0% packet loss, time 7263ms
725 packets transmitted, 724 received, +28 duplicates, 0% packet loss, time 7955ms
636 packets transmitted, 635 received, +28 duplicates, 0% packet loss, time 6973ms
752 packets transmitted, 750 received, +27 duplicates, 0% packet loss, time 8251ms
961 packets transmitted, 961 received, +31 duplicates, 0% packet loss, time 10551ms
737 packets transmitted, 737 received, +29 duplicates, 0% packet loss, time 8084ms
869 packets transmitted, 869 received, +27 duplicates, 0% packet loss, time 9543ms
841 packets transmitted, 840 received, +28 duplicates, 0% packet loss, time 9228ms
複製程式碼

發現最多出現 1 個丟包,說明斷網時間最長 10ms。但是發現了很多 duplicates 的包,這個是因為 mlnx 網絡卡在 switchdev 模式下有一個 bug:當出現雙程序時,本應該流量被映象到另一個程序,結果 mlnx 網絡卡讓一個程序收到了兩個重複包,而另一個程序沒有包。目前 mlnx 已經確認了這個問題。

iperf 測試

觀測到升級期間,有 1s 速率減半,由滿速率 22Gbps 到 13Gbps,估計是和 MLNX bug 引發的重傳包和升級斷網有關。1s 之後迅速回到 22Gbps。

vhost-user + virtio 模式

ping 測試

斷網時間在 70~80ms 左右。通過對日誌分析,發現是老程序在退出時,反覆進行了 vhost 重連導致,這塊通過繼續優化,斷網時間會進一步降低。這裡就不在展開了。

iperf 測試

和 VF 方式結果類似,也是吞吐會有一定的下降,升級完成後立刻恢復。

相關程式碼

我們使用的 ovs-dpdk 已經開源。如果對熱升級的具體實現有興趣,可以參考 vswitchd 目錄下 ndu.c 檔案。在 utilities 目錄下我們提供了 ovs-nductl 工具用於測試熱升級 JSON-RPC 服務,可以模擬熱升級。升級指令碼參考 utilities 目錄下的 ovs-hotupgrade.sh。 我們的開源連結為:https://github.com/bytedance/ovs-dpdk

更多分享

eBPF技術實踐:高效能ACL

自動化彈性伸縮如何支援百萬級核心錯峰混部 | 架構沙龍回顧

位元組跳動分散式表格儲存系統的演進

位元組跳動系統部 STE 團隊

位元組跳動系統部 STE 團隊一直致力於作業系統核心與虛擬化、系統基礎軟體與基礎庫的構建和效能優化、超大規模資料中心的穩定性和可靠性建設、新硬體與軟體的協同設計等基礎技術領域的研發與工程化落地,具備全面的基礎軟體工程能力,為位元組上層業務保駕護航。同時,團隊積極關注社群技術動向,擁抱開源和標準。歡迎更多有志之士加入,如有意向可傳送簡歷至 [email protected]

歡迎關注位元組跳動技術團隊