最讓你手足無措的一個問題:你的系統如何支撐高併發?(面試)

lizhiqiang666發表於2019-02-20

目錄
(1)一道面試題的背景引入
(2)先考慮一個最簡單的系統架構
(3)系統叢集化部署
(4)資料庫分庫分表 + 讀寫分離
(5)快取叢集引入
(6)引入訊息中介軟體叢集
(7)現在能hold住高併發面試題了嗎?
(8)本文能帶給你什麼啟發?
(1)一道面試題的背景引入
這篇文章,我們聊聊大量同學問我的一個問題,面試的時候被問到一個讓人特別手足無措的問題:你的系統如何支撐高併發?
大多數同學被問到這個問題壓根兒沒什麼思路去回答,不知道從什麼地方說起,其實本質就是沒經歷過一些真正有高併發系統的錘鍊罷了。
因為沒有過相關的專案經歷,所以就沒法從真實的自身體會和經驗中提煉出一套回答,然後系統的闡述出來自己複雜過的系統如何支撐高併發的。
所以,這篇文章就從這個角度切入來簡單說說這個問題,用一個最簡單的思路來回答,大致如何應對。
當然這裡首先說清楚一個前提:高併發系統各不相同。比如每秒百萬併發的中介軟體系統、每日百億請求的閘道器係統、瞬時每秒幾十萬請求的秒殺大促系統。
他們在應對高併發的時候,因為系統各自自身特點的不同,所以應對架構都是不一樣的。
另外,比如電商平臺中的訂單系統、商品系統、庫存系統,在高併發場景下的架構設計也是不同的,因為背後的業務場景什麼的都不一樣。
所以,這篇文章主要是給大家提供一個回答這類問題的思路,不涉及任何複雜架構設計,讓你不至於在面試中被問到這個問題時,跟面試官大眼瞪小眼。
具體要真能在面試的時候回答好這個問題,建議各位參考一下本文思路,然後對你自己手頭負責的系統多去思考一下,最好做一些相關的架構實踐。
(2)先考慮一個最簡單的系統架構
假設剛剛開始你的系統就部署在一臺機器上,背後就連線了一臺資料庫,資料庫部署在一臺伺服器上。
我們甚至可以再現實點,給個例子,你的系統部署的機器是4核8G,資料庫伺服器是16核32G。
此時假設你的系統使用者量總共就10萬,使用者量很少,日活使用者按照不同系統的場景有區別,我們取一個較為客觀的比例,10%吧,每天活躍的使用者就1萬。
按照28法則,每天高峰期算他4個小時,高峰期活躍的使用者佔比達到80%,就是8000人活躍在4小時內。
然後每個人對你的系統發起的請求,我們算他每天是20次吧。那麼高峰期8000人發起的請求也才16萬次,平均到4小時內的每秒(14400秒),每秒也就10次請求。
好吧!完全跟高併發搭不上邊,對不對?
然後系統層面每秒是10次請求,對資料庫的呼叫每次請求都會好幾次資料庫操作的,比如做做crud之類的。
那麼我們取一個一次請求對應3次資料庫請求吧,那這樣的話,資料庫層每秒也就30次請求,對不對?
按照這臺資料庫伺服器的配置,支撐是絕對沒問題的。
上述描述的系統,用一張圖表示,就是下面這樣:
file
(3)系統叢集化部署
假設此時你的使用者數開始快速增長,比如註冊使用者量增長了50倍,上升到了500萬。
此時日活使用者是50萬,高峰期對系統每秒請求是500/s。然後對資料庫的每秒請求數量是1500/s,這個時候會怎麼樣呢?
按照上述的機器配置來說,如果你的系統內處理的是較為複雜的一些業務邏輯,是那種重業務邏輯的系統的話,是比較耗費CPU的。
此時,4核8G的機器每秒請求達到500/s的時候,很可能你會發現你的機器CPU負載較高了。
然後資料庫層面,以上述的配置而言,其實基本上1500/s的高峰請求壓力的話,還算可以接受。
這個主要是要觀察資料庫所在機器的磁碟負載、網路負載、CPU負載、記憶體負載,按照我們的線上經驗而言,那個配置的資料庫在1500/s請求壓力下是沒問題的。
所以此時你需要做的一個事情,首先就是要支援你的系統叢集化部署。
你可以在前面掛一個負載均衡層,把請求均勻打到系統層面,讓系統可以用多臺機器叢集化支撐更高的併發壓力。
比如說這裡假設給系統增加部署一臺機器,那麼每臺機器就只有250/s的請求了。
這樣一來,兩臺機器的CPU負載都會明顯降低,這個初步的“高併發”不就先cover住了嗎?
要是連這個都不做,那單臺機器負載越來越高的時候,極端情況下是可能出現機器上部署的系統無法有足夠的資源響應請求了,然後出現請求卡死,甚至系統當機之類的問題。
所以,簡單小結,第一步要做的:
新增負載均衡層,將請求均勻打到系統層。
系統層採用叢集化部署多臺機器,扛住初步的併發壓力。
此時的架構圖變成下面的樣子:
file
(4)資料庫分庫分表 + 讀寫分離
假設此時使用者量繼續增長,達到了1000萬註冊使用者,然後每天日活使用者是100萬。
那麼此時對系統層面的請求量會達到每秒1000/s,系統層面,你可以繼續通過叢集化的方式來擴容,反正前面的負載均衡層會均勻分散流量過去的。
但是,這時資料庫層面接受的請求量會達到3000/s,這個就有點問題了。
此時資料庫層面的併發請求翻了一倍,你一定會發現線上的資料庫負載越來越高。
每次到了高峰期,磁碟IO、網路IO、記憶體消耗、CPU負載的壓力都會很高,大家很擔心資料庫伺服器能否抗住。
沒錯,一般來說,對那種普通配置的線上資料庫,建議就是讀寫併發加起來,按照上述我們舉例的那個配置,不要超過3000/s。
因為資料庫壓力過大,首先一個問題就是高峰期系統效能可能會降低,因為資料庫負載過高對效能會有影響。
另外一個,壓力過大把你的資料庫給搞掛了怎麼辦?
所以此時你必須得對系統做分庫分表 + 讀寫分離,也就是把一個庫拆分為多個庫,部署在多個資料庫服務上,這是作為主庫承載寫入請求的。
然後每個主庫都掛載至少一個從庫,由從庫來承載讀請求。
此時假設對資料庫層面的讀寫併發是3000/s,其中寫併發佔到了1000/s,讀併發佔到了2000/s。
那麼一旦分庫分表之後,採用兩臺資料庫伺服器上部署主庫來支撐寫請求,每臺伺服器承載的寫併發就是500/s。每臺主庫掛載一個伺服器部署從庫,那麼2個從庫每個從庫支撐的讀併發就是1000/s。
簡單總結,併發量繼續增長時,我們就需要focus在資料庫層面:分庫分表、讀寫分離。
此時的架構圖如下所示:
file
(5)快取叢集引入
接著就好辦了,如果你的註冊使用者量越來越大,此時你可以不停的加機器,比如說系統層面不停加機器,就可以承載更高的併發請求。
然後資料庫層面如果寫入併發越來越高,就擴容加資料庫伺服器,通過分庫分表是可以支援擴容機器的,如果資料庫層面的讀併發越來越高,就擴容加更多的從庫。
但是這裡有一個很大的問題:資料庫其實本身不是用來承載高併發請求的,所以通常來說,資料庫單機每秒承載的併發就在幾千的數量級,而且資料庫使用的機器都是比較高配置,比較昂貴的機器,成本很高。
如果你就是簡單的不停的加機器,其實是不對的。
所以在高併發架構裡通常都有快取這個環節,快取系統的設計就是為了承載高併發而生。
所以單機承載的併發量都在每秒幾萬,甚至每秒數十萬,對高併發的承載能力比資料庫系統要高出一到兩個數量級。
所以你完全可以根據系統的業務特性,對那種寫少讀多的請求,引入快取叢集。
具體來說,就是在寫資料庫的時候同時寫一份資料到快取叢集裡,然後用快取叢集來承載大部分的讀請求。
這樣的話,通過快取叢集,就可以用更少的機器資源承載更高的併發。
比如說上面那個圖裡,讀請求目前是每秒2000/s,兩個從庫各自抗了1000/s讀請求,但是其中可能每秒1800次的讀請求都是可以直接讀快取裡的不怎麼變化的資料的。
那麼此時你一旦引入快取叢集,就可以抗下來這1800/s讀請求,落到資料庫層面的讀請求就200/s。
同樣,給大家來一張架構圖,一起來感受一下:
file
按照上述架構,他的好處是什麼呢?
可能未來你的系統讀請求每秒都幾萬次了,但是可能80%~90%都是通過快取叢集來讀的,而快取叢集裡的機器可能單機每秒都可以支撐幾萬讀請求,所以耗費機器資源很少,可能就兩三臺機器就夠了。
你要是換成是資料庫來試一下,可能就要不停的加從庫到10臺、20臺機器才能抗住每秒幾萬的讀併發,那個成本是極高的。
好了,我們再來簡單小結,承載高併發需要考慮的第三個點:
不要盲目進行資料庫擴容,資料庫伺服器成本昂貴,且本身就不是用來承載高併發的
針對寫少讀多的請求,引入快取叢集,用快取叢集抗住大量的讀請求
(6)引入訊息中介軟體叢集
接著再來看看資料庫寫這塊的壓力,其實是跟讀類似的。
假如說你所有寫請求全部都落地資料庫的主庫層,當然是沒問題的,但是寫壓力要是越來越大了呢?
比如每秒要寫幾萬條資料,此時難道也是不停的給主庫加機器嗎?
可以當然也可以,但是同理,你耗費的機器資源是很大的,這個就是資料庫系統的特點所決定的。
相同的資源下,資料庫系統太重太複雜,所以併發承載能力就在幾千/s的量級,所以此時你需要引入別的一些技術。
比如說訊息中介軟體技術,也就是MQ叢集,他是非常好的做寫請求非同步化處理,實現削峰填谷的效果。
假如說,你現在每秒是1000/s次寫請求,其中比如500次請求是必須請求過來立馬寫入資料庫中的,但是另外500次寫請求是可以允許非同步化等待個幾十秒,甚至幾分鐘後才落入資料庫內的。
那麼此時你完全可以引入訊息中介軟體叢集,把允許非同步化的每秒500次請求寫入MQ,然後基於MQ做一個削峰填谷。比如就以平穩的100/s的速度消費出來然後落入資料庫中即可,此時就會大幅度降低資料庫的寫入壓力。
ps:關於MQ削峰填谷的概念,在公眾號之前講訊息中介軟體的文章中已詳細闡述,如果大夥兒忘記了,可以回顧一下。
此時,架構圖變成了下面這樣:
file
大家看上面的架構圖,首先訊息中介軟體系統本身也是為高併發而生,所以通常單機都是支撐幾萬甚至十萬級的併發請求的。
所以,他本身也跟快取系統一樣,可以用很少的資源支撐很高的併發請求,用他來支撐部分允許非同步化的高併發寫入是沒問題的,比使用資料庫直接支撐那部分高併發請求要減少很多的機器使用量。
而且經過訊息中介軟體的削峰填谷之後,比如就用穩定的100/s的速度寫資料庫,那麼資料庫層面接收的寫請求壓力,不就成了500/s + 100/s = 600/s了麼?
大家看看,是不是發現減輕了資料庫的壓力?
到目前為止,通過下面的手段,我們已經可以讓系統架構儘可能用最小的機器資源抗住了最大的請求壓力,減輕了資料庫的負擔。
系統叢集化
資料庫層面的分庫分表+讀寫分離
針對讀多寫少的請求,引入快取叢集
針對高寫入的壓力,引入訊息中介軟體叢集,
初步來說,簡單的一個高併發系統的闡述是說完了。
但是,其實故事到這裡還遠遠沒有結束。
(7)現在能hold住高併發面試題了嗎?
看完了這篇文章,你覺得自己能回答好面試裡的高併發問題了嗎?
很遺憾,答案是不能。而且我覺得單單憑藉幾篇文章是絕對不可能真的讓你完全回答好這個問題的,這裡有很多原因在裡面。
首先,高併發這個話題本身是非常複雜的,遠遠不是一些文章可以說的清楚的,他的本質就在於,真實的支撐複雜業務場景的高併發系統架構其實是非常複雜的。
比如說每秒百萬併發的中介軟體系統、每日百億請求的閘道器係統、瞬時每秒幾十萬請求的秒殺大促系統、支撐幾億使用者的大規模高併發電商平臺架構,等等。
為了支撐高併發請求,在系統架構的設計時,會結合具體的業務場景和特點,設計出各種複雜的架構,這需要大量底層技術支撐,需要精妙的架構和機制設計的能力。
最終,各種複雜系統呈現出來的架構複雜度會遠遠超出大部分沒接觸過的同學的想象。
如果大家想要看一下有一定發覆雜度的系統的架構設計和演進過程,可以看一下之前寫的一個系列專欄《億級流量系統架構演進》。
但是那麼複雜的系統架構,通過一些文章是很難說的清楚裡面的各種細節以及落地生產的過程的。
其次,高併發這話題本身包含的內容也遠遠不止本文說的這麼幾個topic:分庫分表、快取、訊息。
一個完整而複雜的高併發系統架構中,一定會包含各種複雜的自研基礎架構系統、各種精妙的架構設計(比如熱點快取架構設計、多優先順序高吞吐MQ架構設計、系統全鏈路併發效能優化設計,等等)、還有各種複雜系統組合而成的高併發架構整體技術方案、還有NoSQL(Elasticsearch等)/負載均衡/Web伺服器等相關技術。
所以大家切記要對技術保持敬畏之心,這些東西都很難通過一些文章來表述清楚。
最後,真正在生產落地的時候,高併發場景下你的系統會出現大量的技術問題。
比如說訊息中介軟體吞吐量上不去需要優化、磁碟寫壓力過大效能太差、記憶體消耗過大容易撐爆、分庫分表中介軟體不知道為什麼丟了資料,等等吧。
諸如此類的問題非常多,這些也不可能通過文章給全部說清楚。
(8)本文能帶給你什麼啟發?
其實本文的定位,就是對高併發這個面試topic做一個掃盲,因為我發現大部分來問我這個問題的同學,連本文闡述的最最基本的高併發架構演進思路可能都沒理解。
當然,也是因為畢竟沒真的做過高併發系統,沒相關經驗,確實很難理解好這個問題。
所以本文就是讓很多沒接觸過的同學有一個初步的感知,這個高併發到底是怎麼回事兒,到底對系統哪裡有壓力,要在系統架構裡引入什麼東西,才可以比較好的支撐住較高的併發壓力。
而且你可以順著本文的思路繼續思考下去,結合你自己熟悉和知道的一些技術繼續思考。
比如說,你熟悉Elasticsearch技術,那麼你就可以思考,唉?在高併發的架構之下,是不是可以通過分散式架構的ES技術支撐高併發的搜尋?
上面所說,權當拋磚引玉。大家自己平時一定要多思考,自己多畫圖,盤點盤點自己手頭系統的請求壓力。計算一下分散到各個中介軟體層面的請求壓力,到底應該如何利用最少的機器資源最好的支撐更高的併發請求。
這才是一個好的高併發架構設計思路。
如果起到這個效果,本文就成功了。剩下的,還是建議各位同學,對高併發這個話題,結合自己手頭負責的系統多做思考。
比如當前業務場景下,你的系統有多大的請求壓力?如果請求壓力增長10倍你的架構如何支撐?如果請求壓力增長100倍,你的架構如何支撐?如果請求壓力增長1000倍,你的架構如何支撐?
平時一定多給自己設定一些技術挑戰,敦促自己去思考自己的系統,最好多做寫架構上的演練、落地和實踐,自己實際操作一下,才有更好的感知。
然後在面試的時候,起碼自己做過一定深度的思考,結合自己負責的系統做過一些實踐,可以跟面試官有一個較為清晰和系統的闡述。
雖然大部分同學可能沒機會經歷那種真正大規模超高併發的系統架構的設計,但是本文如果能讓大家平時對自己的專案多一些思考。在面試的時候,有一些系統性的思路和闡述,那麼也就達到本文的目的了。
END

作者:石杉的架構筆記
連結:https://juejin.im/post/5c45aaee6fb9a049e6609115
來源:掘金
著作權歸作者所有。商業轉載請聯絡作者獲得授權,非商業轉載請註明出處。

相關文章