天天看點

高并發,我把握不住啊!什麼是高并發高并發目标高并發架構演進高并發架構實作高并發架構要點

慎入,作者高并發搞得少(沒搞過),這裡面水太深,什麼高并發,大流量的東西都是虛拟的,作者還太年輕,沒有那個經曆,把握不住。系統隻有幾QPS,開心快樂就行,不PK,文明PK。

高并發,我把握不住啊!什麼是高并發高并發目标高并發架構演進高并發架構實作高并發架構要點
我關注的大佬更新了,在幹貨文章的下面有這麼一小條:
高并發,我把握不住啊!什麼是高并發高并發目标高并發架構演進高并發架構實作高并發架構要點

我承認我有賭的成分,點進去一看,果然是廣告。說真的,内容看起來還是很有吸引力的,但是貧窮阻止了我消費的沖動。

作為一個高并發的門外漢,嘗試結合學過的課程和一些網上的資料來整理一下對于高并發的認識。——實戰是不可能實戰的,隻能動動嘴皮這樣子。

什麼是高并發

高并發

指的是系統同時處理很多請求。

高并發

是一個結果導向的東西,例如,常見的高并發場景有:淘寶的雙11、春運時的搶票、微網誌大V的熱點新聞等,這些典型場景并不是陡然出世,而是随着業務發展的發展而逐漸出現。像2020年淘寶雙11全球狂歡季,訂單建立峰值達到了驚人的58.3萬筆/秒,4年前的2016年,這個數字大概是四分之一,再往前四年,這個資料不可考,但是肯定就沒這麼誇張了。

高并發

的業務場景出現了,随之而來的就是要支援這個

高并發

業務場景的架構——技術要為業務服務,業務倒逼技術發展。

高并發

的架構也不是某個天才冥思苦想或者靈機一動,這個過程是随着業務的發展而演進。用一個比喻,先有了秋名山,才到了老司機。

高并發,我把握不住啊!什麼是高并發高并發目标高并發架構演進高并發架構實作高并發架構要點

那到底多大并發才算高并發呢?

這個本身是沒有具體标準的事情,隻看資料是不行的,要結合具體的場景。不能說10W QPS的秒殺是高并發,而1W QPS的資訊流就不是高并發。資訊流場景涉及複雜的推薦模型和各種人工政策,它的業務邏輯可能比秒殺場景複雜10倍不止。業務場景不一樣,執行複雜度不一樣,單看并發量也沒有意義。

總結就是,高并發無定勢,是要和具體的業務場景相結合的。無高并發場景,無高并發架構。

高并發目标

宏觀目标

高并發絕不意味着隻追求高性能。從宏觀角度看,高并發系統設計的目标有三個:高性能、高可用,以及高可擴充。就是所謂的“三高”,三高不是孤立的,而是互相支撐的。

1、高性能:性能展現了系統的并行處理能力,在有限的硬體投入下,提高性能意味着節省成本。同時,性能也反映了使用者體驗,響應時間分别是100毫秒和1秒,給使用者的感受是完全不同的。

2、高可用:表示系統可以正常服務的時間。一個全年不停機、無故障;另一個隔三差五出線上事故、當機,使用者肯定選擇前者。另外,如果系統隻能做到90%可用,也會大大拖累業務。

3、高擴充:表示系統的擴充能力,流量高峰時能否在短時間内完成擴容,更平穩地承接峰值流量,比如雙11活動、明星離婚等熱點事件。

高并發,我把握不住啊!什麼是高并發高并發目标高并發架構演進高并發架構實作高并發架構要點

這3個目标是需要通盤考慮的,因為它們互相關聯、甚至也會互相影響。

比如說:考慮系統的擴充能力,你需要将服務設計成無狀态的,這種叢集設計保證了高擴充性,其實也間接提升了系統的性能和可用性。

再比如說:為了保證可用性,通常會對服務接口進行逾時設定,以防大量線程阻塞在慢請求上造成系統雪崩,那逾時時間設定成多少合理呢?一般,我們會參考依賴服務的性能表現進行設定。

具體目标

性能名額

性能名額通過性能名額可以度量目前存在的性能問題,也是高并發主要關注的名額,性能和流量方面常用的一些名額有

  1. QPS/TPS/HPS:QPS是每秒查詢數,TPS是每秒事務數,HPS是每秒HTTP請求數。最常用的名額是QPS。

需要注意的是,并發數和QPS是不同的概念,并發數是指系統同時能處理的請求數量,反應了系統的負載能力。

并發數 = QPS✖平均響應時間

  1. 響應時間:從請求發出到收到響應花費的時間,例如一個系統處理一個HTTP請求需要100ms,這個100ms就是系統的響應時間。
  2. 平均響應時間:最常用,但是缺陷很明顯,對于慢請求不敏感。比如 1 萬次請求,其中 9900 次是 1ms,100 次是 100ms,則平均響應時間為 1.99ms,雖然平均耗時僅增加了 0.99ms,但是 1%請求的響應時間已經增加了 100 倍。
  3. TP90、TP99 等分位值:将響應時間按照從小到大排序,TP90 表示排在第 90 分位的響應時間, 分位值越大,對慢請求越敏感。
高并發,我把握不住啊!什麼是高并發高并發目标高并發架構演進高并發架構實作高并發架構要點
  1. RPS(吞吐量):機關時間内處理的請求量,通常由QPS和并發數決定。

    通常,設定性能目标時會兼顧吞吐量和響應時間,比如這樣表述:在每秒 1 萬次請求下,AVG 控制在 50ms 以下,TP99 控制在 100ms 以下。對于高并發系統,AVG 和 TP 分位值必須同時要考慮。

    另外,從使用者體驗角度來看,200 毫秒被認為是第一個分界點,使用者感覺不到延遲,1 秒是第二個分界點,使用者能感受到延遲,但是可以接受。

    是以,對于一個健康的高并發系統,TP99 應該控制在 200 毫秒以内,TP999 或者 TP9999 應該控制在 1 秒以内。

  2. PV:綜合浏覽量,即頁面浏覽量或者點選量,一個訪客在24小時内通路的頁面數量。
  3. UV:獨立訪客 ,即一定時間範圍内相同訪客多次通路網站,隻計算為一個獨立的訪客。
  4. 帶寬: 計算帶寬大小需要關注兩個名額,峰值流量和頁面的平均大小。

    日網站帶寬可以使用下面的公式來粗略計算:

    日網站帶寬=pv/統計時間(換算到秒)*平均頁面大小(機關kB)*8

峰值一般是平均值的倍數;

QPS不等于并發連接配接數,QPS是每秒HTTP請求數量,并發連接配接數是系統同時處理的請求數量:

峰值每秒請求數(QPS) = (總PV數 * 80%) /(6小時秒數 * 20%)

可用性名額

高可用性是指系統具有較高的無故障運作能力,可用性 = 平均故障時間 / 系統總運作時間,一般使用幾個 9 來描述系統的可用性。

高并發,我把握不住啊!什麼是高并發高并發目标高并發架構演進高并發架構實作高并發架構要點

對于大多數系統。2個9是基本可用(如果達不到開發和運維可能就要被祭天了),3個9是較高可用,4個9是具有自動恢複能力的高可用。要想達到3個9和4個9很困難,可用性影響因素非常多,很難控制,需要過硬的技術、大量的裝置資金投入,工程師要具備責任心,甚至還要點運氣。

可擴充性名額

面對突發流量,不可能臨時改造架構,最快的方式就是增加機器來線性提高系統的處理能力。

對于業務叢集或者基礎元件來說,擴充性 = 性能提升比例 / 機器增加比例,理想的擴充能力是:資源增加幾倍,性能提升幾倍。通常來說,擴充能力要維持在 70%以上。

但是從高并發系統的整體架構角度來看,擴充的目标不僅僅是把服務設計成無狀态就行了,因為當流量增加 10 倍,業務服務可以快速擴容 10 倍,但是資料庫可能就成為了新的瓶頸。

像 MySQL 這種有狀态的存儲服務通常是擴充的技術難點,如果架構上沒提前做好規劃(垂直和水準拆分),就會涉及到大量資料的遷移。

我們需要站在整體架構的角度,而不僅僅是業務伺服器的角度來考慮系統的擴充性 。是以說,資料庫、緩存、依賴的第三方、負載均衡、交換機帶寬等等都是系統擴充時需要考慮的因素。我們要知 道系統并發到了某一個量級之後,哪一個因素會成為我們的瓶頸點,進而針對性地進行擴充。

高并發架構演進

誰不是生下來就是老司機,架構也不是架起來就支援高并發。我們來看一個經典的架構演進的例子——淘寶,真實诠釋了“好的架構是進化來的,不是設計來的”。

以下是來自《淘寶技術這十年》描述的淘寶2003—2012年的架構演進。

個人網站

初代淘寶的團隊人員隻有十來個,而且面臨千載難逢的商業機會,是以要求上線的時間越快越好(實際用了不到一個月),那麼淘寶的這些牛人是怎麼做到的呢?

——買一個。

初代淘寶買了這樣一個架構的網站: LAMP(Linux+Apache+MySQL+PHP)。整個系統的架構如下:

高并發,我把握不住啊!什麼是高并發高并發目标高并發架構演進高并發架構實作高并發架構要點

最後開發的網站是這樣的:

高并發,我把握不住啊!什麼是高并發高并發目标高并發架構演進高并發架構實作高并發架構要點

由于商品搜尋比較占用資料庫資源,後來還引入了阿裡巴巴的搜尋引擎iSearch。

Oracle/支付寶/旺旺

淘寶飛速發展,流量和交易量迅速提升,給技術帶來了新的問題——MySQL抗不住了。怎麼辦?要搞點事情嗎?沒有,淘寶買了Oracle資料庫,當然這個也考慮到團隊裡有Oracle大牛的原因。

