Apache ShardingSphere 快速集成使用配置教程

Cosolar 30 阅读 后端技术架构

本教程基于 Apache ShardingSphere 5.5.3(2026 年 3 月 1 日发布)编写,面向初次接触 ShardingSphere 的开发者,从核心概念到实战配置逐步展开。

一、认识 Apache ShardingSphere

Apache ShardingSphere 是一款分布式的数据库生态系统,能够将任意数据库转换为分布式数据库,并通过数据分片、弹性伸缩、加密等能力对原有数据库进行增强。它于 2020 年 4 月成为 Apache 软件基金会顶级项目,采用 Database Plus 设计哲学——不重新造一个数据库,而是在异构数据库上层构建标准和生态,关注数据库之间的协作而非数据库自身。

核心功能一览

功能 作用
数据分片 应对海量数据存储与计算,水平扩展计算和存储能力
分布式事务 基于 XA 和 BASE 混合事务引擎,保证跨数据源数据安全
读写分离 灵活拆分读写流量并提供读流量负载均衡
数据迁移 提供跨数据源数据迁移能力,支持重分片扩展
联邦查询 跨数据源复杂查询分析,实现跨源数据关联与聚合
数据加密 完整、透明、安全、低成本的加密解决方案
影子库 全链路压测场景下数据隔离,避免测试数据污染生产环境

5.5.3 版本关键变化

5.5.3 是目前最新的稳定版本,历时数月开发,合并了来自全球 54 位 Contributor 的 3,330 个 Commit,变更超过 60 万行代码。主要亮点包括:

  • 可插拔 BOM:功能模块(Feature)、数据库类型(DB)、注册中心类型(Registry Center)完全解耦为可插拔插件,应用只需引入核心依赖再按需添加"积木模块"
  • JDBC URL 极致简化:只需在 JDBC URL 中提供注册中心地址即可完成数据源初始化,替代本地 YAML 配置
  • SQL 兼容度提升:深度强化 MySQL 存储过程及复杂函数语法解析,提升对 Doris、Hive 等分析型数据库的兼容度
  • Firebird 生态支持:正式支持 Firebird 数据库代理
  • 安全加固:集中修复 8 组共 20 个 CVE 漏洞
  • JDK 支持:支持在 OpenJDK 24 和 25 环境下编译运行,JDBC URL 支持 IPv6 协议

二、核心架构与概念

三层可插拔架构

ShardingSphere 的架构划分为三层,各层职责清晰、互不耦合:

graph TB
    subgraph L3["L3 生态层"]
        A1["数据库协议<br/>MySQL / PostgreSQL / Firebird"]
        A2["SQL 解析器<br/>方言适配"]
        A3["存储适配器<br/>对接各类数据库"]
    end
    subgraph L2["L2 功能层 - 可选"]
        B1["数据分片"]
        B2["读写分离"]
        B3["数据加密"]
        B4["影子库"]
        B5["数据脱敏"]
    end
    subgraph L1["L1 内核层 - 必须"]
        C1["查询优化器"]
        C2["分布式事务引擎"]
        C3["分布式执行引擎"]
        C4["权限引擎"]
        C5["调度引擎"]
    end
    L3 --> L2 --> L1
  • L1 内核层:数据库基本能力的抽象,所有组件必须存在,但实现方式可通过可插拔方式更换
  • L2 功能层:提供增量能力,组件完全隔离、互无感知,多组件可叠加使用,用户可自定义扩展
  • L3 生态层:对接现有数据库生态,包括数据库协议、SQL 解析器和存储适配器

两种部署形态

ShardingSphere 提供两款既可独立部署又可混合使用的产品:

graph LR
    subgraph JDBC["ShardingSphere-JDBC"]
        J1["Java 应用"] --> J2["ShardingSphere-JDBC<br/>(JAR 包)"]
        J2 --> J3["数据库"]
    end
    subgraph Proxy["ShardingSphere-Proxy"]
        P1["任意语言应用"] --> P2["ShardingSphere-Proxy<br/>(独立服务进程)"]
        P2 --> P3["数据库"]
        P2 --> P4["数据库"]
    end
对比维度 ShardingSphere-JDBC ShardingSphere-Proxy
数据库支持 任意(通过 JDBC 访问的数据库) MySQL / PostgreSQL / Firebird
连接消耗 高(每个应用实例各自建连) 低(统一连接池)
异构语言 仅 Java 任意语言
性能 损耗低(直连数据库) 损耗略高(多一跳网络 IO)
无中心化
静态入口 有(固定连接地址)

选择建议:Java 高性能 OLTP 应用优先用 JDBC;异构语言、OLAP 场景或 DBA 运维管理用 Proxy;复杂场景可混合部署,JDBC 处理 OLTP,Proxy 处理 OLAP 和运维。

关键术语

  • 逻辑表:相同结构的水平拆分表的逻辑名称。例如 t_user_0t_user_9 的逻辑表名为 t_user
  • 真实表:在水平拆分数据库中真实存在的物理表,如 t_user_0
  • 数据节点:数据分片的最小单元,由数据源名和真实表组成,如 ds_0.t_user_0
  • 绑定表:分片规则一致的主表和子表,关联查询时走同路由避免笛卡尔积
  • 广播表:所有库中都存在的表,写入时同时写入多个库,查询时随机读一个

三、快速开始:ShardingSphere-JDBC

