概述
PostgreSQL的控制文件記錄了數(shù)據(jù)庫(kù)的重要信息咨油, 如數(shù)據(jù)庫(kù)的系統(tǒng)標(biāo)識(shí)符“system_identifier”您炉、 系統(tǒng)表版本“Catalog version number”、 實(shí)例狀態(tài)役电、 Checkpoint信息赚爵、 數(shù)據(jù)頁(yè)的塊大小、 WAL日志的頁(yè)大小及文件大小法瑟、 一些實(shí)例備份和恢復(fù)信息等冀膝。
所以PostgreSQL的控制文件與Oracle數(shù)據(jù)庫(kù)的控制文件的作用基本相同, 都是記錄數(shù)據(jù)庫(kù)的重要信息霎挟, 只是在細(xì)節(jié)上有所不同窝剖, PostgreSQL的控制文件沒(méi)有Oracle數(shù)據(jù)庫(kù)中的那么復(fù)雜。
在PostgreSQL中提供了pg_controldata命令顯示控制文件中的內(nèi)容:
osdba-mac:~ osdba$ pg_controldata
pg_control version number: 1002
Catalog version number: 201707211
Database system identifier: 6531601841114581486
Database cluster state: in production
pg_control last modified: Mon Nov 26 15:35:41 2018
Latest checkpoint location: 2/5DB47D48
Prior checkpoint location: 2/5DB42E90
Latest checkpoint's REDO location: 2/5DB47D10
Latest checkpoint's REDO WAL file: 00000001000000020000005D
Latest checkpoint's TimeLineID: 1
Latest checkpoint's PrevTimeLineID: 1
Latest checkpoint's full_page_writes: on
Latest checkpoint's NextXID: 0:4000
Latest checkpoint's NextOID: 56205
Latest checkpoint's NextMultiXactId: 1
Latest checkpoint's NextMultiOffset: 0
Latest checkpoint's oldestXID: 548
Latest checkpoint's oldestXID's DB: 1
Latest checkpoint's oldestActiveXID: 4000
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: Mon Nov 26 15:35:38 2018
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:
73be4963d7bef303c8a6fd8924270c65137fd18d3ec7db097388565d7fc782f8
數(shù)據(jù)庫(kù)的唯一標(biāo)識(shí)串
數(shù)據(jù)庫(kù)的唯一標(biāo)識(shí)串“Database system identifier”用于唯一標(biāo)識(shí)一套數(shù)據(jù)庫(kù)系統(tǒng)氓扛, 物理復(fù)制的主數(shù)據(jù)庫(kù)和備數(shù)據(jù)庫(kù)有相同的數(shù)據(jù)庫(kù)唯一標(biāo)識(shí)串枯芬。
數(shù)據(jù)庫(kù)的唯一標(biāo)識(shí)串是在Initdb初始化數(shù)據(jù)庫(kù)實(shí)例時(shí)生成的, 它是一個(gè)64bit的整數(shù)采郎。
該整數(shù)由當(dāng)前的時(shí)間戳和執(zhí)行Initdb進(jìn)程的PID的兩個(gè)部分組成千所, 生成的算法可參見(jiàn)PostgreSQL源碼xlog.c中的BootStrapXLOG函數(shù), 內(nèi)容如下:
pg_control version number:
gettimeofday(&tv, NULL);
sysidentifier = ((uint64) tv.tv_sec) << 32;
sysidentifier |= ((uint64) tv.tv_usec) << 12;
sysidentifier |= getpid() & 0xFFF;
從上面的算法中我們可以知道蒜埋, 高44位的時(shí)間戳中由于取了時(shí)間戳的微秒部分淫痰, 所以重復(fù)的概率極低。
低12位是進(jìn)程PID整份。
根據(jù)上面的原理我們就可以知道待错, 如果知道了PostgreSQL數(shù)據(jù)庫(kù)的唯一標(biāo)識(shí)串(見(jiàn)pg_controldata命令打印的Database system identifier部分)籽孙, 就能知道該數(shù)據(jù)庫(kù)是什么時(shí)候創(chuàng)建的, 我們可以用下面的SQL語(yǔ)句把唯一標(biāo)識(shí)串中的時(shí)間戳取出來(lái):
SELECT to_timestamp(((6531601841114581486>>32) & (2^32 -1)::bigint));
實(shí)際執(zhí)行效果如下:
osdba-mac:~ osdba$ psql
psql (10.5)
Type "help" for help.
osdba=# SELECT to_timestamp(((6531601841114581486>>32) & (2^32 -1)::bigint));
to_timestamp
------------------------
2018-03-11 16:31:00+08
(1 row)
Checkpoint信息
什么是檢查點(diǎn)(Checkpoint)?
可以想象一個(gè)場(chǎng)景: 如果WAL重做日志可以無(wú)限地增大火俄, 如果僅從不丟失數(shù)據(jù)的角度來(lái)看是不需要把緩沖池中的臟數(shù)據(jù)塊寫入磁盤的犯建, 因?yàn)楫?dāng)發(fā)生宕機(jī)時(shí), 完全可以通過(guò)WAL重做日志來(lái)恢復(fù)整個(gè)數(shù)據(jù)庫(kù)系統(tǒng)中的數(shù)據(jù)到宕機(jī)發(fā)生的時(shí)刻瓜客。
但這種想法明顯存在以下幾個(gè)問(wèn)題:
- WAL重做日志不可以無(wú)限增大适瓦, 因?yàn)閃AL日志會(huì)占用一定的空間。
- 重放WAL日志會(huì)占用時(shí)間谱仪, 不可能一個(gè)數(shù)據(jù)庫(kù)宕機(jī)后我們花費(fèi)很長(zhǎng)時(shí)間來(lái)進(jìn)行恢復(fù)玻熙, 通常需要在有限的時(shí)間內(nèi)完成恢復(fù), 如在幾分鐘之內(nèi)完成疯攒。
- 緩沖區(qū)不可能無(wú)限大嗦随, 所以不管怎么樣, 都需要把一定的臟數(shù)據(jù)刷新到磁盤中敬尺, 需要考慮必須要先刷新哪些臟數(shù)據(jù)等問(wèn)題枚尼。
應(yīng)用檢查點(diǎn)技術(shù)就是為了解決這些問(wèn)題。
當(dāng)恢復(fù)數(shù)據(jù)庫(kù)時(shí)筷转, 不需要把所有的WAL日志全部重新應(yīng)用姑原, 只需要應(yīng)用某個(gè)時(shí)間點(diǎn)之后的WAL日志應(yīng)用就可以了悬而, 當(dāng)然要做到這一點(diǎn)呜舒, 就需要把這一時(shí)間點(diǎn)之前產(chǎn)生的臟數(shù)據(jù)全部刷新到磁盤中, 所以檢查點(diǎn)只是一個(gè)數(shù)據(jù)庫(kù)事件笨奠, 該事件觸發(fā)后將會(huì)執(zhí)行一個(gè)操作袭蝗, 而此操作可以保證把事件之前的臟數(shù)據(jù)全部刷新到磁盤中。
當(dāng)然般婆, 我們讓Checkpoint發(fā)生得越頻繁到腥, 在數(shù)據(jù)庫(kù)實(shí)例宕機(jī)后重放的WAL日志量就越少, 當(dāng)然重做的日志量的多少也取決于發(fā)生宕機(jī)的時(shí)間點(diǎn)蔚袍, 發(fā)生宕機(jī)的時(shí)間點(diǎn)越靠近最后的檢查點(diǎn)乡范, 重做的日志量也就越少。
我們通過(guò)pg_controldata命令看到控制文件中關(guān)于Checkpoint的信息有以下幾項(xiàng):
Latest checkpoint location: 2/5DB47D48
Prior checkpoint location: 2/5DB42E90
Latest checkpoint's REDO location: 2/5DB47D10
Latest checkpoint's REDO WAL file: 00000001000000020000005D
“Latest checkpoint location”和“Prior checkpoint location”這兩項(xiàng)容易理解啤咽, 就是“最后一次的Checkpoint位置”和“前一次的Checkpoint位置”晋辆, 但當(dāng)看到“Latest checkpoint's REDO location”中也有一個(gè)Checkpoint的位置時(shí)就讓人疑惑了: “Latest checkpoint location”“Latest checkpoint's REDO location”為什么有兩個(gè)“最后的Checkpoint位置”?
為了講明白這個(gè)問(wèn)題宇整, 我們需要簡(jiǎn)單介紹一下發(fā)生Checkpoint的操作過(guò)程瓶佳, 雖然Checkpoint事件是一個(gè)時(shí)間點(diǎn), 但執(zhí)行Checkpoint刷盤的操作是需要進(jìn)行一段時(shí)間的鳞青,如現(xiàn)在我們要開(kāi)始做Checkpoint了霸饲, 先記錄當(dāng)前點(diǎn)为朋, 該當(dāng)前點(diǎn)就記錄在“Latest checkpoint'sREDO location”中, 當(dāng)完成刷盤操作之后厚脉, 把Checkpoint相關(guān)信息也生成一條WAL記錄习寸,再把這條WAL記錄也寫入WAL日志文件中, 此WAL日志的位置就是“Latest checkpoint location:2/5DB47D48”傻工, 然后更新控制文件中有關(guān)Checkpoint的信息融涣。
從上面的分析中我們知道, 在數(shù)據(jù)庫(kù)實(shí)例宕機(jī)之后精钮, 開(kāi)始重做WAL日志時(shí)威鹿, 開(kāi)始的日志點(diǎn)為“Latest checkpoint's REDO location”, 而不是“Latest checkpoint location”轨香, 而“Latest checkpoint location”指向的是WAL日志中的一條Checkpoint的WAL記錄忽你, 這條記錄中記錄了本次Checkpoint事件的一些信息。
與Standby相關(guān)的信息
如果我們用pg_controldata顯示備庫(kù)的控制文件會(huì)發(fā)現(xiàn)以下兩項(xiàng)不同臂容,
在主庫(kù)中下面這兩項(xiàng)都是“0/0”和“0”:
Minimum recovery ending location: 0/0
Min recovery ending loc's timeline: 0
而在備庫(kù)中這兩項(xiàng)不為“0”科雳, 示例如下:
Minimum recovery ending location: 0/271E81A8
Min recovery ending loc's timeline: 1
這兩項(xiàng)是做什么的呢? 下面我們解釋一下脓杉。
我們知道備庫(kù)在不停地應(yīng)用WAL日志糟秘, 對(duì)于Hot Standby, 在應(yīng)用WAL日志的同時(shí)球散,還會(huì)對(duì)外提供服務(wù)尿赚。
備庫(kù)本身也可能因斷電或其他故障而宕機(jī), 當(dāng)備庫(kù)在重新啟動(dòng)時(shí)蕉堰, 不能一啟動(dòng)就對(duì)外提供只讀服務(wù)凌净, 因?yàn)檫@時(shí)的數(shù)據(jù)可能還不一致, 如果這時(shí)提供只讀服務(wù)屋讶,用戶會(huì)讀到不一致的數(shù)據(jù)冰寻。
這兩個(gè)參數(shù)用于指定當(dāng)備庫(kù)異常終止再啟動(dòng)時(shí), 只有應(yīng)用WAL日志超過(guò)指定點(diǎn)之后才能對(duì)外提供只讀服務(wù)皿渗。 而有人可能會(huì)問(wèn)斩芭, 為什么在主庫(kù)上不需要這兩項(xiàng)內(nèi)容呢?
因?yàn)樵谥鲙?kù)上乐疆, 只有把當(dāng)前所有的WAL日志全部應(yīng)用完成之后才能對(duì)外提供服務(wù)划乖, 而備庫(kù)是不斷地從主庫(kù)接收日志, 然后不斷地應(yīng)用日志诀拭, 沒(méi)有把當(dāng)前WAL日志應(yīng)用完的說(shuō)法迁筛, 所以在備庫(kù)上需要知道應(yīng)用多少日志之后就可以對(duì)外提供只讀服務(wù)了。