替換了資料庫之後的架構:

高并發,我把握不住啊!什麼是高并發高并發目标高并發架構演進高并發架構實作高并發架構要點

比較有意思的,當時由于

買不起

商用的連接配接池,是以用了一個開源的連接配接池代理服務SQLRelay,這個代理服務經常會死鎖,怎麼解決呢?人肉運維,工程師24小時待命,出現問題趕緊

重新開機

SQL Relay服務。😂😂

後來為了優化存儲,又買了NAS(Network Attached Storage,網絡附屬存儲),NetApp 的 NAS 存儲作為了資料庫的儲存設備,加上 Oracle RAC(Real Application Clusters,實時應用叢集)來實作負載均衡。

Java 時代 1.0

2004年,淘寶已經運作了一年的時間,上面提到的SQLRelay的問題解決不了,資料庫必須要用Oracle,是以決定更換開發語言。

在不拖慢現有業務發展的情況下,平滑更換整體的架構,對當時的淘寶仍然是個有挑戰性的事情。是以怎麼辦?淘寶的解決方案是請了Sun公司的大佬。

當時,由于struts1.x存在很多問題,是以淘寶自研了一套MVC架構。Sun當時在推EJB,是以這套架構裡也引入了EJB。

高并發,我把握不住啊!什麼是高并發高并發目标高并發架構演進高并發架構實作高并發架構要點

Java 時代 2.0

在之前,淘寶的架構的架構主要思路還是“買”,随着業務的發展,到了2005 年,“買”已經很難解決問題了,需要對整個架構進行調整和優化,需要綜合考慮容量、性能、成本的問題。

在Java時代2.0,主要做了對資料分庫、放棄EJB、引入Spring、加入緩存、加入CDN等。

高并發,我把握不住啊!什麼是高并發高并發目标高并發架構演進高并發架構實作高并發架構要點

Java時代3.0

Java時代3.0的最大特點就是淘寶開始從商用轉為“自研”,開始真正創造自己的核心技術,例如緩存存儲引擎Tair,分布式存儲系統TFS。搜尋引擎iSearch也進行了更新。引入了自研技術的淘寶架構:

高并發,我把握不住啊!什麼是高并發高并發目标高并發架構演進高并發架構實作高并發架構要點

分布式時代1.0

到了2008年的時候,淘寶的業務進一步發展。

整個主站系統的容量已經到了瓶頸,商品數在1億個以上,PV在2.5億個以上,會員數超過了 5000萬個。這時Oracle的連接配接池數量都不夠用了,資料庫的容量到了極限,即使上層系統加機器也無法繼續擴容,我們隻有把底層的基礎服務繼續拆分,從底層開始擴容,上層才能擴充,這才能容納以後三五年的增長。

淘寶開始對業務子產品逐漸拆分和服務化改造。例如拆分出了商品中心、商品中心等等。同時引入了一些自研的中間件,如分布式資料庫中間件,分布式消息中間件等等。

高并發,我把握不住啊!什麼是高并發高并發目标高并發架構演進高并發架構實作高并發架構要點

《淘寶技術這十年》這本書隻描述到了2012年,也就是分布式時代。上圖是根據參考【8】畫的一張圖。

轉眼理2012又快過了十年,這十年,阿裡巴巴逐漸進入極盛時代,技術上也是風起雲湧,才人輩出。粒度更細的微服務、隔離差距的容器化技術、快速伸縮的雲平台技術…… 如果《淘寶技術這十年》的作者能再寫一個十年,一定也是非常精彩。

按照參考【10】,接下來的淘寶服務化開始逐漸演進到雲平台架構,由于資料實在難找,而且這時候以淘寶的體量,内部的架構複雜度足以寫一本書了。是以接下來的架構演進參考

服務端高并發分布式架構演進之路

,是一個牛人以淘寶為模拟對象進行的架構演進,雖然不是淘寶真正的架構技術演進,但也很值得借鑒。

在這裡我們略過了微服務架構——分布式時代2.0,微服務本身是更細粒度、更輕量級的服務化,這裡插入一個關于微服務很有意思的說法——馬丁老哥老被人說設計的東西不符合面向服務的概念,于是他就自己發明創造了一個靈活的微服務理論,以後再有人說:馬老師,你又不遵循微服務架構設計的原則了。嗯,你說哪一點不符合,我立馬去改微服務的理論。

容器化時代

前最流行的容器化技術是Docker,最流行的容器管理服務是Kubernetes(K8S),應用/服務可以打包為Docker鏡像,通過K8S來動态分發和部署鏡像。Docker鏡像可了解為一個能運作你的應用/服務的最小的作業系統,裡面放着應用/服務的運作代碼,運作環境根據實際的需要設定好。把整個“作業系統”打包為一個鏡像後,就可以分發到需要部署相關服務的機器上,直接啟動Docker鏡像就可以把服務起起來,使服務的部署和運維變得簡單。

在大促的之前,可以在現有的機器叢集上劃分出伺服器來啟動Docker鏡像,增強服務的性能,大促過後就可以關閉鏡像,對機器上的其他服務不造成影響。

高并發,我把握不住啊!什麼是高并發高并發目标高并發架構演進高并發架構實作高并發架構要點

雲平台時代

在服務化的時候,淘寶已經演進到了雲平台架構。

所謂的雲平台,就是把海量機器資源,通過統一的資源管理,抽象為一個資源整體,在之上可按需動态申請硬體資源(如CPU、記憶體、網絡等),并且之上提供通用的作業系統,提供常用的技術元件(如Hadoop技術棧,MPP資料庫等)供使用者使用,甚至提供開發好的應用,使用者不需要關系應用内部使用了什麼技術,就能夠解決需求(如音視訊轉碼服務、郵件服務、個人部落格等)。

高并發,我把握不住啊!什麼是高并發高并發目标高并發架構演進高并發架構實作高并發架構要點

簡單總結一下:高并發的架構某種程度上是逼出來的,一般人誰能想到淘寶當年抛棄php是因為解決不了資料庫連接配接池的問題。架構演進就像是西湖的水——西湖的水,工程師的淚,說起來容易,裡面究竟滅了多少火,填了多少坑。我們外人看到的平湖秋波,裡面水很深🐶。

高并發架構實作

想讓系統抗住更多的并發,主要就是兩個方向:

  • 縱向擴充:

    1、提升單機的硬體性能:通過增加記憶體、 CPU核數、存儲容量、或者将磁盤 更新成SSD等堆硬體的方式來提升

    2、提升單機的軟體性能:使用緩存減少IO次數,使用并發或者異步的方式增加吞吐量。

  • 橫向擴充:單機性能總會存在極限,是以最終還需要引入橫向擴充,通過叢集部署以進一步提高并發處理能力。

    1、做好分層架構:這是橫向擴充的前提,因為高并發系統往往業務複雜,通過分層處理可以簡化複雜問題,更容易做到橫向擴充。

    2、各層進行水準擴充:無狀态水準擴容,有狀态做分片路由。業務叢集通常能設計成無狀态的,而資料庫和緩存往往是有狀态的,是以需要設計分區鍵做好存儲分片,當然也可以通過主從同步、讀寫分離的方案提升讀性能。

用一個比喻,你要去打十個大漢,你大概是打不過的,最好的結果就是他們打不倒你——吊起來打。是以這時候就得想辦法了。第一個辦法就是努力鍛煉,然後全副武裝,也許還有點希望,這就是縱向擴充;第二個辦法,不行,你一看對面人多,你就叫了十九個兄弟,然後你們二十個打他們十個,唉,這下看上去能打的過了,這就是橫向擴充;還有第三個不常用的辦法,你找個門把住,每次就放一個大漢進來,打倒一個再放下一個,這個就是削峰限流的做法。

高并發,我把握不住啊!什麼是高并發高并發目标高并發架構演進高并發架構實作高并發架構要點

我們看一下一個大概的支援三高的典型架構:

高并發,我把握不住啊!什麼是高并發高并發目标高并發架構演進高并發架構實作高并發架構要點

接下來,我們從上往下,看一下,各層的一些關鍵技術。

網絡層

多機器

堆機器不是萬能的,不堆機器是萬萬不能的。

我們努力地更新改造架構,最後讓我們提供的服務能夠快速橫向擴充。橫向擴充的基礎同樣是要有一定數量的、一定性能的機器。

還是上面哪個比喻,你要打十個大漢,等你努力練成了葉師傅,你突然發現對面的孩子都長大了,人數×2,這時候你還是得叫兄弟。

一般狗大戶大廠在全國各地都有機房,可能光北京就有兩個,把不同地方的請求分到不同的機房,再分到不同的叢集,再分到不同的機器,這麼一勻,就在服務能扛的範疇之内了。我們大概來看一下,怎麼估算所需機器的數量。

  • 通過QPS和PV計算部署伺服器的台數

單台伺服器每天PV計算:

公式1:每天總PV = QPS * 3600 * 6

公式2:每天總PV = QPS * 3600 * 8

伺服器計算:

伺服器數量 = ceil( 每天總PV / 單台伺服器每天總PV )

  • 峰值QPS和機器計算公式

原理:每天80%的通路集中在20%的時間裡,這20%時間叫做峰值時間

公式:( 總PV數 * 80% ) / ( 每天秒數 * 20% ) = 峰值時間每秒請求數(QPS)

機器:峰值時間每秒QPS / 單台機器的QPS = 需要的機器。

一般有大流量業務的公司都實作了多機房,包括同城多機房、跨城多機房、跨國多機房等。為了保證可用性,财大氣粗的公司會預備大量的備援,一般會保證機器數是計算峰值所需機器數的兩倍。需要節約成本的,也可以考慮目前流行的雲平台,之前熱點事件的時候,微網誌就從阿裡雲租了不少雲伺服器。

DNS

