首页 > 其他分享 >pg- AutoVacuum(2)

pg- AutoVacuum(2)

时间:2023-04-08 11:11:06浏览次数:46  
标签:AutoVacuum autovacuum age freeze cost pg vacuum analyze

根据之前月报的分析,PostgreSQL数据库为了定时清理因为MVCC 引入的垃圾数据,实现了自动清理机制。其中涉及到了两种辅助进程:

  • autovacuum launcher
  • autovacuum worker

其中,autovacuum launcher 主要负责调度autovacuum worker,autovacuum worker进程进行具体的自动清理工作。本文主要是对autovacuum worker进行分析。

相关参数

除了之前月报提到的参数track_counts,autovacuum,autovacuum_max_workers,autovacuum_naptime,autovacuum_vacuum_cost_limit,autovacuum_vacuum_cost_delay,autovacuum_freeze_max_age,autovacuum_multixact_freeze_max_age之外,autovacuum worker还涉及到以下参数:

  • log_autovacuum_min_duration:所有运行超过此时间或者因为锁冲突而退出的autovacuum 会被打印在日志中,该参数每个表可以单独设置。
  • autovacuum_vacuum_threshold :与下文的autovacuum_vacuum_scale_factor配合使用,该参数每个表可以单独设置。
  • autovacuum_analyze_threshold:与下文的autovacuum_analyze_scale_factor配合使用,该参数每个表可以单独设置。
  • autovacuum_vacuum_scale_factor :当表更新或者删除的元组数超过autovacuum_vacuum_threshold+ autovacuum_vacuum_scale_factor* table_size会触发VACUUM,该参数每个表可以单独设置。
  • autovacuum_analyze_scale_factor:当表插入,更新或者删除的元组数超过autovacuum_analyze_threshold+ autovacuum_analyze_scale_factor* table_size会触发ANALYZE,该参数每个表可以单独设置。
  • vacuum_cost_page_hit:清理一个在共享缓存中找到的缓冲区的估计代价。它表示锁住缓冲池、查找共享哈希表和扫描页内容的代价。默认值为1。
  • vacuum_cost_page_miss:清理一个必须从磁盘上读取的缓冲区的代价。它表示锁住缓冲池、查找共享哈希表、从磁盘读取需要的块以及扫描其内容的代价。默认值为10。
  • vacuum_cost_page_dirty:当清理修改一个之前干净的块时需要花费的估计代价。它表示再次把脏块刷出到磁盘所需要的额外I/O。默认值为20。

其中,autovacuum_vacuum_threshold和autovacuum_vacuum_scale_factor参数配置会决定VACUUM 的频繁程度。因为autovacuum会消耗一定的资源,设置的不合适,有可能会影响用户的其他正常的查询。对PostgreSQL使用者来说,一般有2种方案:

  • 调大触发阈值,在业务低峰期,主动去做VACUUM。在VACUUM过程中,性能可能会出现抖动。
  • 调小触发阈值,将清理工作分摊到一段时间内。但是参数如果设置不合理,会使得正常查询性能都会下降。

为了降低对并发正常查询的影响,autovacuum引入了vacuum_cost_delay,vacuum_cost_page_hit,vacuum_cost_page_miss,vacuum_cost_page_dirty,vacuum_cost_limit参数。在VACUUM和ANALYZE命令的执行过程中,系统维护着一个内部计数器来跟踪各种被执行的I/O操作的估算开销。当累计的代价达到一个阈值(vacuum_cost_limit),执行这些操作的进程将按照vacuum_cost_delay所指定的休眠一小段时间。然后它将重置计数器并继续执行,这样就大大降低了这些命令对并发的数据库活动产生的I/O影响。

autovacuum worker 的启动

根据之前月报的分析,autovacuum launcher 在选取合适的database 之后会向Postmaster 守护进程发送PMSIGNAL_START_AUTOVAC_WORKER信号。Postmaster 接受信号会调用StartAutovacuumWorker函数:

  • 调用StartAutoVacWorker 启动worker
  • 调用成功,则释放后台进程slot进行善后处理,否则向autovacuum launcher发送信息,标记其为失败的autovacuum worker

