億級流量系統架構之如何設計承載百億流量的高效能架構【石杉的架構筆記】

石杉的架構筆記發表於2018-11-28

歡迎關注個人公眾號:石杉的架構筆記(ID:shishan100)

週一至週五早8點半!精品技術文章準時送上!

一、往期回顧

上篇文章《大型系統架構演進之如何設計高容錯分散式計算系統》,主要聊了一下將單塊系統重構為分散式系統,以此來避免單臺機器的負載過高。同時引申出來了彈性資源排程、分散式容錯機制等相關的東西。

這篇文章我們繼續來聊聊這個系統後續的重構演進過程,先來看下目前的系統架構圖,一起來回顧一下。

億級流量系統架構之如何設計承載百億流量的高效能架構【石杉的架構筆記】

二、百億流量的高併發技術挑戰

上篇文章說到,如果僅僅只是每天億級流量的話,其實基本上目前的系統架構就足夠支撐了,但是呢,我們面臨的可不僅僅是億級流量那麼簡單。我們面對的是日益增多和複雜的各種業務系統,我們面對的是不斷增加的系統使用者,我們面對的是即將迎來每天百億級的高併發流量。

給大家先說下當時的系統部署情況,資料庫那塊一共部署了8主8從,也就是16臺資料庫伺服器,每個庫都是部署在獨立的資料庫伺服器上的,而且全部用的是物理機,機器的配置,如果沒記錯的話,應該是32核+128G+SSD固態硬碟。

為啥要搞這麼多物理機,而且全部都是高配置呢?不知道大家發現沒有,目前為止,我們最大的依賴就是MySQL!

之前給大家解釋過,在當時的背景下,我們要對湧入的億級海量資料,實時的執行數百個複雜度為幾百行到上千行的大SQL,幾秒鐘就要出分析結果。

這個是沒有任何一個開源系統可以做到的,Storm不行,Spark Streaming也不行,因此必須得基於MySQL純自研一套資料平臺架構出來,支撐這個需求場景。

所以,只有MySQL是可以支撐如此複雜的SQL語句完美執行的,因此我們在早期必須嚴重依賴於MySQL作為資料的儲存和計算,將源源不斷湧入的資料放在MySQL中進行儲存,接著基於資料分片計算的架構來高效能的執行復雜大SQL基於MySQL來進行計算。

所以大家就知道了,MySQL目前為止是這套系統的命脈。在當時的場景下,每臺資料庫伺服器都要抗住每秒2000左右的併發請求,高峰期的CPU負載、IO負載其實都非常高,而且主庫和從庫的延遲在高峰期已經有點嚴重,會達到秒級了。

在我們的生產系統的實際線上執行情況下,單臺MySQL資料庫伺服器,我們一般是不會讓他的高峰期併發請求超過2000/s的,因為一旦達到每秒幾千的請求,根據當時線上的資源負載情況來看,很可能MySQL伺服器負載過高會當機。

所以此時就有一個很尷尬的問題了,假如說每天億級流量的場景下,需要用8主8從這麼多高配置的資料庫伺服器來抗,那如果是幾十億流量呢?甚至如果是百億流量呢?難道不停的增加更多的高配置機器嗎?

要知道,這種高配置的資料庫伺服器,如果是物理機的話,是非常昂貴的!

之前給大家簡單介紹過專案背景,這整套大型系統組成的商業級平臺,涉及到N多個系統,這個資料產品只是一個子產品而已,不可能為了這麼一個產品,投入大量的預算通過不停的砸高配置的機器來撐住更高的併發寫入。

我們必須用技術的手段來重構系統架構,儘量用有限的機器資源,通過最優秀的架構來抗住超高的併發寫入壓力!

三、計算與儲存分離的架構

這個架構裡的致命問題之一,就是資料的儲存和計算混在了一個地方,都在同一個MySQL庫裡!

大家想想,在一個單表裡放上千萬資料,然後你每次執行一個複雜SQL的時候,SQL裡都是通過索引定位到表中他要計算的那個資料分片。這樣搞合適嗎?

答案顯然是否定的!因為表裡的資料量很大,但是你每次實際SQL運算只要對其中很小很小的一部分資料計算就可以了,實際上我們在生產環境中實踐過後發現,如果你在一個大表執行一個複雜SQL,哪怕通過各種索引保證定位到的資料量很少,因為表資料量過大,也是會導致效能直線下降的。

