Linux IPC之Socket網絡編程服務器的負載均衡

導言:在設計高性能併發型服務器時,傳統的爲每一個客戶端創建一個新的子進程(或線程)所帶來的開銷對服務器來說是個沉重的負擔,因此本文考慮幾種可選方案。

在服務器上預先創建進程或線程(進程池或線程池)

  • 服務器在啓動階段(即,在任何客戶端請求到來之前)就立刻預先創建好一定數量的子進程(或線程),而不是針對每個客戶端來創建一個新的子進程(或線程)。這些子進程構成了一種服務池(server pool),即,進程池或線程池。

  • 服務池中的每個子進程一次只處理一個客戶端。在處理完客戶端請求後,子進程並不會終止,而是獲取下一個待處理的客戶端繼續處理。

  • 服務池的方式,需要服務器父進程必須對未佔用的子進程加以監視,並且在服務器處於負載高峯期時,增加服務池的大小,而在負載低時,降低服務池的大小(因爲過多的空餘進程會降低系統的整體性能)。

  • 服務池中的子進程必須遵循某些協議,使得它們能以獨佔的方式選擇一個客戶端連接。(例如,在大多數UNIX實現中,讓服務池中的每個子進程在監聽描述符的accept()調用上阻塞就足夠了。即,服務器父進程在創建任何子進程之前先創建監聽套接字,然後每個子進程fork()調用中繼承該套接字的文件描述符,當一個新的客戶端連接到來時,只有其中一個子進程能完成accept()調用。但是,由於accpet()在一些老式的實現中並不是一個原子化的系統調用,因此可能需要通過一些互斥技術,例如,文件鎖來支持,以確保每次只有一個子進程可以執行accpet()調用。)

在單個進程中處理多個客戶端(I/O多路複用)

爲了達到單個服務器進程來處理多個客戶端,必須採用一種能允許單個進程同時監視多個文件描述符上I/O事件的I/O模型。例如,使用Linux的epoll。

在設計單進程服務器時,服務器進程必須做一些通常由內核來處理的調度任務,我們可以依靠內核來確保每個服務器進程能公平地訪問到服務器主機的資源,但當我們用單個服務器進程來處理多個客戶端時,服務器進程必須自行確保一個或多個客戶端不會獨佔服務器,從而使其他的客戶端處於飢餓狀態。

服務器集羣

使用多個服務器系統(即,服務器集羣,server farm)來支持客戶端的併發高負載。

  • DNS

構建服務器集羣最簡單的一種方式是使用DNS,將同一個域名映射到多個服務器的IP,然後DNS服務器對域名解析請求以輪詢的方式返回不同的服務器IP地址。

問題:DNS的方式(循環輪詢)優勢是成本低且易實施,但是也存在一些問題。一個是DNS緩存的問題,導致切換可能不能立即生效。另外一個是,循環輪詢不能達到很好的負載均衡,因爲後端的服務器配置可能不同,資源利用率可能無法達到最大化。

  • 親和性

在多臺服務器的設計中,另一個需要考慮的因素是,服務器親和性(server affinity),即,確保來自同一個客戶端的請求序列能夠全部定向到同一臺服務器上,這樣由服務器維護的任何有關客戶端狀態的信息都能夠保持準確。

  • 服務器負載均衡(server load balancing)

由一臺負載均衡服務器(主備容災),將客戶端請求路由到服務器集羣中的其中一個成員上。此方式的優點是:

  1. 消除了由DNS緩存所引起的問題,因爲服務器集羣只對外提供了一個單獨的IP地址,即,負載均衡服務器的IP地址。
  2. 負載均衡服務器結合一些算法來衡量或計算服務器負載,可能根據服務器集羣的成員所提供的量值,並智能地將負載分發到集羣中的各個成員之上。
  3. 負載均衡服務器也會自動檢測集羣中的失效成員,或者新增加的服務器成員。
  4. 負載均衡服務器可能還會提供對服務器親和力的支持。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章