副本延迟是什么
只读副本(从库)靠回放主库产生的日志来同步数据,回放天然滞后于主库写入,滞后程度就是复制延迟。延迟是异步复制的固有属性,真正的麻烦在于把它用进「写后立即读」的场景:客户端刚写完就去副本查,很容易读到旧版本的数据。延迟指标是估算值,不等于精确的落后时间。
基本信息
| 同步机制 | 主库写日志(MySQL binlog / PostgreSQL WAL),副本拉取并在本地回放 |
|---|---|
| 延迟来源 | 大事务、DDL、单线程回放、网络与磁盘、副本自身的查询负载 |
| 衡量方式 | 时间差(秒级指标)与位点差(日志位点比较) |
| 一致性风险 | 写后立即读副本可能读到旧数据,强一致读须路由主库 |
| 常见用途 | 读流量卸载、离线分析、故障切换 |
典型使用场景
- 读写分离扩容:把报表、列表页等只读流量压到副本,给主库减负
- 延迟监控告警:把回放滞后与位点差纳入监控,超阈值把流量切回主库
- 离线分析:耗时统计跑在副本上,避免拖慢主库的在线事务
- 写后读取舍:下单、支付等必须立刻看到自己写入的查询绕开副本
- 计划内维护:先在副本上换版本或加索引,验证通过再切主
- 故障切换:确认副本位点已追平,再提升为新主
MySQL 查看延迟
MySQL 查看延迟
SHOW REPLICA STATUS\G # 查看复制线程与滞后,老版本可用 SHOW SLAVE STATUS\G
-- 关注 Replica_IO_Running / Replica_SQL_Running 是否都是 Yes
-- 关注 Seconds_Behind_Source(旧称 Seconds_Behind_Master)与已读到的日志位点
SELECT * FROM performance_schema.replication_applier_status_by_worker\G
-- 并行回放时查看各 worker 进度与最近事务,定位卡在哪个线程
SELECT WAIT_FOR_EXECUTED_GTID_SET('3f9c...:1-1000', 5); # 等副本回放到指定位点,超时返回 1PostgreSQL 查看延迟
PostgreSQL 查看延迟
SELECT client_addr, state, sent_lsn, replay_lsn,
write_lag, flush_lag, replay_lag -- 主库端:每个副本各阶段滞后
FROM pg_stat_replication;
SELECT pg_last_wal_replay_lsn(), -- 副本端:已回放到的位点
pg_last_xact_replay_timestamp(); -- 副本端:最近一次重放事务的时间
SELECT confl_snapshot, confl_lock, confl_bufferpin -- 副本端:热备冲突被取消的查询次数
FROM pg_stat_database_conflicts WHERE datname = 'app';延迟指标逐项读法
| 指标 | 含义 | 正常与异常 |
|---|---|---|
| Seconds_Behind_Source | 副本回放进度与主库的时间差(秒) | 短时为正常;为 NULL 表示无法判断,常见于线程停止或连接中断 |
| Replica_IO_Running | 拉取主库日志的 IO 线程状态 | 非 Yes 说明日志已拉不下来 |
| Replica_SQL_Running | 回放日志的 SQL 线程状态 | 非 Yes 说明回放停了,延迟只会继续拉大 |
| sent_lsn / replay_lsn | 已发送与已回放的日志位点 | 两者差距持续扩大即回放跟不上 |
| write_lag / flush_lag / replay_lag | 写入、刷盘、回放三个阶段各自滞后 | 哪一项抬头就指向对应环节的瓶颈 |
| confl_* 冲突计数 | 热备回放取消查询的次数统计 | 持续增长说明副本查询在和回放抢资源 |
秒级延迟指标不能尽信:复制长时间空闲或网络断开时它会给出误导性读数,判断数据新鲜度应结合位点差、线程状态和业务能容忍的滞后时间一起看。
写后读一致性要在应用层解决:要么把这类查询显式路由回主库,要么在读取前等待目标位点(MySQL 用 WAIT_FOR_EXECUTED_GTID_SET 等 GTID,PostgreSQL 轮询回放位点),不要指望副本瞬间同步。
PostgreSQL 热备上运行的长时间查询可能因回放冲突被取消,冲突容忍度由 max_standby_streaming_delay 一类参数控制;业务侧要么能重试,要么把长查询放到专用副本。