控制文件的位置与大小

  • 逻辑位置:存放在pg_global表空间中
  • 物理位置与名字:$PGDATA/global/pg_control
  • 代码位置:src/include/catalog/pg_control.h
  • 控制文件的大小是8K
  • 控制文件内容尽量保持小于512个字节

什么是控制文件

控制文件里存储了数据库唯一系统标识符、系统状态数据、数据库启动前系统必须恢复到的检查点信息、数据库的配置兼容backend进程执行的参数、指明类型timestamp、interval、time内部格式的标志、指明不同类型传值(pass-by-value)状态的标志以及一些数据库的重要信息。

控制文件内容主要分为是三部分,初始化静态信息、WAL及检查点的动态信息、一些数据库配置信息。

initdb时生成的静态信息

#控制文件版本号
pg_control version number:            960
#系统表版本号,格式是yyyymmddN。记录系统不兼容性的改变。**N是yyymmdd当天改变的次数。**具体可以查看源码文件src/include/catalog/catversion.h
Catalog version number:               201608131
#数据库系统号,这个标识串是一个64bit的整数,其中包含了创建数据库的时间戳和initdb时初始化的进程号,具体初始化方法可查看源码文件src/backend/access/transam/xlog.c。创建时间可以通过to_timestamp转换查看到(这个时间就是数据库安装的时间)
Database system identifier:           7188464634205259812
#记录实例的状态。源码文件中看到数据库的几种状态,源码在pg_control.h中
Database cluster state: 				in production
#元组的对齐要求,数据结构最大的对齐值
Maximum data alignment:               8
#数据块的大小,参数block_size
Database block size:                  8192
#每段大关系的块,参数segment_size
Blocks per segment of large relation: 131072
#文件中的块大小,参数wal_block_size
WAL block size:                       8192
#每个WAL段的大小,数据库初始化时通过--wal-segsize参数进行修改
Bytes per WAL segment:                16777216
#目录名称字段宽度,是指一些数据库对象名称的最大长度,如表名、索引名的最大长度,目前是64,src/include/pg_config_manual.h中的NAMEDATALEN
Maximum length of identifiers:        64
#表示一个索引最多多少列,目前为32个, 参考:src/include/pg_config_manual.h中的INDEX_MAX_KEYSsrc/include/pg_config_manual.h记录PostgreSQL一些限制信息。Maximum length of identifiers和Maximum columns in an index可以通过修改源码文件重新编译进行重置
Maximum columns in an index:          32
#TOAST表中的块大小,是TOAST chunk的最大长度。TOAST是解决当列的内容太长,在一个数据块中存不下时的一种行外存储的方式,这个值的计算方式详见src/include/access/tuptoaster.h
Maximum size of a TOAST chunk:        1996
#大对象的块的大小,这个值的计算方式详见utils/snapshot.h
Size of a large-object chunk:         2048
#Date/time表示类型
Date/time type storage:               64-bit integers
#参数传递方式,按值传递
Float4 argument passing:              by value
Float8 argument passing:              by value
#数据页是否受校验和保护?如果没有校验和版本则为零,数据块checksum的版本,默认为0,数据块没有使用checksum,1是启用。运行initdb时加了-k参数,PG才会在数据块上启用checksum功能
Data page checksum version:           0			
#用于需要进行的认证请求基于集群唯一的值
Mock authentication nonce:            aaa8abf569631ec60ba05e3f625495da70007738b831e46e1cfda0d26c370987  

数据库状态的几种含义:

  • starting up:表示数据库正在启动状态。
  • shut down:数据库实例(非Standby)正常关闭后控制文件中就是此状态。
  • shut down in recovery:Standby实例正常关闭后控制文件中就是此状态。
  • shutting down:正常停库时,先做checkpoint,开始做checkpoint时,会把状态设置为此状态,做完后把状态设置为shut down。
  • in crash recovery:数据库实例非异常停止后,重新启动后,会先进行实例的恢复,在实例恢复时的状态就是此状态。
  • in archive recovery:Standby实例正常启动后,就是此状态。
  • in production:数据库实例正常启动后就是此状态。Standby数据库正常启动后in archive recovery状态。

postgresql.conf中的配置信息

wal_level setting:                    minimal
wal_log_hints setting:                off
max_connections setting:              100
max_worker_processes setting:         8
max_prepared_xacts setting:           0
max_locks_per_xact setting:           64
track_commit_timestamp setting:       off

WAL及检查点的动态信息

