digoal
2024-05-30
PostgreSQL , PolarDB , DuckDB , vacuum , freeze
今天来采访讯飞的胡杨老师, 感谢胡老师临走时给我的吐槽信息, PG的垃圾回收调度有问题, 有可能会在业务高峰期发生, 造成业务影响(如性能抖动).
知识点:
1、vacuum analyze, 扫描部分page, 触发时机取决于 autovacuum_analyze_threshold和autovacuum_analyze_scale_factor参数配置, 简单理解为数据记录变化量超过一定比率就触发. 采样精度取决于default_statistics_target, 一定程度上决定了扫描多少个数据块.
2、vacuum, 扫描部分page, 触发时机取决于 autovacuum_vacuum_threshold和autovacuum_vacuum_insert_threshold和autovacuum_vacuum_scale_factor和autovacuum_vacuum_insert_scale_factor参数, 简单理解为数据记录变化量超过一定比率就触发. (其中insert操作引发的变化比率被单独拿出来了, 因为insert不产生垃圾, 但是也需要vacuum从而刷新vm文件和hit bit信息.)
3、vacuum freeze whole table, 扫描表的全部page, 触发时机取决于 vacuum_freeze_table_age和vacuum_multixact_freeze_table_age参数配置, 简单理解为表的年龄达到一定值时触发. 并清除年龄大于vacuum_freeze_min_age,vacuum_multixact_freeze_min_age值的tuple的事务号信息, 因此可能产生大量wal日志、大量IO和CPU.
4、vacuum freeze whole table, 扫描表的全部page, 还有一个触发时机取决于 autovacuum_freeze_max_age和autovacuum_multixact_freeze_max_age, 也就是即使没有开启autovacuum, 如果表年龄达到这个阈值也会触发, 因此可能产生大量wal日志、大量IO和CPU.
5、如果配置了 vacuum_defer_cleanup_age (老版本)则可能导致垃圾阈值已经达到, 但是不允许回收的情况, 导致cpu和io持续飙升. 在不断扫描需要回收垃圾的table, 判断dead tuple是否能被回收.
如果有long query、未关闭2pc事务、长事务存在, 或者如果配置了hot_standby_feedback并且standby上有长事务存在, 也容易造成垃圾阈值已经达到, 但是不允许回收(因为垃圾版本可能需要被未结束的事务查看)的情况, 导致cpu和io持续飙升. 在不断扫描需要回收垃圾的table, 判断dead tuple是否能被回收.
通过配置old_snapshot_threshold, 可以强制回收年龄过久的垃圾tuple. ps: 这个参数被17废弃了, 因为开启后太影响性能, 未来有其他实现方式.
1、为了减轻vacuum时产生大量cpu和IO造成业务影响, vacuum 的睡眠机制取决于一些参数配置, 干活/休息/干活/休息...
#vacuum_cost_delay = 0 # 0-100 milliseconds (0 disables)
#vacuum_cost_page_hit = 1 # 0-10000 credits
#vacuum_cost_page_miss = 2 # 0-10000 credits
#vacuum_cost_page_dirty = 20 # 0-10000 credits
#vacuum_cost_limit = 200 # 1-10000 credits
#autovacuum_max_workers = 3 # max number of autovacuum subprocesses
#autovacuum_naptime = 1min # time between autovacuum runs
#autovacuum_vacuum_cost_delay = 2ms # default vacuum cost delay for
#autovacuum_vacuum_cost_limit = -1 # default vacuum cost limit for
2、同时通过配置参数控制垃圾回收的并发度
#autovacuum_max_workers = 3 # max number of autovacuum subprocesses
对于单表(指单个分区), 目前还没有支持并发. 但是单表(指单个分区)的多个索引是可以并发的.
你肯定发现了上面PG减轻vacuum时造成的业务影响的手段比较粗糙, 为什么就不从业务繁忙程度方面入手来解决呢?
业务空闲时就全速回收.
业务繁忙时就低速回收, 当然也要考虑垃圾产生速度, 如果回收限速太低可能导致垃圾回收不及时膨胀.
因为PG的vacuum不够智能, 很多朋友给我反馈过在业务高峰期发生vacuum freeze导致业务性能受损的问题. 所以我给他们提供了一些补救措施, 例如预测什么时候可能产生freeze风暴, 通过拆成分区表, 给不同分区定义不同的回收阈值, 或者人为设置vacuum调度, 避开高峰期等.
详细文档参考:
《PostgreSQL Freeze 风暴预测续 - 珍藏级SQL》
《PostgreSQL freeze 风暴导致的IOPS飙升 - 事后追溯》
《PostgreSQL的"天气预报" - 如何预测Freeze IO风暴》
以上方法会增加dba的管理任务, 其实是不友好的. 为什么就不从业务繁忙程度方面入手来解决呢?
业务空闲时就全速回收/freeze.
业务繁忙时就低速回收/freeze.
很期待PG更加智能.
