跳到正文

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-JDBCShardingSphere-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: Seata

Seata 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,并在测试环境验证回滚。

把一门技术讲透到既懂也会用