ShardingSphere-JDBC 定位为轻量级 Java 框架,以 JAR 包形式提供服务,可理解为增强版的 JDBC 驱动,完全兼容 JDBC 和各种 ORM 框架。

3.1 工作原理

sequenceDiagram
    participant App as 应用程序
    participant SS as ShardingSphere-JDBC
    participant DB0 as 数据库 ds_0
    participant DB1 as 数据库 ds_1

    App->>SS: 发送 SQL(操作逻辑表)
    SS->>SS: SQL 解析(Parse)
    SS->>SS: SQL 路由(Route)— 根据分片键计算目标节点
    SS->>SS: SQL 改写(Rewrite)— 逻辑表替换为真实表
    SS->>DB0: 执行 SQL(真实表)
    SS->>DB1: 执行 SQL(真实表)
    DB0-->>SS: 返回结果
    DB1-->>SS: 返回结果
    SS->>SS: 结果归并(Merge)
    SS-->>App: 返回归并后的结果集

3.2 环境准备

  • JDK 17+(5.5.3 支持 OpenJDK 24/25)
  • Maven 3.6+
  • MySQL 8.0+
  • Spring Boot 3.x(本教程示例)

先创建两个数据库和对应的分表:

-- 创建数据库
CREATE DATABASE shardingdb0;
CREATE DATABASE shardingdb1;

-- 在 shardingdb0 中创建分表
USE shardingdb0;
CREATE TABLE t_order_0 (
    order_id BIGINT NOT NULL,
    user_id BIGINT NOT NULL,
    amount DECIMAL(10,2),
    status VARCHAR(20),
    PRIMARY KEY (order_id)
);
CREATE TABLE t_order_1 (
    order_id BIGINT NOT NULL,
    user_id BIGINT NOT NULL,
    amount DECIMAL(10,2),
    status VARCHAR(20),
    PRIMARY KEY (order_id)
);

-- 在 shardingdb1 中创建相同的分表
USE shardingdb1;
CREATE TABLE t_order_0 (
    order_id BIGINT NOT NULL,
    user_id BIGINT NOT NULL,
    amount DECIMAL(10,2),
    status VARCHAR(20),
    PRIMARY KEY (order_id)
);
CREATE TABLE t_order_1 (
    order_id BIGINT NOT NULL,
    user_id BIGINT NOT NULL,
    amount DECIMAL(10,2),
    status VARCHAR(20),
    PRIMARY KEY (order_id)
);

3.3 添加 Maven 依赖

<!-- MySQL 驱动 -->
<dependency>
    <groupId>com.mysql</groupId>
    <artifactId>mysql-connector-j</artifactId>
    <scope>runtime</scope>
</dependency>

<!-- ShardingSphere JDBC 核心依赖 -->
<dependency>
    <groupId>org.apache.shardingsphere</groupId>
    <artifactId>shardingsphere-jdbc</artifactId>
    <version>5.5.3</version>
</dependency>

<!-- 连接池 HikariCP -->
<dependency>
    <groupId>com.zaxxer</groupId>
    <artifactId>HikariCP</artifactId>
</dependency>

<!-- MyBatis Plus(可选,本教程示例使用) -->
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-spring-boot3-starter</artifactId>
    <version>3.5.12</version>
</dependency>

5.5.3 引入了 BOM(Bill of Materials)统一版本基线,开发者只需引入核心依赖,再按需添加具体功能模块。如果想统一管理 ShardingSphere 全家桶版本,可以在 dependencyManagement 中引入 BOM:

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.apache.shardingsphere</groupId>
            <artifactId>shardingsphere-bom</artifactId>
            <version>5.5.3</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

3.4 配置数据源

在 Spring Boot 的 application.yml 中配置 ShardingSphere 驱动:

spring:
  datasource:
    driver-class-name: org.apache.shardingsphere.driver.ShardingSphereDriver
    # 指向类路径下的分片配置文件
    url: jdbc:shardingsphere:classpath:sharding.yaml

5.5.3 的新特性:如果使用集群模式并接入了 ZooKeeper 或 ETCD 注册中心,JDBC URL 可以直接写注册中心地址,无需本地 YAML 文件:

# ZooKeeper 方式
url: jdbc:shardingsphere:zk://127.0.0.1:2181/sharding_sphere_config

# ETCD 方式
url: jdbc:shardingsphere:etcd://127.0.0.1:2379/sharding_sphere_config

也可以通过 Java 配置类创建数据源(适用于多数据源场景):

@Configuration
public class DataSourceConfig {

    @Bean(name = "shardingDataSource")
    public DataSource shardingDataSource() throws SQLException, IOException {
        try (InputStream inputStream = getClass().getClassLoader()
                .getResourceAsStream("sharding.yaml")) {
            if (inputStream == null) {
                throw new IllegalStateException("Cannot find sharding.yaml in classpath");
            }
            byte[] yamlBytes = inputStream.readAllBytes();
            return YamlShardingSphereDataSourceFactory.createDataSource(yamlBytes);
        }
    }
}

3.5 编写分片配置

src/main/resources/sharding.yaml 中编写分片规则:

