乐趣区

关于postgresql:问题定位-PostgreSQL-报错-requested-WAL-segment-already-been-removed

本文首发于 2016-04-25 20:59:52

问题形容

在应用配置了热备的 PostgreSQL 数据库时,在执行大量事务时,尤其是一个须要插入几千万条数据的 insert 事务时(典型的做法是继续 insert into t select * from t;),后盾 csv log 中报错如下:

2015-07-01 13:25:29.430 CST,,,27738,,51d112c8.6c5a,1,,2015-07-01 13:25:28 CST,,0,LOG,00000,"streaming replication successfully connected to primary",,,,,,,,"libpqrcv_connect, libpqwalreceiver.c:171",""2015-07-01 13:25:29.430 CST,,,27738,,51d112c8.6c5a,2,,2015-07-01 13:25:28 CST,,0,FATAL,XX000,"could not receive data from WAL stream:FATAL:  requested WAL segment 0000000800002A0000000000 has already been removed
",,,,,,,,"libpqrcv_receive, libpqwalreceiver.c:389",""

问题剖析

依据报错信息剖析,揣测是主库大事务产生了大量 xlog,这是因为 PostgreSQL 在执行事务过程中,直到提交时才会发送到备库。

因为该事务须要执行的工夫过长,超过了 checkpoint 的默认距离,所以导致有的 xlog 还未发送到备库却被 remove 掉了。

解决办法

要解决该问题,个别可用的计划有:

办法一:调大参数 wal_keep_segments 的值

将 GUC 参数 wal_keep_segments 设大一些,比方设置为 2000,而每个 segment 默认值为 16MB,就相当于有 32000MB,那么,最多可保留 30GB 的 xlog,超过则删除最早的 xlog。

不过, 该办法并不能从根本上解决该问题 。毕竟,在生产环境中或 TPCC 等测试灌数时,如果某条事务须要插入几十亿条记录,有可能还是会呈现该问题。

办法二:启用归档

归档,就是将未发送到备库的 xlog 备份到某个目录下,待重启数据库时再将其复原到备库中去。

GUC 参数设置示例如下:

  • 主库的 postgresql.conf 文件中:

    wal_level = hot_standby
    archive_mode = on
    archive_command = 'rsync -zaq %p postgres@pg-slave:/var/lib/pgsql/wal_restore/%f && test ! -f /var/lib/pgsql/backup/wal_archive/%f && cp %p /var/lib/pgsql/backup/wal_archive/'
    archive_timeout = 300
    max_wal_senders = 5
    wal_keep_segments = 0
  • 备库的 postgresql.conf 文件中:

    wal_level = hot_standby
    archive_mode = on
    archive_command = 'test ! -f /var/lib/pgsql/backup/wal_archive/%f && cp -i %p /var/lib/pgsql/backup/wal_archive/%f < /dev/null'
    hot_standby = on
    wal_keep_segments = 1
  • 备库的 recovery.conf 文件中:

    standby_mode = 'on'
    primary_conninfo = 'host=pg-master port=5432 user=replicator'
    restore_command = 'cp /var/lib/psql/wal_restore/%f %p'
    archive_cleanup_command = 'pg_archivecleanup /var/lib/pgsql/wal_restore/ %r'

办法三:启用 replication slot(PG 9.4 开始反对)

该办法是基本解决办法,不会造成 xlog 的失落 。也就是说,在 xlog 被拷贝到从库之前,主库不会删除。

启用办法:

  1. 在 postgresql.conf 中增加:

    max_replication_slots = 2000
  2. 在拷贝到备库之前,主库要创立一个 slot:

    postgres=# SELECT * FROM pg_create_physical_replication_slot('node_a_slot');
      slot_name  | xlog_position
    -------------+---------------
     node_a_slot |
    
    postgres=# SELECT * FROM pg_replication_slots;
      slot_name  | slot_type | datoid | database | active | xmin | restart_lsn
    -------------+-----------+--------+----------+--------+------+-------------
     node_a_slot | physical  |        |          | f      |      |
    (1 row)
  3. 在备库的 recovery.conf 文件中增加一行:

    standby_mode = 'on'
    primary_conninfo = 'host=192.168.4.225 port=19000 user=wslu password=xxxx'
    primary_slot_name = 'node_a_slot'

参考

  • https://www.postgresql.org/do…
  • https://www.postgresql.org/do…
  • http://blog.2ndquadrant.com/p…
  • http://grokbase.com/t/postgre…
  • http://stackoverflow.com/ques…

欢送关注我的微信公众号【数据库内核】:分享支流开源数据库和存储引擎相干技术。

题目 网址
GitHub https://dbkernel.github.io
知乎 https://www.zhihu.com/people/…
思否(SegmentFault) https://segmentfault.com/u/db…
掘金 https://juejin.im/user/5e9d3e…
开源中国(oschina) https://my.oschina.net/dbkernel
博客园(cnblogs) https://www.cnblogs.com/dbkernel
退出移动版