當前位置:編程學習大全網 - 編程語言 - 網絡服務器的幾種並發服務模型

網絡服務器的幾種並發服務模型

服務程序最為關鍵的設計是並發服務模型,當前有以下幾種典型的模型:

- 單進程服務,使用非阻塞IO

使用壹個進程服務多個客戶,通常與客戶通信的套接字設置為非阻塞的,阻塞只發生在select()、poll()、epoll_wait()等系統調用上面。這是壹種行之有效的單進程狀態機式服務方式,已被廣泛采用。

缺點是它無法利用SMP(對稱多處理器)的優勢,除非啟動多個進程。此外,它嘗試就緒的IO文件描述符後,立即從系統調用返回,這會導致大量的系統調用發生,尤其是在較慢的字節傳輸時。

select()本身的實現也是有局限的:能打開的文件描述符最多不能超過FD_SETSIZE,很容易耗盡;每次從select()返回的描述符組中掃描就緒的描述符需要時間,如果就緒的描述符在末尾時更是如此(epoll特別徹底修復了這個問題)。

- 多進程服務,使用阻塞IO

也稱作 accept/fork 模型,每當有客戶連線時產生壹個新的進程為之服務。這種方式有時是必要的,比如可以通過操作系統獲得良好的內存保護,可以以不同的用戶身份運行程序,可以讓服務運行在不同的目錄下面。但是它的缺點也很明顯:進程比較占資源,進程切換開銷太大,***享某些信息比較麻煩。Apache 1.3就使用了這種模型,MaxClients數很容易就可以達到。

- 多線程服務,使用阻塞IO

也稱之 accept/pthread_create模型,有新客戶來時創建壹個服務線程而不是服務進程。這解決了多進程服務的壹些問題,比如它占用資源少,信息***享方便。但是麻煩在於線程仍有可能消耗光,線程切換也需要開銷。

- 混合服務方式

所謂的混合服務方式,以打破服務方和客戶方之間嚴格的1:1關系。基本做法是:

新客戶到來時創建新的工作線程,當該工作線程檢測到網絡IO會有延遲時停止處理過程,返回給Server壹個延遲處理狀態,同時告訴 Server被延遲的文件描述符,延遲超時時間。Server會在合適的時候返回工作線程繼續處理。註意這裏的工作線程不是通過 pthread_create()創建的,而是被包裝在專門用於處理延遲工作的函數裏。

這裏還有壹個問題,工作線程如何檢測網絡IO會有延遲?方法有很多,比如設置較短的超時時間調用poll(),或者甚至使用非阻塞IO。如果是套接字,可以設置SO_RCVTIMEO和SO_SNDTIMEO選項,這樣更有效率。

除了延遲線程,Server還應提供了未完成線程的支持。

如有有特別耗費時間的操作,妳可以在完成部分工作後停止處理,返回給Server壹個未完成狀態。這樣Server會檢查工作隊列是否有別的線程,如果有則讓它們運行,否則讓該工作線程繼續處理,這可以防止某些線程挨餓。

典型的壹個混合服務模型開源實現ServerKit

Serverkit的這些線程支持功能可簡化我們的服務程序設計,效率上應該也是有保證的。

2. 隊列(queue)

ServerKit提供的隊列是壹個單向鏈表,隊列的存取是原子操作,如果只有壹個執行單元建議不要用,因為原子操作的開銷較大。

3. 堆(heap)

malloc()分配內存有壹定的局限,比如在多線程的環境裏,需要序列化內存分配操作。ServerKit提供的堆管理函數,可快速分配內存,可有效減少分配內存的序列化操作,堆的大小可動態增長,堆有引用計數,這些特征比較適合多線程環境。目前ServerKit堆的最大局限是分配單元必須是固定大小。

4. 日誌記錄

日誌被保存在隊列,有壹個專門的線程處理隊列中的日誌記錄:它或者調用syslog()寫進系統日誌,或者通過UDP直接寫到遠程機器。後者更有效。

5. 讀寫鎖

GNU libc也在pthreads庫裏實現了讀寫鎖,如果定義了__USE_UNIX98就可以使用。不過ServerKit還提供了讀寫鎖互相轉換的函數,這使得鎖的應用更為彈性。比如擁有讀鎖的若幹個線程對同壹個hash表進行檢索,其中壹個線程檢索到了數據,此時需要修改它,壹種辦法是獲取寫鎖,但這會導致釋放讀鎖和獲取寫鎖之間存在時間窗,另壹種辦法是使用ServerKit提供的函數把讀鎖轉換成寫鎖,無疑這種方式更有效率。

除了以上這些功能,ServerKit還提供了數據庫連接池的管理(當前只支持MySQL)和序列化(Sequences),如感興趣可參見相關的API文檔。

二、ServerKit服務模塊編寫

ServerKit由3部分組成:server程序,負責加載服務模塊、解析配置文件、建立數據庫連接池;libserver,動態鏈接庫,提供所有功能的庫支持,包括server本身也是調用這個庫寫的;API,編程接口,妳編寫的服務模塊和ServerKit框架進行對話的接口。

ServerKit需要libConfuse解析配置文件,所以出了安裝ServerKit,還需要安裝libConfuse。關於libConfuse可參考 >", NULL};

SERVER_MODULE(FOO,0,0,1,"Example module that does nothing but sleep")

按以下方法編譯:

$ gcc -c -fPIC -pthread -D_REENTRANT -g FOO.c

$ gcc -shared -lserver -lconfuse -lpthread -g -e __server_module_main -o FOO.so FOO.o

-e選項指定程序運行入口,這使得妳可以直接在命令行敲 ./FOO.so 運行模塊。

server程序根據環境變量SERVER_PERSONALITY_PATH定位主目錄,並查找主目錄下的c11n作為配置文件,動態加載的模塊需放在主目錄下的modules目錄。

$ export SERVER_PERSONALITY_PATH=`pwd`

$ mkdir modules

$ cp FOO.so modules

$ vi c11n

c11n的內容:

identity = "any_id"

FOO {

sleep_duration = 1;

}

identity標識server實例,用ps可看到程序名稱形如server.identity,本例為server.any_id。

執行server啟動服務程序。

三、ServerKit其他功能缺陷

缺乏daemon模式;

只能運行在Linux box;

DB pool只支持MySQL;

Heap管理內存的功力有限

  • 上一篇:算法編程
  • 下一篇:G38空調面板編程
  • copyright 2024編程學習大全網