Cloudflare 修復 CUBIC 擁塞視窗死亡螺旋:Linux 2017 核心最佳化如何在 QUIC 中製造 Bug
Cloudflare Blog · 2026-05-12
Cloudflare 工程師在 2026 年五月發表事後分析,說明在 QUIC 的 Rust 實作 quiche 中發現的一個 CUBIC 擁塞控制 Bug:嚴重封包丟失後,擁塞視窗(cwnd)被永久鎖死在最小值(2 個封包 / 2700 bytes),即便丟包停止後連線也無法恢復,陷入死亡螺旋——每 14ms 往返一次的無限狀態轉換迴圈。
漏洞機制
問題根源是一個 2017 年的 Linux 核心優化被移植至 QUIC 時,語義出現了偏移。原始核心優化的目的是修復 CUBIC 在應用程式「閒置後恢復」場景中的 epoch 計算錯誤:閒置期間若不更新 epoch(增長曲線的基準時間戳記),會導致重新開始傳輸時出現人為的 cwnd 膨脹(約 1.5 × RTT 的虛假增長)。核心的修補方式是「將 epoch 向前移動閒置時長」,而非重置它,保留增長曲線的形狀。
quiche 的移植方式是在 on_packet_sent() 中以 bytes_in_flight == 0 判斷「閒置時間」。然而在最小擁塞視窗的情境下,每個 ACK 週期都會讓 bytes_in_flight 短暫降至零——這不是真正的閒置,而是擁塞限制——系統因此每個 RTT 都誤判一次閒置,不斷將 epoch 向前移動,導致恢復邊界在每個週期都向前追趕,cwnd 永遠無法正常增長。
修補與緩解
修補方案加入 last_ack_time 追蹤,改以最近一次 ACK(近似 bytes_in_flight 歸零的時間點)和最近一次資料傳送兩者取較晚的時間點來量測閒置時長:
// 修復前:用 bytes_in_flight == 0 判斷閒置
// 修復後:以最近 ACK 或最近傳送(取較晚者)量測閒置修復後測試通過率從 39% 恢復至 100%,下載在預期的 4-5 秒內完成並呈現正常的 CUBIC 增長曲線。
影響範圍
這個 Bug 的發現過程完全由整合測試驅動:10 MB HTTP/3 下載加上前 2 秒 30% 隨機丟包的模擬場景,61% 失敗率觸發調查。Bug 的根本原因是核心優化在語義上依賴「bytes_in_flight == 0 等於閒置」,但這個假設在最小 cwnd 的擁塞場景中不成立。這個案例同時說明 CUBIC 從 TCP 移植至 QUIC 實作時,需要重新驗證所有依賴 TCP 協議棧特性的最佳化假設。
原始來源:Cloudflare Blog
Meta 百 PB 級 MySQL 資料擷取系統重構:影子遷移與 CDC 壞資料隔離的工程設計
Meta Engineering · 2026-05-12
Meta 工程部落格在 2026 年五月描述了其資料擷取系統的架構重構:將每日數 PB 資料量、數萬個 MySQL 增量擷取任務從分散式用戶自管管線遷移至統一的自管資料倉儲服務,實現 100% 工作負載覆蓋,無重大資料損失事件。
原本的問題
舊架構讓各業務團隊各自維護 MySQL 到資料倉儲的 CDC 擷取管線,缺乏統一的監控、驗證和故障處理標準。數萬個任務的差異化設定讓跨任務的問題診斷和版本升級極為困難。CDC 特有的壞資料傳播問題(上游一筆損壞記錄沿 delta 鏈污染所有下游分區)在舊架構中沒有系統性防護機制。
採用的方法
核心是三階段影子測試:影子階段(Shadow Phase)讓新服務在不影響舊管線的前提下以生產規模平行運行並比較輸出;反向影子(Reverse Shadow Phase)交換主從關係,新服務成為主要資料流,舊管線降為驗證角色;清除階段(Migration Cleanup)在最終驗證後下線舊系統。自動化驗證以列數和 checksum 比對作為任務晉升條件,避免人工確認數萬個任務。新系統在分區層級設置元資料標記來防止壞資料傳播,讓下游系統隔離問題分區而不需停止整個任務。
實際效果
100% 工作負載覆蓋,資料落地延遲持平或改善,整合 Scuba 分析系統的統一監控儀表板使問題定位時間顯著縮短。Meta 特別強調影子測試不是性能測試,是行為一致性測試——在如此規模的系統切換中,行為差異的早期發現才是零事故的根本保障。