讀寫分離優化了互聯網讀多寫少場景下的性能問題,考慮一個業務場景,如果讀庫的數據規模非常大,除了增加多個從庫之外,還有其他的手段嗎?實現數據庫高可用,還有另外一個撒手鐧,就是分庫分表。
為什么要分庫分表
一般Mysql一個單庫最多支持並發量到2000,且最好保持在1000。如果有20000並發量的需求,這時就需要擴容了,可以將一個庫的數據拆分到多個庫中,訪問的時候根據一定條件訪問單庫,緩解單庫的性能壓力。
分表也是一樣的,如果單表的數據量太大,就會影響SQL語句的執行性能。分表就是按照一定的策略將單表的數據拆分到多個表中,查詢的時候也按照一定的策略去查詢對應的表,這樣就將一次查詢的數據范圍縮小了。比如按照用戶id來分表,將一個用戶的數據就放在一個表中,crud先通過用戶id找到那個表在進行操作就可以了。這樣就把每個表的數據量控制在一定范圍內,提升SQL語句的執行性能。
分庫分表原理
分庫分表,顧名思義,就是將原本存儲於單個數據庫上的數據拆分到多個數據庫,把原來存儲在單張數據表的數據拆分到多張數據表中,實現數據切分,從而提升數據庫操作性能。分庫分表的實現可以分為兩種方式:垂直切分和水平切分。
垂直切分
垂直拆分一般是按照業務和功能的維度進行拆分,把數據分別放到不同的數據庫中。

水平切分
水平拆分是把相同的表結構分散到不同的數據庫和不同的數據表中,避免訪問集中的單個數據庫或者單張數據表,具體的分庫和分表規則,一般是通過業務主鍵,進行哈希取模操作。
例如,電商業務中的訂單信息訪問頻繁,可以將訂單表分散到多個數據庫中,實現分庫;在每個數據庫中,繼續進行拆分到多個數據表中,實現分表。路由策略可以使用訂單 ID 或者用戶 ID,進行取模運算,路由到不同的數據庫和數據表中。

分庫分表后引入的問題
下面看一下,引入分庫分表后額外增加了哪些系統設計的問題。
1)分布式事務問題
對業務進行分庫之后,同一個操作會分散到多個數據庫中,涉及跨庫執行 SQL 語句,也就出現了分布式事務問題。
比如數據庫拆分后,訂單和庫存在兩個庫中,一個下單減庫存的操作,就涉及跨庫事務。關於分布式事務的處理,我們在專欄“分布式事務”的模塊中也介紹過,可以使用分布式事務中間件,實現 TCC 等事務模型;也可以使用基於本地消息表的分布式事務實現。如果對這部分印象不深,你可以回顧下前面講過的內容。
2)跨庫關聯查詢問題
分庫分表后,跨庫和跨表的查詢操作實現起來會比較復雜,性能也無法保證。在實際開發中,針對這種需要跨庫訪問的業務場景,一般會使用額外的存儲,比如維護一份文件索引。另一個方案是通過合理的數據庫字段冗余,避免出現跨庫查詢。
3)跨庫跨表的合並和排序問題
分庫分表以后,數據分散存儲到不同的數據庫和表中,如果查詢指定數據列表,或者需要對數據列表進行排序時,就變得異常復雜,則需要在內存中進行處理,整體性能會比較差,一般來說,會限制這類型的操作。具體的實現,可以依賴開源的分庫分表中間件來處理。
分庫分表常見的中間件
1)cobar
cobar是阿里的b2b團隊開發和開源的,屬於proxy層方案,介於應用服務器和數據庫服務器之間。應用程序通過JDBC驅動訪問cobar集群,cobar根據SQL和分庫規則對SQL做分解,然后分發到MySQL集群不同的數據庫實例上執行。cobar並不支持讀寫分離、存儲過程、跨庫join和分頁等操作。早些年還可以用,但是最近幾年都沒更新了,基本沒啥人用,算是淘汰了。
2)TDDL
TDDL是淘寶團隊開發的,屬於client層方案。支持基本的crud語法和讀寫分離,但是並不支持join、多表查詢等語法。目前使用的也不多,因為使用還需要依賴淘寶的diamond配置管理系統。
3)atlas
atlas是360開源的,屬於proxy層方案。以前是有一些公司再用的,但是社區最新的維護都在5年前了,現在用的公司也基本沒有了。
4)sharding-jdbc
sharding-jdbc是當當開源的,屬於client層方案。這個中間件對SQL語法的支持比較多,沒有太多限制。2.0版本也開始支持分庫分表、讀寫分離、分布式id生成、柔性事務(最大努力送達型事務、TCC事務)。目前社區也還一直在開發和維護,算是比較活躍,是一個現在也可以選擇的方案。
5)mycat
mycat是基於cobar改造的,屬於proxy層方案。其支持的功能十分完善,是目前非常火的一個數據庫中間件。社區很活躍,不斷在更新。