高并發,我把握不住啊!什麼是高并發高并發目标高并發架構演進高并發架構實作高并發架構要點

DNS是請求分發的第一個關口,實作的是地理級别的均衡。dns-server對一個域名配置了多個解析ip,每次DNS解析請求來通路dns-server。通常會傳回離使用者距離比較近的ip,使用者再去通路ip。例如,北京的使用者通路北京的機房,南京的使用者通路南京的資源。

一般不會使用DNS來做機器級别的負載均衡,因為造不起,IP資源實在太寶貴了,例如百度搜尋可能需要數萬台機器,不可能給每個機器都配置公網IP。一般隻會有有限的公網IP的節點,然後再在這些節點上做機器級别的負載均衡,這樣各個機房的機器隻需要配置區域網路IP就行了。

DNS負載均衡的優點是通用(全球通用)、成本低(申請域名,注冊DNS即可)。

缺點也比較明顯,主要展現在:

  • DNS 緩存的時間比較長,即使将某台業務機器從 DNS 伺服器上删除,由于緩存的原因,還是有很多使用者會繼續通路已經被删除的機器。
  • DNS 不夠靈活。DNS 不能感覺後端伺服器的狀态,隻能根據配置政策進行負載均衡,無法做到更加靈活的負載均衡政策。比如說某台機器的配置比其他機器要好很多,理論上來說應該多配置設定一些請求給它,但 DNS 無法做到這一點。

是以對于時延和故障敏感的業務,有實力的公司可能會嘗試實作HTTP-DNS的功能,即使用HTTP 協定實作一個私有的 DNS 系統。HTTP-DNS 主要應用在通過 App 提供服務的業務上,因為在 App 端可以實作靈活的伺服器通路政策,如果是 Web 業務,實作起來就比較麻煩一些,因為 URL 的解析是由浏覽器來完成的,隻有 Javascript 的通路可以像 App 那樣實作比較靈活的控制。

CDN

CDN是為了解決使用者網絡通路時的“最後一公裡”效應,本質是一種“以空間換時間”的加速政策,即将内容緩存在離使用者最近的地方,使用者通路的是緩存的内容,而不是站點實時通路的内容。

由于CDN部署在網絡營運商的機房,這些營運商又是終端使用者的網絡提供商,是以使用者請求路由的第一跳就到達了CDN伺服器,當CDN中存在浏覽器請求的資源時,從CDN直接傳回給浏覽器,最短路徑傳回響應,加快使用者通路速度。

下面是簡單的CDN請求流程示意圖:

高并發,我把握不住啊!什麼是高并發高并發目标高并發架構演進高并發架構實作高并發架構要點

CDN能夠緩存的一般是靜态資源,如圖檔、檔案、CSS、Script腳本、靜态網頁等,但是這些檔案通路頻度很高,将其緩存在CDN可極大改善網頁的打開速度。

反向代理層

我們把這一層叫反向代理層,也可以叫接入層、或者負載層。這一層是流量的入口,是系統抗并發很關鍵的一層。

還是那個比喻,還是你打十個大漢,這次你叫了十九個兄弟,理想的情況是你們兩個打對面一個,但是你由于太激動,沖在了最前面,結果瞬間被十個大漢暴打……

反向代理會對流量進行分發,保證最終落到每個服務上的流量是服務能扛的範圍之内。

Nginx、LVS、F5

DNS 用于實作地理級别的負載均衡,而 Nginx、 LVS、 F5 用于同一地點内機器級别的負載均衡。其中 Nginx 是軟體的 7 層負載均衡,LVS 是核心的 4 層負載均衡,F5 是硬體的 4 層負載均衡。

軟體和硬體的差別就在于性能,硬體遠遠高于軟體,Ngxin 的性能是萬級,一般的 Linux 伺服器上裝個 Nginx 大概能到 5 萬 / 秒;LVS 的性能是十萬級,據說可達到 80萬 / 秒;F5 性能是百萬級,從 200 萬 / 秒到 800 萬 / 秒都有。

硬體雖然性能高,但是單台硬體的成本也很高,一台最便宜的 F5 都是幾十萬,但是如果按照同等請求量級來計算成本的話,實際上硬體負載均衡裝置可能會更便宜,例如假設每秒處理 100 萬請求,用一台 F5 就夠了,但用 Nginx, 可能要 20 台,這樣折算下來用 F5 的成本反而低。是以通常情況下,如果性能要求不高,可以用軟體負載均衡;如果性能要求很髙,推薦用硬體負載均衡。

4 層和 7 層的差別就在于協定和靈活性。Nginx 支援 HTTP、 E-mail 協定,而 LVS 和 F5 是 4層負載均衡,和協定無關,幾乎所有應用都可以做,例如聊天、資料庫等。目前很多雲服務商都已經提供了負載均衡的産品,例如阿裡雲的 SLB、UCIoud 的 ULB 等,中小公司直接購買即可。

對于開發而言,一般隻需要關注到Nginx這一層面就行了。

高并發,我把握不住啊!什麼是高并發高并發目标高并發架構演進高并發架構實作高并發架構要點

負載均衡典型架構

像上面提到的負載均衡機制,在使用中,可以組合使用。

DNS負載均衡用于實作地理級别的負載均衡,硬體件負載均衡用于實作叢集級别的負載均衡;軟體負載均衡用于實作機器級别的負載均衡。

整個系統的負載均衡分為三層。

  • 地理級别負載均衡:www.xxx.com 部署在北京、廣州、上海三個機房,當使用者通路時,DNS 會根據使用者的地理位置來決定傳回哪個機房的 IP,圖中傳回了廣州機房的 IP 位址,這樣使用者就通路到廣州機房了。
  • 叢集級别負載均衡:廣州機房的負載均衡用的是 F5 裝置,F5 收到使用者請求後,進行叢集級别的負載均衡,将使用者請求發給 3 個本地叢集中的一個,我們假設 F5 将使用者請求發給了 “廣州叢集 2” 。
  • 機器級别的負載均衡:廣州叢集 2 的負載均衡用的是 Nginx, Nginx 收到使用者請求後,将使用者請求發送給叢集裡面的某台伺服器,伺服器處理使用者的業務請求并傳回業務響應。

Nginx負載均衡

我們主要關心是Nginx這一層的負載,通常LVS 和 F5這兩層都是由網絡運維工程師管控。

高并發,我把握不住啊!什麼是高并發高并發目标高并發架構演進高并發架構實作高并發架構要點

對于負載均衡我們主要關心的幾個方面如下:

  • 上遊伺服器配置:使用 upstream server配置上遊伺服器
  • 負載均衡算法:配置多個上遊伺服器時的負載均衡機制。
  • 失敗重試機制:配置當逾時或上遊伺服器不存活時,是否需要重試其他上遊伺服器。
  • 伺服器心跳檢查:上遊伺服器的健康檢查/心跳檢查。
upstream server中文直接翻譯是上遊伺服器,意思就是負載均衡伺服器設定,就是被nginx代理最後真實通路的伺服器。

負載均衡算法

負載均衡算法數量較多,Nginx主要支援以下幾種負載均衡算法:

1、輪詢(預設)

每個請求按時間順序逐一配置設定到不同的後端服務,如果後端某台伺服器當機,自動剔除故障系統,使使用者通路不受影響。

2、weight(輪詢權值)

weight的值越大配置設定到的通路機率越高,主要用于後端每台伺服器性能不均衡的情況下。或者僅僅為在主從的情況下設定不同的權值,達到合理有效的地利用主機資源。

3、ip_hash

每個請求按通路IP的哈希結果配置設定,使來自同一個IP的訪客固定通路一台後端伺服器,并且可以有效解決動态網頁存在的session共享問題。

4、fair

比 weight、ip_hash更加智能的負載均衡算法,fair算法可以根據頁面大小和加載時間長短智能地進行負載均衡,也就是根據後端伺服器的響應時間 來配置設定請求,響應時間短的優先配置設定。Nginx本身不支援fair,如果需要這種排程算法,則必須安裝upstream_fair子產品。

5、url_hash

按通路的URL的哈希結果來配置設定請求,使每個URL定向到一台後端伺服器,可以進一步提高後端緩存伺服器的效率。Nginx本身不支援url_hash,如果需要這種排程算法,則必須安裝Nginx的hash軟體包。

失敗重試

Nginx關于失敗重試主要有兩部配置設定置,upstream server 和 proxy_pass。

通過配置上遊伺服器的 max_fails和 fail_timeout,來指定每個上遊伺服器,當fail_timeout時間内失敗了max_fail次請求,則認為該上遊伺服器不可用/不存活,然後将會摘掉該上遊伺服器,fail_timeout時間後會再次将該伺服器加入到存活上遊伺服器清單進行重試。

健康檢查

Nginx 對上遊伺服器的健康檢查預設采用的是惰性政策,Nginx 商業版提供了healthcheck 進 行 主 動 健 康 檢 查 。當 然 也 可 以 集 成 nginx_upstream_check_module(

https://github.com/yaoweibin/nginx_upstream_check

module ) 子產品來進行主動健康檢查。

nginx_upstream_check_module 支援 TCP 心跳和 HTTP 心跳來實作健康檢查。

流量控制

流量分發

流量分發就不多說了,上面已經講了,是接入層的基本功能。

流量切換

我聽朋友說過一個有意思的事情,他們公司将流量從一個機房切到另一個機房,結果翻車,所有工程師運維平台一片飄紅,全公司集體圍觀,運維團隊就很丢面子。

高并發,我把握不住啊!什麼是高并發高并發目标高并發架構演進高并發架構實作高并發架構要點

流量切換就是在某些情況下,比如機房故障、光纖被挖斷、伺服器故障故障情況,或者灰階釋出、A/B等運維測試場景,需要将流量切到不同的機房、伺服器等等。

