Linux網絡編程模型和Ceph Async 模型探討

IO多路複用

所謂的I/O多路複用,就是可以監控多個socket上的IO請求。允許多個socket在可讀或可寫準備好時,應用能被通知到,這樣應用就可以一次非阻塞的處理多個socket相關的IO請求。

IO多路複用的有三種實現方式:

Select

I/O複用模型早期用select實現。

int select (int n, 
            fd_set *readfds, 
            fd_set *writefds, 
            fd_set *exceptfds, 
            struct timeval *timeout);

select 函數可以實現IO多路複用。但是select在大規模網絡環境下有如下的缺點:

  1. 可監控的socket有限(內部用數組保存)
  2. 要遍歷所有的fd集合來確定是否相關事件
  3. 大量的fd的數組被整體複製於用戶態和內核地址空間之間,而不管這樣的複製是不是有意義。

poll

int poll(struct pollfd *fds, nfds_t nfds, int timeout);  

其有如下特點:
1. 監控的socket沒有限制(內部用鏈表,當socket數量多時,性能下降明顯)
2. 和select一樣,要遍歷所有的socket來檢查相關事件的產生
3.epoll還有一個特點是“水平觸發”,如果報告了fd後,沒有被處理,那麼下次poll時會再次報告該fd

epoll

epoll是目前使用最廣泛的IO多路複用機制。它克服了select 和 epoll 的一些缺點。

  1. 其內部使用了 紅黑樹和鏈表機制,通過紅黑樹高效管理大量fd
  2. 通過內核的回調機制,直接把產生事件的fd添加到內部的鏈表中。從而不需要遍歷所有的fd,直接返回發生fd
  3. 支持水平觸發(Level Triger)和邊沿觸發(Edge Trigger)兩種模式

水平觸發指的是:當有事件發生時,如果應用沒有完該IO,系統會不斷的產生相關事件提醒應用去處理。

邊沿觸發指的是:當有事件發生時,只產生一次通知事件,需要應用一次性把該事件處理完。

在大規模高性能的網絡編程中,一般都採用邊沿觸發的模式。

Epoll的使用流程如下

  1. 調用函數 epoll_create()系統調用。此調用返回一個fd 。
  2. epoll_ctl()系統調用。通過此調用向epoll對象中添加、刪除、修改感興趣的事件,返回0標識成功,返回-1表示失敗。
  3. epoll_wait()系統調用。通過此調用收集收集在epoll監控中已經發生的事件。

IO 多路複用的模式

兩種I/O多路複用模式:Reactor和Proactor

Reactor

Reactor 用於同步IO
對於linux, epoll 是同步操作,所以只能用Reactor模式, 其核心在於:當通過epoll觸發事件後,只是表明數據就緒, 需要自己去在socket上接收數據。

Proactor

Proactor用於異步IO
對於Windows, IOCP是異步操作。當由事件觸發時,其數據已經從socket上接收完畢並拷貝到應用的緩存區中,數據接收已經完成,通知應用可以使用該數據。

IO 多路複用多線程模型

Half-sync/Half-async模型

本模型主要實現如下:

  1. 有一個專用的獨立線程(事件監聽線程)調用epoll_wait 函數來監聽網絡IO事件
  2. 線程池(工作線程)用於處理網絡IO事件 : 每個線程會有一個事件處理隊列。
  3. 事件監聽線程獲取到 IO事件後,選擇一個線程,把事件投遞到該線程的處理隊列,由該線程後續處理。

這裏關鍵的一點是:如果選擇一個線程?一般根據 socket 的 fd 來 hash映射到線程池中的線程。這裏特別要避免的是:同一個socket不能有多個線程處理,只能由單個線程處理。

這裏寫圖片描述

如圖所示,系統有一個監聽線程,一般爲主線程 main_loop 調用 epoll_wait 來獲取併產生事件,根據socket的 fd 的 hash算法來調度到相應的 線程,把事件投遞到線程對應的隊列中。工作線程負責處理具體的事件。

這個模型的優點是結構清晰,實現比較直觀。 但也有如下的 不足:

  1. 生產事件的線程(main_loop線程) 和 消費事件的線程(工作者線程)訪問同一個隊列會有鎖的互斥和線程的切換。
  2. main_loop是同步的,如果有線程的隊列滿,會阻塞main_loop線程,導致其它線程臨時沒有事件可消費。

Leader/Follower

當Leader監聽到socket事件後:處理模式
1)指定一個Follower爲新的Leader負責監聽socket事件,自己成爲Follower去處理事件
2)指定Follower 去完成相應的事件,自己仍然是Leader

由於Leader自己監聽IO事件並處理客戶請求,該模式不需要在線程間傳遞額外數據,也無需像半同步/半反應堆模式那樣在線程間同步對請求隊列的訪問。

ceph Async 模型

這裏寫圖片描述

在Ceph Async模型裏,一個Worker類對應一個工作線程和一個事件中心EventCenter。 每個socket對應的AsyncConnection在創建時根據負載均衡綁定到對應的Worker中,以後都由該Worker處理該AsyncConnection上的所有的讀寫事件。

這裏寫圖片描述

如圖所示,在Ceph Async模型裏,沒有單獨的main_loop線程,每個工作線程都是獨立的,其循環處理如下:

  1. epoll_wait 等待事件
  2. 處理獲取到的所有IO事件
  3. 處理所有時間相關的事件
  4. 處理外部事件

在這個模型中,消除了Half-sync/half-async的 隊列互斥訪問和 線程切換的問題。 本模型的優點本質上是利用了操作系統的事件隊列,而沒有自己去處理事件隊列。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章