# ==================== 数据源配置 ====================
dataSources:
  ds_0:
    dataSourceClassName: com.zaxxer.hikari.HikariDataSource
    driverClassName: com.mysql.cj.jdbc.Driver
    jdbcUrl: jdbc:mysql://127.0.0.1:3306/shardingdb0?useSSL=false&serverTimezone=UTC&useUnicode=true&characterEncoding=UTF-8
    username: root
    password: your_password
  ds_1:
    dataSourceClassName: com.zaxxer.hikari.HikariDataSource
    driverClassName: com.mysql.cj.jdbc.Driver
    jdbcUrl: jdbc:mysql://127.0.0.1:3306/shardingdb1?useSSL=false&serverTimezone=UTC&useUnicode=true&characterEncoding=UTF-8
    username: root
    password: your_password

# ==================== 分片规则 ====================
rules:
  - !SHARDING
    tables:
      t_order:                              # 逻辑表名
        actualDataNodes: ds_${0..1}.t_order_${0..1}  # 实际数据节点:2库 x 2表
        databaseStrategy:                   # 分库策略
          standard:                         # 单分片键标准分片
            shardingColumn: user_id         # 分片列
            shardingAlgorithmName: db_inline  # 分片算法名称
        tableStrategy:                      # 分表策略
          standard:
            shardingColumn: order_id        # 分片列
            shardingAlgorithmName: t_order_inline
        keyGenerateStrategy:                # 分布式主键策略
          column: order_id                  # 自增列
          keyGeneratorName: snowflake       # 主键生成器

      # 绑定表:主子表分片规则一致,关联查询走同路由
      t_order_item:
        actualDataNodes: ds_${0..1}.t_order_item_${0..1}
        databaseStrategy:
          standard:
            shardingColumn: user_id
            shardingAlgorithmName: db_inline
        tableStrategy:
          standard:
            shardingColumn: order_id
            shardingAlgorithmName: t_order_inline
        keyGenerateStrategy:
          column: item_id
          keyGeneratorName: snowflake

    bindingTables:                          # 绑定表声明
      - t_order,t_order_item

    # 分片算法定义
    shardingAlgorithms:
      db_inline:                            # 分库算法:user_id 取模
        type: INLINE
        props:
          algorithm-expression: ds_${user_id % 2}
          allow-range-query-with-inline-sharding: true  # 允许范围查询
      t_order_inline:                       # 分表算法:order_id 取模
        type: INLINE
        props:
          algorithm-expression: t_order_${order_id % 2}

    # 主键生成器定义
    keyGenerators:
      snowflake:                            # 雪花算法(Long 类型)
        type: SNOWFLAKE

# ==================== 属性配置 ====================
props:
  sql-show: true                            # 打印改写后的真实 SQL,便于调试
  check-table-metadata-enabled: false       # 启动时不检查分片元数据一致性

3.6 配置项说明

配置文件由三大块组成,结构如下:

graph TD
    A["sharding.yaml"] --> B["dataSources<br/>数据源配置"]
    A --> C["rules<br/>规则配置"]
    A --> D["props<br/>属性配置"]

    B --> B1["ds_0 / ds_1<br/>物理数据源"]
    C --> C1["!SHARDING<br/>分片规则"]
    C --> C2["!READWRITE_SPLITTING<br/>读写分离"]
    C --> C3["!ENCRYPT<br/>数据加密"]
    C --> C4["!BROADCAST<br/>广播表"]
    C --> C5["!SINGLE<br/>单表规则"]
    C --> C6["!MASK<br/>数据脱敏"]
    D --> D1["sql-show<br/>SQL 日志"]
    D --> D2["check-table-metadata-enabled<br/>元数据检查"]

分片策略类型对照

策略类型 配置关键字 适用场景
标准分片 standard 单分片键,精确分片 + 可选范围分片
复合分片 complex 多分片键组合分片
Hint 分片 hint 不通过 SQL 而通过程序指定分片
自动分片 autoTables 只指定数据源和算法,自动分配数据节点

内置分片算法

算法类型 type 值 说明
行表达式分片 INLINE 基于 Groovy 表达式,最常用
取模分片 MOD 基于取模运算
哈希取模分片 HASH_MOD 先对分片键哈希再取模
范围分片 INTERVAL 基于时间或数值范围分片
自定义分片 CLASS_BASED 通过实现接口自定义算法

主键生成器类型

类型 type 值 生成的主键类型
雪花算法 SNOWFLAKE Long
UUID UUID String(带连字符)
NanoID NANOID String

3.7 代码实战

定义实体和 Mapper:

@Data
@TableName("t_order")
public class Order {
    @TableId(type = IdType.ASSIGN_ID)  // 使用 ShardingSphere 生成主键
    private Long orderId;
    private Long userId;
    private BigDecimal amount;
    private String status;
}

@Mapper
public interface OrderMapper extends BaseMapper<Order> {
}

编写测试代码:

@SpringBootTest
public class ShardingTest {

    @Autowired
    private OrderMapper orderMapper;

    @Test
    void testInsert() {
        for (long i = 1; i <= 10; i++) {
            Order order = new Order();
            order.setUserId(i);           // 分库键
            order.setAmount(new BigDecimal("100.00"));
            order.setStatus("INIT");
            orderMapper.insert(order);    // order_id 由雪花算法自动生成
        }
    }

    @Test
    void testQuery() {
        // 精确查询:根据分片键路由到单库单表
        LambdaQueryWrapper<Order> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Order::getUserId, 1L);
        List<Order> orders = orderMapper.selectList(wrapper);
        orders.forEach(System.out::println);
    }

    @Test
    void testQueryAll() {
        // 无分片键查询:全路由,归并结果
        List<Order> orders = orderMapper.selectList(null);
        orders.forEach(System.out::println);
    }
}