StartAutoVacWorker 函数调用AutoVacWorkerMain 函数启动worker 进程:

  • 注册信号处理函数
  • 更新GUC参数配置:
    • zero_damaged_pages 参数强制设置为off,这个参数会忽略掉坏页,在自动清理的过程中,这样设置太危险
    • statement_timeout,lock_timeout,idle_in_transaction_session_timeout 为0,防止这些配置阻碍清理任务
    • default_transaction_isolation 设置为read committed,相对于设置为serializable,没增加死锁的风险,同时也不会阻塞其他的事务
    • synchronous_commit 设置为local,这样就允许我们不受备库的影响能够进行正常的清理任务
  • 读取共享内存中的AutoVacuumShmem 结构中的av_startingWorker 并更新需要清理的databaseoid 和wi_proc,放在运行中的autovacuum worker进程列表里面,并更新av_startingWorker 为NULL唤醒autovacuum launcher
  • 更新统计信息中autovacuum 的开始时间
  • 连接数据库,并读取最新的xid 和multixactid
  • 调用do_autovacuum 函数清理数据

do_autovacuum 函数的具体流程

do_autovacuum 函数会去遍历选中数据库的所有relation对象,进行自动清理工作,具体过程如下:

  • 初始化内存上下文
  • 更新统计信息
  • 获取effective_multixact_freeze_max_age
  • 设置default_freeze_min_age,default_freeze_table_age,default_multixact_freeze_min_age,default_multixact_freeze_table_age
  • 遍历pg_class所有的对象,并相应的进行处理:
    • 孤儿临时表(创建的session已经退出)打标并等待删除
    • 判断relation是否需要vacuum,analyze,wraparound,判断方法如下:
      • 该表统计信息中标记为dead的元组数大于autovacuum_vacuum_threshold+ autovacuum_vacuum_scale_factor* reltuples时,需要vacuum
      • 该表统计信息中从上次analyze之后改变的元组数大约autovacuum_analyze_threshold+ autovacuum_analyze_scale_factor* reltuples时,需要analyze
      • vacuum_freeze_table_age < recentXid - autovacuum_freeze_max_age 或者 relminmxid < recentMulti - multixact_freeze_max_age,为了防止XID 的回卷带来的问题,详见文档,标记为wraparound,这时必须强制vacuum
  • 根据上个步骤得到所有需要进行vacuum or analyze的对象,遍历所有对象,进行如下操作:
    • 重载最新的GUC 参数
    • 检查是否有其他的worker 进程正在对该relation进行清理,如果有,则跳过
    • 再次检查该relation是否需要清理,并生成用于追踪的autovac_table 结构
    • 根据上文所说的参数,对所有的worker 做资源平衡
    • 调用函数autovacuum_do_vac_analyze,进行vacuum or analyze
    • 释放缓存,更新之前月报分析的MyWorkerInfo结构
  • 更新该database的datfrozenxid

可以看出,do_autovacuum中利用共享内存AutoVacuumShmem 获取当前其他worker 的运行情况,避免并行worker 造成冲突。在此过程中调用函数autovacuum_do_vac_analyze 时会传递autovac_table 为参数,其定义如下:

/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
typedef struct autovac_table
{
	Oid			at_relid;
	int			at_vacoptions;	/* bitmask of VacuumOption */
	VacuumParams at_params;
	int			at_vacuum_cost_delay;
	int			at_vacuum_cost_limit;
	bool		at_dobalance;
	bool		at_sharedrel;
	char	   *at_relname;
	char	   *at_nspname;
	char	   *at_datname;
} autovac_table;

其中at_vacoptions指示vacuum的类型,具体如下:

