PostgreSQL控制文件講解及案例


PostgreSQL控制文件內容:

主要分為是三部分,初始化靜態信息、WAL及檢查點的動態信息、一些配置信息。

我們可以用過pg_controldata命令直接讀取PostgreSQL控制文件內容:

[postgres@postgresdb ~]$ /u01/postgres/pgsql/bin/pg_controldata -D /data/postgres/data
pg_control version number: 1100
Catalog version number: 201809051
Database system identifier: 6709564017377676696
Database cluster state: in production
pg_control last modified: Wed 17 Jul 2019 02:27:12 PM HKT
Latest checkpoint location: 5A/F522A8E0
Latest checkpoint's REDO location: 5A/F522A8A8
Latest checkpoint's REDO WAL file: 000000010000005A000000F5
Latest checkpoint's TimeLineID: 1
Latest checkpoint's PrevTimeLineID: 1
Latest checkpoint's full_page_writes: on
Latest checkpoint's NextXID: 0:57914
Latest checkpoint's NextOID: 73874
Latest checkpoint's NextMultiXactId: 1
Latest checkpoint's NextMultiOffset: 0
Latest checkpoint's oldestXID: 561
Latest checkpoint's oldestXID's DB: 1
Latest checkpoint's oldestActiveXID: 57914
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: Wed 17 Jul 2019 02:27:07 PM HKT
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: replica
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: 1310720
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: ce6a83651b3b6ba8a8c8fcc8ee22ffb9c47d1aebaf3dae82462d23826c10f26f
[postgres@postgresdb ~]$
下面詳細介紹下各參數含義。

pg_control version number是控制文件版本號。

Catalog version number 是系統表版本號,格式是yyyymmddN。記錄系統不兼容性的改變。N是yyymmdd當天改變的次數。具體可以查看源碼文件catversion.h。

Database system identifier 數據庫系統號 這個標識串是一個64bit的整數,其中包含了創建數據庫的時間戳和initdb時初始化的進程號,具體初始化方法可查看源碼文件xlog.c。

創建時間可以通過to_timestamp轉換查看到。

postgres=# SELECT to_timestamp(((6709564017377676696>>32) & (2^32 -1)::bigint));
to_timestamp 
------------------------
2019-07-04 06:15:08+08
Database cluster state 記錄實例的狀態。源碼文件中看到數據庫的幾種狀態,源碼pg_control.h中可以看到:
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數據庫正常啟動后不是此狀態
Latest checkpoint location數據庫異常停止后再重新啟動時,需要做實例恢復,實例恢復的過程是從WAL日志中,找到最后一次的checkpoint點,然后讀取這個點之后的WAL日志,重新應用這些日志,此過程稱為數據庫實例前滾,最后一次的checkpoint點的信息記錄在Latest checkpont項中。
Latest checkpoint's REDO location 記錄數據庫日志文件上檢查點。
Latest checkpoint's REDO WAL file記錄WAL日志名,目錄下pg_wal可以查到文件。
Latest checkpoint's NextXID前面是新紀元值,冒號后面是下一個事務號,當前事務號最大值安全值可以在pg_xact目錄下通過文件名計算出來。 
Latest checkpoint's NextMultiXactId參數,可以通過pg_multixact/offsets文件名計算出來安全值。
Latest checkpoint's NextMultiOffset參數,當恢復控制文件時可以通過pg_multixact/members文件夾下計算出此參數的安全值。 
Maximum length of identifiers是指一些數據庫對象名稱的最大長度,如表名、索引名的最大長度 Maximum columns in an index 表示一個索引最多多少列,目前為32個。 
Maximum size of a TOAST chunk是TOAST chunk的最大長度。TOAST是解決當列的內容太長,在一個數據塊中存不下時的一種行外存儲的方式。類似Oracle的行鏈接。
Data page checksum version是數據塊checksum的版本,默認為0,數據塊沒有使用checksum。運行initdb時加了-k參數,PG才會在數據塊上啟用checksum功能。
參數介紹到這里,控制文件各內容定義可以查看源文件pg_control.h。
PostgreSQL控制文件重建
pg9.6前使用 pg_resetxlog,pg10之后使用pg_resetwal清理wal日志或重置控制文件中一些控制信息。
命令詳細介紹可以查看官方文檔:
https://www.postgresql.org/docs/11/app-pgresetwal.html
[postgres@lsl-test1 ~]$ /u01/postgres/pgsql/bin/pg_resetwal -n -D /data/postgres/data
pg_resetwal: lock file "postmaster.pid" exists
Is a server running? If not, delete the lock file and try again.
[postgres@lsl-test1 ~]$ /u01/postgres/pgsql/bin/pg_resetwal --help
pg_resetwal resets the PostgreSQL write-ahead log.
Usage:
pg_resetwal [OPTION]... DATADIR
Options:
-c, --commit-timestamp-ids=XID,XID
set oldest and newest transactions bearing
commit timestamp (zero means no change)
[-D, --pgdata=]DATADIR data directory
-e, --epoch=XIDEPOCH set next transaction ID epoch
-f, --force force update to be done
-l, --next-wal-file=WALFILE set minimum starting location for new WAL
-m, --multixact-ids=MXID,MXID set next and oldest multitransaction ID
-n, --dry-run no update, just show what would be done
-o, --next-oid=OID set next OID
-O, --multixact-offset=OFFSET set next multitransaction offset
-V, --version output version information, then exit
-x, --next-transaction-id=XID set next transaction ID
--wal-segsize=SIZE size of WAL segments, in megabytes
-?, --help show this help, then exit