就像我們上面提到的負載均衡典型架構,不同層級的負載負責切換不同層級的流量。

  1. DNS:切換機房入口。
  2. HttpDNS:主要 APP 場景下,在用戶端配置設定好流量入口,繞過營運商 LocalDNS并實作更精準流量排程。
  3. LVS/HaProxy:切換故障的 Nginx 接入層。
  4. Nginx:切換故障的應用層。

另外,有些應用為了更友善切換,還可以在 Nginx 接入層做切換,通過 Nginx 進行一些流量切換,而沒有通過如 LVS/HaProxy 做切換。

限流

限流是保證系統可用的一個重要手段,防止超負荷的流量直接打在服務上,限流算法主要有令牌桶、漏桶。

高并發,我把握不住啊!什麼是高并發高并發目标高并發架構演進高并發架構實作高并發架構要點

可以在很多層面做限流,例如服務層網關限流、消息隊列限流、Redis限流,這些主要是業務上的限流。

這裡我們主要讨論的是接入層的限流,直接在流量入口上限流。

對于 Nginx接入層限流可以使用 Nginx自帶的兩個子產品:連接配接數限流子產品

ngx_http_limit_conn_module

和漏桶算法實作的請求限流子產品

ngx_http_limit_req_moduleo

還可以使用 OpenResty提供的 Lua限流子產品 ua-resty**-**limit-traffic應對更複雜的限流場景。

limmit_conn用來對某個 key 對應的總的網絡連接配接數進行限流,可以按照如 IP、域名次元進行限流。limit_req用來對某個 key對應的請求的平均速率進行限流,有兩種用法:平滑模式(delay ) 和允許突發模式(nodelay )。

流量過濾

很多時候,一個網站有很多流量是爬蟲流量,或者直接是惡意的流量。

可以在接入層,對請求的參數進行校驗,如果參數校驗不合法,則直接拒絕請求,或者把請求打到專門用來處理非法請求的服務。

最簡單的是使用Nginx,實際場景可能會使用OpenResty,對爬蟲 user-agent 過濾和一些惡意IP (通過統計 IP 通路量來配置門檻值),将它們分流到固定分組,這種情況會存在一定程度的誤殺,因為公司的公網 IP —般情況下是同一個,大家使用同一個公網出口 IP 通路網站,是以,可以考慮 IP+Cookie 的方式,在使用者浏覽器種植辨別使用者身份的唯一 Cookie。通路服務前先種植 Cookie, 通路服務時驗證該 Cookie, 如果沒有或者不正确,則可以考慮分流到固定分組,或者提示輸入驗證碼後通路。

高并發,我把握不住啊!什麼是高并發高并發目标高并發架構演進高并發架構實作高并發架構要點

降級

降級也是保證高可用的一把利劍,降級的思路是“棄車保帥”,在眼看着不能保證全局可用的情況下,抛棄或者限制一些不重要的服務。

降級一般分為多個層級,例如在應用層進行降級,通過配置中心設定降級的門檻值,一旦達到門檻值,根據不同的降級政策進行降級。

也可以把降級開關前置到接入層,在接入層配置功能降級開發,然後根據情況行自動/人工降級。後端應用服務出問題時,通過接入層降級,可以避免無謂的流量再打到後端服務,進而給應用服務有足夠的時間恢複服務。

Web層

經過一系列的負載均衡,使用者終于請求到了web層的服務。web服務開發完成,經過部署,運作在web伺服器中給使用者提供服務。

叢集

一般會根據業務子產品,來劃分不同的服務,一個服務部署多個執行個體組成叢集。

高并發,我把握不住啊!什麼是高并發高并發目标高并發架構演進高并發架構實作高并發架構要點

為了隔離故障,可以再将叢集進行分組,這樣一個分組出現問題,也不會影響其它分組。像比較常問的秒殺,通常會将秒殺的服務叢集和普通的服務叢集進行隔離。

能做到叢集化部署的三個要點是無狀态、拆分、服務化。

  • 無狀态:設計的應用是無狀态的,那麼應用比較容易進行水準擴充。
  • 拆分:設計初期可以不用拆分,但是後期通路量大的時候,就可以考慮按功能拆分系統。拆分的次元也比較靈活,根據實際情況來選擇,例如根據系統次元、功能次元、讀寫次元、AOP 次元、子產品次元等等。
  • 服務化:拆分更多的是設計,服務化是落地,服務化一般都得服務治理的問題。除了最基本的遠端調用,還得考慮負載均衡、服務發現、服務隔離、服務限流、服務通路黑白名單等。甚至還有細節需要考慮,如逾時時間、重試機制、服務路由、故障補償等。

Web伺服器

獨立開發一個成熟的 Web 伺服器,成本非常高,況且業界又有那麼多成熟的開源 Web 伺服器,是以網際網路行業基本上都是 “拿來主義” ,挑選一個流行的開源伺服器即可。大一點的公司,可能會在開源伺服器的基礎上,結合自己的業務特點做二次開發,例如淘寶的 Tengine,但一般公司基本上隻需要将開源伺服器摸透,優化一下參數,調整一下配置就差不多了。

伺服器的選擇主要和開發語言相關,例如,Java 的有 Tomcat、JBoss、Resin 等,PHP/Python 的用 Nginx。

Web伺服器的性能之類的一般不會成為瓶頸,例如Java最流行的Web伺服器Tomcat預設配置的最大請求數是 150,但是沒有關系,叢集部署就行了。

容器

容器是最近幾年才開始火起來的,其中以 Docker 為代表,在 BAT 級别的公司已經有較多的應用。

容器化可以說給運維帶來了革命性的變化。Docker 啟動快,幾乎不占資源,随時啟動和停止,基于Docker 打造自動化運維、智能化運維逐漸成為主流方式。

容器化技術也天生适合目前流行的微服務,容器将微服務程序和應用程式隔離到更小的執行個體裡,使用更少的資源,更快捷地部署。結合容器編排技術,可以更友善快速地搭建服務高可用叢集。

高并發,我把握不住啊!什麼是高并發高并發目标高并發架構演進高并發架構實作高并發架構要點

服務層

開發架構

一般,網際網路公司都會指定一個大的技術方向,然後使用統一的開發架構。例如,Java 相關的開發架構 SSH、SpringBoot, Ruby 的 Ruby on Rails, PHP 的 ThinkPHP, Python 的Django 等。

架構的選擇,有一個總的原則:優選成熟的架構,避免盲目追逐新技術!

對于一般的螺絲工而言,所做的主要工作都是在這個開發架構之下。對于開發語言和架構的使用,一定要充分了解和利用語言和架構的特性。

以Java為例,在作者的開發中,涉及到一個加密解密的服務調用,服務提供方利用了JNI的技術——簡單說就是C語言編寫代碼,提供api供Java調用,彌補了Java相對沒那麼底層的劣勢,大大提高了運算的速度。

在服務開發這個日常工作的層面,可以做到這些事情來提高性能:

  • 并發處理,通過多線程将串行邏輯并行化。
  • 減少IO次數,比如資料庫和緩存的批量讀寫、RPC的批量接口支援、或者通過備援資料的方式幹掉RPC調用。
  • 減少IO時的資料包大小,包括采用輕量級的通信協定、合适的資料結構、去掉接口中的多餘字段、減少緩存key的大小、壓縮緩存value等。
  • 程式邏輯優化,比如将大機率阻斷執行流程的判斷邏輯前置、For循環的計算邏輯優化,或者采用更高效的算法
  • 各種池化技術的使用和池大小的設定,包括HTTP請求池、線程池(考慮CPU密集型還是IO密集型設定核心參數)、資料庫和Redis連接配接池等。
  • JVM優化,包括新生代和老年代的大小、GC算法的選擇等,盡可能減少GC頻率和耗時。
  • 鎖選擇,讀多寫少的場景用樂觀鎖,或者考慮通過分段鎖的方式減少鎖沖突。

可以通過這些事情來提高可用性:

  • 設定合适的逾時時間、重試次數及機制,必要時要及時降級,傳回兜底資料等,防止把服務提方供打崩
  • 防重設計:通過防重key、防重表等方式實作防重
  • 幂等設計:在接口層面實作幂等設計

服務中心

當系統數量不多的時候,系統間的調用一般都是直接通過配置檔案記錄在各系統内部的,但當系統數量多了以後,這種方式就存在問題了。

比如說總共有 10 個系統依賴 A 系統的 X 接口,A 系統實作了一個新接口 Y, 能夠更好地提供原有 X 接口的功能,如果要讓已有的 10 個系統都切換到 Y 接口,則這 10 個系統的幾十上百台器的配置都要修改,然後重新開機,可想而知這個效率是很低的。

服務中心的實作主要采用服務名字系統。

  • 服務務名字系統 (Service Name System)

看到這個翻譯,相信你會立刻聯想到 DNS, 即 Domain Name System。沒錯,兩者的性質是基本類似的。

DNS 的作用将域名解析為 IP 位址,主要原因是我們記不住太多的數字 IP, 域名就容易記住。服務名字系統是為了将 Service 名稱解析為 “host + port + 接口名稱” ,但是和 DNS一樣,真正發起請求的還是請求方。

高并發,我把握不住啊!什麼是高并發高并發目标高并發架構演進高并發架構實作高并發架構要點

在微服務的架構下,實作這個功能的稱之為注冊中心,例如在Java語言體系下,開源的注冊中心有Nacos、Ecuraka等。

配置中心

配置中心就是集中管理各個服務的配置。

在服務不多的時候,各個服務各自管理自己的配置,沒有問題,但是當服務成百上千,再各行其政,就是一個比較頭疼的事。

是以将配置中心抽象成公共的元件,集中配置多個系統,操作效率高。

在微服務架構體系下,配置中心的開源方案有SpringCloud的SpringCloud Config、阿裡的Nacos等。

服務架構