#最后一次检查点
Latest checkpoint location:           0/5DF46AC8
#记录数据库日志文件上检查点,数据库异常关闭后会从这个点开始恢复。当数据库刚启动时Latest checkpoint location与Latest checkpoint's REDO location一致,随着时间的变化Latest checkpoint's REDO location会随之变化
Latest checkpoint's REDO location:    0/5DF46AC8
Latest checkpoint's REDO WAL file:    00000001000000000000005D
#当前时间线
Latest checkpoint's TimeLineID:       1
#前一个时间线,如果这个记录开始一个新的时间线(否则等于 ThisTimeLineID)
Latest checkpoint's PrevTimeLineID:   1
#数据库参数,默认值为on
Latest checkpoint's full_page_writes: on
#下一个空闲XID,前面是新纪元值,冒号后面是下一个事务ID,当前事务号最大值安全值可以在pg_xact目录下通过文件名计算出来安全值
Latest checkpoint's NextXID:          0:12595119
#下一个空闲OID(OID,object 是pg内部使用,作为系统表的主键)
Latest checkpoint's NextOID:          50047
#下一个空闲的MultiXactId,多事务ID,可以通过pg_multixact/offsets文件名计算出来安全值
Latest checkpoint's NextMultiXactId:  1
#下一个空闲的MultiXact偏移,多事务偏移量,通pg_multixact/members文件夹下计算出此参数的安全值
Latest checkpoint's NextMultiOffset:  0
#集群范围的最小datfrozenxid,WAL中存储的是oldest XID之后的XID,也就是说这个XID之后的事务,都保留了事务提交的状态值,之前的WAL可能被删除或者正在被删除
Latest checkpoint's oldestXID:        1754
#具有最小datfrozenxid的数据库,可以通过pg_database表进行查看
Latest checkpoint's oldestXID's DB:   1
#最旧的的仍在运行的事务ID
Latest checkpoint's oldestActiveXID:  0
Latest checkpoint's oldestMultiXid:   1
Latest checkpoint's oldestMulti's DB: 1
#有效提交的最旧Xid时间戳
Latest checkpoint's oldestCommitTsXid:0
#有效提交的最新Xid*时间戳
Latest checkpoint's newestCommitTsXid:0
#最后一次执行检查点时间
Time of latest checkpoint:            Mon 27 Mar 2023 12:31:46 AM CST
#当前假 LSN 值,用于未记录的rels
Fake LSN counter for unlogged rels:   0/1
#standby节点最小恢复结束位置
Minimum recovery ending location:     0/0
#standby节点最小恢复结束时间线
Min recovery ending loc's timeline:   0
#备库开始同步主库时重做日志的位置
Backup start location:                0/0
#备库同步结束后重做日志的位置
Backup end location:                  0/0
#记录了备库恢复过程中的一些中间状态(yes正在恢复/no未恢复)
End-of-backup record required:        no

控制文件维护

  1. 固定部分

    初始化数据库时产生,固定不变

  2. 有些信息随时更新

    如果发生检查点、备份、日志切换等操作,则自动更新

  3. postgresql.conf相关参数被更新

    如果配置文件中重要的参数被修改,则也会自动更新

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

  5. 不能手动修改该文件

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

控制文件备份

  1. 冷备

    tar -jcv -f baseline.tar.bz2 $PGDATA
    
  2. pg_basebackup命令

    pg_basebackup -D bk1 -Ft -z -P
    
  3. pg_rman命令

    pg_rman backup --backup-mode=full -B /home/postgres/pg_rman_bk/ -C -P
    

重建控制文件

重建控制文件在pg9.6前使用 pg_resetxlog,pg10之后使用 pg_resetwal 清理wal日志或重置控制文件中一些控制信息。配置指导详见源码 doc/src/sgml/html/app-pgresetwal.html

下面看下命令各个参数具体含义:

[pg10@localhost ~]$ pg_waldump --help
pg_waldump decodes and displays PostgreSQL write-ahead logs for debugging.

Usage:
  pg_waldump [OPTION]... [STARTSEG [ENDSEG]]

Options:
  -b, --bkp-details      output detailed information about backup blocks
  -e, --end=RECPTR       stop reading at WAL location RECPTR
  -f, --follow           keep retrying after reaching end of WAL
  -n, --limit=N          number of records to display
  -p, --path=PATH        directory in which to find log segment files or a
                         directory with a ./pg_wal that contains such files
                         (default: current directory, ./pg_wal, $PGDATA/pg_wal)
  -r, --rmgr=RMGR        only show records generated by resource manager RMGR;
                         use --rmgr=list to list valid resource manager names
  -s, --start=RECPTR     start reading at WAL location RECPTR
  -t, --timeline=TLI     timeline from which to read log records
                         (default: 1 or the value used in STARTSEG)
  -V, --version          output version information, then exit
  -x, --xid=XID          only show records with transaction ID XID
  -z, --stats[=record]   show statistics instead of records
                         (optionally, show per-record statistics)
  -?, --help             show this help, then exit

  • -f, --force force update to be done