由于配置了 sql-show: true,控制台会打印路由后的真实 SQL,方便调试:

[ShardingSphere-SQL] Actual SQL: ds_0 ::: INSERT INTO t_order_0 (order_id, user_id, amount, status) VALUES (?, ?, ?, ?)
[ShardingSphere-SQL] Actual SQL: ds_1 ::: INSERT INTO t_order_1 (order_id, user_id, amount, status) VALUES (?, ?, ?, ?)

四、快速开始:ShardingSphere-Proxy

ShardingSphere-Proxy 是一个独立的服务进程,通过实现数据库二进制协议,将自己伪装成 MySQL/PostgreSQL 数据库,对客户端完全透明。

4.1 工作原理

sequenceDiagram
    participant Client as 客户端<br/>(MySQL CLI / Navicat / 应用)
    participant Proxy as ShardingSphere-Proxy<br/>(端口 3307)
    participant DB0 as MySQL ds_0
    participant DB1 as MySQL ds_1

    Client->>Proxy: MySQL 协议连接(以为是 MySQL)
    Client->>Proxy: SELECT * FROM t_order WHERE user_id=1
    Proxy->>Proxy: 解析 SQL + 路由计算
    Proxy->>DB0: SELECT * FROM t_order_0 WHERE user_id=1
    Proxy->>DB1: SELECT * FROM t_order_1 WHERE user_id=1
    DB0-->>Proxy: 结果集
    DB1-->>Proxy: 结果集
    Proxy->>Proxy: 结果归并
    Proxy-->>Client: 返回归并结果(MySQL 协议)

4.2 下载与安装

从官方下载页面获取二进制安装包:

https://shardingsphere.apache.org/document/5.5.3/cn/downloads/

解压后的目录结构:

shardingsphere-proxy-bin/
├── LICENSE
├── NOTICE
├── README.txt
├── bin/          # 启动停止脚本
├── conf/         # 配置文件目录
├── lib/          # JAR 包
└── licenses/

需要手动创建 ext-lib 目录并放入 MySQL JDBC 驱动:

mkdir ext-lib
# 下载 MySQL 驱动到 ext-lib 目录
wget -O ext-lib/mysql-connector-j-8.0.33.jar \
  https://repo1.maven.org/maven2/com/mysql/mysql-connector-j/8.0.33/mysql-connector-j-8.0.33.jar

4.3 配置 server.yaml

conf/server.yaml 是 Proxy 的全局配置,包含运行模式、认证信息、事务类型等:

mode:
  type: Standalone                    # 单机模式(生产环境用 Cluster)
  repository:
    type: JDBC                        # 元数据持久化方式
    props:
      provider: H2
      jdbc_url: jdbc:h2:mem:config;DB_CLOSE_DELAY=-1;MODE=MySQL

rules:
  - !AUTHORITY                        # 认证配置
    users:
      - root@%:root                   # 用户名:密码,% 表示任意主机
      - sharding@:sharding
    provider:
      type: ALL_PERMITTED             # 权限策略:全部允许(生产环境应细化)

  - !TRANSACTION                      # 事务配置
    defaultType: XA                   # 默认事务类型:XA / BASE
    providerType: Atomikos            # XA 事务管理器

  - !SQL_PARSER                       # SQL 解析器缓存配置
    sqlStatementCache:
      initialCapacity: 2000
      maximumSize: 65535
    parseTreeCache:
      initialCapacity: 128
      maximumSize: 1024

props:
  max-connections-size-per-query: 1   # 单次查询最大连接数
  kernel-executor-size: 16            # 内核执行线程数
  proxy-frontend-flush-threshold: 128 # 前端刷新阈值
  sql-show: false                     # 是否打印真实 SQL
  proxy-frontend-max-connections: 0   # 最大前端连接数(0=不限制)
  proxy-backend-executor-suitable: OLAP  # 后端执行器类型:OLAP / OLTP

4.4 配置分片规则

conf/config-sharding.yaml 定义逻辑库和分片规则:

schemaName: sharding_db               # 逻辑库名称(客户端看到的数据库名)

dataSources:                          # 物理数据源
  ds_0:
    url: jdbc:mysql://127.0.0.1:3306/shardingdb0?serverTimezone=UTC&useSSL=false
    username: root
    password: your_password
    connectionTimeoutMilliseconds: 30000
    idleTimeoutMilliseconds: 60000
    maxLifetimeMilliseconds: 1800000
    maxPoolSize: 50
    minPoolSize: 1
  ds_1:
    url: jdbc:mysql://127.0.0.1:3306/shardingdb1?serverTimezone=UTC&useSSL=false
    username: root
    password: your_password
    connectionTimeoutMilliseconds: 30000
    idleTimeoutMilliseconds: 60000
    maxLifetimeMilliseconds: 1800000
    maxPoolSize: 50
    minPoolSize: 1

rules:
  - !SHARDING
    tables:
      t_order:
        actualDataNodes: ds_${0..1}.t_order_${0..1}
        databaseStrategy:
          standard:
            shardingColumn: user_id
            shardingAlgorithmName: database_inline
        tableStrategy:
          standard:
            shardingColumn: order_id
            shardingAlgorithmName: t_order_inline
        keyGenerateStrategy:
          column: order_id
          keyGeneratorName: snowflake

    shardingAlgorithms:
      database_inline:
        type: INLINE
        props:
          algorithm-expression: ds_${user_id % 2}
      t_order_inline:
        type: INLINE
        props:
          algorithm-expression: t_order_${order_id % 2}

    keyGenerators:
      snowflake:
        type: SNOWFLAKE