typedef enum VacuumOption
{
	VACOPT_VACUUM = 1 << 0,		/* do VACUUM */
	VACOPT_ANALYZE = 1 << 1,	/* do ANALYZE */
	VACOPT_VERBOSE = 1 << 2,	/* print progress info */
	VACOPT_FREEZE = 1 << 3,		/* FREEZE option */
	VACOPT_FULL = 1 << 4,		/* FULL (non-concurrent) vacuum */
	VACOPT_NOWAIT = 1 << 5,		/* don't wait to get lock (autovacuum only) */
	VACOPT_SKIPTOAST = 1 << 6,	/* don't process the TOAST table, if any */
	VACOPT_DISABLE_PAGE_SKIPPING = 1 << 7	/* don't skip any pages */
} VacuumOption;

在autovacuum中,只涉及到VACOPT_SKIPTOAST,VACOPT_VACUUM,VACOPT_ANALYZE,VACOPT_NOWAIT。其中默认有VACOPT_SKIPTOAST选项,即会自动跳过TOAST表,关于TOAST表的autovacuum,我们在之后的月报详细分析。而VACOPT_VACUUM,VACOPT_ANALYZE,VACOPT_NOWAIT对应上文的vacuum,analyze,wraparound。

at_params存储vacuum的相关参数,其结构VacuumParams定义如下:

/*
 * Parameters customizing behavior of VACUUM and ANALYZE.
 */
typedef struct VacuumParams
{
	int			freeze_min_age; /* min freeze age, -1 to use default */
	int			freeze_table_age;	/* age at which to scan whole table */
	int			multixact_freeze_min_age;	/* min multixact freeze age, -1 to
											 * use default */
	int			multixact_freeze_table_age; /* multixact age at which to scan
											 * whole table */
	bool		is_wraparound;	/* force a for-wraparound vacuum */
	int			log_min_duration;	/* minimum execution threshold in ms at
									 * which  verbose logs are activated, -1
									 * to use default */
} VacuumParams;

vacuum函数的具体流程

vacuum 函数会根据传递的at_vacoptions 参数和at_params 参数对对应的对象进行VACUUM,既可以被autovacuum调用,又被用户手动执行VACUUM命令调用。所以这里的对象可以是relation,也可以是一个database,如果是database则会默认去vacuum该数据库所有relation 对象。autovacuum 调用vacuum函数时,这里的对象是具体的某个relation,其过程如下:

  • 检查at_vacoptions 参数正确性
  • 更新统计信息(autovacuum 在之前已经做过了,所以跳过)
  • 设置上下文
  • 如果需要VACUUM,则调用vacuum_rel 函数
  • 如果需要ANALYZE,则调用analyze_rel函数
  • 释放上下文,更新该database的datfrozenxid(autovacuum在do_autovacuum中已经做了,无需再做)

vacuum_rel函数具体去做VACUUM,这里根据at_vacoptions 参数的不同可以分为:

  • LAZY vacuum:只是找到dead的元组,把它们的状态标记为可用状态。但是它不进行空间合并。
  • FULL vacuum:除了 LAZY vacuum,还进行空间合并,因此它需要锁表。

autovacuum 是调用的LAZY vacuum。对于不断增长的表来说,LAZY vacuum显然是更合适的,LAZY vacuum主要完成:

  • 遍历该relation所有的页面,标记dead 元组为可用
  • 清理无用的index
  • 更新visibility map
  • 更新数据统计信息

LAZY vacuum该过程的调用函数关系为vacuum_rel—>lazy_scan_heap—>lazy_vacuum_heap—>lazy_vacuum_page,整个过程我们可以简单概括为:

  • 清理无用的index
  • 遍历所有的relation(table级数据库对象):
    • 遍历relation所有的page:
      • 把page 放在缓存中
      • 更新页面的组织形式(详见之前的月报),将无效元组对应的iterm设置为UNUSED,并将页面所有的tuples重新布局,使页尾保存空闲的空间,并将本页面打标为含有未使用的空间PD_HAS_FREE_LINES
      • 更新页面的free space 信息
      • 设置页面为脏页,等待后台进程将该页面刷新到磁盘
    • 更新该relation的统计信息
  • 更新visibility map
  • freeze tuple操作

总结

至此,我们得到的database 就是已经经过自动清理后的database。不过本文中还有很多问题没有涉及到:

  • 为了避免XID 回卷,freeze tuple等操作是如何实现的
  • FULL vacuum的具体操作是如何实现的
  • TOAST 表的vacuum 是如何实现的