服務拆分最直接的影響就是本地調用的服務變成了遠端調用,服務消費者A需要通過注冊中心去查詢服務提供者B的位址,然後發起調用,這個看似簡單的過程就可能會遇到下面幾種情況,比如:

  • 注冊中心當機;
  • 服務提供者B有節點當機;
  • 服務消費者A和注冊中心之間的網絡不通;
  • 服務提供者B和注冊中心之間的網絡不通;
  • 服務消費者A和服務提供者B之間的網絡不通;
  • 服務提供者B有些節點性能變慢;
  • 服務提供者B短時間内出現問題。

怎麼去保證服務消費者成功調用服務生産者?這就是服務治理架構要解決的問題。

在Java語言體系下,目前流行的服務治理架構有SpringCloud和Dubbo。

以SpringCloud為例:

高并發,我把握不住啊!什麼是高并發高并發目标高并發架構演進高并發架構實作高并發架構要點
  • Feign封裝RestTemplate實作http請求方式的遠端調用
  • Feign封裝Ribbon實作用戶端負載均衡
  • Euraka叢集部署實作注冊中心高可用
  • 注冊中心心跳監測,更新服務可用狀态
  • 內建Hystrix實作熔斷機制
  • Zuul作為API 網關 ,提供路由轉發、請求過濾等功能
  • Config實作分布式配置管理
  • Sluth實作調用鍊路跟蹤
  • 內建ELK,通過Kafka隊列将日志異步寫入Elasticsearch,通過Kibana可視化檢視

SpringCloud是一整套完整微服務解決方案,被稱為“SpringCloud 全家桶”。這裡隻是簡單地介紹一下。

Dubbo主要提供了最基礎的RPC功能。

不過SpringCloud的RPC采用了HTTP協定,可能性能會差一些。

利好的是,“SpringCloud2.0”——SpringCloud Alibaba流行了起來,Dubbo也可以完美地融入SpringCloud的生态。

消息隊列

消息隊列在高性能、高擴充、高可用的架構中扮演着很重要的角色。

消息隊列是用來解耦一些不需要同步調用的服務或者訂閱一些自己系統關心的變化。使用消息隊列可以實作服務解耦(一對多消費)、異步處理、流量削峰/緩沖等。

服務解耦

服務解耦可以降低服務間耦合,提高系統系統的擴充性。

例如一個訂單服務,有多個下遊,如果不用消息隊列,那麼訂單服務就要調用多個下遊。如果需求要再加下遊,那麼訂單服務就得添加調用新下流的功能,這就比較煩。

引入消息隊列之後,訂單服務就可以直接把訂單相關消息塞到消息隊列中,下遊系統隻管訂閱就行了。

高并發,我把握不住啊!什麼是高并發高并發目标高并發架構演進高并發架構實作高并發架構要點

異步處理

異步處理可以降低響應時間,提高系統性能。

随着業務的發展項目的請求鍊路越來越長,這樣一來導緻的後果就是響應時間變長,有些操作其實不用同步處理,這時候就可以考慮采用異步的方式了。

高并發,我把握不住啊!什麼是高并發高并發目标高并發架構演進高并發架構實作高并發架構要點

流量削峰/緩沖

流量削峰/緩沖可以提高系統的可用性。

我們前面提到了接入層的限流,在服務層的限流可以通過消息隊列來實作。網關的請求先放入消息隊列中,後端服務盡可能去消息隊列中消費請求。逾時的請求可以直接傳回錯誤,也可以在消息隊列中等待。

高并發,我把握不住啊!什麼是高并發高并發目标高并發架構演進高并發架構實作高并發架構要點

消息隊列系統基本功能的實作比較簡單,但要做到高性能、高可用、消息時序性、消息事務性則比較難。業界已經有很多成熟的開源實作方案,如果要求不高,基本上拿來用即可,例如,RocketMQ、Kafka、ActiveMQ 等。

但如果業務對消息的可靠性、時序、事務性要求較高時,則要深入研究這些開源方案,提前考慮可能會遇到的問題,例如消息重複消費、消息丢失、消息堆積等等。

平台層

當業務規模比較小、系統複雜度不高時,運維、測試、資料分析、管理等支撐功能主要由各系統或者團隊獨立完成。随着業務規模越來越大,系統複雜度越來越高,子系統數量越來越多,如果繼續采取各自為政的方式來實作這些支撐功能,會發現重複工作非常多。是以就會自然地把相關功能抽離出來,作為公共的服務,避免重複造輪子,減少不規範帶來的溝通和協作成本。

平台層是服務化思維下的産物。将公共的一些功能拆分出來,讓相關的業務服務隻專注于自己的業務,這樣有利于明确服務的職責,友善服務擴充。

同時一些公共的平台,也有利于各個服務之間的統籌,例如資料平台,可以對資料進行聚合,某個服務以前需要一些整合一些資料可能要調用多個上遊服務,但是引入資料平台以後,隻需要從資料平台取資料就可以了,可以降低服務的響應時間。

運維平台

運維平台核心的職責分為四大塊:配置、部署、監控、應急,每個職責對應系統生命周期的一個階段,如下圖所示:

高并發,我把握不住啊!什麼是高并發高并發目标高并發架構演進高并發架構實作高并發架構要點
  • 部署:主要負責将系統釋出到線上。例如,包管理、灰階釋出管理、復原等。
  • 監控:主要負責收集系統上線運作後的相關資料并進行監控,以便及時發現問題。
  • 應急:主要負責系統出故障後的處理。例如,停止程式、下線故障機器、切換 IP 等。

運維平台的核心設計要素是“四化"——标準化、平台化、自動化、可視化。

  • 标準化:要制定運維标準,規範配置管理、部署流程、監控名額、應急能力等,各系統按照運維标準來

    實作,避免不同的系統不同的處理方式。

  • 平台化:傳統的手工運維方式需要投入大量人力,效率低,容易出錯,是以需要在運維标準化的基礎上,

    将運維的相關操作都內建到運維平台中,通過運維平台來完成運維工作。

  • 自動化:傳統手工運維方式效率低下的一個主要原因就是要執行大量重複的操作,運維平台可以将這些重

    複操作固化下來,由系統自動完成。

  • 可視化:運維平台有非常多的資料,如果全部通過人工去查詢資料再來判斷,則效率很低,可視化的主要目的就是為了提升資料檢視效率。

測試平台

測試平台核心的職責當然就是測試了,包括單元測試、內建測試、接口測試、性能測試等,都可以在測試平台來完成。

測試平台的核心目的是提升測試效率,進而提升産品品質,其設計關鍵就是自動化。

高并發,我把握不住啊!什麼是高并發高并發目标高并發架構演進高并發架構實作高并發架構要點

資料平台

資料平台的核心職責主要包括三部分:資料管理、資料分析和資料應用。每一部分又包含更多的細分領域,詳細的資料平台架構如下圖所示:

高并發,我把握不住啊!什麼是高并發高并發目标高并發架構演進高并發架構實作高并發架構要點
  1. 資料管理

資料管理包含資料采集、資料存儲、資料通路和資料安全四個核心職責,是資料平台的基礎功能。

  • 資料采集:從業務系統搜集各類資料。例如,日志、使用者行為、業務資料等,将這些資料傳送到資料平台。
  • 資料存儲:将從業務系統采集的資料存儲到資料平台,用于後續資料分析。
  • 資料通路:負責對外提供各種協定用于讀寫資料。例如,SQL、 Hive、 Key-Value 等讀寫協定。
  • 資料安全:通常情況下資料平台都是多個業務共享的,部分業務敏感資料需要加以保護,防止被其他業務讀取甚至修改,是以需要設計資料安全政策來保護資料。
  1. 資料分析

資料分析包括資料統計、資料挖掘、機器學習、深度學習等幾個細分領域。

  • 資料挖掘:資料挖掘這個概念本身含義可以很廣,為了與機器學習和深度學習區分開,這裡的資料挖掘主要是指傳統的資料挖掘方式。例如,有經驗的資料分析人員基于資料倉庫建構一系列規則來對資料進行分析進而發現一些隐含的規律、現象、問題等,經典的資料挖掘案例就是沃爾瑪的啤酒與尿布的關聯關系的發現。
  • 機器學習、深度學習:機器學習和深度學習屬于資料挖掘的一種具體實作方式,由于其實作方式與傳統的資料挖掘方式差異較大,是以資料平台在實作機器學習和深度學習時,需要針對機器學習和深度學習獨立進行設計。
  1. 資料應用

資料應用很廣泛,既包括線上業務,也包括離線業務。例如,推薦、廣告等屬于線上應用,報表、欺詐檢測、異常檢測等屬于離線應用。資料應用能夠發揮價值的前提是需要有 “大資料” ,隻有當資料的規模達到一定程度,基于資料的分析、挖掘才能發現有價值的規律、現象、問題等。如果資料沒有達到一定規模,通常情況下做好資料統計就足夠了,尤其是很多初創企業,無須一開始就參考 BAT 來建構自己的資料平台。

管理平台

管理平台的核心職責就是權限管理,無論是業務系統(例如,淘寶網) 、中間件系統(例如,消息隊列 Kafka) , 還是平台系統(例如,運維平台) ,都需要進行管理。如果每個系統都自己來實作權限管理,效率太低,重複工作很多,是以需要統一的管理平台來管理所有的系統的權限。

說到“平台”,不由地想起這幾年一會兒被人猛吹,一會兒被人唱衰的“中台”。在平台裡的資料平台,其實已經和所謂的“資料中台”類似了。“中台”是個概念性的東西,具體怎麼實作,沒有統一的标準方案。作者所在的公司,也跟風建了中台,以“資料中台”為例,我們資料中台的建設主要為了資料共享和資料可視化,簡單說就是把各個業務子產品的一些資料彙聚起來。說起來簡單,落地很難,資料彙聚的及時性、資料共享的快速響應……最終的解決方案是采購了阿裡的一些商業化元件,花了老鼻子錢,但是效果,不能說一地雞毛,也差不多吧。