即使 pg_resetwal 无法从 pg_control 中确定有效的数据(也可以说成此时控制文件损坏或者缺失),也强迫 pg_resetwal 继续运行。

  • -n, --dry-run no update, just show what would be done

pg_resetwal 打印从 pg_control 重构出来的值以及要被改变的值,然后不修改任何东西退出。这主要是一个调试工具,但是可以用来在允许pg_resetwal真正执行下去之前进行完整性检查。

  • -V, --version output version information, then exit

显示版本信息然后退出。

  • -?, --help show this help, then exit

只有当 pg_resetwal 无法通过读取 pg_control 确定合适的值时,才需要下列选项。安全值可以按下文所述来确定。对于接收数字参数的值,可以使用前缀0x指定16进制值。

  • -c, --commit-timestamp-ids=XID,XID set oldest and newest transactions bearing

手工设置提交时间可以检索到的最老的和最新的事务ID。

能检索到提交时间的最老事务 ID 的安全值(第一部分)可以通过在数据目录下 pg_commit_ts 目录中数字上最小的文件名来决定。反过来,能检索到提交时间的最新事务 ID 的安全值(第二部分)可以通过同一个目录中数字上最大的文件名来决定。文件名都是十六进制的。对应控制文件中,查看 pg_commit_ts 目录,一般情况下该目录均为空,需要开启 track_commit_timestamp 参数才会记录事物提交时间,在未开启的情况下:

Latest checkpoint's oldestCommitTsXid:0

Latest checkpoint's newestCommitTsXid:0

  • [-D, --pgdata=]DATADIR data directory

数据库目录。

  • -e, --epoch=XIDEPOCH set next transaction ID epoch

手工设置下一个事务 ID 的 epoch。事务 ID 的 epoch 实际上并没有存储在数据库中的任何地方,除了被 pg_resetwal 设置在这个域中,所以只要关心的是数据库本身,任何值都可以用,可以不用设置。

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

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

通过指定下一个WAL段文件名称来手工设置WAL开始位置。下一个WAL段文件的名称应该比当前存在于数据目录下pg_wal目录中的任意 WAL 段文件名更大。这些名称也是十六进制的并且有三个部分。第一部分是“时间线 ID”并且通常应该被保持相同。例如,如果00000001000000320000004A是 pg_wal 中最大的项,则使用-l 00000001000000320000004B或更高的值。

注意在使用非默认WAL段尺寸时,WAL文件名中的数字与系统函数和系统视图报告的LSN不同。这个选项要的是WAL文件名而不是LSN。

注意 pg_resetwal 本身查看pg_wal中的文件并选择一个超出最新现存文件名的默认-l设置。因此,只有当你知道 WAL 段文件当前不在pg_wal中时,或者当 pg_wal 的内容完全丢失时,才需要对-l的手工调整,例如一个离线归档中的项。

这些名称也是十六进制的,文件名包含三部分 ,第一部分时间线号(timeline ID) ,第二部分逻辑日志号 ,第三部分日志段号。

000000030000000A000000CA

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

手工设置下一个多事物ID和最老的多事务ID。确定下一个多事务 ID(第一部分)的安全值的方法:在数据目录下的pg_multixact/offsets 目录中查找最大的数字文件名,然后在它的基础上加一并且乘以 65536(0x10000)。反过来,确定最老的多事务 ID(-m的第二部分)的方法:在同一个目录中查找最小的数字文件名并且乘以 65536。文件名是十六进制的数字,因此实现上述方法最简单的方式是以十六进制指定选项值并且追加四个零。所以下一个多事务号为(0000+1)65536,最旧的多事务号为0000*65536。

  • -o, --next-oid=OID set next OID

参数是设置下一个OID(OID,object 是pg内部使用,作为系统表的主键),我们恢复时可以不设置这个参数,因为设置一个超过数据库中最大值OID没有好的办法。

  • -O, --multixact-offset=OFFSET set next multitransaction offset

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

确定安全值的方法:查找数据目录下 pg_multixact/members 目录中最大的数字文件名,然后在它的基础上加一并且乘以 52352 (0xCC80)。文件名是十六进制数字。没有像其他选项那样追加零的简单方法。

  • -x, --next-transaction-id=XID set next transaction ID

