PostgreSQL 为什么怕听到 FREEZEN 这个词的解释与"盯着"他

完美无缺的系统是不存在的,或者认为某个系统很完美的你,不完美,今天就的开始talk一下Postgresql 的一个“不可回避的问题”, FREEZEN.

POSTGRESQL FREEZEN 到底是什么,为什么提到这个事情心里总有些惴惴不安,的从POSTGRESQL 的原理开始,POSTGRESQL 中的事务ID 是32位组成的,也就是说系统分配的事务的ID是有限的.

在一个繁忙的系统中,事务的ID被用完怎么办,系统就停止了?  POSTGRESQL 通过HALF BY HALF 的方式来解决这个问题,就是一半可用一半不可用,将可用的事务的ID 变成2.1亿.

通过下面粗略的比喻的图, 我们这样讲解,如果我就有12个事务的ID, 那么我不能说我把事务号都分了,然后我的事务分到12,下面就没有号了,我就的想着我需要将这些号分成两个部分, 一部分为不能见人的(不让你用), 一部分是被使用的.

然后我们通过增加的模式,我当前的事务号如果用到了2 ,下一个就是1 ,但是原来7 号可见, 那如果1号可见了,7号就必须要回收,变成不可见.

那么这里就会产生

我从数字1 开始使用依次为   1   12  11  10  9  8  , 当我用到 7 的时,我已经达到一半一半的状态了, 此时我就需要回收的TIX 事务号了, 1 12  11 10 9 8  这些数字我的回收了. 

听上去回收事务号并不太难,但这些事务的ID 在哪里,在每行tuple 上, 那21亿个事务,并且使用这些事务的行,都要对回收的这个事情进行响应.  每行上都有 t_xmin 和 t_xmax 两个值并且这些值都存储了事务ID

那么此时系统是不是应该处于这个状态.

PostgreSQL 有三个特殊的事务的ID , 

0 是不可见的事务ID 

1 是数据库初始化时的事务ID

2 是冻结的事务的ID ,这个ID 比任何的事务的ID 都老,也就是不可见,并且POSTGRESQL 会掌握处于"冻结"的

那么此时有同学会问,虽然2.1一个亿的数字也是蛮大的,但是我还是不想去脑瘫,那我应该怎么办.

POSTGRESQL 这么聪明的数据库当然有办法解决问题,怎么解决, 一个字, "滚". 滚动的滚.

vacuum_freeze_min_age 这个参数将帮助你,解决上面的问题, 默认是5000万,当你的事务的ID 使用的数量达到5000万的时候, 那么frozen的动作就开始了, 

大白话就是我如果从7开始使用 我不会说用到2的时候,在进行FROZEN,而是我在用到4的时候我就将6  ,7 就变成不可见,将 1  ,12 变成可见.

那么接下来的问题是,他怎么进行冻结的活动,也就是 frozen processing, forzen 的方式有两种, 我们可以叫他们 lazy 和 eager 两种模式,这两种模式中的区别是,前者lazy模式中,是通过vacuum process的方式来处理,扫描dead tuple 来进行冻结的活动,而采用eager的方式将扫描所有的PAGE来进行FROZEN的活动,  并且更新相关系统的VIEW,和清理不在使用的CLOG文件。

怎么计算那些事务的ID 是可以被回收的

可以回收的TXID = 当前最老的xmin - vacuum_freeze_min_age,普通的vacuum进程逐个扫描页面,同时与vm可见性映射协作跳过没有死元组的页面,并将元组t_infomask (xmin小于freezelimit_txid)设置为XMIN_FROZEN。清理完成后,n_live_tuple、n_dead_tuple、vacuum_count、autovacuum_count、last_autovacuum、last_vacuum等统计信息将被更新。

对于表来说,通过PG_CLASS 中的 relfrozenxid来鉴别表中的最小的xmin id  ,对于数据库也是一样通过pg_database  的字段datfrozenxid 来判别。

触发数据库的急冻datfrozenxid < oldestxmin-vacuum_freeze_table_age,

怎么监控

WITH max_age AS (    
SELECT 2000000000 as max_old_txid
, setting AS autovacuum_freeze_max_age        
FROM pg_catalog.pg_settings        
WHERE name = 'autovacuum_freeze_max_age' ),
per_database_stats AS (    
SELECT datname        ,
m.max_old_txid::int        , m.autovacuum_freeze_max_age::int        ,
age(d.datfrozenxid) AS oldest_current_txid    
FROM pg_catalog.pg_database d   
 JOIN max_age m ON (true)    
 WHERE d.datallowconn )
 SELECT max(oldest_current_txid) AS oldest_current_txid    ,
 max(ROUND(100*(oldest_current_txid/max_old_txid::float))) ASconsumed_txid_pct    ,
 max(ROUND(100*(oldest_current_txid/autovacuum_freeze_max_age::float)))AS consumed_autovac_max_age
 FROM per_database_stats;

 oldest_current_txid 表示为当前所有数据库中最老的事务ID,

asconsumed_trix_pct 为当前消耗了多少事务ID 占据的百分比,数字越大,就说明距离危险越近了。

consumed_autovac_max_age 参数说明你距离触发FREAZON的距离还有多远

那如果发现了上面的情况不大对头的情况下,怎么办

SELECT datname, age(datfrozenxid) AS frozen_xid_age , ROUND(100*(age(datfrozenxid)/2000000000.0::float)) consumed_txid_pct , current_setting('autovacuum_freeze_max_age')::int - age(datfrozenxid) AS remaining_aggressive_vacuum FROM pg_database;

赶紧针对数据库去查看那个数据库要出事. 最后去定位那个表要出事,然后下一步就是解决他

实际上POSTGRESQLVACUUM 以及 AUTOVUCUUM  和事务ID内卷化的参数调整,还需要继续一段文字的描述,  不过首先我们先认识他,以及他的危害,并通过手段来监控,是第一步.

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值