分布式技術(shù)原理與實(shí)戰(zhàn)45講--第21講:為什么需要分庫分表,如何實(shí)現(xiàn)
你好,歡迎來到第 21 課時(shí),本課時(shí)我們主要講解“為什么需要分庫分表,如何實(shí)現(xiàn)”。
在上一課時(shí)中講到了讀寫分離,讀寫分離優(yōu)化了互聯(lián)網(wǎng) 讀多寫少 場(chǎng)景下的性能問題,考慮一個(gè)業(yè)務(wù)場(chǎng)景,如果讀庫的數(shù)據(jù)規(guī)模非常大,除了增加多個(gè)從庫之外,還有其他的手段嗎?
方法總比問題多,實(shí)現(xiàn) 數(shù)據(jù)庫高可用,還有另外一個(gè)撒手锏,就是 分庫分表,分庫分表也是面試的常客,今天一起來看一下相關(guān)的知識(shí)。
分庫分表的背景
互聯(lián)網(wǎng)業(yè)務(wù)的一個(gè)特點(diǎn)就是用戶量巨大,BAT等頭部公司都是億級(jí)用戶,產(chǎn)生的數(shù)據(jù)規(guī)模也飛速增長(zhǎng),傳統(tǒng)的單庫單表架構(gòu)不足以支撐業(yè)務(wù)發(fā)展,存在下面的性能瓶頸:
讀寫的數(shù)據(jù)量限制
數(shù)據(jù)庫的數(shù)據(jù)量增大會(huì)直接影響讀寫的性能,比如一次查詢操作,掃描 5 萬條數(shù)據(jù)和 500 萬條數(shù)據(jù),查詢速度肯定是不同的。
關(guān)于 MySQL 單庫和單表的數(shù)據(jù)量限制,和不同的服務(wù)器配置,以及不同結(jié)構(gòu)的數(shù)據(jù)存儲(chǔ)有關(guān),并沒有一個(gè)確切的數(shù)字。這里參考阿里巴巴的《Java 開發(fā)手冊(cè)》中數(shù)據(jù)庫部分的建表規(guī)約:
單表行數(shù)超過 500 萬行或者單表容量超過 2GB,才推薦進(jìn)行分庫分表。
基于阿里巴巴的海量業(yè)務(wù)數(shù)據(jù)和多年實(shí)踐,這一條數(shù)據(jù)庫規(guī)約,可以認(rèn)為是數(shù)據(jù)庫應(yīng)用中的一個(gè)最佳實(shí)踐。也就是在新業(yè)務(wù)建表規(guī)劃時(shí),或者當(dāng)前數(shù)據(jù)庫單表已經(jīng)超過對(duì)應(yīng)的限制,可以進(jìn)行分庫分表,同時(shí)也要避免過度設(shè)計(jì)。因?yàn)榉謳旆直黼m然可以提高性能,但是盲目地進(jìn)行分庫分表只會(huì)增加系統(tǒng)的復(fù)雜度。
數(shù)據(jù)庫連接限制
數(shù)據(jù)庫的連接是有限制的,不能無限制創(chuàng)建,比如 MySQL 中可以使用 max_connections 查看默認(rèn)的最大連接數(shù),當(dāng)訪問連接數(shù)過多時(shí),就會(huì)導(dǎo)致連接失敗。以電商為例,假設(shè)存儲(chǔ)沒有進(jìn)行分庫,用戶、商品、訂單和交易,所有的業(yè)務(wù)請(qǐng)求都訪問同一個(gè)數(shù)據(jù)庫,產(chǎn)生的連接數(shù)是非常可觀的,可能導(dǎo)致數(shù)據(jù)庫無法支持業(yè)務(wù)請(qǐng)求。
使用數(shù)據(jù)庫連接池,可以優(yōu)化連接數(shù)問題,但是更好的方式是通過分庫等手段,避免數(shù)據(jù)庫連接成為業(yè)務(wù)瓶頸。
除了這些,如果不進(jìn)行數(shù)據(jù)庫拆分,大量數(shù)據(jù)訪問都集中在單臺(tái)機(jī)器上,對(duì)磁盤 IO、CPU 負(fù)載等都會(huì)產(chǎn)生很大的壓力,并且直接影響業(yè)務(wù)操作的性能。
分庫分表原理
分庫分表,顧名思義,就是將原本存儲(chǔ)于單個(gè)數(shù)據(jù)庫上的數(shù)據(jù)拆分到多個(gè)數(shù)據(jù)庫,把原來存儲(chǔ)在單張數(shù)據(jù)表的數(shù)據(jù)拆分到多張數(shù)據(jù)表中,實(shí)現(xiàn)數(shù)據(jù)切分,從而提升數(shù)據(jù)庫操作性能。分庫分表的實(shí)現(xiàn)可以分為兩種方式:垂直切分和水平切分。
垂直切分
垂直拆分一般是按照業(yè)務(wù)和功能的維度進(jìn)行拆分,把數(shù)據(jù)分別放到不同的數(shù)據(jù)庫中。

垂直分庫針對(duì)的是一個(gè)系統(tǒng)中對(duì)不同的業(yè)務(wù)進(jìn)行拆分,根據(jù)業(yè)務(wù)維度進(jìn)行數(shù)據(jù)的分離,剝離為多個(gè)數(shù)據(jù)庫。比如電商網(wǎng)站早期,商品數(shù)據(jù)、會(huì)員數(shù)據(jù)、訂單數(shù)據(jù)都是集中在一個(gè)數(shù)據(jù)庫中,隨著業(yè)務(wù)的發(fā)展,單庫處理能力已成為瓶頸,這個(gè)時(shí)候就需要進(jìn)行相關(guān)的優(yōu)化,進(jìn)行業(yè)務(wù)維度的拆分,分離出會(huì)員數(shù)據(jù)庫、商品數(shù)據(jù)庫和訂單數(shù)據(jù)庫等。
垂直分表是針對(duì)業(yè)務(wù)上的字段比較多的大表進(jìn)行的,一般是把業(yè)務(wù)寬表中比較獨(dú)立的字段,或者不常用的字段拆分到單獨(dú)的數(shù)據(jù)表中。比如早期的商品表中,可能包含了商品信息、價(jià)格、庫存等,可以拆分出來價(jià)格擴(kuò)展表、庫存擴(kuò)展表等。
水平切分
水平拆分是把相同的表結(jié)構(gòu)分散到不同的數(shù)據(jù)庫和不同的數(shù)據(jù)表中,避免訪問集中的單個(gè)數(shù)據(jù)庫或者單張數(shù)據(jù)表,具體的分庫和分表規(guī)則,一般是通過業(yè)務(wù)主鍵,進(jìn)行哈希取模操作。
例如,電商業(yè)務(wù)中的訂單信息訪問頻繁,可以將訂單表分散到多個(gè)數(shù)據(jù)庫中,實(shí)現(xiàn)分庫;在每個(gè)數(shù)據(jù)庫中,繼續(xù)進(jìn)行拆分到多個(gè)數(shù)據(jù)表中,實(shí)現(xiàn)分表。路由策略可以使用訂單 ID 或者用戶 ID,進(jìn)行取模運(yùn)算,路由到不同的數(shù)據(jù)庫和數(shù)據(jù)表中。

