MPTCP(MultiPath TCP)在 Linux 5.6 進入主線已經六年,一直被當成實驗室玩具。原因很單純:核心路徑管理器把預設子流上限鎖在 8 條,任何想拿多條線路湊頻寬的場景都會馬上撞到天花板。Linux 7.2 在 2026 年 8 月 16 日釋出,一併把子流與 ADD_ADDR 接受上限拉到 64。改動看起來只是把常數改大,卻足以讓多網卡 VPS 的頻寬聚合從 PoC 走進上線階段,也逼著網路架構重新思考單一 TCP 連線該怎麼跨網段流動。
為什麼 8 條子流一直是心理障礙
在 MPTCP 的設計裡,「子流」是一條普通的 TCP 連線,經過協定層黏合對外看起來像單一連線。8 條這個數字並非規範限制,而是核心開發者一開始為了保守而設下的預設值。對只在筆電上做行動網路切換的使用者夠用,對機房裡插了四張網卡、每張又要跨 IPv4 與 IPv6 的伺服器就完全不夠——邊際數量一出來就是 8 條起跳,連「每條網卡走一條子流」都要靠捨去。
社群的 patch series 在 2026 年 5 月送進 net-next,理由寫得很直接:技術上沒有天花板,效能上也沒觀察到副作用,拉高等於是解鎖研究者跟正經多網卡場景。這個改動搭配 Linux 7.2 的其他 MPTCP 修正進了 mainline,實務上讓「一條 MPTCP 連線 = 一個大水管」這件事從理論走到可以規劃容量。
MPTCP 到底在幹嘛:一句話的協定層說明
握手階段一方在 SYN 加上 MP_CAPABLE 選項,對端回應同樣選項就啟動 MPTCP。之後任何一邊都可以透過 ADD_ADDR 廣播自己另一個位址,對端收到後用 MP_JOIN 開新的 TCP 三向交握,綁到同一個邏輯連線上。應用層拿到的還是一個 socket,但底下同時可能有 8 到 64 條 TCP 各自走不同的 5-tuple。
Scheduler 決定每個資料段要塞進哪條子流,預設策略是把最快的路徑吃到滿再溢到下一條。這對頻寬聚合來說不完全直觀——想要真的把兩條線的頻寬加總,得靠應用層或使用者自己調整排程策略,或者直接送並發連線讓所有子流都被拉滿。純序列的單一大檔下載跨路徑不會神奇變成 2x。
兩種路徑管理器該選哪一個
Linux 提供兩套 Path Manager:核心內建(type 0)跟使用者空間 mptcpd(type 1)。核心版本用 sysctl 一鍵套用全域規則,適合「所有連線都用同樣一套策略」的伺服器場景。mptcpd 則是走 Netlink 掛出來,能為每個連線指定不同規則,適合根據應用區分子流拓撲的複雜環境。
多數 VPS 場景直接選核心內建就對了。fullmesh 模式會嘗試在客戶端已知位址與伺服器公告位址間拉出全連通的子流網格,設定量最少、行為最好預測。除非有明確的每連線客製需求,不然裝 mptcpd 只是引入另一個要顧的 daemon 和一個 crash 進程。
多網卡 VPS 的實際設定
打開核心 MPTCP 開關與新的限制:
1 | cat >/etc/sysctl.d/90-mptcp.conf <<'EOF' |
假設一臺 VPS 有兩張介面 eth0(203.0.113.10)跟 eth1(198.51.100.20),要讓兩張都當成對外可宣告的位址:
1 | ip mptcp endpoint add 203.0.113.10 dev eth0 signal |
signal 旗標代表「把這個位址透過 ADD_ADDR 主動廣播給對端」——伺服器端要做的就是這件事。客戶端則是拿 subflow 旗標,代表「聽到對端 ADD_ADDR 之後從這個位址主動發起新子流」。這兩個旗標分開下,設計上就把伺服器與客戶端的角色寫清楚,也讓混合部署(例如反向代理同時扮演 MPTCP 客戶端與伺服器)不會互相干擾。
驗證有沒有真的建立多條子流,直接抓 ss -Ml 或 ip mptcp monitor 看事件流;nstat -a MPTcp* 也能看到 SubflowsMax、MPCapableSYNACK 這類累計計數器,比 tcpdump 好抓長期趨勢。
沒有原生支援的服務:mptcpize 這條路
curl 從 7.85 起、HAProxy 從 2.9 起、Apache 從 2.4.61 起、systemd socket 幾年前就已經原生支援 IPPROTO_MPTCP,Go 寫的服務只要把 dial network 開成 "mptcp" 也能直接切過去。真正麻煩的是沒動過原始碼、也不打算改的舊服務。
mptcpize 走的是 LD_PRELOAD 攔截 socket() 呼叫的路子:程序啟動時預先注入 libmptcpwrap,把要求建立 AF_INET/SOCK_STREAM/IPPROTO_TCP 的呼叫改寫成 IPPROTO_MPTCP。這對絕大多數老舊 daemon 都夠用,只要它們不在 socket 上做奇怪的自訂 setsockopt,包起來跑就能立刻擁有多路徑能力。
systemd 單元檔可以直接透過 mptcpize enable <service> 更新,之後 systemctl restart 就會走 MPTCP。對 Nginx 這種明確表態不打算把 MPTCP 併進 HTTP 模組的專案來說,這幾乎是唯一乾淨的選項——比魔改編譯選項或包一層 iptables 導流可靠得多。
中介盒與 Fallback 才是真正的地雷
MPTCP 規範強制要求:握手期間只要任何一個中介盒剝掉 MP_CAPABLE 選項,連線必須乖乖 fallback 到普通 TCP,而且不能事後再嘗試升級。這是為了讓部署更安全,代價是在部分 CGN、透明代理、傳輸層防火牆後面,多路徑會靜靜地消失。上線前務必用 nstat MPTcpExtMPCapableFallback* 觀察 fallback 事件是否成常態,一旦壓過總連線數的 5% 以上,代表路徑上有東西在偷 SYN 選項,得先修中介盒才有意義往下推。
另一個常被低估的雷是 NAT。ADD_ADDR 廣播的是伺服器認為自己有的位址,如果 VPS 本身在 1:1 NAT 後面,宣告出去的私有位址對外根本不通。這種場景要嘛在 endpoint 加上明確的 external address 覆寫,要嘛乾脆走客戶端主動用多個公網 IP 發起子流的模式,讓伺服器只被動接收,避免對外廣播錯位址。
什麼場景值得動手,什麼場景別碰
值得投入的場景很清楚:跨 ISP 的多線路 VPS、雙 uplink 的邊緣代理、SSH 或資料庫連線需要無縫換路徑的維運通道、行動基地台旁的網關(Wi-Fi 加 5G 同時吃)。這幾個情境的共同特徵是「有多條實體或邏輯路徑,希望在單條 TCP 連線內做失效切換或聚合」,MPTCP 是目前唯一能不改應用層就達到這件事的協定。
反過來,沒有第二條路徑、應用層本身已經跑 HTTP/3 或 QUIC、或工作負載主要是短連線 API 呼叫的場景,MPTCP 帶不了多少好處,設定成本卻要吸收。把 MPTCP 當廉價 LACP 替代品是想錯方向——L4 聚合的顆粒是連線,L2 bonding 的顆粒是封包,兩者解決的問題不重疊,替換不了彼此。
收尾與下一步
Linux 7.2 這個看似只是把常數改大的補丁,實務意義比表面看起來重。多網卡 VPS 從此有一個原生、不改應用、真能跨路徑跑資料的協定層方案;再加上 mptcpize 對舊服務的包裝,門檻低到值得把 MPTCP 排進網路架構的候選清單。剩下要處理的只是中介盒、NAT 與 scheduler 選擇這些工程細節。
NCSE Network 在臺灣是方電訊機房提供多線路 IP Transit 與雙 uplink VPS 選項,天生就是 MPTCP 這類多路徑技術的合適舞台。想把生產環境的關鍵連線做跨路徑容錯,或拿多條線路湊實測頻寬的團隊,可以參考 ncse.tw 的網路與 VPS 服務規格。