4.5 启动与连接

# Linux / macOS 启动
sh bin/start.sh

# 指定端口启动(默认 3307)
sh bin/start.sh 3308

# Windows 启动
bin/start.bat

# 查看启动日志
tail -100f logs/stdout.log

看到以下日志表示启动成功:

[INFO ] 2026-xx-xx xx:xx:xx.xxx [main] o.a.s.p.frontend.ShardingSphereProxy
  - ShardingSphere-Proxy Standalone mode started successfully

使用 MySQL 客户端连接:

mysql -h 127.0.0.1 -u root -proot -P 3307

连接后操作逻辑库和逻辑表,ShardingSphere 会自动路由到真实的物理表:

mysql> SHOW DATABASES;
+-------------+
| schema_name |
+-------------+
| sharding_db |
+-------------+

mysql> USE sharding_db;

-- 插入数据,ShardingSphere 自动路由到对应分表
mysql> INSERT INTO t_order (user_id, amount, status) VALUES
       (1, 100.00, 'INIT'),
       (2, 200.00, 'INIT'),
       (3, 300.00, 'INIT');

-- 查询时透明聚合所有分表
mysql> SELECT * FROM t_order WHERE user_id = 1;
+--------------------+---------+--------+--------+
| order_id           | user_id | amount | status |
+--------------------+---------+--------+--------+
| 786812345678901234 |       1 | 100.00 | INIT   |
+--------------------+---------+--------+--------+

4.6 Docker 部署

docker run -d \
  --name shardingsphere-proxy \
  -p 3307:3307 \
  -v /path/to/conf:/opt/shardingsphere-proxy/conf \
  -v /path/to/ext-lib:/opt/shardingsphere-proxy/ext-lib \
  apache/shardingsphere-proxy:5.5.3

五、核心功能配置详解

5.1 读写分离

读写分离将写请求路由到主库,读请求按负载均衡策略路由到从库,是应对高并发读访问的常见手段。

graph LR
    App["应用"] --> SS["ShardingSphere"]
    SS -->|写请求| Write["主库 write_ds"]
    SS -->|读请求| LB["负载均衡"]
    LB -->|轮询/随机| Read0["从库 read_ds_0"]
    LB -->|轮询/随机| Read1["从库 read_ds_1"]

配置示例:

rules:
  - !READWRITE_SPLITTING
    dataSourceGroups:
      readwrite_ds:                      # 读写分离逻辑数据源名称
        writeDataSourceName: write_ds    # 写库(主库)数据源名
        readDataSourceNames:             # 读库(从库)数据源名列表
          - read_ds_0
          - read_ds_1
        transactionalReadQueryStrategy: PRIMARY  # 事务内读请求路由策略
        loadBalancerName: random         # 负载均衡算法名称

    loadBalancers:
      random:                            # 随机负载均衡
        type: RANDOM
      round_robin:                       # 轮询负载均衡
        type: ROUND_ROBIN
      weight:                            # 权重负载均衡
        type: WEIGHT
        props:
          read_ds_0: 2                   # 权重值
          read_ds_1: 1

事务内读请求路由策略transactionalReadQueryStrategy):

策略值 行为 适用场景
PRIMARY 事务内读请求路由到主库 默认值,保证读写一致性
FIXED 同一事务内路由至固定数据源 需数据库支持主从强一致同步
DYNAMIC 同一事务内路由至非固定数据源 需数据库支持主从强一致同步

5.2 分片 + 读写分离组合

实际生产中常需要同时使用分片和读写分离。配置时在分片规则中引用读写分离逻辑数据源即可:

dataSources:
  # 主库
  write_ds_0:
    dataSourceClassName: com.zaxxer.hikari.HikariDataSource
    jdbcUrl: jdbc:mysql://127.0.0.1:3306/master_0
    # ... 其他连接参数
  write_ds_1:
    dataSourceClassName: com.zaxxer.hikari.HikariDataSource
    jdbcUrl: jdbc:mysql://127.0.0.1:3306/master_1
  # 从库
  read_ds_0_0:
    dataSourceClassName: com.zaxxer.hikari.HikariDataSource
    jdbcUrl: jdbc:mysql://127.0.0.1:3307/slave_0_0
  read_ds_0_1:
    dataSourceClassName: com.zaxxer.hikari.HikariDataSource
    jdbcUrl: jdbc:mysql://127.0.0.1:3308/slave_0_1
  read_ds_1_0:
    dataSourceClassName: com.zaxxer.hikari.HikariDataSource
    jdbcUrl: jdbc:mysql://127.0.0.1:3307/slave_1_0
  read_ds_1_1:
    dataSourceClassName: com.zaxxer.hikari.HikariDataSource
    jdbcUrl: jdbc:mysql://127.0.0.1:3308/slave_1_1

