读写分离的基本原理是将数据库读写操作分散到不同的节点上。
一、读写分离架构
读写分离主要通过 主从架构(Master-Slave) 实现。
1. 基本原理
数据库服务器搭建一个主库与多个从库:
主库(Master)负责写操作:包括 INSERT、UPDATE、DELETE。
从库(Slave)负责读操作:SELECT。
从库通过 复制机制(如 MySQL 的 binlog 复制)从主库同步数据。
主从数据流
主库将写操作写入 binlog。
从库通过 I/O 线程拉取 binlog。
从库 SQL 线程重放 binlog,将数据更新到从库。
-- 在主库开启 binlog[mysqld]server-id=1log-bin=mysql-bin-- 在从库设置[mysqld]server-id=2relay-log=relay-binread_only=1-- 从库执行CHANGE MASTER TOMASTER_HOST='master_ip',MASTER_USER='repl',MASTER_PASSWORD='xxxx',MASTER_LOG_FILE='mysql-bin.000001',MASTER_LOG_POS=4;START SLAVE;
2. 主从复制延迟问题与解决方式
延迟产生的原因
主库写入时并发高,从库处理 binlog 的速度不及主库写入速度,会导致延迟。例如主库写入成功,但从库还没同步,这时读请求从从库读到了旧数据。
解决方法
方法 1:写后读操作指定到主库
适用于对数据一致性要求高的场景。
写操作后,紧跟着的一次读请求必须指定到主库。
案例:用户下单后立即查看订单列表。
伪代码:
write_order(user_id, order_data)result = read_order_from_master(user_id)
方法 2:读从库失败后再读主库
适用于多数读不敏感 + 部分业务要强一致性的场景。
result = read_from_slave()if not result:result = read_from_master()
方法 3:关键业务读写全部指向主库
非关键业务读写分离,关键业务不分离。
示例:
支付、订单、库存 → 主库
商品列表、推荐、评论 → 从库
3. 读写分离实现方式
读写分离的实际落地大致分为两类:
二、程序代码封装方式实现读写分离
由应用层自行决定 SQL 是读还是写,并路由到对应数据库。
1. 实现原理
应用代码中加入数据库访问层(DAO 层或网关),按照 SQL 类型或业务逻辑判断:
SELECT→ 从库INSERT / UPDATE / DELETE→ 主库
也可在业务逻辑层标记某些操作必须读主库。
2. 典型方案
早期淘宝的 TDDL
Spring 的
AbstractRoutingDataSource扩展各公司自研的 DB Route 组件
3. 代码示例(Java)
public DataSource getDataSource(String sql) {if (sql.trim().toLowerCase().startsWith("select")) {return slaveDataSource;} else {return masterDataSource;}}
或使用注解:
public User getUser(long id) {...}
三、中间件封装实现读写分离
这是更先进、更稳定的方式。
1. 原理
通过一个数据库代理层,例如:
MySQL Router
Atlas(基于 MySQL Proxy)
ProxySQL
应用程序只连接代理,代理根据 SQL 自动分发到主库或从库。
架构示例:
应用程序 → ProxySQL → Master/Slave
2. 特点
优点
支持多种编程语言
稳定性高
故障转移自动化,可以探测主从状态
对业务服务透明,无需修改代码
缺点
实现复杂
配置多
需要专门运维
3. MySQL Router 示例
配置示例
[routing:read_write]bind_address = 0.0.0.0bind_port = 7001mode = read-writedestinations = master_ip:3306[routing:read_only]bind_address = 0.0.0.0bind_port = 7002mode = read-onlydestinations = slave1_ip:3306, slave2_ip:3306
应用侧使用方式:
# 写请求连 7001mysql -h router -P7001# 读请求连 7002mysql -h router -P7002
四、分库分表技术
当单库读写压力依然扛不住,或者数据量达到千亿级时,需要进行 分库分表。
原理
通过分配规则(sharding)将数据分布到多个物理库或表中。
1. 数据分配机制
常见方式:
哈希(user_id % 16)
范围分片(按日期)
地域分片(按城市)
示例:按照 user_id 分库分表
假设用户表非常大,拆成 4 个库,每个库 4 张表:
库名:
userdb_0userdb_1userdb_2userdb_3
user_0user_1user_2user_3
db_index = user_id % 4table_index = (user_id // 4) % 4
2. 实际案例:订单系统分库分表
订单号:order_id = 用户ID + 时间戳
规则:
数据写进:
orderdb_{order_id % 8}表路由:
orders_{(order_id // 8) % 16}
好处:
支持亿级订单数据
查询性能提升 5~10 倍
五、读写分离 + 分库分表协同使用的实战架构
生产环境常见组合:
应用 → ProxySQL(读写分离) → 多主库 + 各自从库(分库分表) → 每库再水平扩展
优点:
多维扩容
支撑大规模业务(电商、直播、支付等)
六、总结
|
|
|
|
|
|---|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|

