为什么需要

一、读压力分担。 大多数应用的读请求远多于写请求。如果所有请求都打到一台数据库,读压力会先成为瓶颈。

二、高可用。 主库故障时,需要有备用节点可以顶上。

三、备份。 从库可以作为备份来源,不影响主库性能。

基本原理

主库(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)问题:如果主库只是"假死"(网络分区),而系统又提升了新主库,就可能出现两个主库同时接受写入,导致数据冲突。

读写分离的注意事项

  • 事务中的读操作必须走主库(否则可能读不到本事务刚写入的数据);
  • 对实时性要求高的查询走主库;
  • 报表类、统计类的慢查询走从库,避免拖慢主库;
  • 注意从库的负载均衡(多个从库之间也要分配流量)。

说明:本文为数据库架构的公开知识整理。