netdev 第二天:從網路代碼中移除「儘可能快」這個目標
嗨!今天是 netdev 會議的第 2 天,我只參加了早上的會議,但它非常有趣。今早會議的主角是 Van Jacobson 給出的一場名為 「從儘可能快中變化:教網卡以時間」的演講,它的主題是關於互聯網中擁塞控制的未來!!!
下面我將嘗試著對我從這次演講中學到的東西做總結,我幾乎肯定下面的內容有些錯誤,但不管怎樣,讓我們開始吧!
這次演講是關於互聯網是如何從 1988 開始改變的,為什麼現在我們需要新的演算法,以及我們可以怎樣改變 Linux 的網路棧來更容易地實現這些演算法。
什麼是擁塞控制?
在網路上的任何成員總是無時無刻地發送信息包,而在互聯網上的連接之間有著極其不同的速度(某些相比其他極其緩慢),而有時候它們將被塞滿!當互聯網的一個設備以超過它能處理的速率接收信息包時,它將丟棄某些信息包。
你所能想像的最天真的發送信息包方式是:
- 將你必須發送的信息包一次性發送完。
- 假如你發現其中有的信息包被丟棄了,就馬上重新發送這些包。
結果表明假如你按照上面的思路來實現 TCP,互聯網將會崩潰並停止運轉。我們知道它會崩潰是因為在 1986 年確實發生了崩潰的現象。為了解決這個問題,專家發明了擁塞控制演算法 —— 描述如何避免互聯網的崩潰的原始論文是 Van Jacobson 於 1988 年發表的 擁塞避免與控制(30 年前!)。
從 1988 年後互聯網發生了什麼改變?
在演講中,Van Jacobson 說互聯網的這些已經發生了改變:在以前的互聯網上,交換機可能總是擁有比伺服器更快的網卡,所以這些位於互聯網中間層的伺服器也可能比客戶端更快,並且並不能對客戶端發送信息包的速率有多大影響。
很顯然今天已經不是這樣的了!眾所周知,今天的計算機相比於 5 年前的計算機在速度上並沒有多大的提升(我們遇到了某些有關光速的問題)。所以我想路由器上的大型交換機並不會在速度上大幅領先於數據中心裡伺服器上的網卡。
這聽起來有些糟糕,因為這意味著客戶端更容易在中間層的連接中達到飽和,而這將導致互聯網變慢(而且 緩衝膨脹 將帶來更高的延遲)。
所以為了提高互聯網的性能且不讓每個路由上的任務隊列都達到飽和,客戶端需要表現得更好並且在發送信息包的時候慢一點。
以更慢的速率發送更多的信息包以達到更好的性能
下面的結論真的讓我非常意外 —— 以更慢的速率發送信息包實際上可能會帶來更好的性能(即便你是在整個傳輸過程中,這樣做的唯一的人),下面是原因:
假設你打算髮送 10MB 的數據,在你和你需要連接的客戶端之間有一個中間層,並且它的傳輸速率非常低,例如 1MB/s。假設你可以辨別這個慢連接(或者更多的後續中間層)的速度,那麼你有 2 個選擇:
- 一次性將這 10MB 的數據發送完,然後看看會發生什麼。
- 減慢速率使得你能夠以 1MB/s 的速率傳給它。
現在,無論你選擇何種方式,你可能都會發生丟包的現象。所以這樣看起來,你可能需要選擇一次性發送所有的信息包這種方式,對吧?不!!實際上在你的數據流的中間環節丟包要比在你的數據流的最後丟包要好得多。假如在中間環節有些包被丟棄了,你需要送往的那個客戶端可以察覺到這個事情,然後再告訴你,這樣你就可以再次發送那些被丟棄的包,這樣便沒有多大的損失。但假如信息包在最末端被丟棄,那麼客戶端將完全沒有辦法知道你一次性發送了所有的信息包!所以基本上在某個時刻被丟棄的包沒有讓你收到 ACK 信號時,你需要啟用超時機制,並且還得重新發送它們。而超時往往意味著需要花費很長時間!
所以為什麼以更慢的速率發送數據會更好呢?假如你發送數據的速率快於連接中的瓶頸,這時所有的信息包將會在某個地方堆積成一個隊列,這個隊列將會被塞滿,然後在你的數據流的最末端的信息包將會被丟棄。並且像我們剛才解釋的那樣,處於數據流最後面的信息包很有可能丟棄!所以相比於最初以合適的速率發送信息包,一次性發送它們將會觸發超時機制,發送 10MB 的數據將會花費更長的時間。
我認為這非常酷,因為這個過程並不需要與互聯網中的其他人合作 —— 即便其他的所有人都已非常快的速率傳送他們的信息包,對你來說以合適的速率(中間層的瓶頸速率)傳送你自己的信息包仍然更有優勢。
如何辨別發送數據的合適速率:BBR!
在上面我說過:「假設你可以辨別出位於你的終端和伺服器之間慢連接的速率……」,那麼如何做到呢?來自 Google(Jacobson 工作的地方)的某些專家已經提出了一個演算法來估計瓶頸的速率!它叫做 BBR,由於本次的分享已經很長了,所以這裡不做具體介紹,但你可以參考 BBR:基於擁塞的擁塞控制 和 來自晨讀論文的總結 這兩處鏈接。
(另外,https://blog.acolyer.org 的每日「晨讀論文」總結基本上是我學習和理解計算機科學論文的唯一方式,它有可能是整個互聯網上最好的博客之一!)
網路代碼被設計為運行得「儘可能快「
所以,假設我們相信我們想以一個更慢的速率(例如以我們連接中的瓶頸速率)來傳輸數據。這很好,但網路軟體並不是被設計為以一個可控速率來傳輸數據的!下面是我所理解的大多數網路軟體怎麼做的:
- 現在有一個隊列的信息包來臨;
- 然後軟體讀取隊列並儘可能快地發送信息包;
- 就這樣,沒有了。
這個過程非常呆板 —— 假設我以一個非常快的速率發送信息包,而另一端的連接卻非常慢。假如我所擁有的就是一個放置所有信息包的隊列,當我實際要發送數據時,我並沒有辦法來控制這個發送過程,所以我便不能減慢這個隊列傳輸的速率。
一個更好的方式:給每個信息包一個「最早的出發時間」
BBR 協議將會修改 Linux 內核中 skb 的數據結構(這個數據結構被用來表達網路信息包),使得它有一個時間戳,這個時間戳代表著這個信息包應該被發送出去的最早時間。
對於 Linux 網路棧我不知道更多的詳情了,但對於我來說,這個協議最有趣的地方是這個改動並不是一個非常大的改動!它只是添加了一個額外的時間戳而已。
用時間輪盤替換隊列!!!
一旦我們將時間戳打到這些信息包上,我們怎樣在合適的時間將它們發送出去呢?使用時間輪盤!
在前不久的「我們喜愛的論文」活動中(這是關於這次聚會描述的某些好的鏈接),有一個演講談論了關於時間輪盤的話題。時間輪盤是一類用來指導 Linux 的進程調度器決定何時運行進程的演算法。
Van Jacobson 說道:時間輪盤實際上比隊列調度工作得更好 —— 它們都提供常數時間的操作,但因為某些緩存機制,時間輪盤的常數要更小一些。我真的沒有太明白這裡他說的關於性能的解釋。
他說道:關於時間輪盤的一個關鍵點是你可以很輕鬆地用時間輪盤實現一個隊列(但反之不能!)—— 假如每次你增加一個新的信息包,在最開始你說我想讓它現在就被發送走,很顯然這樣你就可以得到一個隊列了。而這個時間輪盤方法是向後兼容的,它使得你可以更容易地實現某些更加複雜的對流量非常敏感的演算法,例如讓你針對不同的信息包以不同的速率去發送它們。
或許我們可以通過改善 Linux 來修復互聯網!
對於任何影響到整個互聯網規模的問題,最為棘手的問題是當你要做出改善時,例如改變互聯網協議的實現,你需要面對各種不同的設備。你要面對 Linux 的機器、BSD 的機器、Windows 的機器、各種各樣的手機、瞻博或者思科的路由器以及數量繁多的其他設備!
但是在網路環境中 Linux 處於某種有趣的位置上!
- Android 手機運行著 Linux
- 大多數的消費級 WiFi 路由器運行著 Linux
- 無數的伺服器運行著 Linux
所以在任何給定的網路連接中,實際上很有可能在兩端都有一台 Linux 機器(例如一個 Linux 伺服器、或者一個 Linux 路由器、一台 Android 設備)。
所以重點是假如你想大幅改善互聯網上的擁塞狀況,只需要改變 Linux 網路棧就會大所不同(或許 iOS 網路棧也是類似的)。這也就是為什麼在本次的 Linux 網路會議上有這樣的一個演講!
互聯網仍在改變!酷!
通常我以為 TCP/IP 仍然是上世紀 80 年代的東西,所以當從這些專家口中聽說這些我們正在設計的網路協議仍然有許多嚴重的問題時,真的是非常有趣,並且聽說現在有不同的方式來設計它們。
當然也確實是這樣 —— 網路硬體以及和速度相關的任何設備,以及人們使用網路來乾的各種事情(例如觀看 Netflix 的節目)等等,一直都在隨著時間發生著改變,所以正因為這樣,我們需要為 2018 年的互聯網而不是為 1988 年的互聯網設計我們不同的演算法。
via: https://jvns.ca/blog/2018/07/12/netdev-day-2--moving-away-from--as-fast-as-possible/
作者:Julia Evans 譯者:FSSlc 校對:wxy
本文轉載來自 Linux 中國: https://github.com/Linux-CN/archive