主题
ShardingSphere 深度配置
一句话:ShardingSphere 在 JDBC 驱动或 Proxy 协议层解析并改写 SQL,把逻辑库表映射到物理分片,换来应用少改代码,代价是 SQL 兼容性边界、配置版本漂移和额外的故障面。
适用版本:ShardingSphere 5.5.x(JDBC / Proxy)。5.x 各小版本的 YAML 字段有调整,升级前对照官方文档;Sidecar 已停止研发,不再作为选型项。分片键与扩容的前置判断见 01-分片策略与扩容方案。
为什么需要
应用直接连多个物理库,要自己算路由、拼 SQL、归并结果、处理跨片事务,代码会和分片逻辑绑死。ShardingSphere 把这层收进驱动或代理:应用写逻辑表 t_order,配置把它映射到 ds0.t_order_0 等物理节点,由它解析 SQL、按分片键路由、改写后下发并归并结果,还能在同一层叠加读写分离、加密、影子库。
代价是 SQL 必须能被解析,跨片 JOIN/子查询/分页都有边界,配置也会随版本变化。
核心机制
JDBC 与 Proxy
| 维度 | ShardingSphere-JDBC | ShardingSphere-Proxy |
|---|---|---|
| 形态 | JAR 内嵌应用 | 独立进程 |
| 协议 | JDBC 驱动层 | MySQL / PostgreSQL 协议 |
| 语言 | Java | 任意语言 |
| 额外网络跳转 | 无 | 有 |
| 运维 | 随应用发布 | 独立集群,需高可用 |
| 适用 | Java 栈、追求低延迟 | 多语言、想统一入口 |
SQL 处理链路
一条逻辑 SQL 在 ShardingSphere 内部固定经过五步,成本差异集中出现在路由和归并两步。
分片键能精确路由时只下发一个库;不能时广播所有分片,归并成本随分片数上升。
规则分五类:!SHARDING(分片表、绑定表、广播表、算法、主键)、!READWRITE_SPLITTING(读写分离)、!ENCRYPT(字段加密)、!TRANSACTION(本地/XA/BASE,BASE 用 Seata)、!SHADOW(影子库)。
最小上手
5.5.x JDBC 的 YAML(单库分表 + 读写分离的最小组合):
yaml
databaseName: order_db
dataSources:
ds_0:
dataSourceClassName: com.zaxxer.hikari.HikariDataSource
driverClassName: com.mysql.cj.jdbc.Driver
jdbcUrl: jdbc:mysql://127.0.0.1:3306/order_db_0?useSSL=false&serverTimezone=UTC
username: root
password: root
ds_1:
dataSourceClassName: com.zaxxer.hikari.HikariDataSource
driverClassName: com.mysql.cj.jdbc.Driver
jdbcUrl: jdbc:mysql://127.0.0.1:3306/order_db_1?useSSL=false&serverTimezone=UTC
username: root
password: root
rules:
- !SHARDING
tables:
t_order:
actualDataNodes: ds_${0..1}.t_order_${0..1}
databaseStrategy:
standard:
shardingColumn: user_id
shardingAlgorithmName: db_inline
tableStrategy:
standard:
shardingColumn: order_id
shardingAlgorithmName: tbl_inline
keyGenerateStrategy:
column: order_id
keyGeneratorName: snowflake
bindingTables: [t_order,t_order_item]
broadcastTables: [t_dict_region]
shardingAlgorithms:
db_inline:
type: INLINE
props:
algorithm-expression: ds_${user_id % 2}
tbl_inline:
type: INLINE
props:
algorithm-expression: t_order_${order_id % 2}
keyGenerators:
snowflake:
type: SNOWFLAKE
props:
worker-id: 1验证路由:应用侧执行 SELECT * FROM t_order WHERE user_id = 5 AND order_id = 100,打开 ShardingSphere 的 SQL 日志,确认只下发到 ds_1.t_order_0,而不是两个库都执行。
生产动作
绑定表与广播表
- 绑定表:
t_order和t_order_item的分片键、算法、分片数完全一致时,配bindingTables,JOIN 下推到单库完成,避免笛卡尔积式跨库 JOIN。 - 广播表:字典、配置、枚举等小表配
broadcastTables,每个分片保留一份,写入时广播。广播表不能是大表,否则每次写都放大到所有分片。
Hint 强制路由
后台导出、报表等 SQL 不带分片键时,用 Hint 指定路由:
java
try (HintManager hint = HintManager.getInstance()) {
hint.addDatabaseShardingValue("t_order", "user_id", 5L);
hint.addTableShardingValue("t_order", "order_id", 100L);
// 此查询直接路由到 ds_1.t_order_0
orderMapper.selectByHint();
}HintManager 是线程绑定的,必须关闭;忘记关闭会污染该线程后续所有查询的路由。
分布式事务
5.5.x 的 !TRANSACTION 规则:
yaml
- !TRANSACTION
defaultType: BASE
providerType: SeataSeata AT(BASE)落地要同时满足:依赖 shardingsphere-transaction-base-seata-at(5.5.x 文档要求 Seata 2.3.0+);每个物理库有 undo_log 表;提供 seata.conf(应用 ID、事务分组、超时);Spring Boot 下关掉 Seata 的自动数据源代理,避免冲突。
5.5.0 有过 BASE/Seata 回滚不生效的反馈,上线前必须在测试环境验证「跨片写失败后两个库都回滚」,不要只看配置加载成功。
SQL 兼容性边界
| 限制 | 说明 |
|---|---|
| 跨片 JOIN | 只有绑定表能下推;非绑定表结果可能不正确 |
| 子查询 | 分片键不一定能解析,尽量改写 |
| 跨片排序 + 分页 | 每个分片取 top N 再归并,深分页代价高 |
| DDL | 需要在所有物理分片执行,ShardingSphere 不会替你保证原子性 |
AVG / INSERT ... SELECT | 归并拆成 SUM/COUNT;跨库写入拆成多次操作 |
| 分布式主键 | 用雪花/号段,不要依赖各分片自增 |
边界
- 不是数据库:不支持所有 MySQL 语法,复杂 SQL 要在应用层拆。
- 跨片事务仍有代价:Seata 的分支注册、回滚补偿都会增加延迟;能单库完成就不要跨片。
- Proxy 多一跳:多语言接入方便,但延迟和连接池管理要单独设计。
- 配置随版本漂移:5.x 的 YAML 字段在小版本间有调整,升级前用测试环境验证,不要直接复制旧博客。
讲清楚
ShardingSphere 把分片逻辑收进 JDBC 驱动或 Proxy:应用写逻辑表,它解析 SQL、按分片键路由、改写后下发,再归并结果。JDBC 内嵌、延迟低但只支持 Java;Proxy 独立进程、多语言但多一跳。配置的核心是分片表、分片算法、绑定表、广播表和分布式主键;绑定表让 JOIN 下推,广播表让小字典表每库一份。边界很清楚:跨片 JOIN、深分页、跨片事务都很贵,能单库完成就别跨片。版本上要注意 5.x 配置字段会变,Sidecar 已停止研发,Seata 集成要按 5.5.x 文档补齐依赖、undo_log 和 seata.conf,并在测试环境验证回滚。