PostgreSQL延迟hot standby使用问题及源码浅析

1 minute read

背景

在某些场景中,用户可能需要部署延迟的数据库,比如用来应对误操作。

用户可以创建延迟2小时的standby数据库,如果在2小时内发现了误操作,可以直接使用hot standby,查看误操作前的数据,从而进行恢复。

而不需要对数据库进行PITR恢复操作。

当然这个防范左右还有更好的方法,比如使用我前面写的基于ZFS的快照的备份策略,也可以快速的回档。

好了言归正传,为什么要小心使用PostgreSQL延迟hot standby,如果你的standby不仅仅要延迟,还要用于查询的话,那就需要注意了。

延迟的原理

pic

在PostgreSQL的redo中,只在commit, abort的record中记录了时间戳,所以目前PostgreSQL的延迟备库,只能在APPLY事务结束的redo上面做时间的延迟控制。

typedef struct xl_xact_commit  
{  
        TimestampTz xact_time;          /* time of commit */  
  
        /* xl_xact_xinfo follows if XLOG_XACT_HAS_INFO */  
        /* xl_xact_dbinfo follows if XINFO_HAS_DBINFO */  
        /* xl_xact_subxacts follows if XINFO_HAS_SUBXACT */  
        /* xl_xact_relfilenodes follows if XINFO_HAS_RELFILENODES */  
        /* xl_xact_invals follows if XINFO_HAS_INVALS */  
        /* xl_xact_twophase follows if XINFO_HAS_TWOPHASE */  
        /* xl_xact_origin follows if XINFO_HAS_ORIGIN, stored unaligned! */  
} xl_xact_commit;  
  
typedef struct xl_xact_abort  
{  
        TimestampTz xact_time;          /* time of abort */  
  
        /* xl_xact_xinfo follows if XLOG_XACT_HAS_INFO */  
        /* No db_info required */  
        /* xl_xact_subxacts follows if HAS_SUBXACT */  
        /* xl_xact_relfilenodes follows if HAS_RELFILENODES */  
        /* No invalidation messages needed. */  
        /* xl_xact_twophase follows if XINFO_HAS_TWOPHASE */  
} xl_xact_abort;  

在recovery.conf中也能看到这个描述

# By default, a standby server restores XLOG records from the primary as  
# soon as possible. If you want to explicitly delay the replay of committed  
# transactions from the master, specify a minimum apply delay. For example,  
# if you set this parameter to 5min, the standby will replay each transaction  
# commit only when the system time on the standby is at least five minutes  
# past the commit time reported by the master.  
#  
recovery_min_apply_delay = 0  

了解了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作为常用的只读备库,至少在改进之前不要这么做。
如果你仅仅想做一个误操作保护的话,这么做是没有问题的。

Flag Counter

digoal’s 大量PostgreSQL文章入口