什么是控制文件

控制文件是一个 8kb 大小的二进制文件,该文件默认位置位于$PGDATA/global/pg_control ,该文件中记录了 postgreSQL 服务器内部状态的各方面信息。内容可以分为两部分,一种是静态数据(不会变动),如 initdb 初始化的一些参数,另一种是动态数据,它会随着数据库运行的时间而变动,如我们后面会说到的检查点和postgres.conf相关参数。

数据库会启动前会先打开这个文件两次,第一次是检测该文件是否存在,第二次是为了校验内容。

该文件非常非常非常重要,如果该文件不存在或者损坏(数据内容和当前启动服务的postmaster服务版本不匹配),论出现以上两种情形中的任何一种,PostgreSQL服务都不会正常启动。因为这两种情形的出现都明显表明当前环境上的PostgreSQL服务出现了未知的问题,是不正常的现象

该文件虽然大小为 8kb,但实际有效字段值内容仅有几百字节,剩下的数据全用零填充,这样做减少了在读取pg_control文件时候发生过早的EOF错误的几率。

控制文件解析

想要查看控制文件内容,可通过安装目录 bin 路径下的pg_controldata 工具。

pg_controldata -D /data/pgsql/data/

下面输出的内容为 17.1 版本

pg_control version number:            1700
Catalog version number:               202406281
Database system identifier:           7502811852738500652
Database cluster state:               in production
pg_control last modified:             Sat May 24 23:31:41 2025
Latest checkpoint location:           1/750000B8
Latest checkpoint's REDO location:    1/75000060
Latest checkpoint's REDO WAL file:    000000010000000100000075
Latest checkpoint's TimeLineID:       1
Latest checkpoint's PrevTimeLineID:   1
Latest checkpoint's full_page_writes: on
Latest checkpoint's NextXID:          0:889
Latest checkpoint's NextOID:          41118
Latest checkpoint's NextMultiXactId:  1
Latest checkpoint's NextMultiOffset:  0
Latest checkpoint's oldestXID:        730
Latest checkpoint's oldestXID's DB:   1
Latest checkpoint's oldestActiveXID:  889
Latest checkpoint's oldestMultiXid:   1
Latest checkpoint's oldestMulti's DB: 1
Latest checkpoint's oldestCommitTsXid:0
Latest checkpoint's newestCommitTsXid:0
Time of latest checkpoint:            Sat May 24 23:31:38 2025
Fake LSN counter for unlogged rels:   0/3E8
Minimum recovery ending location:     0/0
Min recovery ending loc's timeline:   0
Backup start location:                0/0
Backup end location:                  0/0
End-of-backup record required:        no
wal_level setting:                    replica
wal_log_hints setting:                off
max_connections setting:              100
max_worker_processes setting:         8
max_wal_senders setting:              10
max_prepared_xacts setting:           0
max_locks_per_xact setting:           64
track_commit_timestamp setting:       off
Maximum data alignment:               8
Database block size:                  8192
Blocks per segment of large relation: 131072
WAL block size:                       8192
Bytes per WAL segment:                16777216
Maximum length of identifiers:        64
Maximum columns in an index:          32
Maximum size of a TOAST chunk:        1996
Size of a large-object chunk:         2048
Date/time type storage:               64-bit integers
Float8 argument passing:              by value
Data page checksum version:           0
Mock authentication nonce:            bbf2a8aa358d0a829ccf49d6e252e5a79cbd9be4eccba675120fbf456cfb85ec

输出内容相信大部分初学者看不懂,没事,慢慢学就行了。我们这里挑出几个重要的参数说说就行了。

● Database cluster state 记录实例的状态,该参数有以下这些值

a. starting up:表示数据库正在启动状态。

b. shut down: 数据库实例(非Standby)正常关闭后控制文件中就是此状态。

c. shut down in recovery:Standby实例正常关闭后控制文件中就是此状态。

d. shutting down:正常停库时,先做checkpoint,开始做checkpoint时,会把状态设置为此状态,做完后把状态设置为shut down。

e. in crash recovery:数据库实例非异常停止后,重新启动后,会先进行实例的恢复,在实例恢复时的状态就是此状态。

f. in archive recovery:Standby实例正常启动后,就是此状态。

g. in production:数据库实例正常启动后就是此状态。Standby数据库正常启动后不是此状态

● Latest checkpoint location:最后一次检查点

● Latest checkpoint's REDO location:记录数据库日志文件上检查点,数据库异常关闭后会从这个点开始恢复。有人就有疑问了为什么有checkpoint还要有redo,这里我们卖个关子,等后面讲检查点再细说。

● Latest checkpoint's REDO WAL file:当前wal日志。

● Database block size:数据块大小

