網路伺服器如何處理併發請求的模型稱之為多工體系結構。
1.inetd模式:在大部分unix作業系統中,預設的多工體系結構是inetd應用程式。通用的網路伺服器體系結構inetd分為兩個部分:主服務程序和客戶服務程序。主服務程序通常用於等待客戶端的連線請求。一旦客戶端發起乙個請求,主伺服器將建立連線,同時呼叫fork建立乙個新的客戶服務程序,並由客戶服務程序處理客戶端的請求,而主服務程序繼續返回進入等待狀態,等待客戶端的請求。
inetd體系結構適合於兩種情況:第一,處理客戶端請求需要大量的時間才能完成,比如ftp,一般情況下,對於稍微大一些的檔案ftp可能需要幾秒甚至幾分鐘的時間。第二,如果子程序需要記住通訊的會話狀態,那麼inetd模式也是適用的,這樣,在第一次返回響應之後,客戶端和服務端的連線就不需要終止。
但是對於http請求而言,上面的兩點都變成缺點。首先http是無狀態的協議,因此在每次會話結束後,伺服器都不儲存上一次的狀態,他只對當前的請求進行響應。因此如果http伺服器基於inetd體系結構,其效率將是非常的低。另外,web伺服器屬於高併發、輕負載的服務型別,這就意味著,伺服器每次處理時間都非常短,但在短的時間內需要處理連線會非常多。而inetd採用的是程序建立的形式,不論unix還是linux上都是非常耗時的,因此不能滿足高併發的需求。
2.leader/follower模式:通常情況下,伺服器中的程序採用的都是即時建立的策略,一旦乙個新的客戶請求就立即創立乙個新的程序或執行緒,而當程序或執行緒執行完畢,程序或執行緒也隨之退出。顯然,這種策略對於小規模的伺服器還能接受,但對於大規模的伺服器而言,建立程序或執行緒的時間將增加,最終會導致響應時間變長,單位時間內請求處理效率降低。l/f模式則不同,它首先一次性建立多個程序或執行緒,儲存到系統中,這些程序或執行緒擔任三種不同的角色:偵聽者、工作者和空閒者,其含義分別如下:
(1)偵聽者角色,該執行緒負責偵聽客戶端的請求,在l/f模式中它屬於leader的角色。通常情況下只執行乙個程序或執行緒擔當偵聽者的角色。
(2)工作者角色,偵聽者偵聽到客戶端的請求時,它將立即轉為工作者角色並開始處理客戶端的請求。工作者的執行緒可以有多個。
(3)空閒者角色,工作者執行任務完畢後它不立即退出,而是轉變它的角色為空閒者,並呆在空閒者佇列中。空閒者出現的原因是客戶端請求不夠多。空閒者們等待變為偵聽者。而當偵聽者變為工作者後,空閒者中的每乙個都相互競爭,最終將會有乙個執行緒變為偵聽者,其餘的繼續保持空閒者的狀態。
(4)幾個可能出現的極端情況是:所有執行緒都變為工作者,忙於處理客戶端的請求,沒有執行緒擔任偵聽者的角色,因此此時客戶端的請求都被拒絕;另乙個極端就是沒有工作者,如果沒有任何請求到達,那麼所有的執行緒都處於空閒狀態。
以上介紹的兩種模型是非常經典的也是被廣泛使用的架構,下面介紹三種在apache伺服器中所使用的三種模型。
3.prefork:基於程序的併發模型。在該模型中存在乙個主程序和多個子程序。每乙個子程序都會為所進行的請求偵聽乙個套接字。當接受到請求時,子程序就會接受它並且提供響應。父程序會監聽所有子程序以確保總是可以使用最少量的程序來處理請求,並且確保等候請求到達的空閒程序不能太少。如果沒有足夠多的空閒程序來處理潛在的請求高峰,那麼父程序就會啟動新的子程序。如果存在過多的子程序,那麼父程序會每次終止乙個空閒程序,直到伺服器回到最大空閒子程序狀況。通過保持一定數量的空閒子程序來接受所引入的請求,伺服器就可以避免在接受到請求時再去啟動新程序的開銷。
父程序和子程序之間通過記分板(一塊共享記憶體區域)進行通訊,對於每乙個產生的子程序,它的狀態資訊都寫入到記分板中,父程序通過讀取記分板可以了解子程序的狀態。當需要關閉子程序時它將通過終止管道傳送終止資訊給子程序,另外的一種通知方式就是通過訊號。
4.worker模型:prefork是乙個精心設計的併發模式,不過因基於程序的先天的限制,在一些作業系統中使用併發的效率並不是很高。在一些系統中,比如linux,執行緒是更適合的執行單元,與程序相比,它能夠節省更多的資源及各種上下文切換。
worker是混合了程序和執行緒的併發模型。整個worker的內部可以分為三大部分:主程序、工作子程序及工作執行緒。主程序啟動後,它會建立一組數目不定的工作子程序,子程序的數目由主程序進行動態調整,這與prefork非常相似,每個子程序又會建立固定數目的工作子執行緒。
每個子程序產生的執行緒屬於一組,每組中的執行緒分為兩種角色:偵聽者執行緒和工作者執行緒。偵聽者執行緒用於偵聽網路並接受客戶端連線,一旦接受完畢,就將會放入連線佇列中。然後,工作者執行緒負責從佇列中獲取連線,為所有來自它的請求提供服務。偵聽者執行緒和工作者執行緒之間通過套接字佇列進行非同步通訊。
當伺服器繁忙時,通常需要產生更多的工作者執行緒。但是worker並不直接建立執行緒,它首先建立乙個子程序,然後有這個程序一次性建立多個執行緒。因此worker中線程的建立總是批量的,與之類似,當伺服器空閒時,worker也不是逐個的終止某個特定執行緒,它仍然以程序為單位,終止乙個程序,讓後該程序一次性的終止該程序下的所有執行緒。
5.winnt:對於apache而言,winnt是windows平台下唯一使用的mpm。與通常的mpm結果相比,winnt具有一些明顯的優勢。首先它使用執行緒而不是程序作為基本的執行單元。另外,它執行的執行緒數目是固定不變的,這與前面所描述的prefork的動態調整形成了對比。在windows下使用執行緒的最主要的原因是因為執行緒能夠得到更高的效能提公升。與unix程序相比,windows程序實在是重量級單位,它消耗的資源要比執行緒多得多。
整個winnt內部可以分為三個重要的組成部分:兩個程序及一組多個工作執行緒。兩個重要的程序分別是:監控程序和工作程序。當mpm啟動後它會立即建立乙個新的工作程序,而原有的程序則轉為監控該工作程序。工作程序則負責產生多個執行緒並監控這些執行緒。所有的工作執行緒都由工作程序即新程序負責建立。工作程序負責處理客戶端的http請求。監控程序又被稱為主程序,它負責監控工作程序的狀態,確保工作程序正常工作。任何時候發現工作程序異常退出,它將重新啟動該程序。
而在工作執行緒內部各個執行緒又被分為不同的角色:偵聽執行緒和工作執行緒。偵聽執行緒負責接受客戶端的連線請求,而工作執行緒則主要負責處理這些請求。偵聽執行緒和工作執行緒之間是非同步的,它們會通過「套接字佇列」進行通訊。
附:為了做到高併發的處理,windows和linux系統對io分別採用了不同的機制,在linux系統中採用的是epoll而在windows系統下採用的是完成埠。
伺服器設計 處理併發請求
伺服器設計技術有很多,按使用的協議來分有tcp伺服器和udp伺服器。按處理方式來分有迴圈伺服器和併發伺服器。在網路程式裡面,一般來說都是許多客戶對應乙個伺服器,為了處理客戶的請求,對服務端的程式就提出了特殊的要求。目前最常用的伺服器模型有 迴圈伺服器 伺服器在同一時刻只能響應乙個客戶端的請求 併發伺...
linux c 高併發tcp伺服器架構
from epoll 接受資料到佇列,執行緒池處理佇列裡的資料 具體實現方式 只使用使用std的的資料結構,未使用boost thread pool.cpp include include include thread pool.h include thread process.h include ...
併發伺服器
併發伺服器 伺服器使用多個控制線程,同時處理多個客戶請求。有關併發執行的細節取決於所用作業系統。但其思路很簡單 併發伺服器程式被分為主程式 執行緒 和控制代碼兩部分,主程式只接受來自客戶的連線請求,並為該客戶建立乙個控制線程 每乙個控制線程只與乙個客戶互動,並執行控制代碼程式。當處理完乙個客戶後,該...