下面看下命令各個參數具體含義:
-c參數有兩個參數值,一個最舊的事務號,一個最新的事務號。最舊的事務號的安全值,可以在pg_commit_ts目錄查詢最小的文件名;
最新事務ID的安全值,可以在pg_commit_ts目錄查詢最大的文件名。文件名都是16進制。實際測試在11的版本pg_commit_ts目錄下未發現文件。
[postgres@lsl-test1 data]$ cd /data/postgres/data/pg_commit_ts/
[postgres@lsl-test1 pg_commit_ts]$ ls -l

-e參數是設置事務號的新紀元(epoch),除了pg_resetwal設置的字段之外,事務ID新紀元實際上並不存儲在數據庫的任何位置。您可能需要調整此值,

以確保Slony或者Skytools等復制系統能夠正確工作。如果是這樣的話,應該可以從下游復制數據庫的狀態獲得適當的值。

-l 參數通過指定下一個WAL段文件的名稱,手動設置WAL啟動位置。該選項使用WAL文件名,而不是LSN。下一個段的名字應該大於當前存在pg_wal目錄下的任何WAL段文件名。

[postgres@lsl-test1 pg_commit_ts]$ cd ../pg_wal/
[postgres@lsl-test1 pg_wal]$ ls -l
total 933892
drwx------. 2 postgres postgres 4096 Jul 4 06:15 archive_status
-rw-------. 1 postgres postgres 16777216 Jul 17 10:49 000000010000005A000000FF
-rw-------. 1 postgres postgres 16777216 Jul 17 10:49 000000010000005B0000001D
-rw-------. 1 postgres postgres 16777216 Jul 17 10:49 000000010000005B00000026
-rw-------. 1 postgres postgres 16777216 Jul 17 10:49 000000010000005B00000028
-rw-------. 1 postgres postgres 16777216 Jul 17 10:50 000000010000005B00000025
-rw-------. 1 postgres postgres 16777216 Jul 17 10:51 000000010000005B00000003
-rw-------. 1 postgres postgres 16777216 Jul 17 10:52 000000010000005B00000004
-rw-------. 1 postgres postgres 16777216 Jul 17 10:52 000000010000005B0000002C
-rw-------. 1 postgres postgres 16777216 Jul 17 10:55 000000010000005B0000002D
-rw-------. 1 postgres postgres 16777216 Jul 17 14:27 000000010000005A000000F5