因此第一件事情,先將資料的儲存和計算這兩件事情拆開。

我們當時的思路如下:

  • 資料直接寫入一個儲存,僅僅只是簡單的寫入即可
  • 然後在計算的時候從資料儲存中提取你需要的那個資料分片裡的可能就一兩千條資料,寫入另外一個專用於計算的臨時表中,那個臨時表內就這一兩千條資料
  • 然後執行你的各種複雜SQL即可。

bingo!一旦將資料儲存和計算兩個事情拆開,架構裡可以發揮的空間就大多了。

首先你的資料儲存只要支撐高併發的寫入,日百億流量的話,高峰每秒併發會達到幾十萬,撐住這就可以了。然後支援計算引擎通過簡單的操作從資料儲存裡提取少量資料就OK。

太好了,這個資料儲存就可以PASS掉MySQL了,就這點兒需求,你還用MySQL幹什麼?兄弟!

當時我們經過充分的技術調研和選型之後,選擇了公司自研的分散式KV儲存系統,這套KV儲存系統是完全分散式的,高可用,高效能,輕量級,支援海量資料,而且之前經歷過公司線上流量的百億級請求量的考驗,絕對沒問題。主要支援高併發的寫入資料以及簡單的查詢操作,完全符合我們的需求。

這裡給大家提一句,其實業內很多類似場景會選擇hbase,所以大家如果沒有公司自研的優秀kv儲存的話,可以用選用hbase也是沒問題的,只不過hbase有可能生產環境會有點坑,需要大家對hbase非常精通,合理避坑和優化。

輕量級的分散式kv系統,一般設計理念都是支援一些簡單的kv操作,大量的依託於記憶體快取熱資料來支援高併發的寫入和讀取,因為不需要支援MySQL裡的那些事務啊、複雜SQL啊之類的重量級的機制。

因此在同等的機器資源條件下,kv儲存對高併發的支撐能力至少是MySQL的數倍甚至數十倍。

就好比說,大家應該都用過Redis,Redis普通配置的單機器撐個每秒幾萬併發都是ok的,其實就是這個道理,他非常的輕量級,轉為高併發而生。

然後,我們還是可以基於MySQL中的一些臨時表來存放kv儲存中提取出來的資料分片,利用MySQL對複雜SQL語法的支援來進行計算就可以了。也就是說,我們在這個架構裡,把kv系統作為儲存,把MySQL用做少量資料的計算。

此時我們在系統架構中引入了分散式kv系統來作為我們的資料儲存,每天的海量資料都存放在這裡就可以了,然後我們的Slave計算引擎每次計算,都是根據那個資料分片從kv儲存中提取對應的資料出來放入MySQL內的一個臨時表,接著就是對那個臨時表內的一兩千條資料分片執行各種複雜SQL進行計算即可。

億級流量系統架構之如何設計承載百億流量的高效能架構【石杉的架構筆記】

大家看上面的圖,此時通過這一步計算與儲存架構的分離,我們選用了適合支撐高併發的kv叢集來抗住每天百億級的流量寫入。然後基於MySQL作為臨時表放入少量資料來進行運算。這一個步驟就直接把高併發請求可以妥妥的抗住了。

而且分散式kv儲存本來就可以按需擴容,如果併發越來越高,只要擴容增加機器就可以了。此時,就完成了架構的一個關鍵的重構步驟。

四、自研純記憶體SQL計算引擎

下一步,我們就要對架構追求極致!因為此時我們面臨的一個痛點就在於說,其實僅僅只是將MySQL作為一個臨時表來計算了,主要就是用他的複雜SQL語法的支援。

但是問題是,對MySQL的併發量雖然大幅度降低了,可是還並不算太低。因為大量的資料分片要計算,還是需要頻繁的讀寫MySQL。

此外,每次從kv儲存裡提取出來了資料,還得放到MySQL的臨時表裡,還得傳送SQL去MySQL裡運算,這還是多了幾個步驟的時間開銷。

因為當時面臨的另外一個問題是,每天請求量大,意味著資料量大,資料量大意味著時間分片的計算任務負載還是較重。

