前言
由於資料庫的承載能力是有限的,當業務增長量達到一定規模後,資料庫的效能就會達到瓶頸。於是產生了分庫分表的解決方案,本文將詳細講解什麼是分庫分表,以及分庫分表的原因和可能產生的問題。
一、為什麼要分庫分表?
1. 分庫的原因
資料庫的關鍵效能指標主要有磁碟空間、記憶體、CPU。在資料庫配置無法升級的情況下,當資料量過大可能產生如下的一些問題:
磁碟空間不足,資料庫將無法進行增刪改等操作;
CPU 或記憶體不足,則可能導致讀寫效能低產生慢 SQL,進而導致資料庫連結池被打滿、記憶體溢位等問題。
這時就需要進行分庫操作,來保證資料庫的穩定和效能。
2. 分表的原因
由於資料庫的承載能力是有限的,當業務增長量達到一定規模後,資料庫的效能就會達到瓶頸。就拿使用最多的 MySQL 來進行說明。
MySQL 的預設引擎是 InnoDB,資料是存在聚簇索引中,而聚簇索引的底層數據結構是 B+ Tree,即使 B+Tree 已經在 B Tree 的基礎上最佳化了空間利用率,但是隨著資料規模的增大,樹的高度也會達到一定規模,高度能夠決定磁碟IO的次數,磁碟IO次數越多,對於效能就會越低。
3. 微服務架構
現在大部分公司的系統架構都已是分散式系統和微服務架構,根據公司的業務劃分,分解為功能單一的資料庫。此時會需要進行分庫分表操作。
二、資料量多大才需要分庫分表?
如下圖,根據阿里開發手冊中描述,單表超 500 萬行,或容量超 2GB 時推薦分庫分表。但是具體的情況還是需要根據業務需求、資料庫硬體配置、CPU 效能等方面綜合評估。
除此之外,要想詳細的估算出資料量的瓶頸,還需要根據表的結構以及索引情況,表的欄位不同的型別佔用的大小也不同,故每條資料佔用的大小也不同, B+Tree 每一層的儲存資料量的大小也會發生變化。
綜上,資料量多大需要根據自身情況去評估,並不一定是網上所說的 1000 萬,也不一定是阿里所說的大於 500 萬,這就是有些企業單表資料即使超過幾千萬仍可穩定執行的原因。
三、什麼是分庫分表?
1. 分庫
將資料庫中的表按照某種規則拆分到多個數據庫中,來保證系統的穩定和效能。
如圖,將 DataBase 中的 2 張表拆分成 trade 庫和 acount 庫,分別存 order 表和 acount 表。
2. 分表
將表中資料按照某種規則拆分到多張表中,提升查詢效率。
如圖,將 order 表拆分成 order_shanghai 和 order_beijing,分別存上海和北京的訂單資料。
四、如何分庫分表?
分庫分表的核心就是資料切分(Sharding),以及切分後對資料的快速定位與結果整合,從而到提升資料庫操作效能的目的。分庫分表可以從垂直和水平兩種緯度進行拆分。
1. 垂直拆分
垂直拆分包含垂直分庫和垂直分表。
1.1 垂直分庫
垂直分庫指的是,將某個庫中的表拆分到多個庫,每個庫包含的表不一樣。一般主要是按照業務維度進行拆分,不同的業務資料放到對應的資料庫中,核心理念是轉庫專用,這也是微服務拆分的一個重要依據。
如圖,在電商系統中,主要包含的業務有商品、使用者、支付、庫存等,在對資料庫進行劃分時,每個業務對應一個數據庫。
垂直分庫優點:
降低單資料庫服務的壓力,增加系統可用性;
業務清晰,各系統間解耦合;
提升 IO 效能,增加資料庫連結數以及其他硬體的瓶頸。
垂直分庫缺點:
不同庫之間的資料一致性無法保證,需要透過分散式事務;
依然存在單庫、單表資料過大的問題,需要結合水平拆分;
1.2 垂直分表
垂直分表指將存在一張表中的不同欄位拆分為多張表,是一種大表拆小表的模式。拆分後的表字段、結構均不同,組合一起則是原表。
一般是將經常修改的、資料較大的、不常查詢的欄位拆分到“擴充套件表”中,這樣拆分以後核心表大多是訪問頻率較高的欄位,而且欄位長度也都較短,減少了查詢時的磁碟 IO,提升資料庫效率。
如下圖,我們在進行下單時一般需要儲存快照資訊,該欄位有長且不常使用,故拆分出來可提高訂單資訊的查詢效率。
垂直分表優點:
降低表的資料規模,提升效率;
減少單條資料佔用空間,減少磁碟 IO。
垂直分表缺點: 依然存在單表資料過大的問題,需要結合水平拆分;
2. 水平拆分
水平拆分包含水平分庫和水平分表。
2.1 水平分庫
水平分庫是將資料庫中的表資料按照某種規則拆分到多個庫中,以實現水平擴充套件,提升資料庫讀寫效能。
一般切分到不同的庫中的表結構是相同的,表中資料不同,且伴隨水平分表。
如下圖,將DB-trade庫中的 order 表水平切分到DB-trade 1和DB-trade 2庫中。
水平分庫優點:
極大降低單庫資料規模,提高系統高併發能力;
業務程式碼改動小,不需要拆分業務。
水平分庫缺點:
跨庫的 join 關聯查詢效能較差,增加開發複雜度;
單庫的自增 ID 受影響。
2.2 水平分表
水平分表是將資料按照某種規則拆分到多張表,多張表還是屬於一個庫且結構相同。大大減少單表資料量,提升查詢效率,但是對資料庫的壓力沒有幫助。
如下圖,一張 order 訂單表有 400 萬資料,經過水平拆分出來 2 個表 order_1 和 order_2,每張表存有資料 200萬,以此類推。
水平分表優點:
大大減少單表資料量,提升查詢效率;
業務程式碼改動小,不需要拆分業務。
水平分表缺點: 多張表屬於一個庫,資料庫的壓力仍存在。
五、分庫分表可能有哪些問題?
1. 事務問題
分庫可能導致一次事務的執行的資料不在同一個伺服器上,資料庫層面無法實現所有服務的事務操作。可能會產生資料不一致的情況。
解決方案是透過分散式事務,來能最大限度保證了資料庫操作的原子性,詳情見我的另一篇文章分散式事務。
2. 主鍵唯一性問題
在資料庫表設計時,經常會使用自增ID作為資料主鍵,這就導致後續在遷庫遷表、或者分庫分表操作時,會因為主鍵的變化或者主鍵不唯一產生衝突。
解決方案是透過一些策略生成全域性唯一的分散式 ID。
3. 跨庫多表join問題
拆分之前,應用中很多列表或詳情的資料可以透過 join 來完成,但是分庫拆分後,資料可能分佈在不同的伺服器上,這種跨節點的 join 會有很多問題。
解決方案是避免掛庫多表 join 的產生:
可以採用多次查詢業務層進行資料組裝;
將存在關聯關係的表拆分在同一資料庫下;
欄位冗餘避免 join 查詢。
4. 跨庫聚合查詢問題
跨庫進行聚合查詢時,如 group by,order by 等,會變的異常複雜,導致常需要複雜的業務程式碼才能實現上述業務邏輯。
解決方案有:
業務程式碼中分別查詢,然後組裝資料(可能需要用一些排序演算法最佳化效率);
使用專業的分散式框架,比如開源框架:ElasticSearch;
結語
本文主要講述的是我們在開發過程中為什麼需要分庫分表,以及分庫分表的場景、方案和可能出現的問題。因為一些內容的擴充套件點還有很多,放在一起影響閱讀,本文只是簡單的講述了分庫分表的一些基礎知識,後續會針對分庫分表分片方案、常用中介軟體的原理和使用,以及如何完整落地一個分庫分表方案進行開展。
參考: