• PostgreSQL克服vacuum wraparoud


     

    当VACUUM进程跟不上数据库活动,就会发生事务id wraparound,PostgreSQL服务被迫关闭。

    更专业的说法是:当多版本并发控制(MVCC)的语义失败,且唯一事务ID的值达到其最大值(大约20亿)时,就会发生事务id wraparound。

    导致这种情况的原因是,由autovacuum worker或用户交互(手动)管理的VACUUM进程跟不上DML操作。

    事务id wraround可以由以下一种或多种情况的组合引起:

    1.autovacuum被关闭了

    2.长时间运行的事务

    3.数据库执行逻辑dump(流复制)

    4.许多带有锁的会话连接

    5.密集的dml操作强制取消了autovacuum

     

    事务wraparound会导致PostgreSQL为了保证数据完整性而关闭。

    PostgreSQL在任何时候都有许多事务,这些事务由一个唯一的ID跟踪。每隔一段时间,这个数字就会达到可以注册的上限,例如,默认的20亿,然后就会被重新编号。但是,如果唯一事务id的数量达到了它的最大事务限制,即TXID wraparound,Postgresql将强制关闭以保护数据。

     

    以下是工作原理:

    ·40亿事务,即2^32,是Postgres中使用的数据类型的整数上限

    ·20亿,即2的31次方,是PostgreSQL在强制关闭前允许的上限

    ·在距离上限1000万事务时,会给出警告信息

    在距离上限100万事务时,PostgreSQL进入只读模式。

    警告标志

    在autovacuum守护进程在整个数据集群中出现滞后的情况下,请检查你的监控解决方案,以便确定这些指标的趋势:

    ·IO等增加 ·CPU负载的增加 ·SQL性能降低

     

    缓解措施包括:

    ·检查内部Postgres监控指标并确认正在清理表。 ·查看Postgres日志,查找被取消的autovacuum工作进程。 ·查看视图"pg_stat_activity ",并寻找一个查询字符串:“preventing transaction id wraparound”。实际上,这是一条正常的信息。但是,人们不应该看到autovacuum运行的目的仅仅是减轻wraparound。

    以下是一些示例错误消息,你可以在Postgres日志中发现,当由于wraparound而受到关机威胁时:

    #
    # When less than 10 million transactions remain before shutdown
    #
    WARNING: database "mydb" must be vacuumed within 177009986 transactions
    HINT: To avoid a database shutdown, execute a database-wide VACUUM in "mydb".

     

    以下查询可以用于检查是否有事务id wraparound的风险:

        --
        -- Database query for transaction age per database
        --  and as a percentage of maximum permitted transactions
        --
    SELECT  datname,
          age(datfrozenxid),
          (age(datfrozenxid)::numeric/1000000000*100)::numeric(4,2) as "% WRAPAROUND RISK"
    FROM pg_database ORDER BY 2 DESC;

     

    --
    -- Database query for transaction age per table
    --
    SELECT  
    c.oid::regclass as table_name,
    greatest(age(c.relfrozenxid),age(t.relfrozenxid)) as "TXID age",
    (greatest(age(c.relfrozenxid),age(t.relfrozenxid))::numeric/1000000000*100)::numeric(4,2) as "%WRAPAROUND RISK"
    FROM pg_class c
    LEFT JOIN pg_class t ON c.reltoastrelid = t.oid
    WHERE c.relkind IN ('r', 'm')
    ORDER BY 2 DESC;

     

    --
    -- Other vacuum runtime parameters of interest
    --  returning TXID age
    --
    SELECT  name, setting
    FROM pg_settings
    WHERE name ~ 'vacuum'
    AND name ~ '_age$'
    ORDER BY 1 ASC;

     

    防止事务id wraparound

    首先,确保所有的表都有正常的vacuum。一般正确配置autovacuum进程就没事。否则,你需要考虑设置一个手动vacuum策略。

     

    以下只是一些建议,毕竟每个环境都具有主观性。

    如果你时间充足,运行以下命令调用vacuumdb。-j参数可以根据cpu的个数调整,-a参数表示按照字母的顺序处理数据库。

    vacuumdb -F -a -z -j 10 -v

    如果你看到有些个别数据库需要紧急处理,可以写个脚本单独数据某个数据库:

    vacuumdb -z -j 10 -v <mydatabase>

     

    紧急操作:距离上限小于1000万个事务时处理wraparound

    以下是即将进行事务wraparound时要采用的一组操作。请记住,你是在跟时间赛跑:你必须在剩余可用事务id下降到100万个事务之前vacuum整个数据集群。

    操作:

    ·尽可能快地对数据库执行vacuum操作

    ·使用vacuumdb命令

    ·尽可能多的使用并发数量

    ·以verbose模式运行vacuum,将信息输出到日志

    ·监控日志输出内容

    ·对单个数据执行执行vacuumdb,如果需要,还可以单独对表执行

    ·避免使用参数-a

     

    脚本:仅供参考

    1.找出数据库最老的TXID

    2.生成一个表的列表,以便将最老的TXID变成最新的

    3.将这些表写入一个脚本,以便调用vacuumdb和vacuum

     

    脚本的秘诀是:xargs 。它使人们能够合理地利用尽可能多的CPU。下面的一对bash脚本针对一系列表调用vacuumdb。 当然,有不止一种方法可以做到这一点。

    脚本一在选定的数据库中生成一个表列表并调用脚本二,脚本二它分别在每个表上执行 VACUUM。

    脚本1:(go1_highspeed_vacuum.sh)

    #!/bin/bash
    #
    # INVOCATION
    # EX: ./go1_highspeed_vacuum.sh
    #

    ########################################################
    # EDIT AS REQUIRED
    export CPU=4
    export PAGER=less PGUSER=postgres PGPASSWORD=mypassword PGDATABASE=db01 PGOPTIONS='-c statement_timeout=0'
    ########################################################

    SQL1="
    with a as (select c.oid::regclass as table_name,
              greatest(age(c.relfrozenxid),age(t.relfrozenxid))
            from pg_class c
            left join pg_class t on c.reltoastrelid = t.oid
            where c.relkind in ('r', 'm')
              order by 2 desc)
    select table_name from a
    "

    LIST="$(echo "$SQL1" | psql -t)"

    # the 'P' sets the number of CPU to use simultaneously
    xargs -t -n 1 -P $CPU ./go2_highspeed_vacuum.sh $PGDATABASE<<<$LIST

    echo "$(date): DONE"

    脚本2:(go2_highspeed_vacuum.sh)

    #!/bin/bash

    ########################################################
    # EDIT AS REQUIRED
    export PAGER=less PGUSER=postgres PGPASSWORD=mypassword PGOPTIONS='-c statement_timeout=0'
    export DB=$1

    ########################################################

    vacuumdb --verbose ${DB} > ${DB}.log 2>&1

    提示:

    ·按照reverse字母顺序对数库执行vacuumdb,以避免与按forward字母顺序进行的autovacuum工作进程发生冲突。

    ·查询表“pg_stat_activity”。

    ·始终监视 autovacuum 进程的工作位置。

    ·避免autovacuum进程和当前正在vacuumdb进程在同一张表上工作。

    ·使用autovacuum工作进程作为仍有待处理的数据库的指标。

    ·在与手动vacuum发生冲突时杀死活跃的autovacuum进程以加快速度。

     

    紧急操作:因为事务id wraparound,PostgreSQL服务已经关闭

    因为事务id waparound,postgresql服务已经被强制关闭的话,需要在单用户模式下执行postgresql cluster级别的vacuum。

    登录服务器,以postgres用户执行:

        # it is understood that environment 
        # variable PGDATA points to the data cluster
        #
        postgres --single -D $PGDATA postgres <<< 'vacuum analyze'

    建议将其写成脚本,因为你需要逐个登录数据库并执行vacuum操作。

    找出所有的数据库:

    postgres --single -D $PGDATA postgres <<< 'select datname from pg_database' \
        | grep '"' | cut -d '"' -f 2 > list_db

    这里是个示例:用到了上面生成的list_db

    #
    # it is understood the database list has 
    #  been edited before invoking this code snippet
    #
    for u in $(cat list_db)
    do
        postgres --single -D $PGDATA $u <<< 'vacuum analyze'
    done

    事务id wraparound是很麻烦的,好在很少发生。

     

     

     

     

     

     

     

     

     

     

  • 相关阅读:
    VMware NAT 静态IP模式下上网
    无法连接虚拟设备 ide1:0
    C# ContainsKey与TryGetValue方法探究
    深入讲解以太坊的数据存储
    sqlserver之查询数据插入新建表@已存在表(oracle)
    python之列表、元祖、字典和数组的使用
    python之列表、元组、字典、数组对比
    python之ConfigParser介绍
    从业人员证券交易行为合规管理测试
    window系统自动设置时间同步脚本
  • 原文地址:https://www.cnblogs.com/abclife/p/16163215.html
Copyright © 2020-2023  润新知