我们会在之后的月报中一一进行分析,敬请期待。

转载:http://mysql.taobao.org/monthly/2018/02/04/

标签:AutoVacuum,autovacuum,age,freeze,cost,pg,vacuum,analyze
From: https://www.cnblogs.com/lovezhr/p/17298185.html

相关文章

  • PG-表膨胀及处理
    背景最近处理了几起线上实例表膨胀的问题。表膨胀是指表的数据和索引所占文件系统的空间,在有效数据量并未发生大的变化的情况下,不断增大。PG使用过程中需要特别关注这方面,我们来给大家解析一下表膨胀的原因。表膨胀的直接触发因素是表上的大量更新,如全表的update操作、大量的ins......
  • PGP加密
    项目中信息传输的安全性,是通过对信息进行非对称加密实现的,这里非对称加密,我们使用了PGP加密。PGP(PrettyGoodPrivacy,优良保密协议)是一套用于讯息加密、验证的应用程序。加密过程是由一系列散列、数据压缩、对称密钥加密,以及公钥加密的算法组合而成。每个步骤均支持几种算法,用户......
  • pg数据库查找外键但没有索引的sql
    SELECTpg_index.indexrelid::regclass,'createindex'||relname||'_'||array_to_string(column_name_list,'_')||'_idxon'||conrelid||'('||array_to_string(column_name_list,......
  • JumpGame
    packageDynamicPlanning;/***55.跳跃游戏*给定一个非负整数数组nums,你最初位于数组的第一个下标。*数组中的每个元素代表你在该位置可以跳跃的最大长度。*判断你是否能够到达最后一个下标。*//***设想一下,对于数组中的任意一个位置y,我们如何判断它是......
  • FPGA verilog can mcp2515 altera xilinx工程 代码 程序
    FPGAverilogcanmcp2515alteraxilinx工程代码程序...altera、xilinx工程均提供...标准帧、扩展帧均提供...提供仿真激励文件testbench资料包清单:1.程序:alteraxilinx工程代码、Verilogtestbench均提供。代码均在电路板验证2.说明书3.quartusii13.0:软件安装包......
  • sudo apt -y upgrade
    sudoapt-yupgrade    直接upgrade,不再询问y/n但是如果是sudo apt-get install scilab -y 那么,就不再显示上图中的信息,即当安装包的时候会询问y/n,这个参数是所有询问默认y,下边不再提醒,在终端输入以上命令时,直接下载安装,不再要求确认......
  • C# http地址下载(后缀.pdf/.jpg/.docx)文件
    一、http后缀.pdf文件下载方法///<summary>///http地址文件下载(url路径格式为:http://192.168.1.218:8088/1231_tr/1762062.pdf"})///</summary>///<paramname="filePath">http文件下载路径</param>///<paramn......
  • PgSQL常用操作
    1、重置表索引REINDEXINDEXindex_name;//重置单个索引REINDEXTABLEtable_name;//重置整个表的索引2、查询父表的分区表selectc.relnamefrompg_classcjoinpg_inheritspionpi.inhrelid=c.oidjoinpg_classc2onc2.oid=pi.inhparentwherec2.relname='父表名'......
  • mysql,pg连接重试参数配置
    PostgreSQLJDBCURL连接重试的示例:StringdbUrl="jdbc:postgresql://localhost:5432/mydb?autoReconnect=true&maxReconnects=5&connectTimeout=5000";Connectionconnection=null;try{connection=DriverManager.getConnection(dbUrl,"user......
  • 基于FPGA的永磁同步伺服控制系统的设计,在FPGA实现了伺服电机的矢量控制
    基于FPGA的永磁同步伺服控制系统的设计,在FPGA实现了伺服电机的矢量控制基于FPGA的永磁同步伺服控制系统的设计,在FPGA实现了伺服电机的矢量控制,坐标变换,电流环,速度环,位置环,电机反馈接口,SVPWM。都是通过Verilog语言来实现的,具有很高的研究价值。   ......