這些名稱也是十六進制的,文件名包含三部分 ,第一部分時間線號(timeline ID) ,第二部分邏輯日志號 ,第三部分日志段號。

-m參數也是兩個值,一個是下一個多事務號,一個是最舊的多事務號。

下一個多事務號的安全值,可以在目錄pg_multixact/offsets查找數值最大的文件名,加1然后乘以65536(0x10000)。

最舊的多事務號的安全值可以通過查詢目錄下數值最小的文件名乘以65536。文件名都是十六進制。

[postgres@lsl-test1 pg_wal]$ ls -lrt /data/postgres/data/pg_multixact/offsets/
[postgres@lsl-test1 offsets]$ ls -l
total 8
-rwx------. 1 postgres postgres 8192 May 17 18:04 0000

-o參數是設置下一個OID(OID,object 是pg內部使用,作為系統表的主鍵),我們恢復時可以不設置這個參數,因為設置一個超過數據庫中最大值OID沒有好的辦法。

-O參數是設置下一個多事務偏移量。查找pg_multixact/members目錄下數值最大的文件名,+1乘以52352 (0xCC80),可以計算出偏移量的安全值。目錄下文件的文件名也是十六進制的。

[postgres@lsl-test1 offsets]$ ls -lrt /data/postgres/data/pg_multixact/members
total 8
-rwx------. 1 postgres postgres 8192 May 17 17:22 0000
--wal-segsize參數設置新的WAL段大小 。
-x參數是手工設置下一個事務ID,pg_xact目錄下可以查看數值最大的文件名,+1乘以 1048576 (0x100000),獲取安全值。文件名也是十六進制。
[postgres@lsl-test1 offsets]$ ls -l /data/postgres/data/pg_xact/
total 16
-rwx------. 1 postgres postgres 8192 May 17 18:04 0000
-rw-------. 1 postgres postgres 8192 May 30 17:26 0001

PostgreSQL控制文件恢復測試

測試過程如下(基於PostgreSQL 11.2) :

1. 新建測試數據, 用到with oids的表, 因為OID無法確定, 看看是否會有異常

