一、為什么要分庫分表?
通常,數據庫性能受到如下幾個限制:
- 硬件瓶頸:單機的 CPU、內存、磁盤 I/O 等資源總是有限。例如,當單表中的記錄達到上億、甚至更高時,表掃描、索引維護和數據遷移會變得非常慢。
- 單點壓力:所有業務都依賴單數據庫實例,一旦主庫宕機,整個系統面臨服務不可用的風險。
- 高并發訪問:瞬時的并發讀寫流量可能壓垮數據庫連接數,導致業務性能急劇下降。
分庫分表的目標:
- 提高數據庫性能:通過分布式擴展,將數據壓力分散到多個獨立的數據庫節點上,減少單庫讀寫開銷。
- 提高系統可用性:分庫分表支持分布式架構,單節點故障不會影響整體服務。
- 支持海量數據存儲:橫向擴展減少單表大小,優化查詢穩定性,降低表掃描的可能性。
二、分庫與分表的核心概念
1. 水平分表 & 垂直分表
-
水平分表:將一個表根據某種規則(如主鍵范圍或哈希值)分成多張子表,數據均勻分布。
- 優點:解決單表數據量大引起的性能問題。
- 缺點:跨分片查詢變復雜,插入引發分片路由。
- 應用場景:訂單表、聊天消息表等高增長、海量記錄的表。
-
垂直分表:按字段將一個表分拆為多張表,按功能屬性劃分。
- 優點:減小單表字段數,降低查詢掃描的 IO。
- 缺點:可能涉及跨表關聯查詢,開發復雜度提升。
- 應用場景:拆分用戶主表和擴展表等。
2. 分庫
分庫是將數據庫從單實例擴展為多實例的架構部署方式。一種常見方式是結合分表邏輯,將分表數據分別存儲到不同的數據庫實例中。分庫后的數據庫實例可以分布在不同的物理節點上,獨立運行并擴展。
分庫更關注于系統間負載的隔離,可以:
- 減少資源競爭。
- 增加數據庫服務器擴展能力。
三、分庫分表的設計原則與實現策略
1. 劃分規則的設計
分庫分表依賴于科學合理的分片規則,具體包括以下幾類方法:
-
范圍分片:
- 將數據按照一定的范圍劃分,例如將表按照時間、ID區間分成若干份。
- 優點:規則簡單,插入和查詢性能高。
- 缺點:數據熱點問題容易產生。
- 適用場景:按時間維度分的日志表、賬單表。
-
哈希分片:
- 基于主鍵進行哈希運算,哈希函數值映射到多個分片中。
- 優點:分布均勻,減少單點壓力。
- 缺點:不支持區間查詢。
- 適用場景:商品表、用戶表。
-
按維度分片(Sharding By Key):
- 針對業務邏輯,將數據通過特定業務字段分拆。
- 舉例:電商系統按商戶 ID、用戶 ID 或地區分片。
- 特點:滿足業務隔離規則,關聯性同維度數據通常集中。
-
動態拆分:
- 初期無需分片,當數據規模達到一定的閾值后,通過動態調整分片規則,逐步將數據遷移到多個分片中進行存儲與查詢。
- 優點:初期設計簡單,降低復雜度,靈活擴展,資源利用率高。
- 缺點:數據遷移過程中存在一定成本,設計與實施難度較高。
- 適用場景:初期數據量較少,后續可能隨業務增長呈指數級擴大,例如不斷增長的訂單表、用戶表等。
2. 分庫分表的關鍵問題與挑戰
在進行分庫分表的實際實施過程中,需要面對一些挑戰性問題。以下是常見的幾個問題以及應對策略:
(1) 數據路由與查詢復雜度
- 問題描述:分庫分表后,數據分散存儲,傳統的單庫查詢方式不再適用。每次請求必須先確定目標庫或目標表。
- 解決方案:
- 路由規則的設計:通過統一的分片鍵(sharding key,通常是 ID 或某些范圍字段),以程序化的方法路由。多使用中間件或配置靜態哈希路由規則。
- 中間件支持:通過分庫分表中間件(如 MyCat、ShardingSphere)簡化數據路由層的開發。
- 分布式環境下的聚合查詢:針對跨庫查詢,通過中間件層負責分布式查詢聚合(MapReduce 類邏輯)。如 Elasticsearch 使用的分布式分片存儲結合索引設計。
(2) 跨分片事務
- 問題描述:傳統關系型數據庫通過鎖定機制或分布式回滾保障事務一致性,但分庫分表的多實例環境中,事務很難局限在單節點內管理。
- 解決方案:
- 分布式事務協議:使用兩階段提交(2PC)或三階段提交,協調資源的一致性。
- 本地事務 + 最終一致性:通過異步補償(如消息隊列)實現弱一致性。
- TCC 模型:Try-Confirm-Cancel,通過應用邏輯隔離事務狀態,適用于電商訂單場景。
- 去中心化事務落地:結合 CAP 理論,優先將核心操作放在單庫內完成,避免高頻跨分片事務。
(3) ID 唯一性問題
- 問題描述:分庫分表后,自增 ID 會失去意義,因為每個分片的序列號沖突可能性大。
- 解決方案:
- 分布式 ID 生成:
- UUID:優點是全局唯一,容易生成;缺點是過長,查詢和索引效率較低。
- 雪花算法(Snowflake):Twitter 提出的分布式 ID 生成器(64 位),結合時間戳、機器 ID 等信息生成遞增的全局唯一 ID。
- 數據庫序列/步長生成:如 MySQL 的 auto_increment,步長分片,避免沖突。
- Redis 計數器:利用 Redis 的原子性操作(如 INCR)生成唯一 ID。
- 聯合主鍵:以分片鍵和記錄本地自增 ID 為聯合主鍵。
- 分布式 ID 生成:
(4) 跨節點關聯查詢問題
- 問題描述:傳統的多表關聯查詢(JOIN)隨著表橫向拆分,可能涉及多個庫或多個節點的操作,使得查詢性能急劇下降。
- 解決方案:
- 查詢拆分:通過業務邏輯解耦查詢,將復雜的多表關聯拆分成多次單表查詢。
- 數據冗余與同步:在不同分片中保存可能關聯的冗余數據,減少 JOIN 的發生。
- 實時索引同步:使用分布式搜索引擎(如 Elasticsearch)作為輔助索引服務。
- 分布式 SQL 中間件:使用支持分布式 JOIN 查詢的中間件,如 ShardingSphere 等,自動完成查詢優化和數據路由。
(5) 數據遷移與擴容
-
問題描述:隨著業務增長,最初設計的分片規則可能無法滿足需求。例如,新加入一個數據庫實例需要重新分片遷移大量數據。
-
解決方案:
- 添加分片規則的靈活性:在設計初期預留一定的擴展字段,如虛擬分區粒度更細。
- 數據遷移策略:
- 全量數據遷移:冷備快照 + 增量數據補償。
- 遷移中間態機制:遷移過程中適配讀寫的雙寫
-
遷移過程中避免服務中斷:
- 雙寫機制:讀寫同時進行到新舊數據庫,直至新數據庫中的數據完全同步后切換流量。
- 灰度遷移:逐步將少量的業務流量切換到新分片庫,通過遷移過程的穩定性測試最終完成全量服務轉移。
- 數據備份與回滾:做好遷移失敗時的應急回滾策略,例如通過定時快照還原到舊數據庫。
3. 分庫分表中間件的選型與特點
在分庫分表實踐中,中間件扮演了舉足輕重的角色,它們屏蔽了分布式架構的復雜性,簡化了開發人員的實現難度。以下是幾種流行的分庫分表中間件及其特點:
(1) MyCat
- 開源的數據庫分庫分表中間件,支持 MySQL 等數據庫。
- 特點:
- 支持水平拆分和垂直拆分。
- 兼容多種分表算法(哈希、范圍等)。
- 提供簡單的跨分庫關聯查詢支持,通過全局聚合完成最終結果。
- 缺點:
- 高并發場景性能相對較低,事務支持能力較弱。
(2) ShardingSphere
- Apache 社區支持的開源分布式數據庫生態,包含 Sharding-JDBC、Sharding-Proxy 等模塊。
- 特點:
- 靈活的分布式 SQL 查詢支持,能在程序中無縫集成。
- 完善的動態分片、負載均衡、高可用機制。
- 支持柔性事務(TCC)和分布式事務(2PC)。
- 缺點:
- 學習曲線較陡,配置復雜度較高。
(3) TiDB
- 分布式 NewSQL 數據庫,天然支持數據分片,具備良好的集群擴展能力。
- 特點:
- 兼容 MySQL 協議,可直接無縫遷移。
- 自動分布式事務支持,避免人工分片邏輯。
- 水平擴展能力強,擅長解決 PB 級別的存儲需求。
- 缺點:
- 對高性能實時寫入會產生一定延遲。
四、分庫分表實戰案例分析
以下結合具體場景,詳細介紹分庫分表的一個落地方案:
場景:大型電商平臺的訂單系統
業務特點:
- 每天高峰期存在數百萬級訂單寫入請求。
- 滯留訂單需要長期統計與查詢。
- 支付狀態、物流信息等多維度數據需要實時更新。
傳統痛點:
- 單表數據過億,索引查詢效率下降。
- 高頻訂單寫操作導致數據庫連接池不堪重負。
- 跨表關聯(如訂單 → 用戶)深受大表影響。
分庫分表架構設計:
-
分表模型設計:
- 對訂單表按用戶 ID 進行哈希分片,每 10 萬用戶分為一個分片(
Hash(user_id) % 16 = 庫編號
),單表內按時間分區存儲。 - 利用時間字段按天創建分區索引,確保歷史訂單查詢性能。
- 對訂單表按用戶 ID 進行哈希分片,每 10 萬用戶分為一個分片(
-
分庫設計:
- 將訂單數據存儲在 16 個數據庫實例中,每個實例組成主從集群。
- 數據庫實例之間物理隔離,分布式部署,減少單機資源競爭。
-
ID 唯一性生成:
- 通過 Twitter 的 Snowflake 算法生成包含時間戳、節點號、自增序列的全局唯一訂單編號。
-
事務保障:
- 主流程訂單寫入盡量避免跨分片操作。
- 對于支付、庫存
參考文檔: https://blog.csdn.net/weixin_61669379/article/details/141648151