rules:
  - !READWRITE_SPLITTING
    dataSourceGroups:
      ds_0:                              # 逻辑数据源 ds_0 = 1主2从
        writeDataSourceName: write_ds_0
        readDataSourceNames: [read_ds_0_0, read_ds_0_1]
        loadBalancerName: round_robin
      ds_1:                              # 逻辑数据源 ds_1 = 1主2从
        writeDataSourceName: write_ds_1
        readDataSourceNames: [read_ds_1_0, read_ds_1_1]
        loadBalancerName: round_robin
    loadBalancers:
      round_robin:
        type: ROUND_ROBIN

  - !SHARDING
    tables:
      t_order:
        actualDataNodes: ds_${0..1}.t_order_${0..1}  # ds_0/ds_1 是读写分离逻辑数据源
        databaseStrategy:
          standard:
            shardingColumn: user_id
            shardingAlgorithmName: db_inline
        tableStrategy:
          standard:
            shardingColumn: order_id
            shardingAlgorithmName: t_order_inline
    shardingAlgorithms:
      db_inline:
        type: INLINE
        props:
          algorithm-expression: ds_${user_id % 2}
      t_order_inline:
        type: INLINE
        props:
          algorithm-expression: t_order_${order_id % 2}

组合后的数据流向:

graph TD
    App["应用"] --> SS["ShardingSphere"]
    SS -->|写 user_id=1| W0["ds_0 主库 write_ds_0"]
    SS -->|读 user_id=1| R0["ds_0 从库<br/>read_ds_0_0 或 read_ds_0_1"]
    SS -->|写 user_id=2| W1["ds_1 主库 write_ds_1"]
    SS -->|读 user_id=2| R1["ds_1 从库<br/>read_ds_1_0 或 read_ds_1_1"]

5.3 分布式事务

ShardingSphere 提供两种分布式事务方案:

事务类型 一致性 性能 适用场景
XA 事务 强一致 较低 对数据一致性要求高的场景
BASE 事务 最终一致 较高 对性能要求高、可容忍短暂不一致

XA 事务配置(JDBC 端):

rules:
  - !TRANSACTION
    defaultType: XA
    providerType: Atomikos              # XA 事务管理器:Atomikos / Narayana

引入事务管理器依赖:

<!-- XA 事务管理器 Atomikos -->
<dependency>
    <groupId>org.apache.shardingsphere</groupId>
    <artifactId>shardingsphere-transaction-xa-atomikos</artifactId>
    <version>5.5.3</version>
</dependency>

BASE 事务配置(需要 Seata):

<dependency>
    <groupId>org.apache.shardingsphere</groupId>
    <artifactId>shardingsphere-transaction-base-seata-at</artifactId>
    <version>5.5.3</version>
</dependency>
rules:
  - !TRANSACTION
    defaultType: BASE
    providerType: Seata

代码中使用注解切换事务类型:

@Service
public class OrderService {

    @Autowired
    private OrderMapper orderMapper;
    @Autowired
    private OrderItemMapper orderItemMapper;

    // 使用默认事务类型(配置文件中指定的)
    @Transactional
    public void createOrder(Order order, OrderItem item) {
        orderMapper.insert(order);       // 可能路由到 ds_0
        orderItemMapper.insert(item);    // 可能路由到 ds_1
        // 跨库操作,由分布式事务保证一致性
    }

    // 显式指定 XA 事务
    @ShardingSphereTransactionType(TransactionType.XA)
    @Transactional
    public void createOrderWithXA(Order order, OrderItem item) {
        orderMapper.insert(order);
        orderItemMapper.insert(item);
    }

    // 显式指定 BASE 事务
    @ShardingSphereTransactionType(TransactionType.BASE)
    @Transactional
    public void createOrderWithBASE(Order order, OrderItem item) {
        orderMapper.insert(order);
        orderItemMapper.insert(item);
    }
}

5.4 数据加密

数据加密对应用透明:写入时自动加密存储,读取时自动解密返回,应用层无需感知。

graph LR
    subgraph 写入流程
        W1["应用写入明文"] --> W2["ShardingSphere 加密"] --> W3["数据库存储密文"]
    end
    subgraph 读取流程
        R1["数据库返回密文"] --> R2["ShardingSphere 解密"] --> R3["应用获取明文"]
    end

配置示例:

rules:
  - !ENCRYPT
    tables:
      t_user:                            # 加密表
        columns:
          password:                      # 加密列(逻辑列名)
            cipher:
              name: password             # 密文列名(物理存储列)
              encryptorName: aes_encryptor  # 加密算法
          phone:
            cipher:
              name: phone_cipher
              encryptorName: aes_encryptor
            assistedQuery:               # 辅助查询列(用于等值查询)
              name: phone_assisted
              encryptorName: md5_assisted

    encryptors:                          # 加密算法定义
      aes_encryptor:
        type: AES
        props:
          aes-key-value: 123456abc       # AES 密钥
          digest-algorithm-name: SHA-1   # 密钥摘要算法
      md5_assisted:                      # 辅助查询加密算法(不可逆)
        type: MD5

应用代码无需任何改动,正常写入和查询即可:

// 写入时,ShardingSphere 自动将 password 加密后存储
userMapper.insert(user);  // user.password = "明文密码"

// 查询时,ShardingSphere 自动解密返回明文
User user = userMapper.selectById(1L);  // user.password = "明文密码"

// 等值查询时,ShardingSphere 自动加密查询条件
wrapper.eq(User::getPhone, "13800138000");
// 实际执行:WHERE phone_cipher = AES('13800138000')
//         AND phone_assisted = MD5('13800138000')