緩存層

雖然我們可以通過各種手段來提升存儲系統的性能,但在某些複雜的業務場景下,單純依靠存儲系統的性能提升不夠的。

絕大部分線上業務都是讀多寫少。例如,微網誌、淘寶、微信這類網際網路業務,讀業務占了整體業務量的 90%以上。以微網誌為例:一個明星發一條微網誌,可能幾千萬人來浏覽。

如果直接從DB中取資料,有兩個問題,一個是DB查詢的速度有瓶頸,會增加系統的響應時間,一個是資料庫本身的并發瓶頸。緩存就是為了彌補讀多寫少場景下存儲系統的不足。

在前面我們提到的CDN可以說是緩存的一種,它緩存的是靜态資源。

從整個架構來看,一般采用多級緩存的架構,在不同層級對資料進行緩存,來提升通路效率。

高并發,我把握不住啊!什麼是高并發高并發目标高并發架構演進高并發架構實作高并發架構要點

簡單說一下整體架構和流程,緩存一級一級地去讀取,沒有命中再去讀取下一級,先讀取本地緩存,再去讀取分布式緩存,分布式緩存也沒有命中,最後就得去讀取DB。

分布式緩存

為了提高緩存的可用性,一般采用分布式緩存。分布式緩存一般采用分片實作,即将資料分散到多個執行個體或多台伺服器。算法一般釆用取模和一緻性哈希。

要采用不過期緩存機制,可以考慮取模機制,擴容時一般是建立一個叢集。

高并發,我把握不住啊!什麼是高并發高并發目标高并發架構演進高并發架構實作高并發架構要點

而對于可以丢失的緩存資料,可以考慮一緻性哈希,即使其中一個執行個體出問題隻是丢一小部分。

高并發,我把握不住啊!什麼是高并發高并發目标高并發架構演進高并發架構實作高并發架構要點

對于分片實作可以考慮用戶端實作,或者使用如Twemproxy 中間件進行代理(分片對用戶端是透明的)。

如果使用 Redis, 則 可 以考慮使用 redis-cluster 分布式叢集方案。

高并發,我把握不住啊!什麼是高并發高并發目标高并發架構演進高并發架構實作高并發架構要點

熱點本地緩存

對于那些通路非常頻繁的熱點緩存,如果每次都去遠端緩存系統中擷取,可能會因為通路量太大導緻遠端緩存系統請求過多、負載過高或者帶寬過高等問題,最終可能導緻緩存響應慢,使用戶端請求逾時。

一種解決方案是通過挂更多的從緩存,用戶端通過負載均衡機制讀取從緩存系統資料。不過也可以在用戶端所在的應用/代理層本地存儲一份,進而避免通路遠端緩存,即使像庫存這種資料,在有些應用系統中也可以進行幾秒鐘的本地緩存,進而降低遠端系統的壓力。

緩存的引入雖然提高了系統的性能,但同時也增加了系統的複雜度,帶來了一些運維的成本。

緩存穿透

緩存穿透是指緩存沒有發揮作用,業務系統雖然去緩存查詢資料,但緩存中沒有資料,業務系統需要再次去存儲系統查詢資料,結果存儲系統也沒有資料。

緩存穿透的示意圖:

高并發,我把握不住啊!什麼是高并發高并發目标高并發架構演進高并發架構實作高并發架構要點

一般情況下,如果存儲系統中沒有某個資料,則不會在緩存中存儲相應的資料,這樣就導緻使用者查詢的時候,在緩存中找不到對應的資料,每次都要去存儲系統中再查詢一遍,然後傳回資料不存在。緩存在這個場景中并沒有起到分擔存儲系統通路壓力的作用。

通常情況下,業務上讀取不存在的資料的請求量并不會太大,但如果出現一些異常情況,例如被黑客攻擊,故意大量通路某些讀取不存在資料的業務,有可能會将存儲系統拖垮。

這種情況的解決辦法有兩種:

一種比較簡單,如果查詢存儲系統的資料沒有找到,則直接設定一個預設值(可以是空值,也可以是具體的值) 存到緩存中,這樣第二次讀取緩存時就會擷取到預設值,而不會繼續通路存儲系統。

一種需要引入布隆過濾器,它的原理也很簡單就是利用高效的資料結構和算法,快速判斷出查詢的Key是否在資料庫中存在,不存在直接傳回空,存在就去查了DB,重新整理KV再傳回值。

緩存擊穿

緩存擊穿和緩存穿透也有點難以區分,緩存穿透表示的是緩存和資料庫中都沒有資料,緩存擊穿表示緩存中沒有資料而資料庫中有資料。緩存擊穿是某個熱點的key失效,大并發集中對其進行請求,就會造成大量請求讀緩存沒讀到資料,進而導緻高并發通路資料庫,引起資料庫壓力劇增。這種現象就叫做緩存擊穿。

緩存擊穿示意圖:

高并發,我把握不住啊!什麼是高并發高并發目标高并發架構演進高并發架構實作高并發架構要點

關鍵在于某個熱點的key失效了,導緻大并發集中打在資料庫上。是以要從兩個方面解決,第一是否可以考慮熱點key不設定過期時間,第二是否可以考慮降低打在資料庫上的請求數量。

主要有兩個解決辦法:

  • 利用互斥鎖保證同一時刻隻有一個用戶端可以查詢底層資料庫的這個資料,一旦查到資料就緩存至Redis内,避免其他大量請求同時穿過Redis通路底層資料庫。這種方式會阻塞其他的線程,此時系統的吞吐量會下降
  • 熱點資料緩存永遠不過期。

永不過期有兩種方式:

  • 實體不過期,針對熱點key不設定過期時間
  • 邏輯過期,把過期時間存在key對應的value裡,如果發現要過期了,通過一個背景的異步線程進行緩存的建構

緩存雪崩

緩存雪崩,指的是是緩存不可用,或者同一時刻是大量熱點key失效。

兩種情況導緻的同樣的後果就是大量的請求直接落在資料庫上,對于一個高并發的業務系統來說,幾百毫秒内可能會接到幾百上千個請求,最嚴重的後果就是直接導緻資料庫當機,可能會引起連鎖反應,導緻系統崩潰。

高并發,我把握不住啊!什麼是高并發高并發目标高并發架構演進高并發架構實作高并發架構要點

緩存雪崩的解決方案可以分為三個次元:

  • 事前:

① 均勻過期:設定不同的過期時間,讓緩存失效的時間盡量均勻,避免相同的過期時間導緻緩存雪崩,造成大量資料庫的通路。

② 分級緩存:第一級緩存失效的基礎上,通路二級緩存,每一級緩存的失效時間都不同。

③ 熱點資料緩存永遠不過期。

④ 保證Redis緩存的高可用,防止Redis當機導緻緩存雪崩的問題。可以使用 Redis叢集等方式來避免 Redis 全盤崩潰的情況。

  • 事中:

① 互斥鎖:在緩存失效後,通過互斥鎖或者隊列來控制讀資料寫緩存的線程數量,比如某個key隻允許一個線程查詢資料和寫緩存,其他線程等待。這種方式會阻塞其他的線程,此時系統的吞吐量會下降

② 使用熔斷機制,限流降級。當流量達到一定的門檻值,直接傳回“系統擁擠”之類的提示,防止過多的請求打在資料庫上将資料庫擊垮,至少能保證一部分使用者是可以正常使用,其他使用者多重新整理幾次也能得到結果。

  • 事後:

① 開啟Redis持久化機制,盡快恢複緩存資料,一旦重新開機,就能從磁盤上自動加載資料恢複記憶體中的資料。

存儲層

不管是為了滿足業務發展的需要,還是為了提升自己的競争力,關系資料庫廠商(Oracle、DB2、MySQL 等)在優化和提升單個資料庫伺服器的性能方面也做了非常多的技術優化和改進。但業務發展速度和資料增長速度,遠遠超出資料庫廠商的優化速度,尤其是網際網路業務興起之後,海量使用者加上海量資料的特點,單個資料庫伺服器已經難以滿足業務需要,必須考慮資料庫叢集的方式來提升性能。

讀寫分離

讀寫分離的基本原理是将資料庫讀寫操作分散到不同的節點上,下面是其基本架構圖:

高并發,我把握不住啊!什麼是高并發高并發目标高并發架構演進高并發架構實作高并發架構要點

讀寫分離的基本實作是:

  • 資料庫伺服器搭建主從叢集,一主一從、一主多從都可以。
  • 資料庫主機負責讀寫操作,從機隻負責讀操作。
  • 資料庫主機通過複制将資料同步到從機,每台資料庫伺服器都存儲了所有的業務資料。
  • 業務伺服器将寫操作發給資料庫主機,将讀操作發給資料庫從機。
高并發,我把握不住啊!什麼是高并發高并發目标高并發架構演進高并發架構實作高并發架構要點

讀寫分離的實作邏輯并不複雜,但有兩個細節點将引入設計複雜度:主從複制延遲和配置設定機制。

複制延遲

以 MySQL 為例,主從複制延遲可能達到 1 秒,如果有大量資料同步,延遲 1 分鐘也是有可能的。

主從複制延遲會帶來一個問題:如果業務伺服器将資料寫入到資料庫主伺服器後立刻 (1 秒 内)進行讀取,此時讀操作通路的是從機,主機還沒有将資料複制過來,到從機讀取資料是讀不到最新資料的,業務上就可能出現問題。

比如說将微網誌的資訊同步給稽核系統,是以我們在更新完主庫之後,會将微網誌的 ID 寫入消息隊列,再由隊列處理機依據 ID 在從庫中 擷取微網誌資訊再發送給稽核系統。此時如果主從資料庫存在延遲,會導緻在從庫中擷取不到微網誌資訊,整個流程會出現異常。