總是這麼依賴MySQL,還要額外維護一大堆的各種臨時表,可能多達幾百個臨時表,你要維護,要注意他的表結構的修改,還有分庫分表的一些運維操作,這一切都讓依賴MySQL這個事兒顯得那麼的多餘和麻煩。

因此,我們做出決定,為了讓架構的維護性更高,而且將效能優化到極致,我們要自己研發純記憶體的SQL計算引擎

其實如果你要自研一個可以支援MySQL那麼複雜SQL語法的記憶體SQL計算引擎,還是有點難度和麻煩的。但是在我們仔細研究了業務需要的那幾百個SQL之後,發現其實問題沒那麼的複雜。

因為其實一般的資料分析類的SQL,主要就是一些常見的功能,沒有那麼多的怪、難、偏的SQL語法。

因此我們將線上的SQL都分析過一遍之後,就針對性的研發出了僅僅支援特定少數語法的SQL引擎,包括了巢狀查詢元件、多表關聯元件、分組聚合元件、多欄位排序元件、少數幾個常用函式,等等。

接著就將系統徹底重構為不再依賴MySQL,每次從kv儲存中提取一個資料分片之後,直接放入記憶體中,然後用我們自研的SQL計算引擎來在純記憶體裡針對一個資料分片執行各種複雜的SQL。

這個純記憶體操作的效能,那就不用多說了,大家應該都能想象到了,基本上純記憶體的SQL執行,都是毫秒級的,基本上一個時間分片的運算全部降低到毫秒級了。效能進一步得到了大幅度的提升,而且從此不再依賴MySQL了,不需要維護複雜的分庫分表等等東西。

億級流量系統架構之如何設計承載百億流量的高效能架構【石杉的架構筆記】

這套架構上線之後,徹底消除了對MySQL的依賴,理論上,無論多大的流量過來,都可以通過立馬擴容kv叢集以及擴容Slave計算叢集來解決,不需要依賴MySQL的分庫分表、幾百張臨時表等比較耗費人力、麻煩而且坑爹的方案了。而且這種純記憶體的計算架構直接把計算效能提升到了毫秒級。

而且消除對MySQL的依賴有另外一個好處,資料庫的機器總是要高配置的,但是Slave機器主要4核8G的普通虛擬機器就夠了,分散式系統的本質就是儘量利用大量的廉價普通機器就可以完成高效的儲存和計算。

因此在百億流量的負載之下,我們Slave機器部署了幾十臺機器就足夠了,那總比你部署幾十臺昂貴的高配置MySQL物理機來的划算多了!

五、MQ削峰以及流量控制

其實如果對高併發架構稍微瞭解點的同學都會發現,這個系統的架構中,針對高併發的寫入這塊,還有一個比較關鍵的元件要加入,就是MQ。

因為我們如果應對的是高併發的非實時響應的寫入請求的話,完全可以使用MQ中介軟體先抗住海量的請求,接著做一箇中間的流量分發系統,將流量非同步轉發到kv儲存中去,同時這個流量分發系統可以對高併發流量進行控制。

比如說如果瞬時高併發的寫入真的導致後臺系統壓力過大,那麼就可以由流量分發系統自動根據我們設定的閾值進行流量控制,避免高併發的壓力打垮後臺系統。

而且在這個流控系統中,我們其實還做了很多的細節性的優化,比如說資料校驗、過濾無效資料、切分資料分片、資料同步的冪等機制、100%保證資料落地到kv叢集的機制保障,等等。

億級流量系統架構之如何設計承載百億流量的高效能架構【石杉的架構筆記】

公司的MQ叢集天然都支撐過大流量寫入以及高併發請求,因此MQ叢集那個層面抗住高併發並不是什麼問題,再高的併發按需擴容就可以了,然後我們自己的流控系統也是叢集部署的,線上採用的是4核8G的虛擬機器,因為這個機器不需要太高的配置。

流控系統,基本線上我們一般保持在每臺機器承載每秒小三千左右的併發請求,百億流量場景下,高峰每秒併發在每秒小几十萬的級別,因此這個流控叢集部署到幾十臺機器就足夠了。

而公司的kv叢集也是天然支撐過大流量高併發寫入的,因此kv叢集按需擴容,抗住高併發帶流量的寫入也不是什麼問題,而且這裡其實我們因為在自身架構層面做了大量的優化(儲存與計算分離的關鍵點),因此kv叢集的定位基本就是online storage,一個線上儲存罷了。

