ShardingSphere 是 Apache 开源的 分布式数据库中间件 ,支持 分库分表、读写分离 ,能有效提升 数据库高并发处理能力 。本文通过一个 高并发订单系统 的案例,讲解 ShardingSphere 如何实现分库分表 + 读写分离。
1.分库分表
✅ 方案概述
分库分表(Database & Table Sharding)是指:
- 分库 (Sharding Database):订单表按
user_id
进行分库,比如user_id % 2
,将数据分别存入db_0
和db_1
。 - 分表 (Sharding Table):订单表在每个库中继续分表,比如
order_id % 4
,将数据存入order_0 ~ order_3
。 - 查询时 ,ShardingSphere 自动路由 SQL 到正确的数据库和表,无需应用层处理。
✅ 数据库结构
假设 2 个数据库 (db_0
、db_1
),每个数据库中有 4 张订单表 (order_0 ~ order_3
):
makefile
db_0:
├── order_0
├── order_1
├── order_2
├── order_3
db_1:
├── order_0
├── order_1
├── order_2
├── order_3
💡 分片规则:
- 分库:
user_id % 2 = 0 → db_0
,user_id % 2 = 1 → db_1
- 分表:
order_id % 4 = 0 ~ 3
(4 张表)
2.读写分离
读写分离 是指:
- 所有写操作(INSERT, UPDATE, DELETE)走主库(Master)。
- 所有读操作(SELECT)走从库(Slave)。
- ShardingSphere 自动路由 SQL 到正确的主从库。
✅ 数据库结构
假设每个数据库 采用主从架构:
scss
db_0 (主库) → db_0_slave1, db_0_slave2
db_1 (主库) → db_1_slave1, db_1_slave2
💡 读写分离策略:
- 写入(INSERT, UPDATE) →
db_0
/db_1
(主库) - 查询(SELECT) →
db_0_slave1, db_0_slave2
/db_1_slave1, db_1_slave2
3. 高并发案例:电商订单系统
📌 场景:秒杀订单
-
业务需求:
- 用户下单时,订单数据写入数据库(分库分表 + 写入主库)。
- 订单查询时,走从库(读写分离)。
- 高并发支持百万 QPS,防止数据库压力过大。
✅ 代码示例(Spring Boot + ShardingSphere)
1️⃣ 配置 sharding.yml
(分库分表 + 读写分离)
yaml
sharding:
datasource:
names: db_0, db_1
# 配置主从数据源(读写分离)
master-slave-rules:
db_0:
master-data-source-name: db_0
slave-data-source-names: db_0_slave1, db_0_slave2
db_1:
master-data-source-name: db_1
slave-data-source-names: db_1_slave1, db_1_slave2
# 分库策略(user_id % 2)
sharding-rules:
order:
actual-data-nodes: db_${0..1}.order_${0..3}
table-strategy:
inline:
sharding-column: order_id
algorithm-expression: order_${order_id % 4}
database-strategy:
inline:
sharding-column: user_id
algorithm-expression: db_${user_id % 2}
2️⃣ 下单(写操作,分库分表 & 主库写入)
java
@Service
public class OrderService {
@Autowired
private OrderRepository orderRepository;
@Transactional
public void createOrder(Long userId, Long productId) {
Order order = new Order();
order.setUserId(userId);
order.setProductId(productId);
order.setOrderId(System.currentTimeMillis()); // 唯一 ID
orderRepository.save(order);
}
}
💡 ShardingSphere 自动路由 SQL:
user_id=1001
,落到db_1
order_id=12345
,落到order_1
sql
INSERT INTO db_1.order_1 (order_id, user_id, product_id) VALUES (12345, 1001, 567);
3️⃣ 查询订单(读操作,自动路由到从库)
java
public Order getOrder(Long userId, Long orderId) {
return orderRepository.findByUserIdAndOrderId(userId, orderId);
}
💡 ShardingSphere 自动路由 SQL:
- 查询
user_id=1001, order_id=12345
,查询db_1_slave1, db_1_slave2
sql
SELECT * FROM db_1.order_1 WHERE user_id = 1001 AND order_id = 12345;
💡 ShardingSphere 自动使用从库,避免影响主库性能。
4. 性能优化(支持百万 QPS)
优化点 | 优化方式 |
---|---|
缓存 | Redis 预加载热点数据(订单查询先查 Redis)。 |
索引优化 | order_id, user_id 建立联合索引,加速查询。 |
异步处理 | 订单入库采用 Kafka + 异步处理,避免阻塞高并发请求。 |
批量插入 | INSERT INTO order_xxx (...) VALUES (...), (...) ,减少数据库连接开销。 |
数据库连接池 | 配置 HikariCP 连接池,提高数据库并发处理能力。 |
5.事务问题
场景 | 事务是否支持 | 解决方案 |
---|---|---|
同一 MySQL 实例(多个库) | ✅ 支持事务 | 普通事务 (START TRANSACTION ) |
分布式数据库(多个 MySQL 实例) | ❌ 不支持事务 | Seata / ShardingSphere / 事务消息 |
高并发分布式架构 | ❌ 不支持事务 | 基于 MQ 的最终一致性 |
- 同一 MySQL 实例内,多库事务 👉 普通事务 or XA 事务(适用于小规模应用)。
- 分库分表,多个 MySQL 实例 👉 ShardingSphere + 读写分离(适用于电商等大规模业务)。
- 分布式事务(跨多个 MySQL 实例) 👉 Seata(TCC / AT 模式) 。
- 高并发、高可用业务 👉 RocketMQ / Kafka 事务消息(最终一致性)。