高并發,我把握不住啊!什麼是高并發高并發目标高并發架構演進高并發架構實作高并發架構要點

解決主從複制延遲的常見方法:

  1. 資料的備援

我們可以在發送消息隊列時不僅僅發送微網誌 ID,而是發送隊列處理機需要的所有微網誌資訊,借此避免從資料庫中重新查詢資料。

  1. 使用緩存

我們可以在同步寫資料庫的同時,也把微網誌的資料寫入到緩存裡面,隊列處理機在擷取微網誌資訊的時候會優先查詢緩存,這樣也可以保證資料的一緻性。

  1. 二次讀取

我們可以對底層資料庫通路的API進行封裝,一次讀取從庫發現不實時之後再讀取一次,例如我們通過微網誌ID沒有在從庫裡讀到微網誌,那麼第二次就直接去主庫讀取。

  1. 查詢主庫

我們可以把關鍵業務,或者對實時性有要求的業務讀寫操作全部指向主機,非關鍵業務或者實時性要求不高的業務采用讀寫分離。

配置設定機制

将讀寫操作區分開來,然後通路不同的資料庫伺服器,一般有兩種方式:程式代碼封裝和中間件封裝。

  1. 程式代碼封裝

程式代碼封裝指在代碼中抽象一個資料通路層(是以有的文章也稱這種方式為 “中間層封裝” ) ,實作讀寫操作分離和資料庫伺服器連接配接的管理。例如,基于 Hibernate 進行簡單封裝,就可以實作讀寫分離,基本架構是:

高并發,我把握不住啊!什麼是高并發高并發目标高并發架構演進高并發架構實作高并發架構要點

程式代碼封裝的方式具備幾個特點:

  • 實作簡單,而且可以根據業務做較多定制化的功能。
  • 每個程式設計語言都需要自己實作一次,無法通用,如果一個業務包含多個程式設計語言寫的多個子系統,則重複開發的工作量比較大。
  • 故障情況下,如果主從發生切換,則可能需要所有系統都修改配置并重新開機。

如果不想自己造輪子,也可以用開源的方案,淘寶的TDDL是比較出名的一個。

高并發,我把握不住啊!什麼是高并發高并發目标高并發架構演進高并發架構實作高并發架構要點
  1. 中間件封裝

中間件封裝指的是獨立一套系統出來,實作讀寫操作分離和資料庫伺服器連接配接的管理。中間件對業務伺服器提供 SQL 相容的協定,業務伺服器無須自己進行讀寫分離。對于業務伺服器來說,通路中間件和通路資料庫沒有差別,事實上在業務伺服器看來,中間件就是一個資料庫伺服器。

其基本架構是:

高并發,我把握不住啊!什麼是高并發高并發目标高并發架構演進高并發架構實作高并發架構要點

資料庫中間件的方式具備的特點是:

  • 能夠支援多種程式設計語言,因為資料庫中間件對業務伺服器提供的是标準 SQL 接口。
  • 資料庫中間件要支援完整的 SQL 文法和資料庫伺服器的協定(例如,MySQL 用戶端和伺服器的連接配接協定) ,實作比較複雜,細節特别多,很容易出現 bug, 需要較長的時間才能穩定。
  • 資料庫中間件自己不執行真正的讀寫操作,但所有的資料庫操作請求都要經過中間件,中間件的性能要求也很高。
  • 資料庫主從切換對業務伺服器無感覺,資料庫中間件可以探測資料庫伺服器的主從狀态。例如,向某個測試表寫入一條資料,成功的就是主機,失敗的就是從機。

目前開源的資料庫中間件有基于 MySQL Proxy 開發的奇虎 360 的 Atlas 、阿 裡 的Cobar、基于 Cobar 開發的 Mycat 等。

分庫分表

讀寫分離分散了資料庫讀寫操作的壓力,但沒有分散存儲壓力,當資料量達到幹萬甚至上億條的時候,單台資料庫伺服器的存儲能力會成為系統的瓶頸,主要展現在這幾個方面:

  • 資料量太大,讀寫的性能會下降,即使有索引,索引也會變得很大,性能同樣會下降。
  • 資料檔案會變得很大,資料庫備份和恢複需要耗費很長時間。
  • 資料檔案越大,極端情況下丟失資料的風險越高(例如,機房火災導緻資料庫主備機都發生故障)。

基于上述原因,單個資料庫伺服器存儲的資料量不能太大,需要控制在一定的範圍内。為了滿足業務資料存儲的需求,就需要将存儲分散到多台資料庫伺服器上。

業務分庫

業務分庫指的是按照業務子產品将資料分散到不同的資料庫伺服器。例如,一個簡單的電商網站,包括使用者、商品、訂單三個業務子產品,我們可以将使用者資料、商品資料、訂單資料分開放到三台不同的資料庫伺服器上,而不是将所有資料都放在一台資料庫伺服器上。

高并發,我把握不住啊!什麼是高并發高并發目标高并發架構演進高并發架構實作高并發架構要點

雖然業務分庫能夠分散存儲和通路壓力,但同時也帶來了新的問題,接下來我們詳細分析一下。

  1. join 操作問題

業務分庫後,原本在同一個資料庫中的表分散到不同資料庫中,導緻無法使用 SQL 的 join 查 詢。

例如: "查詢購買了化妝品的使用者中女性使用者的清單〃 這個功能,雖然訂單資料中有使用者的 ID資訊,但是使用者的性别資料在使用者資料庫中,如果在同一個庫中,簡單的 join 查詢就能完成;但現在資料分散在兩個不同的資料庫中,無法做 join 查詢,隻能采取先從訂單資料庫中查詢購買了化妝品的使用者 ID 清單,然後再到使用者資料庫中查詢這批使用者 ID 中的女性使用者清單,這樣實作就比簡單的 join 查詢要複雜一些。

  1. 事務問題

原本在同一個資料庫中不同的表可以在同一個事務中修改,業務分庫後,表分散到不同的資料庫中,無法通過事務統一修改。雖然資料庫廠商提供了一些分布式事務的解決方案(例如,MySQL 的 XA) , 但性能實在太低,與高性能存儲的目标是相違背的。

例如,使用者下訂單的時候需要扣商品庫存,如果訂單資料和商品資料在同一個資料庫中,我們可訂單,如果因為訂單資料庫異常導緻生成訂單失敗,業務程式又需要将商品庫存加上;而如果因為業務程式自己異常導緻生成訂單失敗,則商品庫存就無法恢複了,需要人工通過曰志等方式來手工修複庫存異常。

  1. 成本問題

業務分庫同時也帶來了成本的代價,本來 1 台伺服器搞定的事情,現在要 3 台,如果考慮備份,那就是 2 台變成了 6 台。

基于上述原因,對于小公司初創業務,并不建議一開始就這樣拆分,主要有幾個原因:初創業務存在很大的不确定性,業務不一定能發展起來,業務開始的時候并沒有真正的存儲和通路壓力,業務分庫并不能為業務帶來價值。業務分庫後,表之間的 join 查詢、資料庫事務無法簡單實作了。

業務分庫後,因為不同的資料要讀寫不同的資料庫,代碼中需要增加根據資料類型映射到不同資料庫的邏輯,增加了工作量。而業務初創期間最重要的是快速實作、快速驗證,業務分庫會拖慢業務節奏。

單表拆分

将不同業務資料分散存儲到不同的資料庫伺服器,能夠支撐百萬甚至千萬使用者規模的業務,但如果業務繼續發展,同一業務的單表資料也會達到單台資料庫伺服器的處理瓶頸。例如,淘寶的幾億使用者資料,如果全部存放在一台資料庫伺服器的一張表中,肯定是無法滿足性能要求的,此時就需要對單表資料進行拆分。

單表資料拆分有兩種方式:垂直分表和水準分表。示意圖如下:

高并發,我把握不住啊!什麼是高并發高并發目标高并發架構演進高并發架構實作高并發架構要點

分表能夠有效地分散存儲壓力和帶來性能提升,但和分庫一樣,也會引入各種複雜性。

兩種分表方式可以用一個例子比喻,我們很多人可能都看過這麼一篇文章,怎麼把蘋果切出星星來,答案是橫着切。

高并發,我把握不住啊!什麼是高并發高并發目标高并發架構演進高并發架構實作高并發架構要點
  1. 垂直分表

垂直分表适合将表中某些不常用且占了大量空間的列拆分出去。例如,前面示意圖中的nickname 和 desc 字段,假設我們是一個婚戀網站,使用者在篩選其他使用者的時候,主要是用 age 和 sex 兩個字段進行查詢,而 nickname 和 description 兩個字段主要用于展示,一般不會在業務查詢中用到。description 本身又比較長,是以我們可以将這兩個字段獨立到另外—張表中,這樣在查詢 age 和 sex 時,就能帶來一定的性能提升。垂直分表引入的複雜性主要展現在表操作的數量要增加。例如,原來隻要一次查詢就可以擷取name、age、sex、nickname、description, 現在需要兩次查詢,—次查詢擷取 name、age、 sex, 另一次查詢擷取 nickname、desc。

不過相比接下來要講的水準分表,這個複雜性就是小巫見大巫了。

  1. 水準分表

水準分表适合表行數特别大的表,有的公司要求單表行數超過 5000 萬就必須進行分表,這個數字可以作為參考,但并不是絕對标準,關鍵還是要看表的通路性能。對于一些比較複雜的表,可能超過 1000 萬就要分表了;而對于一些簡單的表,即使存儲資料超過 1 億行,也可以不分表。但不管怎樣,當看到表的資料量達到幹萬級别時,這很可能是架構的性能瓶頸或者隐患。

