為了面試阿里、美團和位元組,我用12張圖就能講清楚分庫分表怎麼做!

語言: CN / TW / HK

文章來源: https://juejin.cn/post/7085132195190276109

目錄

  1. 什麼是分庫分表

  2. 為什麼需要分庫分表

  3. 如何分庫分表?

  4. 什麼時候開始考慮分庫分表

  5. 分庫分表會導致哪些問題

  6. 分庫分表中介軟體簡介

1. 什麼是分庫分表

分庫:就是一個數據庫分成多個數據庫,部署到不同機器。

分表:就是一個數據庫表分成多個表。

2. 為什麼需要分庫分表

2.1 為什麼需要分庫呢?

如果業務量劇增,資料庫可能會出現效能瓶頸,這時候我們就需要考慮拆分資料庫。從這幾方面來看:

  • 磁碟儲存

業務量劇增,MySQL單機磁碟容量會撐爆,拆成多個數據庫,磁碟使用率大大降低。

  • 併發連線支撐

我們知道資料庫連線是有限的。在高併發的場景下,大量請求訪問資料庫,MySQL單機是扛不住的!當前非常火的 微服務架構 出現,就是為了應對高併發。它把 訂單、使用者、商品 等不同模組,拆分成多個應用,並且把單個數據庫也拆分成多個不同功能模組的資料庫( 訂單庫、使用者庫、商品庫 ),以分擔讀寫壓力。

2.2 為什麼需要分表?

資料量太大的話,SQL的查詢就會變慢。如果一個查詢SQL 沒命中索引 ,千百萬資料量的表可能會拖垮這個資料庫。

即使SQL命中了索引,如果表的資料量 超過一千萬 的話, 查詢也是會明顯變慢的 。這是因為索引一般是B+樹結構,資料千萬級別的話,B+樹的高度會增高,查詢就變慢啦。

小夥伴們是否還記得,MySQL的B+樹的高度怎麼計算的呢?順便複習一下吧

InnoDB儲存引擎最小儲存單元是頁,一頁大小就是16k。B+樹葉子存的是資料,內部節點存的是鍵值+指標。索引組織表通過非葉子節點的二分查詢法以及指標確定資料在哪個頁中,進而再去資料頁中找到需要的資料,B+樹結構圖如下:

假設B+樹的高度為2的話,即有一個根結點和若干個葉子結點。這棵B+樹的存放總記錄數為=根結點指標數*單個葉子節點記錄行數。

  • 如果一行記錄的資料大小為1k,那麼單個葉子節點可以存的記錄數   =16k/1k =16 .

  • 非葉子節點記憶體放多少指標呢?我們假設主鍵ID為 bigint型別,長度為8位元組 ( 面試官問你int型別,一個int就是32位,4位元組 ),而指標大小在InnoDB原始碼中設定為6位元組,所以就是 8+6=14 位元組, 16k/14B =16*1024B/14B = 1170

因此,一棵高度為2的B+樹,能存放 1170 * 16=18720 條這樣的資料記錄。

同理一棵高度為 3 的B+樹,能存放 1170 *1170 *16 =21902400 ,大概可以存放兩千萬左右的記錄。B+樹高度一般為1-3層,如果B+到了4層,查詢的時候會 多查磁碟 的次數,SQL就會變慢。

因此單表資料量超過千萬,就需要考慮分表啦。

3. 如何分庫分表

3.1 垂直拆分

3.1.1 垂直分庫

在業務發展初期,業務功能模組比較少,為了快速上線和迭代,往往採用單個數據庫來儲存資料。資料庫架構如下:

但是隨著業務蒸蒸日上,系統功能逐漸完善。這時候,可以按照系統中的不同業務進行拆分,比如拆分成 使用者庫、訂單庫、積分庫、商品庫 ,把它們部署在不同的資料庫伺服器,這就是 垂直分庫

垂直分庫,將原來一個單資料庫的壓力分擔到不同的資料庫,可以很好應對高併發場景。資料庫垂直拆分後的架構如下:

3.1.2 垂直分表

如果一個單表包含了幾十列甚至上百列,管理起來很混亂,每次都 select * 的話,還佔用IO資源。這時候,我們可以將一些 不常用的、資料較大或者長度較長的列 拆分到另外一張表。

比如一張使用者表,它包含 user_id、user_name、mobile_no、age、email、nickname、address、user_desc ,如果 email、address、user_desc 等欄位不常用,我們可以把它拆分到另外一張表,命名為使用者詳細資訊表。這就是垂直分表

3.2 水平拆分

3.2.1 水平分庫

水平分庫是指,將表的資料量切分到不同的資料庫伺服器上,每個伺服器具有相同的庫和表,只是表中的資料集合不一樣。它可以有效的緩解單機單庫的效能瓶頸和壓力。

使用者庫的水平拆分架構如下:

3.2.2 水平分表

如果一個表的資料量太大,可以按照某種規則(如 hash取模、range ),把資料切分到多張表去。

一張訂單表,按 時間range 拆分如下:

3.3. 水平分庫分表策略

分庫分表策略一般有幾種,使用與不同的場景:

  • range範圍

  • hash取模

  • range+hash取模混合

3.3.1 range範圍

