在某些场景中,用户可能需要部署延迟的数据库,比如用来应对误操作。
用户可以创建延迟2小时的standby数据库,如果在2小时内发现了误操作,可以直接使用hot standby,查看误操作前的数据,从而进行恢复。
而不需要对数据库进行pitr恢复操作。
当然这个防范左右还有更好的方法,比如使用我前面写的基于zfs的快照的备份策略,也可以快速的回档。
好了言归正传,为什么要小心使用postgresql延迟hot standby,如果你的standby不仅仅要延迟,还要用于查询的话,那就需要注意了。

在postgresql的redo中,只在commit, abort的record中记录了时间戳,所以目前postgresql的延迟备库,只能在apply事务结束的redo上面做时间的延迟控制。
在recovery.conf中也能看到这个描述
了解了postgresql的延迟恢复原理后,回答一下这么做会有什么问题呢?
比如某个事务包含了ddl操作,那么这笔操作马上会在hot standby执行,锁在hot standby也同时被加载。
但是当遇到这个事务的commit record时,由于设置了recovery_min_apply_delay,这笔record被延迟执行,这个锁也会延迟到这笔record被apply为止。
在此延迟时间段内,对这个被执行ddl的表的query都会被堵塞。
这个锁会持续多长时间呢?
这么长recovery_min_apply_delay。
其他锁和读操作基本上都没有冲突,所以用户在延迟的hot_standby查询数据时感觉不到,但是ddl的感觉是非常明显的。
1. 增加guc参数,apply时,检测事务中是否包含ddl级别的锁,如果包含这种锁,用户可以通过recovery.conf中的参数设置,这个事务的record是否立即执行,而不等待recovery_min_apply_delay。
减少延迟hot standby中事务包含ddl锁带来的问题。
2. 或者增加对事务开启时间的记录,用户可以通过guc参数,设置延迟是从事务开始时间计算,还是从事务结束开始计算。
1. 建议用户不要使用带延迟的hot_standby作为常用的只读备库,至少在改进之前不要这么做。
如果你仅仅想做一个误操作保护的话,这么做是没有问题的。