支撐日活百萬用戶的高併發系統,應該如何設計其數據庫架構?

目錄:sql

  • 用一個創業公司的發展做爲背景引入
  • 用多臺服務器來分庫支撐高併發讀寫
  • 大量分表來保證海量數據下查詢性能
  • 讀寫分離來支撐按需擴容及性能提高
  • 高併發下的數據庫架構設計總結

 

「 這篇文章,咱們來聊一下對於一個支撐日活百萬用戶的高並系統,他的數據庫架構應該如何設計?數據庫

看到這個題目,不少人第一反應就是:安全

分庫分表啊!服務器

可是實際上,數據庫層面的分庫分表究竟是用來幹什麼的,他的不一樣的做用如何應對不一樣的場景,我以爲不少同窗可能都沒搞清楚。網絡


(1)用一個創業公司的發展做爲背景引入架構

假如咱們如今是一個小創業公司,註冊用戶就20萬,天天活躍用戶就1萬,天天單表數據量就1000,而後高峯期每秒鐘併發請求最多就10。併發

天哪!就這種系統,隨便找一個有幾年工做經驗的高級工程師,而後帶幾個年輕工程師,隨便乾乾均可以作出來。分佈式

由於這樣的系統,實際上主要就是在前期快速的進行業務功能的開發,搞一個單塊系統部署在一臺服務器上,而後鏈接一個數據庫就能夠了。高併發

接着你們就是不停的在一個工程裏填充進去各類業務代碼,儘快把公司的業務支撐起來,以下圖所示。性能

 

 

 

 

結果呢,沒想到咱們運氣這麼好,碰上個優秀的CEO帶着咱們走上了康莊大道!

公司業務發展迅猛,過了幾個月,註冊用戶數達到了2000萬!天天活躍用戶數100萬!天天單表新增數據量達到50萬條!高峯期每秒請求量達到1萬!

同時公司還順帶着融資了兩輪,估值達到了驚人的幾億美金!一隻朝氣蓬勃的幼年獨角獸的節奏!

好吧,如今你們感受壓力已經有點大了,爲啥呢?

由於天天單表新增50萬條數據,一個月就多1500萬條數據,一年下來單表會達到上億條數據。

通過一段時間的運行,如今我們單表已經兩三千萬條數據了,勉強還能支撐着。

可是,眼見着系統訪問數據庫的性能怎麼愈來愈差呢,單表數據量愈來愈大,拖垮了一些複雜查詢SQL的性能啊!

而後高峯期請求如今是每秒1萬,我們的系統在線上部署了20臺機器,平均每臺機器每秒支撐500請求,這個還能抗住,沒啥大問題。

可是數據庫層面呢?

若是說此時你仍是一臺數據庫服務器在支撐每秒上萬的請求,負責任的告訴你,每次高峯期會出現下述問題:

  • 你的數據庫服務器的磁盤IO、網絡帶寬、CPU負載、內存消耗,都會達到很是高的狀況,數據庫所在服務器的總體負載會很是重,甚至都快不堪重負了

 

  • 高峯期時,原本你單表數據量就很大,SQL性能就不太好,這時加上你的數據庫服務器負載過高致使性能降低,就會發現你的SQL性能更差了

 

  • 最明顯的一個感受,就是你的系統在高峯期各個功能都運行的很慢,用戶體驗不好,點一個按鈕可能要幾十秒纔出來結果

 

  • 若是你運氣不太好,數據庫服務器的配置不是特別的高的話,弄很差你還會經歷數據庫宕機的狀況,由於負載過高對數據庫壓力太大了

 


(2)多臺服務器分庫支撐高併發讀寫

首先咱們先考慮第一個問題,數據庫每秒上萬的併發請求應該如何來支撐呢?

要搞清楚這個問題,先得明白通常數據庫部署在什麼配置的服務器上。

一般來講,假如你用普通配置的服務器來部署數據庫,那也起碼是16核32G的機器配置。

這種很是普通的機器配置部署的數據庫,通常線上的經驗是:不要讓其每秒請求支撐超過2000,通常控制在2000左右。

控制在這個程度,通常數據庫負載相對合理,不會帶來太大的壓力,沒有太大的宕機風險。

因此首先第一步,就是在上萬併發請求的場景下,部署個5臺服務器,每臺服務器上都部署一個數據庫實例。

而後每一個數據庫實例裏,都建立一個同樣的庫,好比說訂單庫。

此時在5臺服務器上都有一個訂單庫,名字能夠相似爲:db_order_01,db_order_02,等等。

而後每一個訂單庫裏,都有一個相同的表,好比說訂單庫裏有訂單信息表,那麼此時5個訂單庫裏都有一個訂單信息表。

好比db_order_01庫裏就有一個tb_order_01表,db_order_02庫裏就有一個tb_order_02表。

這就實現了一個基本的分庫分表的思路,原來的一臺數據庫服務器變成了5臺數據庫服務器,原來的一個庫變成了5個庫,原來的一張表變成了5個表。

而後你在寫入數據的時候,須要藉助數據庫中間件,好比sharding-jdbc,或者是mycat,均可以。

你能夠根據好比訂單id來hash後按5取模,好比天天訂單表新增50萬數據,此時其中10萬條數據會落入db_order_01庫的tb_order_01表,另外10萬條數據會落入db_order_02庫的tb_order_02表,以此類推。

這樣就能夠把數據均勻分散在5臺服務器上了,查詢的時候,也能夠經過訂單id來hash取模,去對應的服務器上的數據庫裏,從對應的表裏查詢那條數據出來便可。

依據這個思路畫出的圖以下所示,你們能夠看看。

 

 

 

 

作這一步有什麼好處呢?

