读写分离与分库分表
读写分离
基本原理
将数据库的读操作和写操作分散到不同节点:
- 主库(Master):处理 INSERT、UPDATE、DELETE
- 从库(Slave):处理 SELECT
实现方案
| 方案 | 说明 | 优点 | 缺点 |
|---|---|---|---|
| 应用层 | 代码中配置多个数据源 | 灵活可控 | 侵入性强 |
| 中间件 | ProxySQL、MySQL Router、MyCat | 对应用透明 | 多一层网络开销 |
主从延迟问题
读写分离的核心难点是主从延迟:
text
主库写入 → binlog → 从库回放耗时 → 从库数据落后解决方案:
- 强制读主:对一致性要求高的查询走主库
- 延迟监控:
SHOW SLAVE STATUS中的Seconds_Behind_Master - 缓存中间层:写后短暂缓存,读直接命中缓存
分库分表
当单库、单表数据量过大时(如单表超过千万级),需要拆分。
垂直拆分
垂直分库:按业务模块拆分到不同数据库
text
用户服务 → user_db
订单服务 → order_db
商品服务 → product_db垂直分表:将表中不常用的字段拆分到扩展表
sql
-- 原表
users (id, name, age, phone, address, created_at)
-- 拆分为
users (id, name, age, created_at)
users_ext (id, phone, address)水平拆分
将数据按分片键分散到多个表/库中。
水平分表(单库多表):
text
users_0, users_1, users_2, ..., users_15水平分库(多库多表):
text
db0: users_0 ~ users_15
db1: users_16 ~ users_31
db2: users_32 ~ users_47分片策略
| 策略 | 说明 | 优点 | 缺点 |
|---|---|---|---|
| 取模 | id % 16 | 均匀分布 | 扩容需重新分布 |
| 哈希 | hash(key) % N | 均匀分布 | 同取模问题 |
| 范围 | 按时间/ID 范围 | 扩容简单 | 热点问题 |
| 一致性哈希 | 环状哈希 | 扩容影响小 | 实现复杂 |
分片键选择
- 选择访问最频繁的字段(如 user_id、order_id)
- 避免跨分片查询
- 业务尽可能带上分片键条件
ShardingSphere
ShardingSphere 是 Apache 顶级项目,提供分库分表、读写分离、分布式事务等能力。
核心组件
| 组件 | 说明 |
|---|---|
| ShardingSphere-JDBC | 轻量级 Java 客户端,增强 JDBC 驱动 |
| ShardingSphere-Proxy | 透明数据库代理,兼容 MySQL 协议 |
| ShardingSphere-Sidecar | Service Mesh 方案(实验阶段) |
JDBC 配置示例
yaml
# 数据源配置
dataSources:
ds0:
url: jdbc:mysql://host0:3306/db0
ds1:
url: jdbc:mysql://host1:3306/db1
# 分片规则
rules:
- !SHARDING
tables:
t_order:
actualDataNodes: ds${0..1}.t_order_${0..15}
tableStrategy:
standard:
shardingColumn: order_id
shardingAlgorithmName: t_order_inline
keyGenerateStrategy:
column: order_id
keyGeneratorName: snowflake
shardingAlgorithms:
t_order_inline:
type: INLINE
props:
algorithm-expression: t_order_${order_id % 16}分库分表带来的问题
1. 跨节点查询
- 跨分片 JOIN:无法直接 JOIN,需在应用层聚合
- 全局排序 + 分页:合并各分片结果再排序
- 分布式聚合(COUNT、SUM):各分片分别计算后汇总
2. 分布式事务
| 方案 | 一致性 | 性能 | 说明 |
|---|---|---|---|
| XA 协议 | 强一致 | 低 | 两阶段提交,性能瓶颈 |
| TCC(Try-Confirm-Cancel) | 最终一致 | 中 | 业务侵入大 |
| Seata AT | 最终一致 | 中 | 无侵入,依赖 Undo Log |
| 可靠消息 + 本地事务 | 最终一致 | 高 | 需消息中间件配合 |
3. 全局主键
分库分表后不能依赖数据库自增主键,需要全局唯一 ID:
| 方案 | 说明 | 特点 |
|---|---|---|
| 雪花算法(Snowflake) | 时间戳 + 机器号 + 序列号 | 有序递增,不依赖 DB |
| Leaf(美团) | Snowflake 改进版 | 支持号段模式 |
| 号段模式 | 批量获取 ID 段 | 依赖 DB,性能好 |
| UUID | 全局唯一 | 无序,索引性能差 |
分布式事务方案
Seata AT 模式
Seata 是阿里巴巴开源的分布式事务框架,AT 模式是其核心事务模式。
核心角色:
- TC(Transaction Coordinator):事务协调器(独立服务)
- TM(Transaction Manager):事务管理器(嵌入应用)
- RM(Resource Manager):资源管理器(嵌入应用)
执行流程:
- TM 向 TC 申请开启全局事务
- RM 执行本地事务,生成 Undo Log,向 TC 注册分支
- 全局提交:TC 通知各 RM 提交,异步删除 Undo Log
- 全局回滚:TC 通知各 RM 根据 Undo Log 回滚
TCC 模式
| 阶段 | 说明 |
|---|---|
| Try | 预留资源(冻结库存、冻结金额) |
| Confirm | 确认执行(扣减库存、扣减金额) |
| Cancel | 回滚释放(释放冻结资源) |
TCC 对业务侵入门槛较高,但性能优于 XA。