今天我們很高興地宣布 noq(「number 0 QUIC」),我們自行開發的通用型 QUIC 實作,支援多重路徑與 NAT 穿越。它是自 iroh v0.96 以來為 iroh 提供支援的傳輸層,但其用途絕不限於 iroh 的使用情境。
如果您一直關注 iroh 的開發,您可能讀過我們為何在 2024 年 fork 了 Quinn。簡而言之:iroh 在 QUIC 方面做了許多繁重的工作:在轉送路徑與直接路徑之間切換、管理 NAT 穿越、處理擁塞狀態。但 QUIC 本身對這些操作卻毫無感知。這種不匹配造成了我們從外部無法解決的問題。
我們的 fork 最初規模很小。我們希望緊密追蹤上游的 Quinn,盡可能回饋貢獻,並將我們的差異保持在最低限度。當時這是正確的決定。但隨著我們深入研究 QUIC 的多重路徑、NAT 穿越以及我們自己的轉送即路徑架構,兩個專案的開發速度開始出現不匹配的迭代週期。我們不斷的變更會給 Quinn 的維護者帶來不合理的審查負擔。n0 團隊希望對我們的 QUIC 實作進行更深入、結構性的變更,將這些變更的後果強加給所有 Quinn 使用者是不公平的。我們認為,透過硬分叉並持續致力於合作,對各方而言都是更有意義的選擇。
於是我們全力以赴。我們在 Quinn 的多重路徑問題討論串中解釋了我們的想法。這並非否定 Quinn,Quinn 仍然是一個很棒的實作。這只是承認我們正在解決的問題足夠特殊,以至於一個獨立的程式碼庫,在我們的利益重疊的地方進行合作,是誠實的前進道路。
最主要的特色是完整實作了 QUIC 多重路徑規範。這也是真正的架構轉變發生的地方,無論是在 Quinn/noq 內部,還是對於 iroh 的使用而言。在多重路徑出現之前,iroh 透過一種在 QUIC 層以下的技巧來管理多個路徑(轉送、直接 IPv4、直接 IPv6)。Quinn 認為它僅透過一個 IP 位址與對方端點通訊,而我們則在任何運作良好的路徑上交換封包。有點像 iroh 自己為 Quinn 所做的 NAT。
有了多重路徑,這些路徑就成為了 QUIC 的一級概念。轉送路徑是一個 QUIC 路徑。直接 UDP 路徑也是一個 QUIC 路徑。QUIC 了解所有這些路徑,維護每個路徑的擁塞狀態,並能判斷使用哪一個路徑。這意味著我們過去透過重置擁塞控制器來強制實現的延遲改善,現在能夠被正確且系統性地處理。
然而,多重路徑實作是通用的,它不僅服務於 iroh。它的目標是完整實作 QUIC 多重路徑規範,適用於任何目的。不過,該實作仍處於早期階段,如果您需要更多 API,請告訴我們。
我們實作了我們對 QUIC NAT 穿越草案的詮釋。據我們所知,我們是第一個以生產級、穩健的方式實現這一點的。NAT 穿越出了名地難搞,要正確處理現實世界中各種 NAT 行為是一個難題,我們已經在數十萬台已運行 iroh 的裝置上對我們的方法進行了實戰測試。雖然這絕非一個已定案的規範,但我們將持續迭代。
將 NAT 穿越的 hole-punching 直接表達為 QUIC 層級的操作,而不是發生在其下方的事情,這樣更清晰、更可靠,因為它能讓 QUIC 擁塞控制器感知到它,並實現更好的封包遺失偵測。
自 iroh 版本 0.32 起,iroh 一直在使用我們實作的 QUIC 位址發現 (QAD)。QAD 使用 QUIC 連線來了解用戶端的公開 IP 位址,這之前是使用 STUN 來完成的。QUIC 能夠加密這些封包,而不會像 STUN 那樣犧牲往返時間,從而防止協定僵化並增強用戶隱私。
qlog 是一個用於記錄大量 QUIC 連線資訊的草案標準。它是一個很棒的除錯工具,有 qvis 等視覺化工具可以顯示兩個對等節點之間的封包流。
在 noq 中,qlog 的支援已大大擴展,以支援 qlog 日誌架構和 [QUIC 事件定義] 中的更多事件。此外,qlog 的擴展性還被用於為 QUIC 多重路徑添加事件。我們甚至有一個檢視器原型,可以顯示跨越多個路徑的封包流。
雖然 noq 的大部分 API 變更都圍繞著多重路徑支援,但我們也添加了一個 WeakConnectionHandle。這是一種不會自行維持連線存活的類型,但如果連線尚未中斷,則可以升級為完整的 Connection。它的行為非常類似於 [std::sync::Weak],但無需使用 Arc,因為這並不總是那麼容易做到。
這對於建構連線管理器之類的工具很有幫助。我們在 iroh 內部自己就已經需要這個功能了,肯定還有更多好的使用案例。
noq 作為 iroh v0.96 的一部分發布,並自那時起一直在生產環境中運行。如果您正在使用最新版本的 iroh,您已經在使用 noq 了。
除了針對 noq 的多重路徑實作進行自身測試外,我們還針對 picoquic 進行了互通性測試,picoquic 是 QUIC 工作組互通性事件中使用的一個參考實作。
我們將 noq 視為一個長期的基礎。還有更多工作我們希望完成,例如進一步改進 NAT 穿越。多重路徑工作也為以前不可能實現的效能優化開闢了道路。我們將繼續與 QUIC 工作組合作,並在我們的利益一致的領域與 Quinn 團隊合作。
如果您正在從事 QUIC 實作、p2p 傳輸或需要在各種網路條件下運行的應用程式,我們很樂意與您交流。歡迎加入我們的 Discord 或在 GitHub 上開啟一個 issue。
如果您渴望嘗試一個支援 Rust QUIC 多重路徑的實作,請參閱多重路徑 noq Connection 的文件。