postgres=# create table lsl_oid1(id int primary key) with oids; 
CREATE TABLE
postgres=# insert into lsl_oid1 select generate_series(1,100000);
INSERT 0 100000
postgres=# select min(oid),max(oid) from lsl_oid1 ; 
min | max 
-------+--------
16400 | 116399
(1 row)
2. 正常關閉數據,記錄下控制文件信息
[postgres@lsl-test1 bin]$ /u01/postgres/pgsql/bin/pg_ctl stop -D /data/postgres/data
waiting for server to shut down.... done
server stopped
## 記下pg_controldata信息, 方便修復后進行比對
[postgres@lsl-test1 bin]$ /u01/postgres/pgsql/bin/pg_controldata -D /data/postgres/data
pg_control version number: 1100
Catalog version number: 201809051
Database system identifier: 6691945724594983959
Database cluster state: shut down
pg_control last modified: Thu 30 May 2019 05:26:41 PM CST
Latest checkpoint location: 0/79E9888
Latest checkpoint's REDO location: 0/79E9888
Latest checkpoint's REDO WAL file: 000000010000000000000007
Latest checkpoint's TimeLineID: 1
Latest checkpoint's PrevTimeLineID: 1
Latest checkpoint's full_page_writes: on
Latest checkpoint's NextXID: 0:1048585
Latest checkpoint's NextOID: 116400
Latest checkpoint's NextMultiXactId: 65536
Latest checkpoint's NextMultiOffset: 52352
Latest checkpoint's oldestXID: 561
Latest checkpoint's oldestXID's DB: 13878
Latest checkpoint's oldestActiveXID: 0
Latest checkpoint's oldestMultiXid: 1
Latest checkpoint's oldestMulti's DB: 13878
Latest checkpoint's oldestCommitTsXid:0
Latest checkpoint's newestCommitTsXid:0
Time of latest checkpoint: Thu 30 May 2019 05:26:40 PM 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: replica
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
3. 模擬控制文件故障,直接刪除控制文件
[postgres@lsl-test1 global]$ pwd
/pg/pg11/data/global
[postgres@lsl-test1 global]$ rm -rf pg_control
4. 啟動數據庫,模擬控制文件丟失場景(正常關閉數據及處理方法)
[postgres@lsl-test1 global]$ /usr/pgsql-11/bin/pg_ctl start
waiting for server to start....postgres: could not find the database system
Expected to find it in the directory "/pg/pg11/data",
but could not open file "/pg/pg11/data/global/pg_control": No such file or directory
stopped waiting
pg_ctl: could not start server
Examine the log output.
下面開始正式重建控制文件,使得數據庫可以正常啟動。
5. 首先創建一個名為pg_control的空文件
[postgres@lsl-test1 global]$ touch $PGDATA/global/pg_control
6. 使用pg_resetwal修復pg_control
確認pg_resetwal參數值。
首先確認-c參數,上面參數詳細分析發現目錄下為空,因此暫時忽略此參數。
-e參數是設置下一個事務號的新紀元,我們測試環境沒有其它復制系統因此也可以忽略。
-l參數,查看pg_wal下文件文件名,大於文件名最大值即可。
[postgres@lsl-test1 ~]$ cd /data/postgres/data/pg_wal
[postgres@lsl-test1 pg_wal]$ ls -l
因此-m可以取0x10000,0x00000。
-o數不確定時,由於測試沒有復制軟件因此可以暫時忽略。
-O 查找pg_multixact/members目錄下數值最大的文件名,+1乘以52352 (0xCC80)。
[postgres@lsl-test1 offsets]$ cd ../members/
[postgres@lsl-test1 members]$ ls -l
total 8
-rwx------. 1 postgres postgres 8192 May 17 17:22 0000
因此-O=0xCC80。
-x參數查找pg_xact目錄下可以查看數值最大的文件名,+1乘以 1048576 (0x100000)。
[postgres@lsl-test1 members]$ ls -lrt /data/postgres/data/pg_xact/
[postgres@lsl-test1 pg_xact]$ ls -l
total 16
-rwx------. 1 postgres postgres 8192 May 17 18:04 0000
-rw-------. 1 postgres postgres 8192 May 30 17:26 0001
因此-x=0x200000。
不加-f參數時可以查看要寫入控制文件中的參數內容。
[postgres@lsl-test1 pg_xact]$ /u01/postgres/pgsql/bin/pg_resetwal -l 00000001000000000000009E -m 0x10000,0x00001 -O 0xCC80 -x 0x100000 -D /data/postgres/data
pg_resetwal: oldest multitransaction ID (-m) must not be 0
[postgres@lsl-test1 pg_xact]$ /u01/postgres/pgsql/bin/pg_resetwal -l 00000001000000000000009E -m 0x10000,0x00001 -O 0xCC80 -x 0x100000 -D /data/postgres/data
pg_resetwal: pg_control exists but is broken or wrong version; ignoring it
Guessed pg_control values:
pg_control version number: 1100
Catalog version number: 201809051
Database system identifier: 6696828635748080009
Latest checkpoint's TimeLineID: 1
Latest checkpoint's full_page_writes: off
Latest checkpoint's NextXID: 0:3
Latest checkpoint's NextOID: 10000
Latest checkpoint's NextMultiXactId: 1
Latest checkpoint's NextMultiOffset: 0
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
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
Values to be changed:
First log segment after reset: 000000010000000000000009
NextMultiXactId: 65536
OldestMultiXid: 1
OldestMulti's DB: 0
NextMultiOffset: 52352
NextXID: 2097152
OldestXID: 2297064448
OldestXID's DB: 0
If these values seem acceptable, use -f to force reset.
[postgres@lsl-test1 pg_xact]$ cd ../global/
[postgres@lsl-test1 global]$ ls -l pg_control
-rw-r--r--. 1 postgres postgres 0 May 30 17:36 pg_control

