20110408pg 升级修复

来自 PostgreSQL wiki
跳转至导航跳转至搜索

2011-04-08 pg_upgrade/pg_migrator 用户的关键修复:详细信息

以下是已发布至 2011-04-08 公告电子邮件列表并已在 Postgres 8.4.8 和 9.0.4 版本中修复的 pg_upgrade 和(以前)pg_migrator 修复的详细信息。

关于此错误,您能告诉我什么?

这是向所有用户发送的有关此错误的公告

已在所有已发布的 pg_upgrade 和(以前)pg_migrator 版本中发现了一个错误。任何使用过 pg_upgrade 或 pg_migrator 的人都应尽快采取以下纠正措施。如果您尚未拥有最近的副本,您可能还想备份 pg_clog 目录。如果您未能及时采取行动,可能会导致意外停机。

此错误会导致查询返回以下错误

       ERROR: could not access status of transaction ######
       DETAIL: could not open file "pg_clog/####": No such file or directory=20

此错误阻止访问存储在数据库中的非常宽的值。首先,在阅读此内容后,您应该立即将 PostgreSQL 数据库数据目录中的 pg_clog 目录创建文件级备份。接下来,为防止此类故障,用户需要以超级用户的身份在所有已升级数据库中尽快运行以下 psql 脚本

       -- This script fixes data in pre-8.4.8 and pre-PG 9.0.4
       -- servers that were upgraded by pg_upgrade and pg_migrator.
       -- Run the script using psql for every database in the cluster
       -- except 'template0', e.g.:
       --     psql -U postgres -a -f pg_upgrade_fix.sql dbname
       -- This must be run from a writable directory.
       --
       -- Depending on the size and configuration of your database,
       -- this script might generate a lot of I/O and degrade database
       -- performance.  Users should execute this script during a low
       -- traffic period and monitor the database load.
       --
       CREATE TEMPORARY TABLE pg_upgrade_fix AS
               SELECT 'VACUUM FREEZE pg_toast.' || c.relname || ';'
               FROM    pg_class c, pg_namespace n
               WHERE   c.relnamespace = n.oid AND
                       n.nspname = 'pg_toast' AND
                       c.relkind = 't'
               ORDER by c.oid;
       \copy pg_upgrade_fix TO 'pg_upgrade_tmp.sql'
       \i pg_upgrade_tmp.sql

即将发布的 Postgre 8.4.8 和 9.0.4 将解决此问题。这些版本将不再需要在升级后运行上述脚本,因为它们将正确还原已迁移数据库中所有 TOAST 表。但即便已运行 Postgre 9.0.4,已升级数据库仍需要运行该脚本。

此漏洞影响哪些人?

如果您在升级到 Postgres 8.4.8 和 9.0.4 之前采用 pg_upgrade 或 pg_migrator 升级了 PostgreSQL 安装,那么您可能受到此漏洞影响。

具体来说,受影响用户在升级之前使用了包含非常旧记录的 TOAST 表(压缩数据范围)。但是,因为这在事后很难验证,因此 PostgreSQL 项目建议所有使用 pg_upgrade 的用户都应用以下清理脚本。

受影响用户需要尽快运行清理脚本,以防如下所述陷阱此漏洞。

我如何知道我是否受到此漏洞影响?

一般而言,您在升级后不会立即发现任何问题。相反,在升级后数月或数周内,您将在会话或日志中看到如下所示的类似错误消息

  ERROR: could not access status of transaction ######
  DETAIL: could not open file "pg_clog/####": No such file or directory

此错误将阻止部分查询运行。

解决错误

如果您收到以上错误(涉及丢失的日志文件),则您将需要尽可能从 PostgreSQL 数据目录的备份中还原丢失的日志文件。如果您有低于所请求日志文件的日志文件,那么发生了“环绕”,实施此修复之前的时间可能很短,否则会发生更严重的损坏,您可能需要考虑禁用对数据库的访问,以防止日志超出所请求文件涵盖的点。如果日志回溯到错误发生点,那么以前会引发错误的记录可能会突然变得可见,而其他记录可能会消失(如果新的日志将它们标记为已中止)。

