:ShardingSphere-JDBC 從配置到擴容全解析)
分庫分表與 ShardingSphere當(dāng)單庫無法支撐海量數(shù)據(jù)和高并發(fā)寫入時分庫分表成為必經(jīng)之路。本文覆蓋分庫分表核心概念 → ShardingSphere-JDBC 5.5.0 分庫分表實戰(zhàn)配置 → 分片算法對比 → 擴容策略。一、為什么分庫分表1.1 三大根因根因典型閾值后果數(shù)據(jù)量增長單表 2000 萬行三層 BTree 極限樹層數(shù)增加I/O 次數(shù)上升單表寫性能瓶頸寫入 QPS 2000需 8C 高線程寫入高并發(fā)插入爭用自增主鍵鎖熱點頁 X 鎖競爭寫入爭用熱點頁鎖高并發(fā)集中寫入相同 ID 范圍頁鎖沖突導(dǎo)致吞吐量斷崖式下降1.2 分庫 vs 分表維度分庫分表目標水平拆分到不同 MySQL實例跨機器水平拆分到同一 MySQL 實例內(nèi)不同表解決單機硬件上限CPU/內(nèi)存/磁盤/網(wǎng)絡(luò)帶寬單表行數(shù)/數(shù)據(jù)量上限2000 萬行分片策略數(shù)據(jù)分布到不同物理機器ds0, ds1數(shù)據(jù)分布到同庫的不同物理表table_0, table_1性能瓶頸分布式事務(wù)跨庫跨分片 JOIN、分片鍵回表、排序橫向拆分水平分片才是互聯(lián)網(wǎng)業(yè)務(wù)最常見的第一優(yōu)先級先解決數(shù)據(jù)量上限再解決寫入瓶頸。1.3 數(shù)據(jù)傾斜 vs 熱點概念定義場景數(shù)據(jù)傾斜數(shù)據(jù)不均勻分布到分片如user_id1寫滿 shard1其余幾乎沒數(shù)據(jù)大客戶歷史數(shù)據(jù)占全量 99%熱點數(shù)據(jù)寫請求集中寫入同一個分片如user_id1在當(dāng)前時刻同時寫入 1000 次訂單高峰期用戶下單集中爆發(fā)分庫分表無法解決數(shù)據(jù)傾斜必須設(shè)計業(yè)務(wù)規(guī)則。比如設(shè)定分片鍵為時間維度確保新數(shù)據(jù)分散到不同分片或者寫入前用本地緩存來隨機選擇分片。二、項目結(jié)構(gòu)與依賴2.1 pom.xml分庫分表專用propertiesshardingsphere.version5.5.0/shardingsphere.version/propertiesdependencies!-- 核心JDBC 驅(qū)動模式 --dependencygroupIdorg.apache.shardingsphere/groupIdartifactIdshardingsphere-jdbc/artifactIdversion${shardingsphere.version}/version/dependency!-- 必須顯式引入spring-boot-starter-jdbc 在 5.5.0 中是內(nèi)嵌模塊默認不拉取 --dependencygroupIdorg.apache.shardingsphere/groupIdartifactIdshardingsphere-jdbc-core-spring-boot-starter/artifactIdversion${shardingsphere.version}/version/dependency!-- 必須JAXB 2.3.9javax 命名空間--dependencygroupIdorg.glassfish.jaxb/groupIdartifactIdjaxb-runtime/artifactIdversion2.3.9/version/dependency/dependencies版本鐵律SS 必須5.5.0。shardingsphere-jdbc-core-spring-boot-starter在 5.5.0 之前未包含spring-boot-starter-jdbc的傳遞依賴這是 5.5.0 版本特有的。生產(chǎn) 5.5.0 實測穩(wěn)定5.5.1 模塊拆分導(dǎo)致缺包。2.2 項目結(jié)構(gòu)shardingsphere-jdbc5.5.0-sharding-springboot-3.2.5/ ├── pom.xml # 依賴 共享常量 ├── shardingsphere.yaml # 核心配置數(shù)據(jù)源、分庫、分表、日期路由算法 ├── src/main/java │ ├── Application.java │ └── shardingsphere/sharding/ │ ├── config/DateBasedSharding.java # 自定義日期表名路由算法 │ ├── entity/Order.java │ ├── mapper/OrderMapper.java │ └── test/ShardingSphereTest.java # 主入口先表結(jié)構(gòu) → 再寫測試 → 再查結(jié)果 └── src/main/resources/application.yml # 數(shù)據(jù)庫連接、MyBatis、日志級別分庫分表 6 板斧① 主鍵雪花自增② 按字段分庫③ 按字段日期分表④ 初始化spring.factories⑤ 表結(jié)構(gòu)自動化⑥ 集成 SS-JDBC 5.5.0 配置動態(tài)數(shù)據(jù)源。三、shardingsphere.yaml 配置詳解3.1 數(shù)據(jù)源配置4 個 MySQL 實例# 共用連接池常量DB_HOST、DB_USER、DB_PASS 等通過 Maven Filter 或環(huán)境變量注入dataSources:ds0:dataSourceClassName:com.zaxxer.hikari.HikariDataSourcedriverClassName:com.mysql.cj.jdbc.DriverjdbcUrl:jdbc:mysql://${DB_HOST}:3300/${DB_NAME}?useSSLfalseserverTimezoneAsia/ShanghaiallowPublicKeyRetrievaltrueusername:${DB_USER}password:${DB_PASS}maximumPoolSize:10ds1:jdbcUrl:jdbc:mysql://${DB_HOST}:3301/${DB_NAME}?useSSLfalseserverTimezoneAsia/ShanghaiallowPublicKeyRetrievaltrue# ... 同上ds2:jdbcUrl:jdbc:mysql://${DB_HOST}:3302/${DB_NAME}?useSSLfalseserverTimezoneAsia/ShanghaiallowPublicKeyRetrievaltrue# ... 同上ds3:jdbcUrl:jdbc:mysql://${DB_HOST}:3303/${DB_NAME}?useSSLfalseserverTimezoneAsia/ShanghaiallowPublicKeyRetrievaltrue# ... 同上關(guān)鍵共用一個 Maven 常量只改端口。3.2 分庫算法Shard4Mod_4rules:-!SHARDINGtables:t_order:actualDataNodes:ds${0..3}.t_order_${0..3}tableStrategy:standard:shardingColumn:order_idshardingAlgorithmName:hash4mod_4databaseStrategy:standard:shardingColumn:user_idshardingAlgorithmName:shard4mod_4shardingAlgorithms:shard4mod_4:type:INLINEprops:algorithm-expression:ds${user_id % 4}hash4mod_4:type:INLINEprops:algorithm-expression:t_order_${(order_id.hashCode() Integer.MAX_VALUE) % 4}Shard4Mod_4 公式4 取模 4 0 庫/表1 % 4 12 % 4 23 % 4 3。推薦做法分庫鍵 → 跨庫的平鍵user_id分表鍵 → 跨表的分鍵order_id。actualDataNodes: ds${0..3}.t_order_${0..3}即 4 庫 × 4 表 16 個實際表。3.3 按日期分片鍵分表HashDate 雙算法-!SHARDINGtables:t_order:actualDataNodes:ds${0..3}.t_order_${0..3}tableStrategy:complex:shardingColumns:user_id,order_dateshardingAlgorithmName:date_shard_hashdatabaseStrategy:standard:shardingColumn:user_idshardingAlgorithmName:shard4mod_4shardingAlgorithms:date_shard_hash:type:CLASS_BASEDprops:strategy:complexalgorithmClassName:com.xxx.config.DateBasedSharding3.4 日期表名路由自定義算法JavaComponentShardingSphereAlgorithmType(date_shard)publicclassDateBasedShardingimplementsComplexShardingAlgorithmString{OverridepublicCollectionStringdoSharding(CollectionStringavailableTargetNames,ComplexShardingValueStringcomplexShardingValue){MapString,CollectionStringcolumnNameAndShardingValuesMapcomplexShardingValue.getColumnNameAndShardingValuesMap();// 取出 order_date 分片值寫 SQL 時按字符串傳CollectionStringdateValuescolumnNameAndShardingValuesMap.get(order_date);if(CollectionUtils.isEmpty(dateValues)){returnavailableTargetNames;// 沒傳日期就全掃}StringdateValuedateValues.iterator().next();// 統(tǒng)一格式化2026-06-30StringtableDatedateValue.split( )[0].replace(-,);returnCollections.singletonList(t_order_tableDate);}OverridepublicStringgetType(){returndate_shard;}Overridepublicvoidinit(Propertiesprops){}}實際路由1 庫 → 4 表基于用戶 ID Hash 日期→2026_06_30單日 10 萬單。HashDate 雙算法2 維度分片order_date二次 Hash 確保同一用戶跨表日期的數(shù)據(jù)均勻分布。t_order_20260630。四、分片算法對比4.1 大表 vs 按分片對比大表未分片按分片分庫分表主鍵特性標準順序遞增AUTO_INCREMENT亂序無順序意義ID 只是唯一標識業(yè)務(wù)邏輯順序好追蹤、統(tǒng)計易必須加order_id或user_id作為查詢條件典型應(yīng)用無索引復(fù)雜但性能很好精確查詢無影響慢路由算法只能定位聚簇查詢?nèi)珤?/4 或 1/8 范圍精準定位關(guān)鍵性能慢索引維護、熱點頁鎖非常快范圍掃描1 個表掃描多個分片表掃描分庫分表后沒有唯一遞增 ID總訂單號不是系統(tǒng)問題必須額外設(shè)計全局序號中心。4.2 標準設(shè)計 vs 按片設(shè)計維度標準設(shè)計老系統(tǒng)按片設(shè)計分庫分表表名t_order無后綴t_order_0/t_order_1/t_order_20260630主鍵id自增必須改為user_id非業(yè)務(wù)主鍵或雪花 ID查詢條件直接WHERE idxx必須帶user_id或order_id分片鍵業(yè)務(wù)影響無影響查詢所有接口必須改 WHERE 條件主鍵追蹤可以先查主鍵再查必須按順序先查詢后追蹤優(yōu)點簡單按分片快速查詢寫無熱點查詢 1 對 N 好擴展缺點熱點沖突不適合超大數(shù)據(jù)需要改分片鍵不能 id 查詢但性能 3~10 倍4.3 分片鍵對比適合帶操作分片鍵優(yōu)點缺點適用場景user_id查詢快易查詢用戶中心用戶操作集中無利于訂單訂單表、用戶中心order_id訂單分布均勻無熱點訂單操作查詢后不利于主鍵無業(yè)務(wù)語義訂單表、用戶中心order_date時間范圍查詢好適合歷史天熱點、無法定位用戶歷史表、物流表user_id order_date時間用戶雙維度平衡無法 1 主鍵查詢復(fù)雜訂單表、分庫分表優(yōu)先分庫分表后查詢必須帶分片鍵user_id或order_date否則全掃4 庫 × 4 表 16 個表。實戰(zhàn)最佳分庫鍵用user_id分表鍵用order_date Hash雙維度。user_id5, 10, 15, 20均勻分到 4 個庫庫內(nèi)按日期再分 4 表。五、跨分片查詢問題5.1 跨分片聚合JOIN場景問題方案跨分片 JOIN 等值性能良好路由無問題無需改造跨分片 JOIN 范圍條件路由不可計算需全表改為分片鍵或切分表跨分片聚合COUNT/SUM需聚合結(jié)果全局聚合如t_order_total逐片后聚合排序后分頁查詢 16 張表后排序必須按分片鍵分頁或先查詢后內(nèi)存聚合5.2 大表分區(qū) vs 分庫分表方案優(yōu)缺場景大表不分片簡單支持事務(wù)數(shù)據(jù)量小無并發(fā)大表分區(qū)如按時間單庫簡單維護范圍查詢優(yōu)秀中等數(shù)據(jù)查詢模式固定如按月分庫分表高擴展抗并發(fā)但路由復(fù)雜JOIN 難大數(shù)據(jù)、高并發(fā)、讀寫分離、擴容分區(qū)也是一次方案但遷移成本高。建議按分片鍵初定但分區(qū)庫就固定根據(jù)大小決定是否合并。六、擴容策略6.1 三種擴容策略策略核心優(yōu)點缺點適用場景靜態(tài)分片預(yù)先分 16 片DBA 配置管理按容量分簡單無復(fù)雜規(guī)則擴容需遷移維護復(fù)雜數(shù)據(jù)量小、增長可預(yù)測動態(tài)分片庫按容量動態(tài)調(diào)整系統(tǒng)自動按規(guī)則動態(tài)增長彈性好無需人工規(guī)則復(fù)雜需管理元數(shù)據(jù)數(shù)據(jù)量大動態(tài)增長一致性哈希虛擬節(jié)點映射到實際節(jié)點Hash 環(huán)均勻動態(tài)擴容平滑無需全遷移新增虛擬節(jié)點需微調(diào)映射大規(guī)模、無規(guī)律增長靜態(tài)分片最簡單但最復(fù)雜的是管理映射規(guī)則一致性哈希最復(fù)雜但擴容最平滑。在數(shù)據(jù)可控、容量預(yù)期明確的場景下靜態(tài)分片足夠。6.2 一致性哈希詳解核心思想不直接對實際節(jié)點取模而是對虛擬節(jié)點取模。每個真實節(jié)點在 Hash 環(huán)上對應(yīng)多個虛擬節(jié)點如 150~300 個。維度一致性哈希標準 Hash如user_id % 4擴容只需遷移相鄰虛擬節(jié)點對應(yīng)的數(shù)據(jù)約 1/N所有數(shù)據(jù)都需重新計算 Hash全量遷移縮容同上只需遷移消失節(jié)點的數(shù)據(jù)同上全量遷移數(shù)據(jù)傾斜風(fēng)險虛擬節(jié)點足夠多 → 均勻分布簡單取模分布不均虛擬節(jié)點數(shù)量通常 150~300 個 / 真實節(jié)點無無論是靜態(tài)分片、動態(tài)分片還是一致性哈希核心是** Hash → 分片鍵 → 數(shù)據(jù)映射**。標準 Hash 簡單但擴容時所有數(shù)據(jù)遷移一致性哈希只遷移約 1/N但需管理虛擬節(jié)點。大規(guī)模系統(tǒng)Redis 集群、MongoDB 分片用一致性哈希 虛擬節(jié)點。6.3 擴容 4 步驟靜態(tài)分片1. 新庫DB4、DB5建好與舊庫DB0~3并行 2. DBA 將分片規(guī)則從「4 取模」改為「6 取?!?3. 老數(shù)據(jù)按新規(guī)則「6 取?!怪匦逻w移到 DB4、DB5 4. 新寫按新規(guī)則路由新數(shù)據(jù)按 6 取模分配靜態(tài)分片擴容的關(guān)鍵① 新庫并行建好② 規(guī)則修改4→6③ 老數(shù)據(jù)遷移④ 新寫按新規(guī)則。一致性哈希只需改虛擬節(jié)點映射不需要全量遷移老數(shù)據(jù)。七、核心速查與踩坑7.1 分庫分表 6 板斧主鍵雪花自增IdWorker.getId()非順序遞增防分片熱點按字段分庫user_id % 4 → ds0~3按字段日期分表t_order_20260630日期Hash 雙維度初始化spring.factoriesSS 5.5.0 啟動掃描 SPI 依賴表結(jié)構(gòu)自動化TableName或自動建表腳本集成 SS-JDBC 5.5.0Driver 模式 顯式 starter JAXB 2.3.97.2 踩坑速查表#坑根因解1spring-boot-starter-jdbc缺失5.5.0 中內(nèi)嵌不自動拉取顯式引入shardingsphere-jdbc-core-spring-boot-starter2動態(tài)數(shù)據(jù)源不生效shardingsphere.yaml沒有!SHARDING規(guī)則必須配置databaseStrategy和tableStrategy3查詢不帶分片鍵 → 全掃 16 表路由算法無法定位所有查詢必須帶user_id或order_date4日期分表未按order_date格式SQL 傳2026-06-30 10:00:00而非純?nèi)掌谧远x算法中split( )[0].replace(-, )標準化5自定義算法未注冊spring.factories未配置org.apache.shardingsphere.sharding.spi.ShardingAlgorithmcom.xxx.DateBasedSharding6按片 ID 查詢必須用分片鍵按片系統(tǒng)無全局遞增 ID 追蹤系統(tǒng)生成全局唯一 ID雪花業(yè)務(wù)層映射7分庫后全局 ID 沖突4 個庫各自自增統(tǒng)一用雪花 ID非 DB 自增8跨分片 JOIN 性能差數(shù)據(jù)分布到不同庫/表避免跨分片 JOIN或先查單表再聚合7.3 讀寫分離與分庫分表的聯(lián)動假設(shè)配置rules:-!READWRITE_SPLITTINGdataSources:ds_0:# 對應(yīng) ds0writeDataSourceName:ds0readDataSourceNames:-ds0_slaveds_1:writeDataSourceName:ds1readDataSourceNames:-ds1_slave# ... ds2, ds3 同理先分庫分表水平拆分再讀寫分離垂直拆分。先切數(shù)據(jù)再優(yōu)化讀寫負載。核心速查表分片鍵設(shè)計決策查詢是否按用戶維度 ├─ 是 → 分庫鍵 user_id分表鍵 order_date Hash └─ 否 → 分庫鍵 業(yè)務(wù)主鍵分表鍵 時間維度 查詢是否按時間范圍 ├─ 是 → 日期分表優(yōu)先如 t_order_202606 └─ 否 → Hash 分表優(yōu)先如 t_order_0~3三種分片策略對比策略擴容方式數(shù)據(jù)遷移量復(fù)雜度推薦度靜態(tài)分片改取模數(shù) 全量遷移全量低數(shù)據(jù)量可控、有 DBA動態(tài)分片自動增加容量無需遷移中云原生、彈性需求一致性哈希加虛擬節(jié)點1/N高大規(guī)模、Redis/MongoDB一句話心法分庫分表不是銀彈它解決了數(shù)據(jù)量上限和寫入熱點但引入了跨分片查詢、分布式事務(wù)、全局 ID 等復(fù)雜度。設(shè)計時先選對分片鍵決定 80% 的查詢性能再選對分片策略決定擴容成本最后才是框架配置ShardingSphere 只是執(zhí)行器。