Skip to content

netpoll

Go 的 netpoll 是 Go 語言運行時(runtime)實現的核心 I/O 多路復用機制,它使得 Go 能夠以簡潔的同步編程模型(每個連接一個 Goroutine)實現高性能的網絡服務。其本質是將操作系統底層的 I/O 多路復用系統調用(如 Linux 的 epoll)與 Go 的 Goroutine 調度器深度結合。

Netpoll與原生GoNet對比

  1. Goroutine數目 Go Net:一個Goroutine下只有一個連接。

NetPoll:一個Goroutine下有多個連接。

  1. goroutine 上下文切換調度 壓力 Go Net: 高並發時 切換壓力大。 因為 GoNet 一個鏈接對應一個goroutine,goroutine數目多時切換頻繁。

NetPoll:高並發時 切換壓力 小。 因為 NetPoll 多個鏈接共用一個goroutine,切換次數少。

  1. 內存消耗: Go Net: 內存消耗‌與連接數正相關‌,高並發時可能因Goroutine數量爆炸導致內存壓力‌

NetPoll:預先分配緩沖區,創建緩沖區池。

  1. 觸發方式 Go Net:使用 邊緣觸發 ET。一次讀完數據,實現簡單。

NetPoll:使用 水平觸發 LT。不需要預分配足夠大的內存做數據緩沖區。

  1. 是否支持內核和用戶層共用buff池,少拷貝一次數據。 Go Net:不支持。

NetPoll:支持。管理一個Buffer池直接交給用戶,少拷貝一次。

  1. 適用場景 Go Net:低並發簡單場景

NetPoll:高並發低延遲場景

netpoll 設計思路

  1. 基本架構 原生網絡庫 基於epoll lt模式 開發,基本架構如下圖所示: netpoll 基本架構

  2. goroutine的使用 存在一個 poll對象池,每個poll對象帶有一個epoll,和單獨對應一個 goroutine。 goroutine數目和 poll對象數目一致,每個poll對象可以監聽多個 文件描述符fd

  3. IO讀寫邏輯

    • 每個poll對象開啟一個goroutine來不斷輪詢當前epoll上的可讀可寫等事件
    • 每個epoll會關聯多個fd,每個fd關聯一個 Buffer。
    • 當從 fd 監聽到有可讀事件後,會把數據讀到 Buffer裡。
    • 不斷輪詢處理 Buffer 的數據,當發現數據讀完整之後,通知後面的處理邏輯的協程池 GoPoll去執行
    • 與內核的系統調用交互完全由netpoll控制,用戶層對 Conn 的讀寫都只是在操作共用的Buffer而已。
  4. 優劣勢 優勢: 支持高並發能力更強。

    • (1) 輪詢處理Buffer的數據,不存在數據得不到處理的情況。
    • (2) 一個goroutine對應多個連接,即使連接非常多,資源調度切換上的開銷也不大。
    • (3) 支持用戶和內核共享buff,減少一次數據拷貝操作,提升效率。

劣勢:需要佔用更多的內存。

Golang學習網由www.golangdev.cn整理維護