系統是如何支撐高併發的?

  一、先考慮一個最簡單的系統架構

假設剛剛開始你的系統就部署在一臺機器上,背後就連接了一臺數據庫,數據庫部署在一臺服務器上。

我們甚至可以再現實點,例如你的系統部署的機器是4核8G,數據庫服務器是16核32G。

此時假設系統用戶量總共就10萬,用戶量很少,日活用戶按照不同系統的場景有區別,我們取一個較爲客觀的比例,10%吧,每天活躍的用戶就1萬。

按照二八法則,每天高峯期算4個小時,高峯期活躍的用戶佔比達到80%,就是8000人活躍在4小時內。

然後每個人對系統發起請求,我們按照每天20次算吧。那麼高峯期8000人發起的請求也才16萬次,平均到4小時內的每秒(14400秒),每秒也就10次請求。

好吧!完全跟高併發搭不上邊,對不對?

然後系統層面每秒是10次請求,對數據庫的調用每次請求都會好幾次數據庫操作的,比如做CRUD之類的。

那麼我們取一個一次請求對應3次數據庫請求吧,那這樣的話,數據庫層每秒也就30次請求,對不對?

按照這臺數據庫服務器的配置,支撐是絕對沒問題的。

上述描述的系統,用一張圖表示,就是下面這樣:

 

 

二、系統集羣化部署

假設此時用戶數開始快速增長,比如註冊用戶量增長了50倍,上升到了500萬。

此時日活用戶是50萬,高峯期對系統每秒請求是500/s。然後對數據庫的每秒請求數量是1500/s,這個時候會怎麼樣呢?

按照上述的機器配置來說,如果系統內處理的是較爲複雜的一些業務邏輯,是那種重業務邏輯的系統的話,是比較耗費CPU的。

此時,4核8G的機器每秒請求達到500/s的時候,很可能你的機器CPU負載較高了。

然後數據庫層面,以上述的配置而言,其實基本上1500/s的高峯請求壓力的話,還算可以接受。

這個主要是要觀察數據庫所在機器的磁盤負載、網絡負載、CPU負載、內存負載,按照我們的線上經驗而言,那個配置的數據庫在1500/s請求壓力下是沒問題的。

所以此時需要做的一個事情,首先就是要支持你的系統集羣化部署。

可以在前面掛一個負載均衡層,把請求均勻打到系統層面,讓系統可以用多臺機器集羣化支撐更高的併發壓力。

比如說這裏假設給系統增加部署一臺機器,那麼每臺機器就只有250/s的請求了。

這樣一來,兩臺機器的CPU負載都會明顯降低,這個初步的“高併發”不就先cover住了嗎?

要是連這個都不做,那單臺機器負載越來越高的時候,極端情況下是可能出現機器上部署的系統無法有足夠的資源響應請求了,然後出現請求卡死,甚至系統宕機之類的問題。

所以,簡單小結,第一步要做的:

  1. 添加負載均衡層,將請求均勻打到系統層。
  2. 系統層採用集羣化部署多臺機器,扛住初步的併發壓力。

此時的架構圖變成下面的樣子:

 

 

三、數據庫分庫分表 + 讀寫分離

假設此時用戶量繼續增長,達到了1000萬註冊用戶,然後每天日活用戶是100萬。

那麼此時對系統層面的請求量會達到每秒1000/s,系統層面,你可以繼續通過集羣化的方式來擴容,反正前面的負載均衡層會均勻分散流量過去的。

但是,這時數據庫層面接受的請求量會達到3000/s,這個就有點問題了。

此時數據庫層面的併發請求翻了一倍,你一定會發現線上的數據庫負載越來越高。

每次到了高峯期,磁盤IO、網絡IO、內存消耗、CPU負載的壓力都會很高,大家很擔心數據庫服務器能否抗住。

沒錯,一般來說,對那種普通配置的線上數據庫,建議就是讀寫併發加起來,按照上述我們舉例的那個配置,不要超過3000/s。

因爲數據庫壓力過大,首先一個問題就是高峯期系統性能可能會降低,因爲數據庫負載過高對性能會有影響。

另外一個,壓力過大把你的數據庫給搞掛了怎麼辦?

所以此時你必須得對系統做分庫分表 + 讀寫分離,也就是把一個庫拆分爲多個庫,部署在多個數據庫服務上,這是作爲主庫承載寫入請求的。

然後每個主庫都掛載至少一個從庫,由從庫來承載讀請求。

此時假設對數據庫層面的讀寫併發是3000/s,其中寫併發佔到了1000/s,讀併發佔到了2000/s。

那麼一旦分庫分表之後,採用兩臺數據庫服務器上部署主庫來支撐寫請求,每臺服務器承載的寫併發就是500/s。每臺主庫掛載一個服務器部署從庫,那麼2個從庫每個從庫支撐的讀併發就是1000/s。

簡單總結,併發量繼續增長時,我們就需要focus在數據庫層面:分庫分表、讀寫分離。

此時的架構圖如下所示:

 

 

 

四、緩存集羣引入

接着就好辦了,如果註冊用戶量越來越大,此時你可以不停地加機器,比如說系統層面不停加機器,就可以承載更高的併發請求。

然後數據庫層面如果寫入併發越來越高,就擴容加數據庫服務器,通過分庫分表是可以支持擴容機器的,如果數據庫層面的讀併發越來越高,就擴容加更多的從庫。

但是這裏有一個很大的問題:數據庫其實本身不是用來承載高併發請求的。所以通常來說,數據庫單機每秒承載的併發就在幾千的數量級,而且數據庫使用的機器都是比較高配置,比較昂貴的機器,成本很高。

