ShardingSphere 实战:分库分表与读写分离落地

当单库单表的数据量突破千万、写入 QPS 顶到 MySQL 上限时,简单地”加从库”只能缓解读压力,却解决不了写入瓶颈和存储天花板。ShardingSphere 是一套 Apache 开源的数据库中间件,用分库分表把数据按规则打散到多个库与表,用读写分离把查询流量导向从库,让业务层几乎不用改 SQL 就能完成横向扩展。本文基于 ShardingSphere 5.x,从核心概念到 Spring Boot 落地,给你一套可直接复用的配置。

一、为什么需要 ShardingSphere

数据库扩展通常分两步。第一步是垂直拆分:把大表拆到独立库、把读压力分到从库。但当单表行数继续膨胀到几千万,索引树变深、B+ 树层级增加,即便是主键查询也会变慢,单实例的 CPU 和磁盘 IO 也终会触顶。水平拆分(分库分表)才是最终解法——把一张逻辑表按分片键切成多张物理表,分散在不同库的不同实例上。

难点在于,手写路由逻辑会让所有 DAO 层代码“中毒”:每个 SQL 都要先算库和表名。ShardingSphere 的价值正是在这一层做无侵入拦截——你照常写 INSERT INTO t_order ...,它在 JDBC 驱动或代理层帮你改写 SQL、路由到正确的库表,再把结果归并回来。

二、两种接入模式:JDBC 与 Proxy

ShardingSphere 提供两种形态,适用场景不同:

维度ShardingSphere-JDBCShardingSphere-Proxy
部署位置嵌入应用进程(Jar 包)独立服务,对应用透明
性能无网络跳转,损耗最小多一跳网络,略有损耗
异构语言仅 Java任意语言(MySQL/PG 协议)
运维成本配置随应用发布集中管理,统一治理
适合场景Java 单体/微服务多语言、需统一管控的平台

对绝大多数 Spring Boot 团队,JDBC 模式是首选:零额外组件、性能最好、配置即代码。下文全部以 JDBC 模式演示。

三、环境准备:Docker 起两套分片库

用 Docker Compose 起两个 MySQL 实例,分别代表两个分片库 ds0 与 ds1。每个库里都预先建好 t_order_0、t_order_1 两张物理表。

version: "3.8"
services:
  ds0:
    image: mysql:8.0
    environment:
      MYSQL_ROOT_PASSWORD: root
      MYSQL_DATABASE: order_db0
    ports: ["3306:3306"]
  ds1:
    image: mysql:8.0
    environment:
      MYSQL_ROOT_PASSWORD: root
      MYSQL_DATABASE: order_db1
    ports: ["3307:3306"]

生产环境里,每个分片通常还配一主多从做读写分离;下面第六节的配置会展示如何在分片之上叠加读写分离。

四、核心概念:分片键、逻辑表与分片算法

动手前先厘清三个关键概念:

  • 逻辑表:业务 SQL 里写的表名,例如 t_order。
  • 真实表:物理落库表,例如 ds0.t_order_0、ds1.t_order_1。
  • 分片键(sharding key):决定数据落到哪里的列,如 user_id、order_id。

常见分片策略各有取舍:

策略算法优点注意点
取模分片MOD数据均匀、实现简单扩容需迁移数据
范围分片RANGE范围查询友好、易扩容易产生热点
哈希分片HASH / INLINE分布均匀、可控分片数固定
时间分片按年/月/日天然冷热分离近期库压力大

五、实战:订单表分库分表配置

场景:t_order 按 user_id 取模分 2 个库,按 order_id 取模分 2 张表,最终形成 ds{0..1}.t_order_{0..1} 共 4 张物理表。

5.1 引入依赖

<dependency>
  <groupId>org.apache.shardingsphere</groupId>
  <artifactId>shardingsphere-jdbc-core-spring-boot-starter</artifactId>
  <version>5.4.1</version>
</dependency>

5.2 分片规则配置

spring:
  shardingsphere:
    datasource:
      names: ds0, ds1
      ds0:
        type: com.zaxxer.hikari.HikariDataSource
        jdbc-url: jdbc:mysql://127.0.0.1:3306/order_db0
        username: root
        password: root
      ds1:
        type: com.zaxxer.hikari.HikariDataSource
        jdbc-url: jdbc:mysql://127.0.0.1:3307/order_db1
        username: root
        password: root
    rules:
      sharding:
        tables:
          t_order:
            actual-data-nodes: ds${0..1}.t_order_${0..1}
            database-strategy:
              standard:
                sharding-column: user_id
                sharding-algorithm-name: db-mod
            table-strategy:
              standard:
                sharding-column: order_id
                sharding-algorithm-name: tbl-mod
        sharding-algorithms:
          db-mod:
            type: MOD
            props:
              sharding-count: 2
          tbl-mod:
            type: INLINE
            props:
              algorithm-expression: t_order_${order_id % 2}
    props:
      sql-show: true

5.3 业务代码零改造

配置完成后,你的 Repository 完全不用感知分片。ShardingSphere 在 JDBC 层拦截并重写 SQL:

@Insert("INSERT INTO t_order (order_id, user_id, amount) VALUES (#{o}, #{u}, #{a})")
void create(@Param("o") long orderId, @Param("u") long userId, @Param("a") BigDecimal amount);

// user_id=101, order_id=2001
// 路由:db-mod(101) -> ds1;tbl-mod(2001) -> t_order_1
// 实际执行:INSERT INTO ds1.t_order_1 ...