7. 啟動數據庫

確認控制文件參數無誤后加上-f會寫入到控制文件里。

[postgres@postgresdb global]$ /u01/postgres/pgsql/bin/pg_resetwal -l 00000001000000000000009E -m 0x10000,0x00001 -O 0xCC80 -x 0x100000 -D /data/postgres/data -f
pg_resetwal: lock file "postmaster.pid" exists
Is a server running? If not, delete the lock file and try again.
[postgres@postgresdb global]$ ls
1136 1213_fsm 1232 1261 1262_vm 2671 2695 2847 2966_vm 4060 6001 6115
1136_fsm 1213_vm 1233 1261_fsm 2396 2672 2697 2964 2967 4060_vm 6002 pg_control
1136_vm 1214 1260 1261_vm 2396_fsm 2676 2698 2964_vm 3592 4061 6100 pg_control1
1137 1214_fsm 1260_fsm 1262 2396_vm 2677 2846 2965 3592_vm 6000 6100_vm pg_filenode.map
1213 1214_vm 1260_vm 1262_fsm 2397 2694 2846_vm 2966 3593 6000_vm 6114 pg_internal.init
[postgres@postgresdb global]$ cd ..
[postgres@postgresdb data]$ ls
base pg_dynshmem pg_logical pg_replslot pg_stat pg_tblspc pg_wal postgresql.conf
global pg_hba.conf pg_multixact pg_serial pg_stat_tmp pg_twophase pg_xact postmaster.opts
pg_commit_ts pg_ident.conf pg_notify pg_snapshots pg_subtrans PG_VERSION postgresql.auto.conf postmaster.pid
[postgres@postgresdb data]$ mv postmaster.pid postmaster.pid1 (非正常關閉需要關閉這個,正常關閉的不需要這個步驟)
[postgres@postgresdb data]$ /u01/postgres/pgsql/bin/pg_resetwal -l 00000001000000000000009E -m 0x10000,0x00001 -O 0xCC80 -x 0x100000 -D /data/postgres/data -f
pg_resetwal: pg_control exists but is broken or wrong version; ignoring it
Write-ahead log reset
[postgres@postgresdb data]$ /u01/postgres/pgsql/bin/pg_resetwal -l 000000010000005A000000F6 -m 0x10000,0x00001 -O 0xCC80 -x 0x100000 -D /data/postgres/data -f
[postgres@lsl-test1 global]$ /u01/postgres/pgsql/bin/pg_resetwal -l 000000010000005A000000F6-m 0x10000,0x00001 -O 0xCC80 -x 0x100000 -D /data/postgres/data -f
pg_resetwal: pg_control exists but is broken or wrong version; ignoring it
Write-ahead log reset
啟動數據庫。
[postgres@lsl-test1 global]$ /u01/postgres/pgsql/bin/pg_ctl start -D /data/postgres/data
waiting for server to start....2019-05-30 22:42:50.946 CST [2471] LOG: listening on IPv6 address "::1", port 5432
2019-05-30 22:42:50.946 CST [2471] LOG: listening on IPv4 address "127.0.0.1", port 5432
2019-05-30 22:42:50.949 CST [2471] LOG: listening on Unix socket "/var/run/postgresql/.s.PGSQL.5432"
2019-05-30 22:42:50.961 CST [2471] LOG: listening on Unix socket "/tmp/.s.PGSQL.5432"
2019-05-30 22:42:50.987 CST [2471] LOG: redirecting log output to logging collector process
2019-05-30 22:42:50.987 CST [2471] HINT: Future log output will appear in directory "log".
done
server started
8. 查看測試數據是否正常,然后插入新數據看數據庫是否可用
[postgres@lsl-test1 global]$ psql
psql (11.2)
Type "help" for help.
postgres=# select min(oid),max(oid),count(*) from test_table1;
數據庫可以正常訪問。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM