繞過核心
一般而言,當程式要送出一個網路封包或從磁碟讀取時,它會透過系統呼叫請作業系統核心代勞,核心為了安全與共享而居中處理一切。那份居中處理通常是值得的,但在極端速度下它本身就成了瓶頸:每次系統呼叫都要跨進核心模式再跨回來、在緩衝區之間複製資料,還可能引發一次中斷與一次環境切換——這些開銷對一個網站無妨,但當你必須每秒處理數千萬個封包時就成了災難。繞過核心(kernel bypass)的構想,就是讓受信任的應用程式更直接地與硬體交談,把核心從熱路徑中移出去。
有兩種值得認識的風味。真正的繞過核心,把一個裝置幾乎直接交給使用者空間的程式:像 DPDK 這樣的框架讓網路應用程式輪詢網路卡、在使用者空間搬移封包,而不必每個封包一次系統呼叫,於是它能以全線速驅動網卡。代價是該應用程式如今獨佔那個裝置,並且必須做核心原本做的工作。較溫和的風味保留核心、但大砍其開銷:io_uring 是一個 Linux 介面,應用程式與核心在記憶體中共享一對環形緩衝區,於是程式能提交許多輸入輸出請求並成批收取結果,幾乎不需或完全不需系統呼叫,也沒有每次操作的複製——在保留安全的同時削減跨越次數。
誠實的取捨正是本領域反覆出現的主題:繞過或削薄核心,是以核心所提供的保護、共享與便利為代價來換取速度。一個專屬於單一應用程式的裝置無法安全地與他者共享,而把核心職責推進使用者空間,意味著應用程式必須自己正確地處理它們。繞過核心對高效能網路與儲存不可或缺,但它是專家工具,而非預設——多數軟體還是走那條普通、安全的核心路徑更好。
一台網路設備必須每秒過濾四千萬個封包。若每個封包一次系統呼叫,光是核心跨越就會把 CPU 淹沒。改用 DPDK,應用程式在使用者空間直接輪詢網路卡,以緊湊的批次處理封包、毫無每封包的系統呼叫——達到普通核心路徑永遠撐不住的全線速。
把核心從熱路徑移出,以達到它撐不住的速度。
繞過核心是以安全與共享換取速度。一個直接交給單一 app 的裝置無法被安全共享,而該 app 必須正確地做核心原本做的保護工作——所以它是專家工具,而非預設。