为什么需要
一、读压力分担。 大多数应用的读请求远多于写请求。如果所有请求都打到一台数据库,读压力会先成为瓶颈。
二、高可用。 主库故障时,需要有备用节点可以顶上。
三、备份。 从库可以作为备份来源,不影响主库性能。
基本原理
主库(Master)记录所有数据变更到 binlog(二进制日志)。
从库(Slave)有两个线程:
- I/O 线程:连接主库,读取 binlog,写入本地的中继日志(relay log);
- SQL 线程:读取中继日志,在本地重放(replay)这些变更。
复制的三种格式
Statement-based:记录 SQL 语句本身。
- 优点:日志量小;
- 缺点:某些语句在从库上重放的结果可能与主库不一致(如使用了
NOW()、RAND()、或依赖当前数据的 UPDATE)。
Row-based:记录每一行数据的前后变化。
- 优点:确定性强,不会有不一致;
- 缺点:日志量大(一条 UPDATE 影响 100 万行,就要记录 100 万条变更)。
Mixed:混合模式,MySQL 根据语句类型自动选择。
复制延迟
这是主从架构中最实际的问题。
主库写入后,从库需要时间才能同步到最新状态。这个延迟可能是毫秒级,在负载高或从库性能差时也可能达到秒级甚至分钟级。
带来的问题:用户在主库写入后立即查询,如果查询被路由到从库,可能读不到刚写入的数据。
应对:
- 写后读主库:对一致性要求高的读取,强制走主库;
- 监控延迟:延迟超过阈值时,把读流量切回主库或告警;
- 并行复制:让从库的多个线程并行重放不同数据库或不同事务的变更,提升同步速度(MySQL 5.6 之后支持库级并行,5.7 之后支持组提交并行);
- 减少大事务(一个大事务会让从库重放很久)。
复制模式
异步复制(默认):主库写入 binlog 后立即返回,不等待从库确认。性能好,但主库宕机时可能丢失尚未同步的数据。
半同步复制:主库提交事务时,等待至少一个从库确认已收到日志后才返回。在数据安全和性能之间折中。
全同步:等待所有从库都应用完变更。最安全,但延迟最高,实践中很少用。
主库故障切换
主从复制本身不提供自动故障切换。要实现高可用,需要额外机制:
- 监控主库存活;
- 确认故障后,选择一个从库提升为主库;
- 把其他从库指向新主库;
- 把应用的写流量切到新主库。
这一步要特别小心脑裂(Split-Brain)问题:如果主库只是"假死"(网络分区),而系统又提升了新主库,就可能出现两个主库同时接受写入,导致数据冲突。
读写分离的注意事项
- 事务中的读操作必须走主库(否则可能读不到本事务刚写入的数据);
- 对实时性要求高的查询走主库;
- 报表类、统计类的慢查询走从库,避免拖慢主库;
- 注意从库的负载均衡(多个从库之间也要分配流量)。
说明:本文为数据库架构的公开知识整理。