服務器編程框架
-
IO處理單元 :處理用戶連接,讀寫網絡數據;(單機) ;作為接入服務器,實現負載均衡;(集群)
-
請求隊列 :各個單元之間通信的抽象,通常被實現為池的一部分;一個單元通知另外一個單元,或者多個單元訪問同一個存儲單元時,競爭的協調;對於集群來說,請求隊列是預先建立的
-
邏輯單元:一個進程或者線程;(單機);一台邏輯服務器;(集群)
-
網絡存儲單元:可以是數據庫,文件,緩存;(單機) ;數據庫服務器;(集群)
服務器通常需要處理三種事件:I/O事件,信號事件,定時事件。同步I/O模型常用於實現Reactor,異步I/O模型常用於Proactor。本文整體的介紹高效的事件處理模式
https://blog.csdn.net/enlyhua/article/details/81024206
Reactor
要求主線程(I/O處理單元)只負責監聽文件描述符上是否有事件發生,有的話就立即將事件通知工作線程(邏輯單元)數據的讀寫,接受新的連接以及處理客戶請求均在工作線程中完成;除此之外,邏輯線程不作任何工作。
- 主線程往epoll內核事件表中注冊socket上的讀就緒事件
- 主線程調用epoll_wait等待socket上有數據可讀
- 當socket上有數據可讀時,epoll_wait通知主線程,主線程則將socket可讀事件放入請求隊列。
- 睡眠在請求隊列上的某個工作線程被喚醒,它從socket讀取數據,並處理客戶請求,然后往epoll內核事件表中注冊該socket上的寫就緒事件。
- 主線程調用epoll_wait等待socket可寫
- 當socket可寫時,epoll_wait通知主線程,主線程將socket可寫事件放入請求隊列
- 睡眠在請求隊列上的某個工作線程(工作線程從請求隊列讀取事件后,根據事件的類型來決定如何處理它,沒有必要區分讀工作線程和寫工作線程)被喚醒,它往socket上寫入服務器處理客戶請求的結果
Proactor
Proactor將所有I/O操作都交給主線程和內核來處理,工作線程僅僅負責業務邏輯。使用異步I/O模型(aio_read和aio_write)來實現Proactor模式的工作流程是:
- 主線程調用aio_read向內核注冊socket上的讀完成事件,並告訴內核用戶緩沖區的位置,以及讀操作完成時如何通知應用程序(可以用信號)
- 主線程繼續處理其他邏輯
- 當socket上的讀數據被讀入用戶緩沖區后,內核向應用進程發送一個信號,已通知應用程序數據已經可用
- 應用進程預先定義好的信號處理函數選擇一個工作線程來處理處理客戶請求,工作線程處理完客戶請求之后,調用aio_write向內核注冊socket的完成寫事件,並告訴內核用戶寫緩沖區的位置,以及操作完成時如何通知應用程序(可以用信號)
- 主線程繼續處理其他邏輯
- 當用戶緩沖區的數據被寫入socket之后,內核將向應用程序發送一個信號,已通知應用程序數據已經發送完畢
- 應用程序預先定義好的信號處理函數選擇一個工作線程來做善后處理,比如決定是否關閉socket
可使用同步I/O模擬Proactor:主線程執行讀數據操作,讀完數據之后,主線程向工作線程通知這一“完成事件”,那么從工作線程的角度來看,他們直接獲得了讀寫數據的結果,只需要對讀寫數據進行處理
- 主線程往epoll內核事件表上注冊socket上的讀就緒
- 主線程調用epoll_wait等待socket上有數據可讀
- 當socket上有數據可讀時,epoll_wait通知主線程,主線程從socket上循環讀取數據,直到沒有更多數據可讀,然后將讀取到的數據封裝成一個請求對象並插入到請求隊列
- 睡眠在請求隊列上的某個工作線程被喚醒,他獲得請求對象並處理客戶請求,然后往epoll內核事件表中注冊socket上的寫就緒
- 主線程調用epoll_wait等待socket可寫
- 當socket可寫時,epoll_wait通知主線程,主線程往socket上寫入服務器處理客戶請求結果