大並發服務器框架設計


簡單談一談大並發服務器框架設計的基本思路

基本的服務器框架都是C/S結構的,請求和相應流程是這樣的:

 

這樣的框架存在一個很嚴重的問題,當客戶端大並發請求到來,服務器需要進行大量的數據庫操作,假設數據庫最大連接數為

1000個,此時有10000個請求訪問應用服務器,那么應用服務器只能處理1000個請求,剩下99000個等待1000個請求處理好后

再進行訪問數據庫處理。可以在應用服務器和數據庫服務器中間增加中間層DAL,DAL采用緩沖隊列和連接池設計。

DAL設計緩沖隊列,存儲等待的請求,並且DAL中設計數據庫連接池,當數據庫連接池中有空閑連接,

那么從緩沖隊列中取出一個請求處理,以此類推。這種做法有效的降低了服務器的壓力,但是沒有提高處理速度,

僅僅保證了請求被緩存,處理效率仍受限於數據庫的並發數。那么可以再增加一層緩存,將常用的數據加載如緩存,

有請求到來時,應用服務器先從緩存中獲取數據,如果緩存中有數據,那么不需要訪問數據庫,如果緩存中沒有,

在訪問數據庫取出數據,並更新緩存。

 

緩存如何同步?

有兩種手段:

第一種方法: 緩存是具有時效的,在一定時間過后會超時timeout,如果緩存失效,那么重新去數據庫查詢,

查詢后更新緩存,這種方法不是實時的,實時性比較差。

第二種方法:當有請求修改數據時,更新緩存,並且將要修改的數據投入DAL層,當數據庫有空閑連接時,再持久化

存盤。

緩存的不足之處:

當緩存足夠多時,需要將不活躍緩存數據換出內存,叫做緩存換頁。緩存換出算法和操作系統換頁算法類似,FIFO,LRU(least recently used),

LFU(least  frequently used)等。實際緩存的實現不需要自己去實現,有很多開源技術,nosql技術就是非關系型數據庫的意思。

非關系型數據庫如redis,memcatched等。緩存可以跟應用服務器部署在同一台機器上,也可以部署在單獨機器上。我推薦將緩存服務器部署在

單獨機器上,假設有兩台應用服務器,如果將緩存部署在不同的應用服務器上,那么不同的應用服務器很難訪問彼此的緩存,非常不方便。將緩存

部署在單獨服務器上,各個應用服務器都能訪問該緩存服務器。

 

 

如果有大量的業務請求到來,雖然設計了多個應用服務器,也架設了緩存服務器,完善了中間層的緩沖隊列和數據庫連接池,

但是數據庫服務器仍然會出現瓶頸。比如當有大量復雜的寫操作數據庫,很多讀數據庫的操作就被阻塞了,為解決這個問題可

將數據庫實現讀寫分離。由於數據庫讀操作會比寫操作多,那么可以對數據庫執行負載均衡。主流數據庫都有replication機制,

采用replication機制可以實現負載均衡。中間層的寫數據庫操作投遞到master數據庫中,讀操作從slave數據庫中讀取,

當master數據庫中數據被修改后,數據庫采用replication機制將數據同步給slave服務器。

 

同樣的道理,應用服務器也可以實現負載均衡,架設多個應用服務器,不同的請求分配給不同的應用服務器。

可單獨設計一個任務服務器監控各個應用服務器的負載情況,合理的分配任務給各個應用服務器。這種方式

是任務服務器主動地分配任務給應用服務器,應用服務器被動的接受任務,這種方式在任務請求類型相近的

情況下,分配方式非常合理。但是假設應用服務器A接受了3個任務,應用服務器B接受了5個任務,按照負載均衡的

權重法或最小連接法,肯定會分配給A任務,但是如果這3個任務都是復雜的寫操作,而B的5個任務都是簡單的

讀操作,那么這就存在分配的不合理性,如何解決這個問題呢?

 

可以換一種思路去解決這個問題,讓應用服務器主動去請求任務服務器,主動獲取任務處理,如果應用服務器處於忙碌狀態就不需要

請求新的任務,空閑的應用服務器會去請求任務服務器中的任務,這是最合理的負載均衡。如果所有應用服務器都處於忙碌狀態,

那么任務服務器將任務緩存至自己的任務隊列,當應用服務器空閑時會來取任務。

考慮這樣一個問題,如果任務服務器出現故障怎么辦?

任務服務器需要有多台,並且實現failover機制,多台任務服務器之間實現心跳,如果檢測不到對方心跳,則使自己成為主任務服務器。

 到目前為止,這個框架可以適用於大部分服務器邏輯。為保證數據庫的響應速度和處理效率,可以對數據庫進行分區。

數據庫分區有兩種形式(分庫、分表)

分庫:數據庫可以按照一定的邏輯把表分散到不同的數據庫。這叫做垂直分區,就是所每個庫的表不同,功能不同。

這樣做不常見,因為很大情況下,數據庫中各個表是關聯的,如果將不同的表分配到不同的數據庫中,會存在很多不便。

分表:將一個表的不同數據分配到各個數據庫,這樣每個數據庫的表結構是一樣的,只是存儲的用戶數據不同而已,叫做水平

分區。分表的方式很常見,如果數據庫的壓力增加,我們就采取分表的方式減少數據庫的壓力。

 

另外服務器開發的幾個性能殺手:

1 數據拷貝,數據從內核態copy到用戶態,或者在用戶態之間copy會造成性能損失,盡量采用緩存的方式解決。

2 環境切換 ,多線程上下文切換造成開銷。如果服務器是單核的,那么采用狀態機方式單線程效果最佳。如果是多核的,

合理采用多線程,可以提升性能。

3 內存分配,可以采用內存池,提前分配。

4 鎖競爭,加鎖解鎖會造成一定的效率衰減。

 

到此為止,服務器框架介紹完畢,謝謝關注我的微信公眾號:

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM