单库的三个痛点

MySQL 用一台库跑起来很简单,但业务一上来就碰到三个问题:单点故障(这台机挂了全站停写)、读压力大(所有查询都打在主库上,CPU 打满)、备份影响线上(在主库上做备份会占资源)。主从复制正是为解决这三件事而生:把数据复制到多台从库,读请求分流到从库,主库挂了还有备份顶上。

核心思路一句话:主库负责写,从库负责读和灾备。主库的每一次变更,通过 binlog 异步同步到从库,从库回放同样的操作,保持数据一致。

本文核心知识点
  • binlog主库记录所有写操作的日志,是复制的源头。
  • IO/SQL 线程从库拉日志并回放的两个核心线程。
  • 读写分离写走主库、读走从库,分摊压力。
  • 高可用切换主库宕机时自动提升从库为主。
MySQL 主从复制配图:蓝色渐变背景中央主数据库圆柱向左右两个镜像从库同步发光箭头,上方一个仲裁故障切换节点连接三者,扁平科技插画
主库向两个从库同步,上方仲裁节点负责主库故障时自动切换。

binlog 复制原理

主库把每一次 INSERT、UPDATE、DELETE 记到 binlog(二进制日志)。从库拉起两个线程:IO 线程负责连到主库、把 binlog 拉下来写到本地 relay log;SQL 线程负责读 relay log、在从库上重放这些变更。这样从库就一步步跟上了主库的每一次写入。

-- 主库:开启 binlog
[mysqld]
server-id=1
log-bin=mysql-bin

-- 从库:指定主库位置并启动
CHANGE REPLICATION SOURCE TO
  SOURCE_HOST='10.0.0.1',
  SOURCE_USER='repl',
  SOURCE_PASSWORD='***',
  SOURCE_LOG_FILE='mysql-bin.000001',
  SOURCE_LOG_POS=156;
START REPLICA;

server-id 每台库必须唯一,主从靠它区分身份。复制默认是异步的:主库写完就返回,不等从库确认,性能好但极端情况下从库可能落后。

一主多从与读写分离

一台主库可以挂多个从库,通常 1 主 2 到 3 从。写操作走主库,读操作通过代理层(如 ProxySQL、ShardingSphere-JDBC)分发到从库。这样查询压力被分摊,主库专注写入。

但要牢记:刚写完立刻读,可能命中从库、还没同步到,读到旧数据。所以“写后立刻读”的场景(如下单后查订单)要强制走主库,普通列表、报表、后台查询再走从库。

自动故障切换

主库宕机不能靠人手工切,太慢。高可用方案(MHA、Orchestrator、或云厂商的高可用版)会自动做三件事:检测主库是否真挂了(防止误判)、从多个从库里选一个数据最新的提升为新主、把其他从库和应用切到新主上。

切换一般配合 VIP(虚拟 IP)或服务发现:应用连的是一个漂移地址,主变了地址跟着漂,应用无感。这个过程通常在几十秒到一两分钟内完成。

复制延迟与一致性

异步复制下,从库总会比主库慢一点,叫复制延迟。延迟来源:从库单线程回放(高并发主库写入太快追不上)、从库本身在跑大查询拖慢了回放。监控上必须盯 Seconds_Behind_Source 这个延迟值,延迟过大就要告警。

降低延迟的常用手段:从库用并行复制(按库或按事务组并行回放)、给从库留出足够内存和 IO、别在从库上跑重型报表。

半同步与数据安全

异步复制的风险是:主库写完就崩、binlog 还没同步到从库,这条数据就丢了。对不能丢钱的业务(如账户、订单),用半同步复制:主库写完后,至少等一个从库确认收到 binlog 才向客户端返回成功。这样牺牲一点延迟,换“主库宕机不丢已提交数据”。

更严格的还可以配合 GTID(全局事务 ID),让主从切换时不用人工记 binlog 位点,自动找到从哪个位置继续,切换更稳。