水準分表相比垂直分表,會引入更多的複雜性,主要表現在下面幾個方面:

  • 路由

水準分表後,某條資料具體屬于哪個切分後的子表,需要增加路由算法進行計算,這個算法會引入一定的複雜性。

常見的路由算法有:

高并發,我把握不住啊!什麼是高并發高并發目标高并發架構演進高并發架構實作高并發架構要點

範圍路由:選取有序的資料列 (例如,整形、時間戳等) 作為路由的條件,不同分段分散到不同的資料庫表中。以訂單 Id 為例,路由算法可以按照 1000萬 的範圍大小進行分段。範圍路由設計的複雜點主要展現在分段大小的選取上,分段太小會導緻切分後子表數量過多,增加維護複雜度;分段太大可能會導緻單表依然存在性能問題,一般建議分段大小在 100 萬至2000 萬之間,具體需要根據業務選取合适的分段大小。

範圍路由的優點是可以随着資料的增加平滑地擴充新的表。例如,現在的使用者是 100 萬,如果增加到 1000 萬,隻需要增加新的表就可以了,原有的資料不需要動。範圍路由的一個比較隐含的缺點是分布不均勻,假如按照 1000 萬來進行分表,有可能某個分段實際存儲的資料量隻有 1000 條,而另外一個分段實際存儲的資料量有 900 萬條。

Hash 路由:選取某個列 (或者某幾個列組合也可以) 的值進行 Hash 運算,然後根據 Hash 結果分散到不同的資料庫表中。同樣以訂單 id 為例,假如我們一開始就規劃了 4個資料庫表,路由算法可以簡單地用 id % 4 的值來表示資料所屬的資料庫表編号,id 為 12的訂單放到編号為 50的子表中,id為 13的訂單放到編号為 61的字表中。

Hash 路由設計的複雜點主要展現在初始表數量的選取上,表數量太多元護比較麻煩,表數量太少又可能導緻單表性能存在問題。而用了 Hash 路由後,增加字表數量是非常麻煩的,所有資料都要重分布。

Hash 路由的優缺點和範圍路由基本相反,Hash 路由的優點是表分布比較均勻,缺點是擴充新的表很麻煩,所有資料都要重分布。

配置路由:配置路由就是路由表,用一張獨立的表來記錄路由資訊。

同樣以訂單id 為例,我們新增一張 order_router 表,這個表包含 orderjd 和 tablejd 兩列 , 根據 orderjd 就可以查詢對應的 table_id。

配置路由設計簡單,使用起來非常靈活,尤其是在擴充表的時候,隻需要遷移指定的資料,然後修改路由表就可以了。

配置路由的缺點就是必須多查詢一次,會影響整體性能;而且路由表本身如果太大(例如,幾億條資料) ,性能同樣可能成為瓶頸,如果我們再次将路由表分庫分表,則又面臨一個死循環式的路由算法選擇問題。

  • join 操作

水準分表後,資料分散在多個表中,如果需要與其他表進行 join 查詢,需要在業務代碼或者資料庫中間件中進行多次 join 查詢,然後将結果合并。

  • count()操作

分表後就沒那麼簡單了。常見的處理方式有下面兩種:

count() 相加:具體做法是在業務代碼或者資料庫中間件中對每個表進行 count操作,然後将結果相加。這種方式實作簡單,缺點就是性能比較低。例如,水準分表後切分為 20 張表,則要進行 2 0 次 count()操作,如果串行的話,可能需要幾秒鐘才能得到結果。

記錄數表:具體做法是建立一張表,假如表名為 "記錄數表” ,包含 table_name、 row_count兩個字段,每次插入或者删除子表資料成功後,都更新 "記錄數表“。這種方式擷取表記錄數的性能要大大優于 count()相加的方式,因為隻需要一次簡單查詢就可以擷取資料。缺點是複雜度增加不少,對子表的操作要同步操作 “記錄數表” ,如果有一個業務邏輯遺漏了,資料就會不一緻;且針對 “記錄數表” 的操作和針對子表的操作無法放在同一事務中進行處理,異常的情況下會出現操作子表成功了而操作記錄數表失敗,同樣會導緻資料不一緻。

此外,記錄數表的方式也增加了資料庫的寫壓力,因為每次針對子表的 insert 和 delete 操作都要 update 記錄數表,是以對于一些不要求記錄數實時保持精确的業務,也可以通過背景定時更新記錄數表。定時更新實際上就是 “count()相加” 和 “記錄數表” 的結合,即定時通過count()相加計算表的記錄數,然後更新記錄數表中的資料。

  • order by 操作

水準分表後,資料分散到多個子表中,排序操作無法在資料庫中完成,隻能由業務代碼或者資料庫中間件分别查詢每個子表中的資料,然後彙總進行排序。

實作方法

和資料庫讀寫分離類似,分庫分表具體的實作方式也是 “程式代碼封裝” 和 “中間件封裝” ,但實作會更複雜。讀寫分離實作時隻要識别 SQL 操作是讀操作還是寫操作,通過簡單的判斷SELECT、UPDATE、 INSERT、DELETE 幾個關鍵字就可以做到,而分庫分表的實作除了要判斷操作類型外,還要判斷 SQL 中具體需要操作的表、操作函數(例如 count 函數)、order by、group by 操作等,然後再根據不同的操作進行不同的處理。例如 order by 操作,需要先從多個庫查詢到各個庫的資料,然後再重新 order by 才能得到最終的結果。

資料異構

完成分庫分表以後,我們看到存在一些問題,除了"程式代碼封裝" 和 "中間件封裝"之外,我們還有一種辦法,就是資料異構。資料異構就是将資料進行異地存儲,比如業務上将MySQL的資料,寫一份到Redis中,這就是實作了資料在叢集中的異地存儲,也就是資料異構。

在資料量和通路量雙高時使用資料異構是非常有效的,但增加了架構的複雜度。異構時可以通過雙寫、訂閱 MQ 或者 binlog 并解析實作。

  • 雙寫:在寫入資料的時候,同時将資料寫入MySQL和異構存儲系統;
  • MQ:寫入MySQL成功後,發一個mq消息,緩存讀取mq消息并将消息寫入異構存儲系統;
  • binlog:寫入MySQL後,緩存系統x消費binlog,将變動寫入異構存儲系統。

這是一個異構的資料架構示意圖:

高并發,我把握不住啊!什麼是高并發高并發目标高并發架構演進高并發架構實作高并發架構要點

在圖中用到了ES搜尋叢集來處理搜尋業務,同樣也可以我們前面提到的跨庫join的問題。

在設計異構的時候,我們可以充分利用一些流行的NoSQL資料庫。NoSQL盡管已經被證明不能取代關系型資料庫,但是在很多場景下是關系型資料庫的有力補充。

舉幾個例子,像我們熟悉的Redis這樣的KV存儲,有極高的讀寫性能,在讀寫性能有要求的場景可以使用;

Hbase、Cassandra 這樣的列式存儲資料庫。這種資料庫的特點是資料不像傳統資料庫以行為機關來存儲,而是以列來存儲,适用于一些離線資料統計的場景;

MongoDB、CouchDB 這樣的文檔型資料庫,具備 Schema Free(模式自由)的特點,資料表中的字段可以任意擴充,可以用于資料字段不固定的場景。

查詢次元異構

比如對于訂單庫,當對其分庫分表後,如果想按照商家次元或者按照使用者次元進行查詢,那麼是非常困難的,是以可以通過異構資料庫來解決這個問題。可以采用下圖的架構。

高并發,我把握不住啊!什麼是高并發高并發目标高并發架構演進高并發架構實作高并發架構要點

或者采用下圖的ES異構:

高并發,我把握不住啊!什麼是高并發高并發目标高并發架構演進高并發架構實作高并發架構要點

異構資料主要存儲資料之間的關系,然後通過查詢源庫查詢實際資料。不過,有時可以通過資料備援存儲來減少源庫查詢量或者提升查詢性能。

聚合據異構

商品詳情頁中一般包括商品基本資訊、商品屬性、商品圖檔,在前端展示商品詳情頁時,是按照商品 ID 次元進行查詢,并且需要查詢 3 個甚至更多的庫才能查到所有展示資料。此時,如果其中一個庫不穩定,就會導緻商品詳情頁出現問題,是以,我們把資料聚合後異構存儲到 KV 存儲叢集(如存儲 JSON ), 這樣隻需要一次查詢就能得到所有的展示資料。這種方式也需要系統有了一定的資料量和通路量時再考慮。

高并發,我把握不住啊!什麼是高并發高并發目标高并發架構演進高并發架構實作高并發架構要點

高并發架構要點

通過前面的内容,已經差不多了解高并發的架構是一個什麼樣,接下來做一些總結和補充。

高性能要點

高并發,我把握不住啊!什麼是高并發高并發目标高并發架構演進高并發架構實作高并發架構要點

高可用要點

高并發,我把握不住啊!什麼是高并發高并發目标高并發架構演進高并發架構實作高并發架構要點

除了從技術的角度來考慮,保證高可用同樣需要良好的組織制度,來保證服務出現問題的快速恢複。

高擴充要點

1、合理的分層架構:比如上面談到的網際網路最常見的分層架構,另外還能進一步按照資料通路層、業務邏輯層對微服務做更細粒度的分層(但是需要評估性能,會存在網絡多一跳的情況)。

2、存儲層的拆分:按照業務次元做垂直拆分、按照資料特征次元進一步做水準拆分(分庫分表)。

3、業務層的拆分:最常見的是按照業務次元拆(比如電商場景的商品服務、訂單服務等),也可以按照核心請求和非核心請求拆分,還可以按照請求源拆(比如To C和To B,APP和H5 )。

好了,攢的這一篇終于完事了,更深入學習建議閱讀書籍參考【11】。祝各位架構師能真的如江似海,把握高并發,多掙達不溜。