range,即範圍策略劃分表。比如我們可以將表的主鍵,按照從 0~1000萬 的劃分為一個表, 1000~2000萬 劃分到另外一個表。如下圖:

當然,有時候我們也可以按時間範圍來劃分,如不同年月的訂單放到不同的表,它也是一種range的劃分策略。

這種方案的優點:

  • 這種方案有利於擴容,不需要資料遷移。假設資料量增加到5千萬,我們只需要水平增加一張表就好啦,之前 0~4000萬 的資料,不需要遷移。

缺點:

  • 這種方案會有熱點問題,因為訂單id是一直在增大的,也就是說最近一段時間都是匯聚在一張表裡面的。比如最近一個月的訂單都在 1000萬~2000 萬之間,平時使用者一般都查最近一個月的訂單比較多,請求都打到 order_1 表啦,這就導致表的 資料熱點 問題。

3.3.2 hash取模

hash取模策略:指定的路由key(一般是user_id、訂單id作為key)對分表總數進行取模,把資料分散到各個表中。

比如原始訂單表資訊,我們把它分成4張分表:

  • 比如id=1,對4取模,就會得到1,就把它放到第1張表,即 t_order_0 ;

  • id=3,對4取模,就會得到3,就把它放到第3張表,即 t_order_2 ;

這種方案的優點:

  • hash取模的方式,不會存在明顯的熱點問題。

缺點:

  • 如果一開始按照hash取模分成4個表了,未來某個時候,表資料量又到瓶頸了,需要擴容,這就比較棘手了。比如你從4張表,又擴容成 8 張表,那之前 id=5 的資料是在( 5%4=1 ,即第一張表),現在應該放到( 5%8=5 ,即第 5 張表),也就是說 歷史資料要做遷移了

3.3.3 range+hash取模混合

既然range存在熱點資料問題,hash取模擴容遷移資料比較困難,我們可以綜合兩種方案一起嘛,取之之長,棄之之短。

比較簡單的做法就是,在拆分庫的時候,我們可以先用 range範圍 方案,比如訂單id在0 4000萬的區間,劃分為訂單庫1,id在4000萬 8000萬的資料,劃分到訂單庫2,將來要擴容時,id在8000萬~1.2億的資料,劃分到訂單庫3。然後訂單庫內,再用 hash取模 的策略,把不同訂單劃分到不同的表。

4. 什麼時候才考慮分庫分表呢?

4.1 什麼時候分表?

如果你的系統處於快速發展時期,如果每天的訂單流水都新增幾十萬,並且,訂單表的查詢效率明變慢時,就需要規劃分庫分表了。 一般B+樹索引高度是2~3層最佳,如果資料量千萬級別,可能高度就變4層了,資料量就會明顯變慢了。 不過業界流傳,一般500萬資料就要 考慮分表 了。

4.2 什麼時候分庫

業務發展很快,還是多個服務共享一個單體資料庫,資料庫成為了效能瓶頸,就需要考慮分庫了。 比如訂單、使用者等,都可以抽取出來,新搞個應用(其實就是微服務思想),並且拆分資料庫(訂單庫、使用者庫)。

5. 分庫分表會導致哪些問題

分庫分表之後,也會存在一些問題:

  • 事務問題

  • 跨庫關聯

  • 排序問題

  • 分頁問題

  • 分散式ID

5.1 事務問題

分庫分表後,假設兩個表在不同的資料庫,那麼本地事務已經無效啦,需要使用分散式事務了。

5.2 跨庫關聯

跨節點Join的問題: 解決這一問題可以分兩次查詢實現

5.3 排序問題

跨節點的count,order by,group by以及聚合函式等問題: 可以分別在各個節點上得到結果後在應用程式端進行合併。

5.4 分頁問題

  • 方案1:在個節點查到對應結果後,在程式碼端匯聚再分頁。

  • 方案2:把分頁交給前端,前端傳來pageSize和pageNo,在各個資料庫節點都執行分頁,然後匯聚總數量前端。這樣缺點就是會造成空查,如果分頁需要排序,也不好搞。

5.5 分散式ID

據庫被切分後,不能再依賴資料庫自身的主鍵生成機制啦,最簡單可以考慮UUID,或者使用雪花演算法生成分散式ID。

6. 分庫分表中介軟體

目前流行的分庫分表中介軟體比較多:

  • cobar

  • Mycat

  • Sharding-JDBC

  • Atlas

  • TDDL(淘寶)

  • vitess

歡迎掃碼加入儒猿技術交流群,每天晚上20:00都有Java面試、Redis、MySQL、RocketMQ、SpringCloudAlibaba、Java架構等技術答疑分享,更能跟小夥伴們一起交流技術

另外推薦儒猿課堂的1元系列課程給您,歡迎加入一起學習~

網際網路Java工程師面試突擊課

(1元專享)

SpringCloudAlibaba零基礎入門到專案實戰

(1元專享)

億級流量下的電商詳情頁系統實戰專案

(1元專享)

Kafka訊息中介軟體核心原始碼精講

(1元專享)

12個實戰案例帶你玩轉Java併發程式設計

(1元專享)

Elasticsearch零基礎入門到精通

(1元專享)

基於Java手寫分散式中介軟體系統實戰

(1元專享)

基於ShardingSphere的分庫分表實戰課

(1元專享)