TT Lab
博客 开始
学习 学习路径 课程

PostgreSQL 复制与提升

「已连接」不等于「跟得上」

在 TT Lab 中继续学习

一句话总结

复制延迟大多发生在接收与应用之间,而这段差距,与其看 pg_stat_replication 中的时间数字,不如看 LSN 的字节差更诚实。而且,凡是拖住 WAL 的机制(slot、反馈),无一例外都会把成本转嫁给主服务器。

为什么需要它

备用服务器以“streaming”状态挂着,大家就都说复制正常。可是在备用服务器上出报表的团队,某天会说“凌晨以后的数据没有了”。连接完好,主服务器发出的 WAL 也全都落到了备用服务器的磁盘上——只是没有被应用。 也有反方向的事故。删除备用服务器时留下了 slot,主服务器就以为那台备用服务器总有一天会回来,于是不删除 WAL。几周后主服务器磁盘写满,写入停止。

它如何工作

备用服务器内部有两个工作者。WAL 接收器(walreceiver)从主服务器接收并写入磁盘(pg_last_wal_receive_lsn()),startup 进程再逐条应用(pg_last_wal_replay_lsn())。两者可以各自停下。

应用停止的原因 表现
有人调用了 pg_wal_replay_pause() pg_get_wal_replay_pause_state() 为 paused,日志中有 recovery has paused
到达了恢复目标(recovery_target_*) 同样是 paused。日志是 recovery stopping at restore point。此时 resume,恢复会结束并晋级
recovery_min_apply_delay 不是停止。把提交记录压后这么长时间再应用(灾难恢复用的“延迟备用服务器”设置)
与备用服务器查询的冲突 不是停止。主服务器的 VACUUM 删掉的行,如果备用服务器的查询还在看,应用会等待 max_standby_streaming_delay 的时间,然后取消查询。若为 -1 则无限等待

用字节来量。 pg_wal_lsn_diff(flush_lsn, replay_lsn) 是已经接收却没能应用的量。replay_lag 这类时间数字是在应用经过某个点时计算的,所以如果应用完全停住,上一次算出的较小的值有时会原样留着。

避免冲突的两条路各有代价。 延长等待时间,备用服务器就落后那么多;用 hot_standby_feedback = on 告诉主服务器“我的查询还在看这些行”,冲突会消失,代价是主服务器的 VACUUM 删不掉那些行(留在 slot 的 xmin 中)。没有免费的设置。

slot 是一个承诺。 slot 的 restart_lsn 之后的 WAL 不会被删除。即使使用它的备用服务器消失了,承诺依然存在。设置了 max_slot_wal_keep_size 后,拖住超过这个量的 slot 会在检查点时被切断(wal_status = lost),主服务器得以存活——被切断的备用服务器必须从 base backup 重新搭建。

定好测量的顺序,就不会迷路。 第一,在主服务器上把每台备用服务器的 sent_lsn、flush_lsn、replay_lsn 并排,看差距出现在哪里——在发送与接收之间是网络,在接收与确认之间是备用服务器的磁盘,在确认与应用之间是应用。第二,如果是应用一侧,就在备用服务器上查询暂停状态;如果不是暂停,就看 startup 进程在等什么(pg_stat_activity 的 wait_event)以及拖慢应用的设置。第三,阅读备用服务器日志——暂停、恢复目标、冲突等待都会在日志中各留下一行痕迹,而且那一行还写明了该做什么(或不该做什么)。

在现场会遇到的情形

为报表用备用服务器设置 max_standby_streaming_delay = -1,说是“绝对不要取消查询”,结果因为一个通宵运行的分析查询,备用服务器落后了六个小时——这种事很常见。监控只看连接状态,所以一直是绿灯。还有过这样的事:PITR 演练时用过的 recovery_target_name 通过配置管理工具扩散到了备用服务器上,某天遇到同名的还原点时,备用服务器们一齐停了下来。有人按了“停了就 resume”,那台备用服务器便悄悄晋级,开始接受写入。slot 这边的事故更安静。缩减读负载用的备用服务器时只删了服务器、留下了 slot,结果主服务器的 pg_wal 在几周内膨胀到几百 GB,某个凌晨磁盘写满了。这期间没有任何告警——因为没有一个告警去测量 pg_replication_slots 中 active 为 f 的 slot,以及它的 restart_lsn 落后了多少。

下一个实验要做的事

搭建一台备用服务器,只停止应用,用字节测量接收与应用的差距。制造备用服务器查询与应用冲突而被取消的情况,以及打开反馈后代价转移到主服务器清理上的情况。让一个没人使用的 slot 拖住 100MB 以上的 WAL,然后用上限把它切断。最后是事件——连接完好、数据却过时的三台备用服务器,找出原因并在不重启(只在确实需要的地方除外)的情况下修复。