第一個好處,原來好比訂單表就一張表,這個時候不就成了5張表了麼,那麼每一個表的數據就變成1/5了。

假設訂單表一年有1億條數據,此時5張表裏每張表一年就2000萬數據了。

那麼假設當前訂單表裏已經有2000萬數據了,此時作了上述拆分,每一個表裏就只有400萬數據了。

並且天天新增50萬數據的話,那麼每一個表才新增10萬數據,這樣是否是初步緩解了單表數據量過大影響系統性能的問題?

另外就是每秒1萬請求到5臺數據庫上,每臺數據庫就承載每秒2000的請求,是否是一會兒把每臺數據庫服務器的併發請求下降到了安全範圍內?

這樣,下降了數據庫的高峯期負載,同時還保證了高峯期的性能。


(3)大量分表來保證海量數據下的查詢性能

可是上述的數據庫架構還有一個問題,那就是單表數據量仍是過大,如今訂單表才分爲了5張表,那麼若是訂單一年有1億條,每一個表就有2000萬條,這也仍是太大了。

因此還應該繼續分表,大量分表。

好比能夠把訂單表一共拆分爲1024張表,這樣1億數據量的話,分散到每一個表裏也就才10萬量級的數據量,而後這上千張表分散在5臺數據庫裏就能夠了。

在寫入數據的時候,須要作兩次路由,先對訂單id hash後對數據庫的數量取模,能夠路由到一臺數據庫上,而後再對那臺數據庫上的表數量取模,就能夠路由到數據庫上的一個表裏了。

經過這個步驟,就可讓每一個表裏的數據量很是小,每一年1億數據增加,可是到每一個表裏才10萬條數據增加,這個系統運行10年,每一個表裏可能才百萬級的數據量。

這樣能夠一次性爲系統將來的運行作好充足的準備,看下面的圖,一塊兒來感覺一下:

 

 

 

 


(4)讀寫分離來支撐按需擴容以及性能提高

這個時候總體效果已經挺不錯了,大量分表的策略保證可能將來10年,每一個表的數據量都不會太大,這能夠保證單表內的SQL執行效率和性能。

而後多臺數據庫的拆分方式,能夠保證每臺數據庫服務器承載一部分的讀寫請求,下降每臺服務器的負載。

可是此時還有一個問題,假如說每臺數據庫服務器承載每秒2000的請求,而後其中400請求是寫入,1600請求是查詢。

也就是說,增刪改的SQL才佔到了20%的比例,80%的請求是查詢。

此時假如說隨着用戶量愈來愈大,假如說又變成每臺服務器承載4000請求了。

那麼其中800請求是寫入,3200請求是查詢,若是說你按照目前的狀況來擴容,就須要增長一臺數據庫服務器.

可是此時可能就會涉及到表的遷移,由於須要遷移一部分表到新的數據庫服務器上去,是否是很麻煩?

其實徹底不必,數據庫通常都支持讀寫分離,也就是作主從架構。

寫入的時候寫入主數據庫服務器,查詢的時候讀取從數據庫服務器,就可讓一個表的讀寫請求分開落地到不一樣的數據庫上去執行。

這樣的話,假如寫入主庫的請求是每秒400,查詢從庫的請求是每秒1600,那麼圖大概以下所示。

 

 

 

寫入主庫的時候,會自動同步數據到從庫上去,保證主庫和從庫數據一致。

而後查詢的時候都是走從庫去查詢的,這就經過數據庫的主從架構實現了讀寫分離的效果了。

如今的好處就是,假如說如今主庫寫請求增長到800,這個無所謂,不須要擴容。而後從庫的讀請求增長到了3200,須要擴容了。

這時,你直接給主庫再掛載一個新的從庫就能夠了,兩個從庫,每一個從庫支撐1600的讀請求,不須要由於讀請求增加來擴容主庫。

實際上線上生產你會發現,讀請求的增加速度遠遠高於寫請求,因此讀寫分離以後,大部分時候就是擴容從庫支撐更高的讀請求就能夠了。

並且另一點,對同一個表,若是你既寫入數據(涉及加鎖),還從該表查詢數據,可能會牽扯到鎖衝突等問題,不管是寫性能仍是讀性能,都會有影響。

因此一旦讀寫分離以後,對主庫的表就僅僅是寫入,沒任何查詢會影響他,對從庫的表就僅僅是查詢。


(5)高併發下的數據庫架構設計總結

其實從大的一個簡化的角度來講,高併發的場景下,數據庫層面的架構確定是須要通過精心的設計的。

尤爲是涉及到分庫來支撐高併發的請求,大量分表保證每一個表的數據量別太大,讀寫分離實現主庫和從庫按需擴容以及性能保證。

這篇文章就是從一個大的角度來梳理了一下思路,各位同窗能夠結合本身公司的業務和項目來考慮本身的系統如何作分庫分表應該怎麼作。

另外就是,具體的分庫分表落地的時候,須要藉助數據庫中間件來實現分庫分表和讀寫分離,你們能夠本身參考 sharding-jdbc 或者 mycat 的官網便可,裏面的文檔都有詳細的使用描述。

End

歡迎工做一到五年的Java工程師朋友們加入Java高級架構:964357187 羣內提供免費的Java架構學習資料(裏面有高可用、高併發、高性能及分佈式、Jvm性能調優、Spring源碼,MyBatis,Netty,Redis,Kafka,Mysql,Zookeeper,Tomcat,Docker,Dubbo,Nginx等多個知識點的架構資料)合理利用本身每一分每一秒的時間來學習提高本身,不要再用"沒有時間「來掩飾本身思想上的懶惰!趁年輕,使勁拼,給將來的本身一個交代!

相關文章
相關標籤/搜索