如果不停地加機器,這是不對的。

在高併發架構裏通常都有緩存這個環節,緩存系統的設計就是爲了承載高併發而生。

單機承載的併發量都在每秒幾萬,甚至每秒數十萬,對高併發的承載能力比數據庫系統要高出一到兩個數量級。

可以根據系統的業務特性,對那種寫少讀多的請求,引入緩存集羣。

具體來說,就是在寫數據庫的時候同時寫一份數據到緩存集羣裏,然後用緩存集羣來承載大部分的讀請求。

這樣的話,通過緩存集羣,就可以用更少的機器資源承載更高的併發。

比如說上面那個圖裏,讀請求目前是每秒2000/s,兩個從庫各自抗了1000/s讀請求,但是其中可能每秒1800次的讀請求都是可以直接讀緩存裏的不怎麼變化的數據的。

那麼此時你一旦引入緩存集羣,就可以抗下來這1800/s讀請求,落到數據庫層面的讀請求就200/s。

同樣,給大家來一張架構圖,一起來感受一下:

按照上述架構,好處是什麼呢?

可能未來你的系統讀請求每秒都幾萬次了,但是可能80%~90%都是通過緩存集羣來讀的,而緩存集羣裏的機器可能單機每秒都可以支撐幾萬讀請求,所以耗費機器資源很少,可能就兩三臺機器就夠了。

要是換成數據庫來試一下,可能就要不停地加從庫到10臺、20臺機器才能抗住每秒幾萬的讀併發,那個成本是極高的。

好了,我們再來簡單小結,承載高併發需要考慮的第三個點:

  • 不要盲目進行數據庫擴容,數據庫服務器成本昂貴,且本身就不是用來承載高併發的
  • 針對寫少讀多的請求,引入緩存集羣,用緩存集羣抗住大量的讀請求

五、引入消息中間件集羣

接着再來看看數據庫寫這塊的壓力,其實是跟讀類似的。

假如說所有寫請求全部都落地數據庫的主庫層,當然是沒問題的,但是寫壓力要是越來越大了呢?

比如每秒要寫幾萬條數據,此時難道也是不停的給主庫加機器嗎?

可以當然也可以,但是同理,耗費的機器資源是很大的,這個就是數據庫系統的特點所決定的。

相同的資源下,數據庫系統太重太複雜,所以併發承載能力就在幾千/s的量級,所以此時你需要引入別的一些技術。

比如說消息中間件技術,也就是MQ集羣,是非常好的做寫請求異步化處理,實現削峯填谷的效果。

假如說,現在每秒是1000/s次寫請求,其中比如500次請求是必須請求過來立馬寫入數據庫中的,但是另外500次寫請求是可以允許異步化等待個幾十秒,甚至幾分鐘後才落入數據庫內的。

那麼此時完全可以引入消息中間件集羣,把允許異步化的每秒500次請求寫入MQ,然後基於MQ做一個削峯填谷。比如就以平穩的100/s的速度消費出來然後落入數據庫中即可,此時就會大幅度降低數據庫的寫入壓力。

此時,架構圖變成了下面這樣:

 

大家看上面的架構圖,首先消息中間件系統本身也是爲高併發而生,所以通常單機都是支撐幾萬甚至十萬級的併發請求的。

所以,這本身也跟緩存系統一樣,可以用很少的資源支撐很高的併發請求,用來支撐部分允許異步化的高併發寫入是沒問題的,比使用數據庫直接支撐那部分高併發請求要減少很多的機器使用量。

而且經過消息中間件的削峯填谷之後,比如就用穩定的100/s的速度寫數據庫,那麼數據庫層面接收的寫請求壓力,不就成了500/s + 100/s  = 600/s了麼?

大家看看,是不是發現減輕了數據庫的壓力?

到目前爲止,通過下面的手段,我們已經可以讓系統架構儘可能用最小的機器資源抗住了最大的請求壓力,減輕了數據庫的負擔。

  • 系統集羣化
  • 數據庫層面的分庫分表+讀寫分離
  • 針對讀多寫少的請求,引入緩存集羣
  • 針對高寫入的壓力,引入消息中間件集羣

初步來說,簡單的一個高併發系統的闡述是說完了。

但是,其實故事到這裏還遠遠沒有結束。

一個完整而複雜的高併發系統架構中,一定會包含各種複雜的自研基礎架構系統、各種精妙的架構設計(比如熱點緩存架構設計、多優先級高吞吐MQ架構設計、系統全鏈路併發性能優化設計,等等)、還有各種複雜系統組合而成的高併發架構整體技術方案、還有NoSQL(Elasticsearch等)/負載均衡/Web服務器等相關技術。

所以大家切記要對技術保持敬畏之心,這些東西都很難通過一些文章來表述清楚。

最後,真正在生產落地的時候,高併發場景下系統會出現大量的技術問題。

比如說消息中間件吞吐量上不去需要優化、磁盤寫壓力過大性能太差、內存消耗過大容易撐爆、分庫分表中間件不知道爲什麼丟了數據等等吧。諸如此類的問題非常多,這些也不可能通過文章給全部說清楚。

上面所說,權當拋磚引玉。大家自己平時一定要多思考,自己多畫圖,盤點盤點自己手頭系統的請求壓力。計算一下分散到各個中間件層面的請求壓力,到底應該如何利用最少的機器資源最好的支撐更高的併發請求。這纔是一個好的高併發架構設計思路。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章