日志文件保存事务提交/中止状态,一旦创建新的日志文件就很少发生更改。

还原日志文件的流程是

   Stop the PostgreSQL system (we don't want PG to see a partial clog file).
   Modify your postgresql.conf and increase autovacuum_freeze_max_age to 500000000 (500m)
   Restore as many clog files as possible,
       where the clog files aren't greater than existing clog files in pg_clog and aren't overwriting existing files.
       *BE SURE TO NOT OVERWRITE ANY EXISTING CLOG FILES*
   Once the restore is complete, start the PostgreSQL system
   Ideally, then run a CLUSTER-WIDE 'VACUUM FREEZE;' (on every database!)
       NOTE: This will create a *lot* of I/O on your system and may take some time to complete.
       This can be done from the command-line with: vacuumdb -a -v -F
   Alternatively, run the script from above (in every database!!)
       If you had to restore clog files then be prepared to restore them again as they may be removed too early 
       when doing table-by-table VACUUM FREEZE commands, as the script above does.
  (RUNNING VACUUM FREEZE IS NECESSARY!, do not forget this step or the clogs may be removed again and the problem will recur!)

如果您没有 pg_clog 目录的备份,那么在此阶段修复问题会复杂得多。如果您已达到此阶段,则需要 PostgreSQL 社区中的黑客帮助。您可在 irc.freenode.net 频道 #postgresql 中请求帮助,也可将问题发布到 pgsql-admin 或 pgsql-general 邮件列表,或者将电子邮件发送至 [email protected]

是否会因为此错误而丢失任何数据?

是 - 如果你收到的错误与丢失的 clog 文件有关,且没有这些 clog 文件的备份。如果你尚未收到有关丢失 clog 的错误,那么该问题应可以仅通过一点宕机时间来解决。如果你收到了错误,但拥有这些 clog 的备份,那么立即解决此问题*非常重要*,否则你最终可能会丢失数据。如果你已经在所有数据库(非典型)中运行了集群范围内的“VACUUM FREEZE;”,那么你已经安全了。

此错误的根本原因是什么?

原因是 pg_upgrade 未正确恢复 TOAST 表中的 pg_class.relfrozenxid。TOAST 表用于存储不符合 8k 堆页的宽值;有关详细信息,请参阅TOAST 存储

如果我已经使用了包含此错误的 pg_upgrade,该如何修复我的集群?

上述公告中有一个脚本必须运行。它会有效地将所有 TOAST 事务 ID 标记为已冻结,以便它们不必依赖 pg_clog 文件来获取状态。此操作是必需的,因为未为 TOAST 表正确设置 pg_class.relfrozenxid。元组冻结是自动清理执行的正常进程,因此更正操作实际上只是在通常需要之前执行此进程。

如果不能立即运行修复程序怎么办?

如果你做不到,在脚本运行之前,请将 data/pg_clog 目录的内容复制到安全备份中,以防被回收。

我正在运行清理脚本,但它导致了太多 I/O 我的数据库没有响应。我该怎么办?

首先,停止脚本。

然后你要增加 vacuum_cost_delay,以便脚本花费更长的时间,但执行较低强度的 I/O。在运行脚本的会话中,先执行以下操作:

   SET vacuum_cost_delay = 40;
   SET vacuum_cost_limit = 200;

然后重新运行脚本。

此错误在 Postgres 8.4.8 和 9.0.4 中是如何修复的

修复方法是修改 pg_dump 以正确恢复 TOAST 表的 pg_class.relfrozenxid。

谁发现了此错误?

此问题由 irc.freenode.net #postgresql 上的两位用户报告,并由 Andrew Gierth 和 Bruce Momjian 诊断出来。