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