5.5 数据脱敏

数据脱敏用于在查询结果中对敏感数据进行掩码处理,常用于日志展示、数据导出等场景:

rules:
  - !MASK
    tables:
      t_user:
        columns:
          email:
            maskAlgorithm: mask_before_at   # 邮箱脱敏
          phone:
            maskAlgorithm: keep_first_last  # 手机号脱敏
          id_card:
            maskAlgorithm: mask_middle      # 身份证脱敏

    maskAlgorithms:
      mask_before_at:                       # @ 前部分脱敏
        type: MASK_BEFORE_SPECIAL_CHARS
        props:
          special-chars: '@'
          replace-char: '*'
      keep_first_last:                      # 保留前3后4
        type: KEEP_FIRST_N_LAST_M
        props:
          first-n: 3
          last-m: 4
          replace-char: '*'
      mask_middle:                          # 中间脱敏
        type: MASK_FROM_MIDDLE_TO_HEAD
        props:
          replace-char: '*'
          target-chars: '8'

脱敏效果示例:

原始数据 脱敏算法 脱敏结果
zhangsan@qq.com MASK_BEFORE_SPECIAL_CHARS ********@qq.com
13812345678 KEEP_FIRST_N_LAST_M (3,4) 138****5678
110101199001011234 MASK_FROM_MIDDLE_TO_HEAD **********001234

5.6 广播表与单表

广播表:所有库中都存在的表,写入时同时写入多个库,查询时随机读一个。适用于字典表、配置表等数据量小但需要频繁 JOIN 的表:

rules:
  - !BROADCAST
    tables:
      - t_dict          # 字典表
      - t_config        # 配置表

单表:不需要分库分表的普通表,需要显式声明其所在数据源:

rules:
  - !SINGLE
    tables:
      - ds_0.t_address        # 指定单表
      # - ds_1.*              # 加载 ds_1 所有单表
      # - "*.*"              # 加载所有单表(谨慎使用)

六、运行模式与生产部署

6.1 单机模式 vs 集群模式

graph TB
    subgraph Standalone["单机模式"]
        S1["ShardingSphere 实例"] --> S2["本地元数据存储<br/>(H2 文件)"]
    end
    subgraph Cluster["集群模式"]
        C1["ShardingSphere 实例 1"]
        C2["ShardingSphere 实例 2"]
        C3["ShardingSphere 实例 N"]
        C1 --> ZK["注册中心<br/>ZooKeeper / ETCD"]
        C2 --> ZK
        C3 --> ZK
        ZK --> M["元数据共享<br/>状态协调"]
    end
维度 单机模式 集群模式
元数据存储 本地文件(H2) 注册中心(ZooKeeper / ETCD)
实例间感知 无法感知 实时同步
配置变更 仅当前实例生效 全集群即时生效
适用场景 本地开发测试 生产环境

6.2 集群模式配置

JDBC 端集群模式配置:

mode:
  type: Cluster                          # 集群模式
  repository:
    type: ZooKeeper                      # 注册中心类型:ZooKeeper / ETCD
    props:
      namespace: governance_ds           # 命名空间(隔离不同集群)
      server-lists: localhost:2181       # ZooKeeper 地址(多个逗号分隔)
      retryIntervalMilliseconds: 500     # 重试间隔
      timeToLiveSeconds: 60              # 节点存活时间
      maxRetries: 3                      # 最大重试次数
      operationTimeoutMilliseconds: 500  # 操作超时时间

Proxy 端集群模式配置(server.yaml):

mode:
  type: Cluster
  repository:
    type: ZooKeeper
    props:
      namespace: governance_proxy
      server-lists: zk1:2181,zk2:2181,zk3:2181
      retryIntervalMilliseconds: 500
      timeToLiveSeconds: 60
      maxRetries: 3
      operationTimeoutMilliseconds: 500

6.3 混合部署架构

生产环境推荐 JDBC + Proxy 混合部署,各取所长:

graph TB
    subgraph 应用层
        Java["Java 应用<br/>(OLTP)"] --> JDBC["ShardingSphere-JDBC"]
        Other["异构语言应用<br/>(OLAP)"] --> Proxy["ShardingSphere-Proxy"]
        DBA["DBA / 运维"] --> Proxy
    end

    JDBC --> ZK["注册中心<br/>ZooKeeper"]
    Proxy --> ZK

    ZK -->|"共享元数据<br/>统一配置"| Config["分片规则<br/>读写分离规则<br/>加密规则"]

    JDBC --> M0["MySQL 主库 0"]
    JDBC --> M1["MySQL 主库 1"]
    JDBC --> S0["MySQL 从库 0"]
    JDBC --> S1["MySQL 从库 1"]
    Proxy --> M0
    Proxy --> M1
    Proxy --> S0
    Proxy --> S1

七、DistSQL:声明式管理

DistSQL(Distributed SQL)是 ShardingSphere 扩展的 SQL 方言,允许通过 SQL 语句动态管理分片规则、数据源等,无需重启服务。

通过 Proxy 连接后即可使用:

-- 查看所有数据源
SHOW SCHEMA RESOURCES FROM sharding_db;

-- 动态添加数据源
ADD RESOURCE ds_2 (
    HOST="127.0.0.1", PORT=3306, DB="shardingdb2",
    USER="root", PASSWORD="your_password"
);