● Maximum length of identifiers:目录名称字段宽度,是指一些数据库对象名称的最大长度,如表名、索引名的最大长度,目前是64

● Maximum columns in an index:表示一个索引最多多少列

● Maximum size of a TOAST chunk:TOAST 表中的块大小,是TOAST chunk的最大长度。TOAST是解决当列的内容太长,在一个数据块中存不下时的一种行外存储的方式

● Latest checkpoint's NextXID前面是新纪元值,冒号后面是下一个事务号,当前事务号最大值安全值可以在pg_xact目录下通过文件名计算出来。

● Latest checkpoint's NextMultiXactId参数,可以通过pg_multixact/offsets文件名计算出来安全值。

● Latest checkpoint's NextMultiOffset参数,当恢复控制文件时可以通过pg_multixact/members文件夹下计算出此参数的安全值。

PostgreSQL控制文件维护

  1. 固定部分:初始化数据库时产生,固定不变

  2. 有些信息随时更新:如果发生检查点、备份、日志切换等操作,则自动更新

  3. postgres.conf相关参数被更新:如果配置文件中重要的相关参数被修改,则也会自动更新

  4. 数据库备份时会一起备份

  5. 不能手动修改该文件

  6. 启动和恢复数据库时需要,当前没有避免发生单一故障点而设计的保护策略

如何重做控制文件

如果在无备份的情况下误删了控制文件,那么怎么重做该控制文件。Pg10版本以前版本使用pg_resetxlog工具

Pg10及以后版本使用pg_resetwal工具。

$ pg_resetwal --help
pg_resetwal resets the PostgreSQL write-ahead log.

Usage:
  pg_resetwal [OPTION]... DATADIR

Options:
 [-D, --pgdata=]DATADIR  data directory
  -f, --force            force update to be done even after unclean shutdown or
                         if pg_control values had to be guessed
  -n, --dry-run          no update, just show what would be done
  -V, --version          output version information, then exit
  -?, --help             show this help, then exit

Options to override control file values:
  -c, --commit-timestamp-ids=XID,XID
                                   set oldest and newest transactions bearing
                                   commit timestamp (zero means no change)
  -e, --epoch=XIDEPOCH             set next transaction ID epoch
  -l, --next-wal-file=WALFILE      set minimum starting location for new WAL
  -m, --multixact-ids=MXID,MXID    set next and oldest multitransaction ID
  -o, --next-oid=OID               set next OID
  -O, --multixact-offset=OFFSET    set next multitransaction offset
  -u, --oldest-transaction-id=XID  set oldest transaction ID
  -x, --next-transaction-id=XID    set next transaction ID
      --wal-segsize=SIZE           size of WAL segments, in megabytes

pg_resetwal需要知道四个参数才可以进行重建

  • -l, --next-wal-file=WALFILE set minimum starting location for new WAL

参数通过指定下一个WAL段文件的名称,手动设置WAL启动位置。下一个段的名字应该大于当前存在pg_wal目录下的任何WAL段文件名。

要注意的是 wal 日志命名是 16 进制,比如说当前文件为 xxxxxx09,那么下一个文件就是xxxxxx0A,而不是xxxxxx10,要注意这一点。

  • -m, --multixact-ids=MXID,MXID set next and oldest multitransaction ID

手工设置下一个多事物ID和最老的多事务ID。确定下一个多事务 ID(第一部分)的安全值的方法:在数据目录下的pg_multixact/offsets目录中查找最大的数字文件名,然后在它的基础上加一后面跟上 4 个 0

[postgres@192 offsets]$ ls -l
total 8
-rw-------. 1 postgres postgres 8192 May 22 10:41 0000

-m = 0x00010000
  • -O, --multixact-offset=OFFSET set next multitransaction offset

手工设置下一个多事务偏移量。

确定安全值的方法:查找数据目录下pg_multixact/members目录中最大的数字文件名,然后在它的基础上加一并且乘以 65536,转换成16进制为100000,然后后面加上 4 个 0。

[postgres@192 members]$ ls -l
total 8
-rw-------. 1 postgres postgres 8192 May 10 21:41 0000
[postgres@192 members]$ 

-O = 0x1000000000
  • -x, --next-transaction-id=XID set next transaction ID手工设置下一个事务 ID。

确定安全值的方法:在数据目录下的pg_xact目录中查找最大的数字文件名,然后在它的基础上加一后面加 上 5 个 0。

[postgres@192 pg_xact]$ ll -l|head -n 5
total 8
-rw-------. 1 postgres postgres 8192 May 24 15:56 0000

-x=0x000100000

参考文档来源

https://www.modb.pro/db/1813145403890610176

【PostgreSQL从小白到专家(11) - 控制文件管理】- CUUG技术公开课