详解ShardingSphere以及如何用它做读写分离
老规矩,先简单理解一下:
ShardingSphere 可以简单理解为 “数据库的智能管家”,帮你解决数据库在高并发、大数据量时的麻烦。
核心作用就两个:
- 分片:当一张表数据太多(比如上亿条),就像把大蛋糕切成小块,分到多个数据库 / 表里,查数据时不用翻整个蛋糕,效率更高。
- 读写分离:写数据(增删改)只往主库跑,读数据(查)自动分到从库,主库专心干活不被读请求打扰,就像超市收银台分 “结账” 和 “咨询” 窗口,不排队。
它最方便的是:你代码不用改,配置一下就行,该怎么写 SQL 还怎么写,背后的复杂分配逻辑它全帮你搞定。
Apache ShardingSphere 是一套开源的分布式数据库中间件解决方案,旨在解决分布式场景下的数据库分片、读写分离、数据加密、影子库等问题,提供标准化的数据访问层,简化分布式数据库操作。它采用 插件化架构,支持多种数据库(如 MySQL、PostgreSQL、SQL Server 等),并与 Spring、MyBatis 等主流框架无缝集成。
一、核心定位与架构
ShardingSphere 定位为 “数据库生态系统”,而非单一的数据库产品,其核心由三大组件构成:
- ShardingSphere-JDBC:基于 JDBC 的客户端中间件,嵌入应用程序内部,通过重写 JDBC 接口实现分布式功能(无需独立部署)。
- ShardingSphere-Proxy:基于 Proxy 的服务端中间件,独立部署为代理服务器,应用程序通过普通 JDBC 连接 Proxy,透明使用分布式功能。
- ShardingSphere-Sidecar:基于 Kubernetes 的云原生架构组件,以 Sidecar 模式与应用一同部署(适用于云原生场景)。
三者共享 核心功能模块(如分片、读写分离、加密等),可根据场景选择使用:
- 轻量级场景选 JDBC(性能损耗低,无独立部署成本);
- 多语言接入或统一管理场景选 Proxy(支持非 Java 语言,如 Python、Go)。
二、核心功能详解
1. 数据分片(Sharding)
解决单库单表数据量过大的问题,通过 水平分片(按行拆分)或 垂直分片(按表拆分)将数据分布到多个库 / 表中,核心能力包括:
- 分片策略:
- 自动分片:按规则(如范围、哈希、时间)自动路由,支持
INLINE(行表达式)、STANDARD(标准分片)、COMPLEX(复合分片)等。# 示例:按 user_id 取模分片到 2 个库,每个库分 3 个表 rules: sharding: tables: t_order: actual-data-nodes: ds_${0..1}.t_order_${0..2} # 实际表名 database-strategy: # 库分片策略 standard: sharding-column: user_id sharding-algorithm-name: db_inline table-strategy: # 表分片策略 standard: sharding-column: order_id sharding-algorithm-name: table_inline sharding-algorithms: db_inline: type: INLINE props: algorithm-expression: ds_${user_id % 2} table_inline: type: INLINE props: algorithm-expression: t_order_${order_id % 3} - 强制路由:通过
Hint指定分片库 / 表(如按用户权限路由到特定库)。
- 自动分片:按规则(如范围、哈希、时间)自动路由,支持
- 分布式事务:支持 XA 事务(强一致性)和 SAGA 事务(最终一致性),解决跨库事务问题。
- 分布式 ID:内置雪花算法(Snowflake)等生成全局唯一 ID,避免分片后 ID 冲突。
2. 读写分离(Read-Write Splitting)
将写操作路由到主库,读操作路由到从库,分担主库压力(前文已详述,核心点补充):
- 动态主从切换:支持主库故障时自动切换到从库(需配合数据库发现规则,如基于 ZooKeeper 监控主从状态)。
- 读库负载均衡:除轮询、随机外,支持自定义策略(如按从库延迟优先选择)。
- 事务内一致性:事务中的读操作默认走主库,避免从库同步延迟导致的脏读。
3. 数据加密(Encryption)
对敏感数据(如手机号、身份证号)进行透明加密存储,应用层读写时自动加解密,避免明文泄露:
- 加密策略:
- 密文存储:明文加密后存储,支持 AES、RSA 等算法。
- 辅助查询列:保留明文列用于查询(如加密手机号后,用明文列做模糊查询)。
rules: encryption: tables: t_user: columns: phone: # 需加密的列 cipher-column: phone_cipher # 密文存储列 plain-column: phone_plain # 明文查询列(可选) encrypt-algorithm-name: aes_encrypt encrypt-algorithms: aes_encrypt: type: AES props: aes-key-value: 123456abc # 加密密钥
4. 影子库(Shadow DB)
用于线上测试环境,将测试流量路由到影子库,避免影响生产数据:
- 通过 SQL 注释、用户、表名等规则识别测试流量,自动路由到影子库。
- 支持与分片、读写分离结合使用。
5. 其他功能
- 数据库发现:自动感知主从库拓扑变化(如主库宕机后从库晋升为主库)。
- SQL 解析与改写:对用户 SQL 进行解析,根据规则改写为分布式场景下的目标 SQL(如将单表查询改写为多库表联合查询)。
- 监控与运维:集成 Prometheus、Grafana 等工具,监控分片节点状态、SQL 执行效率等。
三、核心优势
- 透明化接入:对应用程序无侵入,无需修改业务代码,通过配置即可启用分布式功能。
- 灵活扩展:插件化架构支持自定义分片算法、加密策略等,适应复杂业务场景。
- 多模式支持:JDBC/Proxy/Sidecar 三种部署模式,满足不同架构需求。
- 生态兼容:支持主流数据库、ORM 框架(MyBatis、JPA)、容器化平台(K8s)。
四、典型应用场景
- 高并发读写:通过读写分离分担主库压力,适用于电商、社交等读多写少场景。
- 海量数据存储:通过分片将数据分散到多个库表,解决单库性能瓶颈(如订单表按用户 ID 分片)。
- 数据安全合规:对敏感数据加密,满足 GDPR、等保等合规要求。
- 线上测试隔离:通过影子库实现生产环境测试,避免数据污染。
五、使用注意事项
- 复杂度权衡:分布式功能会增加系统复杂度,需根据数据量和并发量决定是否引入(小体量业务可能无需分片)。
- 性能损耗:SQL 解析、跨库路由等操作会带来一定性能损耗(JDBC 模式损耗约 10%,Proxy 模式略高)。
- 主从同步延迟:读写分离需容忍从库数据延迟,关键读操作可强制走主库。
- 事务一致性:跨库事务需根据业务选择合适的一致性方案(XA 性能较低,SAGA 实现复杂)。
读写分离
在分布式系统中,使用 ShardingSphere 实现读写分离是提升数据库性能的常见方案,其核心思想是将读操作路由到从库,写操作路由到主库,从而分担主库压力。以下是基于 ShardingSphere-JDBC 实现读写分离的关键步骤和配置说明:
一、核心原理
ShardingSphere 的读写分离通过 主从数据源路由 实现:
- 写操作(INSERT/UPDATE/DELETE)默认路由到主库(Master)。
- 读操作(SELECT)默认路由到从库(Slave),支持从库负载均衡(如轮询、随机等策略)。
- 支持事务内读写操作强制走主库(避免事务内读从库导致的数据不一致)。
二、前提条件
- 已搭建好数据库主从复制(如 MySQL 主从同步),确保从库数据与主库一致。
- 项目中引入 ShardingSphere-JDBC 依赖(以 Maven 为例):
<dependency> <groupId>org.apache.shardingsphere</groupId> <artifactId>shardingsphere-jdbc-core</artifactId> <version>5.3.2</version> <!-- 最新稳定版 --> </dependency> <!-- 数据库驱动,如 MySQL --> <dependency> <groupId>com.mysql</groupId> <artifactId>mysql-connector-j</artifactId> <version>8.0.33</version> </dependency>
三、配置方式
ShardingSphere 支持 YAML 配置、Spring Boot 配置 或 Java 代码配置,以下以 YAML 和 Spring Boot 配置为例。
1. YAML 配置(独立配置文件)
创建 shardingsphere-config.yaml 配置文件,定义主从数据源和读写分离规则:
spring:
shardingsphere:
datasource:
names: master,slave1,slave2 # 数据源名称(主库+从库)
# 主库配置
master:
type: com.zaxxer.hikari.HikariDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://master-host:3306/db_name?useSSL=false&serverTimezone=UTC
username: root
password: master_password
# 从库1配置
slave1:
type: com.zaxxer.hikari.HikariDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://slave1-host:3306/db_name?useSSL=false&serverTimezone=UTC
username: root
password: slave1_password
# 从库2配置(可选,多从库负载均衡)
slave2:
type: com.zaxxer.hikari.HikariDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://slave2-host:3306/db_name?useSSL=false&serverTimezone=UTC
username: root
password: slave2_password
rules:
readwrite-splitting:
data-sources:
# 定义一个读写分离的数据源(逻辑名称)
readwrite_ds:
type: Static # 静态主从(动态主从需配合数据库发现规则)
props:
write-data-source-name: master # 主库数据源名称
read-data-source-names: slave1,slave2 # 从库数据源名称(逗号分隔)
load-balancer-name: round_robin # 从库负载均衡策略名称
load-balancers:
round_robin: # 轮询策略(可选:round_robin, random, 或自定义)
type: ROUND_ROBIN
props:
sql-show: true # 打印SQL,调试用
2. Spring Boot 配置(application.yml)
直接在 Spring Boot 配置文件中集成:
spring:
shardingsphere:
datasource:
names: master,slave1,slave2
master:
type: com.zaxxer.hikari.HikariDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://master-host:3306/db_name?useSSL=false&serverTimezone=UTC
username: root
password: master_password
slave1:
# 同YAML配置...
slave2:
# 同YAML配置...
rules:
readwrite-splitting:
data-sources:
readwrite_ds:
type: Static
props:
write-data-source-name: master
read-data-source-names: slave1,slave2
load-balancer-name: round_robin
load-balancers:
round_robin:
type: ROUND_ROBIN
props:
sql-show: true
# 使用ShardingSphere的数据源作为项目的主数据源
datasource:
type: org.apache.shardingsphere.driver.ShardingSphereDataSource
四、关键配置说明
-
数据源定义:
names列出所有主从库的数据源名称。- 每个数据源需配置连接信息(驱动、URL、用户名、密码)。
-
读写分离规则:
readwrite-splitting.data-sources:定义逻辑数据源(如readwrite_ds),关联主从库。type: Static:适用于主从架构固定的场景;若主从可能动态变化(如主库故障切换),需使用Dynamic并配合数据库发现规则。load-balancer-name:从库负载均衡策略,支持:ROUND_ROBIN:轮询(默认)。RANDOM:随机。- 自定义策略:实现
ReadQueryLoadBalanceAlgorithm接口。
-
事务一致性:
- 事务内的读操作默认路由到主库(避免从库同步延迟导致的脏读)。
- 可通过
hint强制指定路由(如强制读主库):// 强制读主库(需在方法内调用) HintManager.getInstance().setWriteRouteOnly();
五、使用方式
-
项目中直接注入
DataSource或使用JdbcTemplate、MyBatis等 ORM 框架,无需修改业务代码:@Autowired private JdbcTemplate jdbcTemplate; // 写操作(自动路由到主库) public void insertData() { jdbcTemplate.update("INSERT INTO t_user (name) VALUES (?)", "test"); } // 读操作(自动路由到从库) public List<User> queryData() { return jdbcTemplate.query("SELECT * FROM t_user", new BeanPropertyRowMapper<>(User.class)); } -
若使用 MyBatis,只需将数据源配置为 ShardingSphere 的数据源,Mapper 接口无需任何修改。
六、注意事项
- 主从同步延迟:读写分离可能因从库同步延迟导致读不到最新数据,需根据业务场景容忍度调整(如关键读操作强制走主库)。
- 事务边界:确保事务内的读写操作路由一致性(ShardingSphere 已默认处理)。
- 动态主从切换:若需支持主库故障自动切换到从库,需配置
Dynamic类型的读写分离,并结合数据库发现规则(如基于 ZooKeeper 的主从监控)。 - 版本兼容性:ShardingSphere 5.x 与 Spring Boot 2.x/3.x 兼容,注意依赖版本匹配。
通过以上配置,ShardingSphere 可透明地实现读写分离,无需侵入业务代码,有效提升数据库吞吐量。
更多推荐

所有评论(0)