-- 创建分片规则
CREATE SHARDING TABLE RULE t_order (
    DATANODES("ds_${0..2}.t_order_${0..1}"),
    DATABASE_STRATEGY(TYPE="standard", SHARDING_COLUMN=user_id, SHARDING_ALGORITHM(TYPE(NAME=inline, PROPERTIES("algorithm-expression"="ds_${user_id % 3}")))),
    TABLE_STRATEGY(TYPE="standard", SHARDING_COLUMN=order_id, SHARDING_ALGORITHM(TYPE(NAME=inline, PROPERTIES("algorithm-expression"="t_order_${order_id % 2}"))))
);

-- 查看分片规则
SHOW SHARDING TABLE RULES;

-- 查看真实 SQL 路由
PREVIEW SELECT * FROM t_order WHERE user_id = 1;

DistSQL 让 DBA 能够在不修改配置文件、不重启服务的情况下动态调整分片规则,非常适合生产环境运维。

八、常见问题与最佳实践

8.1 分片键选择

分片键的选择直接影响系统性能,遵循以下原则:

  • 高频查询字段优先:选择 WHERE 条件中最常出现的字段,避免全路由扫描
  • 数据分布均匀:避免数据倾斜,如按用户 ID 取模通常比按时间分片更均匀
  • 避免频繁更新:分片键一旦确定不宜变更,更新分片键值会导致数据迁移
  • 考虑关联查询:主子表使用相同分片键配置为绑定表,减少跨库 JOIN

8.2 跨库查询优化

graph TD
    Q["查询请求"] --> R{"是否包含分片键?"}
    R -->|是| S1["精确路由<br/>单库单表执行"]
    R -->|否| S2["全路由广播<br/>所有分表执行并归并"]
    S2 --> S3{"是否使用绑定表?"}
    S3 -->|是| S4["绑定表 JOIN 走同路由<br/>避免笛卡尔积"]
    S3 -->|否| S5["跨库 JOIN<br/>使用联邦查询或应用层组装"]

避免全路由扫描的建议:

  • 尽量在查询条件中带上分片键
  • 使用绑定表优化主子表关联查询
  • 复杂跨库分析查询使用联邦查询(SQL Federation)
  • 合理使用广播表减少跨库 JOIN

8.3 常见问题排查

问题 1:启动报错 “Cannot find sharding.yaml”

确认配置文件位于 src/main/resources/ 目录下,且 application.yml 中的路径正确:

url: jdbc:shardingsphere:classpath:sharding.yaml

问题 2:SQL 路由到全部分表

检查 SQL 是否包含分片键条件。如果没有分片键,ShardingSphere 会广播到所有分表执行。开启 sql-show: true 查看实际路由情况。

问题 3:分片算法表达式报错

INLINE 算法使用 Groovy 表达式,注意以下规则:

# 正确:取模运算
algorithm-expression: ds_${user_id % 2}

# 正确:字符串哈希取模
algorithm-expression: ds_${Math.abs(id.hashCode() % 2)}

# 错误:MOD 算法不支持表达式,应使用 INLINE
# shardingAlgorithms:
#   xxx:
#     type: MOD                    # MOD 只接受 sharding-count 参数
#     props:
#       algorithm-expression: ...  # 这行会报错

问题 4:分布式事务不生效

确认已引入对应的事务管理器依赖,且配置文件中正确指定了事务类型。XA 事务需要数据库支持 XA 协议(MySQL 的 InnoDB 引擎支持)。

问题 5:Proxy 连接报权限错误

检查 server.yaml 中的认证配置,确认用户名密码正确,且权限策略允许当前操作:

rules:
  - !AUTHORITY
    users:
      - root@%:root          # @% 表示允许任意 IP 连接
    provider:
      type: ALL_PERMITTED    # 生产环境应使用 SCHEMA_PRIVILEGES_PERMITTED 细化权限

8.4 生产环境检查清单

检查项 说明
运行模式 生产环境必须使用 Cluster 模式 + ZooKeeper/ETCD
连接池参数 根据业务并发量调整 maxPoolSize、minPoolSize
事务类型 根据一致性要求选择 XA 或 BASE
权限策略 Proxy 端使用 SCHEMA_PRIVILEGES_PERMITTED 而非 ALL_PERMITTED
日志级别 生产环境关闭 sql-show,避免日志膨胀
监控告警 接入 Prometheus + Grafana 监控连接数、SQL 执行时间
数据备份 定期备份注册中心元数据和物理数据库
版本管理 通过 BOM 统一管理 ShardingSphere 组件版本

九、版本升级与生态

从旧版本升级到 5.5.3

5.5.3 相比 5.x 早期版本有以下不兼容变更,升级时需注意:

  • 分片规则持久化移除 default_strategies 前缀
  • Proxy 移除 SQL 格式化及日志规则(logging rule)功能
  • Proxy 移除配置项 system-log-level,SQL 日志 topic 调整为 org.apache.shardingsphere.sql
  • 建议通过 BOM 统一管理依赖版本,避免传递依赖冲突

相关资源

本教程覆盖了 ShardingSphere 5.5.3 的核心概念、两种部署形态的快速集成、分片/读写分离/事务/加密/脱敏等功能配置,以及生产部署的最佳实践。建议先在本地用单机模式跑通 ShardingSphere-JDBC 的分库分表示例,再逐步尝试读写分离和 Proxy 部署,最后过渡到集群模式的生产架构。