PostgreSQL故障恢復能力之檢查點(Checkpoint)


復習下前面的知識點:

1、緩沖區高速緩存(Buffer Cache)位於服務器的共享內存中,並且所有進程均可訪問。在讀取或更新數據時,進程將頁面讀入緩存。當頁面位於緩存中時,我們在RAM中使用它並保存數據到磁盤。

2、當遇到掉電等故障場景,所有 RAM 內容丟失時,要在故障后恢復數據,pg必須維護一份預寫式日志(WAL),在故障恢復過程中通過重放WAL日志進行數據恢復。

checkpoint

本文需要討論的是,我們不知道在恢復期間從哪里開始重放 WAL 記錄。

方案一:

從頭開始恢復,帶來是問題是我們不一定保留了所有歷史的WAL日志記錄(保留所有歷史WAL會占用大量磁盤空間),即使我們通過歸檔保留了所有的WAL記錄,恢復的時長也會難以接受。

方案二:

我們需要一個逐漸向前推進的時間點,我們可以從該時間點開始恢復(並可以安全地刪除時間點以前的WAL 記錄),為此,pg引入了檢查點(checkpoint)

當執行checkpoint后,會確保檢查點開始時所有臟的緩沖區都刷到磁盤上,此時checkpoint執行完成。后續我們可以使用checkpoint記錄的開始時間作為開始恢復的點。

 checkpoint會執行多久

checkpoint執行后會帶來大量的頁面寫入操作,為了避免大量的頁面寫入對I/O造成沖擊,在檢查點期間寫入臟緩沖區的過程會分散為一段時間。該周期由checkpoint_completion_target控制,它是檢查點間隔的一部分,默認為0.5,也就是說每個checkpoint需要在checkpoints間隔時間的50%內完成。

通常checkpoint_completion_target值會增加到 0.9 以獲得更好的均勻性,PostgreSQL 14版本中會將默認值修改為0.9。

 checkpoint執行過程

1、首先會對緩沖區中的臟頁進行標記

 

 

 2、然后檢查指針遍歷所有緩存並將標記的臟頁刷新到磁盤(頁面不會從緩存中逐出,而只會寫入磁盤)。

3、新的臟緩沖區不會被標記,並且檢查指針不會寫入它們。

 

 

 4、創建檢查點結束的 WAL 記錄,該記錄包含檢查點開始時間的 LSN。

5、更新控制文件信息($PGDATA/global/pg_control)。

 

 

 演示

1、創建一個表;它的頁面將進入緩沖區緩存並變臟:

CREATE EXTENSION pg_buffercache;
CREATE TABLE chkpt AS SELECT * FROM generate_series(1,10000) AS g(n);
SELECT count(*) FROM pg_buffercache WHERE isdirty;
postgres=# SELECT count(*) FROM pg_buffercache WHERE isdirty;
 count
-------
    62
(1 row)

2、記住當前的 WAL 位置

SELECT pg_current_wal_insert_lsn();
 pg_current_wal_insert_lsn
---------------------------
 3/8A0B3810
(1 row)

3、手動執行檢查點操作

CHECKPOINT;
SELECT count(*) FROM pg_buffercache WHERE isdirty;
 count
-------
     0
(1 row)

4、看看檢查點是如何反映在 WAL 中的

SELECT pg_current_wal_insert_lsn();
 pg_current_wal_insert_lsn
---------------------------
 3/8A0B38F8
(1 row)

可以看到lsn有更新,接下來用pg_waldump查看wal日志記錄了哪些內容

查看當前lsn對應的wal日志文件

 SELECT file_name, upper(to_hex(file_offset)) file_offset FROM pg_walfile_name_offset('3/8A0B38F8');
        file_name         | file_offset
--------------------------+-------------
 00000001000000030000008A | B38F8
(1 row)
/usr/local/pgsql/bin/pg_waldump -p /usr/local/pgsql/data/pg_wal/ -s 3/8A0B3810  -e 3/8A0B38F8  00000001000000030000008A
rmgr: Standby     len (rec/tot):     50/    50, tx:          0, lsn: 3/8A0B3810, prev 3/8A0B37D8, desc: RUNNING_XACTS nextXid 58215 latestCompletedXid 58214 oldestRunningXid 58215
rmgr: XLOG        len (rec/tot):    114/   114, tx:          0, lsn: 3/8A0B3848, prev 3/8A0B3810, desc: CHECKPOINT_ONLINE redo 3/8A0B3810; tli 1; prev tli 1; fpw true; xid 0:58215; oid 34053; multi 1; offset 0; oldest xid 479 in DB 1; oldest multi 1 in DB 12723; oldest/newest commit timestamp xid: 0/0; oldest running xid 58215; online

可以看到日志記錄了CHECKPOINT_ONLINE信息,checkpoint start的LSN在單詞“redo”之后輸出,這個位置對應checkpoint start時間最后一個WAL記錄。

5、查看控制文件信息,可知控制文件記錄了最近的checkpoint點對應的lsn信息

pg_controldata -D /usr/local/pgsql/data/ |egrep 'Latest.*location'
Latest checkpoint location:           3/8A0B3848
Latest checkpoint's REDO location:    3/8A0B3810

故障后恢復

如果服務器出現故障,則在后續啟動時,會通過查看pg_control控制文件,查找與“關閉”不同的狀態來檢測此情況。在這種情況下進行自動恢復。

1、直接kill掉postgres主進程

2、查看控制文件Database cluster state狀態,沒有發生變化

pg_controldata -D /usr/local/pgsql/data/ |grep state
--------
Database cluster state:               in production

3、啟動數據庫,查看日志

pg_ctl -D /usr/local/pgsql/data/ start

 

 可知故障后,數據庫從Latest checkpoint's REDO location開始恢復數據

正常關閉后恢復

1、記錄當前的lsn

SELECT pg_current_wal_insert_lsn();

pg_current_wal_insert_lsn
---------------------------
3/8B0000A0
(1 row)

2、正常關閉數據庫

 pg_ctl -D /usr/local/pgsql/data/ stop

3、查看控制文件Database cluster state狀態,可知正確記錄了關閉狀態

pg_controldata -D /usr/local/pgsql/data/ |grep state
Database cluster state:               shut down

4、查看wal日志, 擁有最終檢查點的唯一記錄(CHECKPOINT_SHUTDOWN)

 /usr/local/pgsql/bin/pg_waldump -p /usr/local/pgsql/data/pg_wal/ -s 3/8B0000A0  00000001000000030000008B
rmgr: Standby     len (rec/tot):     50/    50, tx:          0, lsn: 3/8B0000A0, prev 3/8B000028, desc: RUNNING_XACTS nextXid 58215 latestCompletedXid 58214 oldestRunningXid 58215
rmgr: XLOG        len (rec/tot):    114/   114, tx:          0, lsn: 3/8B0000D8, prev 3/8B0000A0, desc: CHECKPOINT_SHUTDOWN redo 3/8B0000D8; tli 1; prev tli 1; fpw true; xid 0:58215; oid 34053; multi 1; offset 0; oldest xid 479 in DB 1; oldest multi 1 in DB 12723; oldest/newest commit timestamp xid: 0/0; oldest running xid 0; shutdown
pg_waldump: fatal: error in WAL record at 3/8B0000D8: invalid record length at 3/8B000150: wanted 24, got 0

5、再次啟動數據庫,可知數據庫正常啟動,無恢復操作

 


免責聲明!

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



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