手工设置下一个事务 ID。

确定安全值的方法:在数据目录下的 pg_xact 目录中查找最大的数字文件名,然后在它的基础上加一并且乘以 1048576 (0x100000)。注意文件名是十六进制的数字。通常以十六进制的形式指定该选项值也是最容易的。例如,如果0011是 pg_xact 中的最大项,-x 0x1200000就可以(五个尾部的零就表示了前面说的乘数)。

  • --wal-segsize=SIZE size of WAL segments, in megabytes

设置新的WAL段尺寸,以兆字节为单位。这个值必须被设为2的1次幂和10次幂(兆字节)之间。更多信息请参考initdb的相同选项。

注意虽然 pg_resetwal 将把WAL起始地址设置成超过最新的现有WAL段文件,但一些段尺寸的改变可能导致之前的WAL文件名被重用。如果WAL文件名重叠会导致归档策略出现问题,推荐把-l和这个选项一起使用来手动设置WAL起始地址。参数设置新的WAL段大小,默认16M 。

实例如下:

pg_resetwal -c 0x00000,0x00000 -D /opt/pg12/pgdata -l 000000030000000A000000CA -m 0x10000,0x00001 -O 0xCC80 --wal-segsize=16 -x 0x100000

图片

图片

恢复实例

按照上边的方法,我们来实做一个恢复:

我们先把旧的 pg_control 文件重命名一下:

[pg10@localhost ~]$ cd $PGDATA/global
[pg10@localhost global]$ ll pg_control
-rw-------. 1 pg10 postgres 8.0K Mar 22 22:04 pg_control
[pg10@localhost global]$ mv pg_control pg_control_bak
[pg10@localhost global]$ pg_controldata
pg_controldata: could not open file "/home/pg10/postgresql10.23/data/global/pg_control" for reading: No such file or directory

1、计算命令行各项参数值

对着命令行:pg_resetwal -c {}} -D {} -l {} -m {} -O {} --wal-segsize={} -x {}

仔细求证各项的值,以求恢复。

e.g.  pg_resetwal -c 0x00000,0x00000 -D $PGDATA  -l 000000030000000A000000CA -m 0x10000,0x00001 -O 0xCC80 --wal-segsize=16 -x 0x100000
  1. -c 不用指定。因为目录下边没有文件。

    [pg10@localhost global]$ ls $PGDATA/pg_commit_ts
    [pg10@localhost global]$
    
  2. -D $PGDATA

    这个用环境变量即可。

  3. -l 找出最新的WAL文件名: 000000010000000000000022

    所以它的值应该是再+1,000000010000000000000023

  4. -m multitx的下一个,以及最旧的xid

    找到目录:$PGDATA/pg_multixact/offsets,

    [pg10@localhost global]$ ll $PGDATA/pg_multixact/offsets
    total 8.0K
    -rw-------. 1 pg10 postgres 8.0K Mar 22 20:49 0000
    

    所以下一个值是:(0000+1) * 65536,最旧的多事务号为0000*65536。

    postgres=# select to_hex(65536);
     to_hex
    --------
     10000
    (1 row)
    

    所以-m 后边的值应该是 -m 0x10000,0x00001。

  5. -O 手工设置下一个多事务偏移量

    查找数据目录下 pg_multixact/members 目录中最大的数字文件名,然后在它的基础上加一并且乘以 52352 (0xCC80)。

    [pg10@localhost global]$ ll $PGDATA/pg_multixact/members
    total 8.0K
    -rw-------. 1 pg10 postgres 8.0K Feb  9 19:46 0000
    

    所以,它的值应该就是:52352, -O 0xCC80。

  6. -x 下一个事务ID

    在数据目录下的pg_xact目录中查找最大的数字文件名,然后在它的基础上加一并且乘以 1048576 (0x100000)。注意文件名是十六进制的数字。

    [pg10@localhost global]$ ll $PGDATA/pg_xact
    total 8.0K
    -rw-------. 1 pg10 postgres 8.0K Mar 22 22:04 0000
    

    这样得到的值应该是0x0100000, -x 0x0100000

  7. --wal-segsize=

    这个比较容易, 直接查看大小,就能得知。

2、完整的命令行:

[pg10@localhost data]$ touch $PGDATA/global/pg_control
[pg10@localhost data]$ pg_resetwal -D $PGDATA -l 000000010000000000000023 -m 0x10000,0x00001 -O 0xCC80 -x 0x0100000 -f
pg_resetwal: pg_control exists but is broken or wrong version; ignoring it
Write-ahead log reset