分庫分表后引入的問題
下面看一下,引入分庫分表后額外增加了哪些系統(tǒng)設(shè)計(jì)的問題。
分布式事務(wù)問題
對(duì)業(yè)務(wù)進(jìn)行分庫之后,同一個(gè)操作會(huì)分散到多個(gè)數(shù)據(jù)庫中,涉及跨庫執(zhí)行 SQL 語句,也就出現(xiàn)了分布式事務(wù)問題。
比如數(shù)據(jù)庫拆分后,訂單和庫存在兩個(gè)庫中,一個(gè)下單減庫存的操作,就涉及跨庫事務(wù)。關(guān)于分布式事務(wù)的處理,我們?cè)趯凇胺植际绞聞?wù)”的模塊中也介紹過,可以使用分布式事務(wù)中間件,實(shí)現(xiàn) TCC 等事務(wù)模型;也可以使用基于本地消息表的分布式事務(wù)實(shí)現(xiàn)。如果對(duì)這部分印象不深,你可以回顧下前面講過的內(nèi)容。
跨庫關(guān)聯(lián)查詢問題
分庫分表后,跨庫和跨表的查詢操作實(shí)現(xiàn)起來會(huì)比較復(fù)雜,性能也無法保證。在實(shí)際開發(fā)中,針對(duì)這種需要跨庫訪問的業(yè)務(wù)場(chǎng)景,一般會(huì)使用額外的存儲(chǔ),比如維護(hù)一份文件索引。另一個(gè)方案是通過合理的數(shù)據(jù)庫字段冗余,避免出現(xiàn)跨庫查詢。
跨庫跨表的合并和排序問題
分庫分表以后,數(shù)據(jù)分散存儲(chǔ)到不同的數(shù)據(jù)庫和表中,如果查詢指定數(shù)據(jù)列表,或者需要對(duì)數(shù)據(jù)列表進(jìn)行排序時(shí),就變得異常復(fù)雜,則需要在內(nèi)存中進(jìn)行處理,整體性能會(huì)比較差,一般來說,會(huì)限制這類型的操作。具體的實(shí)現(xiàn),可以依賴開源的分庫分表中間件來處理,下面就來介紹一下。
分庫分表中間件實(shí)現(xiàn)
業(yè)務(wù)中實(shí)現(xiàn)分庫分表,需要自己去實(shí)現(xiàn)路由規(guī)則,實(shí)現(xiàn)跨庫合并排序等操作,具有一定的開發(fā)成本,可以考慮使用開源的分庫分表中間件。這里比較推薦 Apache ShardingSphere,另外也可以參考淘寶的 TDDL 等。
其中,ShardingSphere 的前身是當(dāng)當(dāng)開源的 Sharding-JDBC,目前更名為 ShardingSphere,并且已經(jīng)加入?Apache 基金會(huì)。ShardingSphere 在 Sharding-JDBC 的基礎(chǔ)上,額外提供了 Sharding-Proxy,以及正在規(guī)劃中的 Sharding-Sidecar。其中 Sharding-JDBC 用來實(shí)現(xiàn)分庫分表,另外也添加了對(duì)分布式事務(wù)等的支持。關(guān)于 ShardingSphere 的具體應(yīng)用,感興趣的同學(xué)可以去瀏覽 《ShardingSphere 用戶手冊(cè)》。
另一款 TDDL(Taobao Distributed Data Layer)是淘寶團(tuán)隊(duì)開發(fā)的數(shù)據(jù)庫中間件,用于解決分庫分表場(chǎng)景下的訪問路由,TDDL 在淘寶大規(guī)模應(yīng)用,遺憾的是開源部分還不太完善,社區(qū)已經(jīng)很長(zhǎng)時(shí)間都沒有更新,可以在 TDDL 項(xiàng)目 倉庫了解更多的信息。
總結(jié)
這一課時(shí)分享了分庫分表相關(guān)的知識(shí)點(diǎn),包括分庫分表的業(yè)務(wù)背景,水平切分和垂直切分的不同方式,分庫分表以后增加的系統(tǒng)復(fù)雜性問題,以及可以使用哪些開源的分庫分表中間件解決對(duì)應(yīng)問題。
你可以考察下目前項(xiàng)目里是否有應(yīng)用分庫分表,以及是如何實(shí)現(xiàn)分庫分表,比如自研或者使用開源組件,并且留言分享。