通過合理、巧妙的設計key以及value的資料型別,使得我們對kv叢集的讀寫請求都是優化成最最簡單的key-value的讀寫操作,天然保證高併發讀寫是沒問題的。

另外稍微給大家一點點的劇透,後面講到全鏈路99.99%高可用架構的時候,這個流控叢集會發揮巨大的作用,他是承上啟下的一個效果,前置的MQ叢集故障的高可用保障,以及後置的KV叢集故障的高可用保障,都是依靠流控叢集來實現的。

六、資料的動靜分離架構

在完成上述重構之後,我們又對核心的自研記憶體SQL計算引擎做了進一步的優化。因為實際生產環境執行過程中,我們發現了一個問題:就是每次如果Slave節點都是對一個資料分片提取相關聯的各種資料出來然後進行計算,其實是沒必要的!

給大家舉個例子,如果你的SQL要對一些表進行關聯計算,裡面涉及到了一些大部分時候靜態不變的資料,那些表的資料一般很少改變,因此沒必要每次都走網路請求從kv儲存裡提取那部分資料。

我們其實完全可以在Slave節點對這種靜態資料做個輕量級的cache,然後只有資料分片裡對應的動態改變的資料才從kv儲存來提取資料。

通過這個資料的動靜分離架構,我們基本上把Slave節點對kv叢集的網路請求降低到了最少,效能提升到了最高。大家看下面的圖。

億級流量系統架構之如何設計承載百億流量的高效能架構【石杉的架構筆記】

七、階段性總結

這套架構到此為止,基本上就演進的比較不錯了,因為超高併發寫入、極速高效能運算、按需任意擴容,等各種特性都可以支援到了,基本上從寫入到計算,這兩個步驟,是沒什麼太大的瓶頸了。

而且通過自研記憶體SQL計算引擎的方案,將我們的實時計算效能提升到了毫秒級的標準,基本已經達到極致。

八、下一步展望

下一步,我們就要看看這個架構中的左側,還有一個MySQL呢!

首先是實時計算鏈路和離線計算鏈路,都會匯入大量的計算結果到那個MySQL中。

其次面向數十萬甚至上百萬的B端商家時,如果是實時展示資料分析結果的話,一般頁面上會有定時的JS指令碼,每隔幾秒鐘就會傳送請求過來載入最新的資料計算結果。

因此實際上那個專門面向終端使用者的MySQL也會承受極大的資料量的壓力,高併發寫入的壓力以及高併發查詢的壓力。

下一篇文章,我們就聊聊《大型系統架構演進之如何設計每秒數十萬查詢的高併發架構》,將左側最後剩下的那個MySQL給徹底重構掉。

END


億級流量架構專欄:


一大波微服務、分散式、高併發、高可用原創系列

文章正在路上,歡迎掃描下方二維碼,持續關注:

億級流量系統架構之如何設計承載百億流量的高效能架構【石杉的架構筆記】

石杉的架構筆記(id:shishan100)

十餘年BAT架構經驗傾囊相授

推薦閱讀:

1、拜託!面試請不要再問我Spring Cloud底層原理

2、【雙11狂歡的背後】微服務註冊中心如何承載大型系統的千萬級訪問?

3、【效能優化之道】每秒上萬併發下的Spring Cloud引數優化實戰

4、微服務架構如何保障雙11狂歡下的99.99%高可用

5、兄弟,用大白話告訴你小白都能聽懂的Hadoop架構原理

6、大規模叢集下Hadoop NameNode如何承載每秒上千次的高併發訪問

7、【效能優化的祕密】Hadoop如何將TB級大檔案的上傳效能優化上百倍

8、拜託,面試請不要再問我TCC分散式事務的實現原理坑爹呀!

9、【坑爹呀!】最終一致性分散式事務如何保障實際生產中99.99%高可用?

10、拜託,面試請不要再問我Redis分散式鎖的實現原理!

11、【眼前一亮!】看Hadoop底層演算法如何優雅的將大規模叢集效能提升10倍以上?

12、億級流量系統架構之如何支撐百億級資料的儲存與計算

13、億級流量系統架構之如何設計高容錯分散式計算系統




相關文章