3、尝试启动

#检验下控制文件内容
[pg10@localhost data]$ pg_controldata
pg_control version number:            1002
Catalog version number:               201707211
Database system identifier:           7216000336784156990
Database cluster state:               shut down
pg_control last modified:             Thu 30 Mar 2023 12:06:43 AM CST
Latest checkpoint location:           0/2E000028
Prior checkpoint location:            0/0
Latest checkpoint's REDO location:    0/2E000028
Latest checkpoint's REDO WAL file:    00000001000000000000002E
Latest checkpoint's TimeLineID:       1
Latest checkpoint's PrevTimeLineID:   1
Latest checkpoint's full_page_writes: off
Latest checkpoint's NextXID:          0:1048576
Latest checkpoint's NextOID:          10000
Latest checkpoint's NextMultiXactId:  65536
Latest checkpoint's NextMultiOffset:  52352
Latest checkpoint's oldestXID:        3
Latest checkpoint's oldestXID's DB:   0
Latest checkpoint's oldestActiveXID:  0
Latest checkpoint's oldestMultiXid:   1
Latest checkpoint's oldestMulti's DB: 0
Latest checkpoint's oldestCommitTsXid:0
Latest checkpoint's newestCommitTsXid:0
Time of latest checkpoint:            Thu 30 Mar 2023 12:06:43 AM CST
Fake LSN counter for unlogged rels:   0/1
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:                    minimal
wal_log_hints setting:                off
max_connections setting:              100
max_worker_processes setting:         8
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
Float4 argument passing:              by value
Float8 argument passing:              by value
Data page checksum version:           0
Mock authentication nonce:            0000000000000000000000000000000000000000000000000000000000000000
[pg10@localhost data]$ pg_ctl start
waiting for server to start....2023-03-30 00:07:48.471 CST [59717] LOG:  listening on IPv4 address "0.0.0.0", port 1921
2023-03-30 00:07:48.471 CST [59717] LOG:  listening on IPv6 address "::", port 1921
2023-03-30 00:07:48.472 CST [59717] LOG:  listening on Unix socket "/tmp/.s.PGSQL.1921"
2023-03-30 00:07:48.508 CST [59718] LOG:  database system was shut down at 2023-03-30 00:06:43 CST
2023-03-30 00:07:48.513 CST [59717] LOG:  database system is ready to accept connections
 done
server started
#成功的启动了。
#再重新看看control文件的信息:
[pg10@localhost data]$ pg_controldata
pg_control version number:            1002
Catalog version number:               201707211
Database system identifier:           7216000336784156990
Database cluster state:               in production
pg_control last modified:             Thu 30 Mar 2023 12:07:48 AM CST
Latest checkpoint location:           0/2E000028
Prior checkpoint location:            0/0
Latest checkpoint's REDO location:    0/2E000028
Latest checkpoint's REDO WAL file:    00000001000000000000002E
Latest checkpoint's TimeLineID:       1
Latest checkpoint's PrevTimeLineID:   1
Latest checkpoint's full_page_writes: off
Latest checkpoint's NextXID:          0:1048576
Latest checkpoint's NextOID:          10000
Latest checkpoint's NextMultiXactId:  65536
Latest checkpoint's NextMultiOffset:  52352
Latest checkpoint's oldestXID:        3
Latest checkpoint's oldestXID's DB:   0
Latest checkpoint's oldestActiveXID:  0
Latest checkpoint's oldestMultiXid:   1
Latest checkpoint's oldestMulti's DB: 0
Latest checkpoint's oldestCommitTsXid:0
Latest checkpoint's newestCommitTsXid:0
Time of latest checkpoint:            Thu 30 Mar 2023 12:06:43 AM CST
Fake LSN counter for unlogged rels:   0/1
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:                    logical
wal_log_hints setting:                off
max_connections setting:              100
max_worker_processes setting:         8
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
Float4 argument passing:              by value
Float8 argument passing:              by value
Data page checksum version:           0
Mock authentication nonce:            0000000000000000000000000000000000000000000000000000000000000000
[pg10@localhost data]$ ll pg_wal
total 17M
-rw-------. 1 pg10 postgres 305 Mar 22 20:29 000000010000000000000020.00000028.backup
-rw-------. 1 pg10 postgres 16M Mar 30 00:08 00000001000000000000002E
drwx------. 2 pg10 postgres  59 Mar 30 00:06 archive_status
posted on 2024-01-14 21:28  jl1771  阅读(17)  评论(0编辑  收藏  举报