即便同一查询跨多个分片,框架也会并行下发、归并结果,对上层透明。这也是它和Vitess 这类基于 MySQL 协议的分片方案最大的体验差异:对应用而言仍是普通 JDBC。

六、读写分离:一主多从与负载均衡

分库分表解决”写”和”容量”,读写分离则进一步把 SELECT 打到从库。在分片规则之外叠加 readwrite-splitting 规则即可:

spring:
  shardingsphere:
    rules:
      readwrite-splitting:
        data-sources:
          ds0:
            type: Static
            props:
              write-data-source-name: ds0_master
              read-data-source-names: ds0_slave0, ds0_slave1
            load-balancer-name: round-robin
        load-balancers:
          round-robin:
            type: ROUND_ROBIN

负载均衡算法可按场景切换:

算法行为适用
ROUND_ROBIN轮询从库从库性能一致
RANDOM随机选从库从库差异小
WEIGHT按权重分发从库配置不均

注意:读写分离默认不保证读已写。主从复制有延迟,刚写入就立即读可能读到旧值。对强一致要求的场景,要么走主库 hint,要么用延迟更低的半同步复制。

七、分布式事务:XA 与 Seata 柔性事务

跨分片写入若涉及多个库,本地事务失效。ShardingSphere 内置 XA(两阶段提交)与基于Seata 的 AT 模式柔性事务两种方案:

spring:
  shardingsphere:
    rules:
      sharding:
        ...
    props:
      transaction:
        default-type: XA
        provider-type: Atomikos

在代码里用注解切换类型:

@ShardingTransactionType(TransactionType.XA)
@Transactional
public void crossShardTransfer() {
    orderMapper.insert(...);   // 落 ds0
    accountMapper.update(...); // 落 ds1
}

XA 保证强一致但锁资源久;高并发写场景推荐 Seata AT 这类最终一致方案,吞吐更高。选型时可参考分布式事务实战里的对照。

八、分页、分布式 ID 与绑定表

三个上线前必处理的细节:

  • 深度分页:LIMIT 100000,10 会向每个分片下发再归并,代价极高。应改用”上一页最大 ID + 游标”或业务游标分页。
  • 分布式 ID:自增主键在分片下会冲突,务必用雪花算法或 UUID。ShardingSphere 内置 雪花算法 主键生成器。
  • 绑定表(Binding Table):t_order 与 按同一分片键分片时,声明为绑定表可避免冗余笛卡尔积,让关联查询只在同分片内执行。
spring:
  shardingsphere:
    rules:
      sharding:
        binding-tables:
          - t_order, t_order_item
        key-generators:
          snowflake:
            type: SNOWFLAKE

九、生产落地检查清单

项检查要点
分片键选高频等值查询列,避免 NULL 与频繁更新
扩容预案取模分片迁移成本高,提前规划翻倍扩容脚本
主从延迟监控 Seconds_Behind_Master,强一致读走主库
分布式事务明确 XA / Seata 边界,防止长事务锁表
慢 SQL开启 sql-show,结合PG/MySQL 慢查询优化手段排查
容量基线单分片建议控制在千万级,超阈值提前再拆

十、小结

ShardingSphere 把分库分表、读写分离、分布式事务打包成”对业务透明”的能力:JDBC 模式零侵入接入 Spring Boot,Proxy 模式统一治理多语言服务。它不是银弹——分片键设计、扩容迁移、主从延迟仍是架构师要操心的事,但有了这套中间件,你至少能把精力放在数据模型本身,而不是和路由 SQL 纠缠。下一步可以结合CI/CD把分片配置纳入版本管理,让每一次扩容都可回滚、可审计。

上一篇 Consul 实战:用服务发现与 KV 存储构建动态微服务网络
下一篇 Apache Pulsar 实战:云原生消息队列与多租户流平台
最新评论
Docker 网络模式详解:bridge/host 生产选型 - FSData
Docker 网络模式详解:bridge/host 生产选型 - FSData
8月20日
[…] 注意最后那条:把端口绑定到 127.0.0.1,再由宿主机上的 Nginx 反代进来,比直接 -p 80:80 暴露安全得多,也方便统一做
Vue3 + TypeScript 工程化:类型安全的前端架构 - FSData
Vue3 + TypeScript 工程化:类型安全的前端架构 - FSData
8月20日
[…] Pinia 的工程化用法,可以参考我们之前的实战文章 《Vue3 组合式 API + Pinia:状态管理从入门到实战》,那里覆盖了 Sto
2026 年最值得装的 10 个 VS Code 插件(AI/前端/后端/效率全覆盖) - FSData
2026 年最值得装的 10 个 VS Code 插件(AI/前端/后端/效率全覆盖) - FSData
8月19日
[…] 状态,点一下就能起停容器,配合我们讲过的 Docker Compose 编排 […]
Redis 缓存设计:穿透、击穿、雪崩与最佳实践 - FSData
Redis 缓存设计:穿透、击穿、雪崩与最佳实践 - FSData
8月19日
[…] 缓存三大坑的本质都是”缓存失效导致请求穿透到数据库”。记住口诀:穿透用布隆、击穿用锁、雪崩用错峰。配合合理的过期策略
GitHub Actions 实战:从零搭建 CI/CD 流水线 - FSData
GitHub Actions 实战:从零搭建 CI/CD 流水线 - FSData
8月19日
[…] Docker 镜像部署。结合我们之前写的 Docker Compose 一键编排实战,可以在 CI […]