PostgreSQL

关注公众号 jb51net

关闭
首页 > 数据库 > PostgreSQL > PostgreSQL .history 文件

PostgreSQL .history 文件详解

作者:脑子进水养啥鱼?

本文解释了PostgreSQL的.history文件(时间线历史文件)的重要性、格式、作用及备份恢复方案,该文件记录时间线切换事件,对PITR、备库构建和pg_rewind等操作至关重要,误删会导致备份失败、备库重建等问题,感兴趣的朋友一起看看吧

一、什么是 .history 文件?

  .history 文件是 PostgreSQL 的时间线历史文件(Timeline History File),位于 $PGDATA/pg_wal/ 目录下(PostgreSQL 10 之前为 pg_xlog),文件命名格式为 000000XX.history(例如 00000009.history),其中 XX 为八位十六进制表示的时间线 ID(Timeline ID)。在 PostgreSQL 运维中,.history 文件是一个虽不起眼却至关重要的元数据文件。它仅在时间线发生分叉时才产生,但一旦被误删,就会导致 pg_basebackup 备份失败、物理备库无法重建等一系列连锁反应。

它是一个纯文本文件,每一行记录一次时间线切换事件,格式如下:

<parentTLI> <switchpoint> <reason>

一个典型的 00000002.history 文件内容如下:

1    0/A000198    before 2018-7-9 12:05:00.861324+00

每一行都代表一次时间线分裂事件,记录了当前时间线是从哪条时间线、在哪个 WAL 位置分叉出来的,以及分叉的原因。

内容中的“原因”条目

reason 字段的具体取值取决于时间线切换的触发方式:

需要注意的是,不同 PostgreSQL 版本中的 reason 字段格式可能存在细微差异,但每条记录都至少包含父时间线 ID 和分叉点 LSN 这两个核心要素。

二、时间线(Timeline)

  理解 .history 文件,必须先了解 PostgreSQL 的时间线概念。这一概念从 PostgreSQL 8.0 开始引入,旨在解决 PITR(Point-In-Time Recovery,时间点恢复)中的 WAL 覆盖问题。考虑如下场景:管理员将数据库恢复到业务受损前的某个时间点后继续运行。若仍沿用原时间线,新生成的 WAL 文件将与旧 WAL 文件同名,导致原有的 WAL 记录被覆盖,无法再次恢复到其他时间点。为解决这一问题,PostgreSQL 引入了时间线机制。每当数据库集簇通过恢复启动后继续运行时,PostgreSQL 都会切换到一条新的时间线——新生成的时间线 ID 在旧的时间线 ID 基础上加 1,并且生成一个 .history 文件记录本次分叉的完整信息。WAL 文件名本身包含时间线 ID(前 8 位十六进制数),这一设计保证了新的时间线不会覆盖旧时间线产生的 WAL 文件。因此,时间线是进行精确 PITR、搭建多级备库等操作的核心基石。

2.1 关于时间线切换的触发时机

一个常见的理解偏差是认为“每次备库提升为主库都会产生一条新的时间线”。这种说法并非完全错误,但需要明确两点:

无论是在 PostgreSQL 12 之前的 recovery.conf 中设置 promoterecovery_target_timeline,还是在新版本的 postgresql.conf 中配置相关参数,其本质都是恢复过程结束后数据库重新启动这一动作触发了时间线的新建。

2.2 关于版本差异的特别说明

PostgreSQL 12 及以后版本中,recovery.conf 文件的功能已被整合到主配置文件 postgresql.confpostgresql.auto.conf 中,但时间线切换的触发机制并未改变。

三、.history 文件的核心作用

.history 文件在以下三个核心场景中发挥作用:

四、.history 文件缺失的影响

  .history 文件缺失对数据库日常运行无直接影响。 数据库常规事务处理、checkpoint、WAL 切换等操作依赖 WAL 段文件,不依赖 .history 文件。因此,删除了 .history 文件,数据库可以继续正常运行——这也是该文件易被忽视的重要原因。

受影响的操作

一旦 .history 文件被误删,以下操作会直接失败:

报错示例

执行 pg_basebackup 时的典型错误信息:

pg_basebackup: error: could not send replication command "TIMELINE_HISTORY": 
ERROR:  could not open file "pg_wal/00000009.history": No such file or directory
30203/30203 kB (100%), 0/1 tablespace (...bak_20260429_2/global/pg_control)
30203/30203 kB (100%), 0/1 tablespace (...bak_20260429_2/global/pg_control)
30203/30203 kB (100%), 1/1 tablespace
pg_basebackup: write-ahead log end point: 4/35000100
pg_basebackup: waiting for background process to finish streaming ...
pg_basebackup: error: child thread exited with error 1
pg_basebackup: removing contents of data directory "/data/highgo/hgdbbak/dbbak/hgdbbak_20260429_2"

该错误表明备份开始时当前时间线为 9,pg_basebackup 需要通过复制协议从主库获取 00000009.history,但由于文件丢失,请求失败。

  为什么数据库能正常运行,备份却失败? 这是运维人员最容易误解的地方。数据库日常运行依赖的是 WAL 段文件,而备份时 pg_basebackup 需要为备份创建一份完整的时间线上下文。原因在于:备份文件在压缩传送之前,必须先完整记录当前的时间线谱系。只有保存了完整的 *.history 文件,将来基于该备份执行恢复时才能正确重放跨时间线的 WAL 段。因此,pg_basebackup 强制要求读取当前时间线的 .history 文件。

五、常见疑问

5.1 备库上的 .history 文件数量与主库不一致,是否异常?

完全正常。 备库由某个时间点的物理备份搭建而来,只继承该备份对应的时间线历史,后续通过流复制接收 WAL 段同步数据,但不会同步主库的 .history 文件。因此,主备节点之间 .history 文件数量不一致是设计特性,而非异常。

5.2 手动构造 .history 文件不可取

虽然从技术上讲,.history 文件的格式相对简单,可以手动构造,但这种方法存在诸多风险:

生产环境切勿采用手动构造的方式。

六、恢复方案

情形方案说明
有归档或备份副本.history 文件从归档目录(或其他备份)复制回 pg_wal/ 目录。这是最安全、最推荐的恢复方式。
无归档副本,但熟悉环境历史仅限测试环境或了解确切时间线关系的应急方案:可手动构造 .history 文件,按格式准确填写父时间线和分叉点信息。生产环境不推荐此方案。
无法找回文件最近一次完整且可靠的物理全量备份恢复整个数据目录。这是唯一可以保证数据一致性的可靠方式。
逻辑备份pg_dump / pg_dumpall 不依赖 .history 文件,不会报错。但逻辑备份无法用于物理备库搭建或 PITR 增量恢复,属于不同维度的备份方案。

七、预防措施

核心原则:不要手动删除 pg_wal/ 目录下的任何文件。

具体方案

特别提醒:不要尝试“绕过”文件检查

  一个常见的误区是尝试修改 pg_basebackup 参数以“跳过”时间线历史文件的检查。这种做法并不可行——TIMELINE_HISTORY 命令是 PostgreSQL 内部复制协议的核心请求,任何物理备份工具都必须完成时间线信息的返回与验证,才能确保备份在将来恢复时不会因缺少必要的 WAL 上下文而完全失效。

到此这篇关于PostgreSQL .history 文件详解的文章就介绍到这了,更多相关PostgreSQL .history 文件内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文