1. 若是沒有WAL,pg掛了會怎麼樣?
1.1 數據庫爲了快速緩存,實現了共享內存池,若沒有實現wal。
1.2 假設第一次插入語句,PG從磁盤中讀取數據到內存裏。而後向內存裏的某一頁插入一個元組。目前是個髒頁,由於尚未寫入到磁盤(也能夠是其餘持久化介質)。
1.3 而後又來一個插入語句,到這一頁。
1.4 若是因爲掉電緣由,操做系統或者PG掛了,數據就沒了。
2. 介紹寫wal數據和數據庫恢復的過程。
2.1 爲了處理上文提到的失敗的狀況,PG引入了WAL。
2.2 XLOG(歷史數據、WALdata),當一個操做如插入刪除或提交操做產生,WAL段文件會馬上寫到磁盤中。
2.3 xlog 的LSN記錄表示一個位置,這條記錄寫在事務日誌裏的位置。每一個xlog是獨一無二的。
2.4 Redo 點,是數據庫恢復的點。也就是最後一個檢查點。事實上,數據恢復和檢查點處理密不可分。
3. wal的概述
(1) 檢查點創造者是一個後臺進程,週期性執行檢查點操做。無論何時檢查點創造者啓動,它就會記錄檢查點記錄到如今的XLog文件。
(2) 假設第一次插入操做,插一條元組到內存頁裏,寫入wal文件。location從LSN_0變爲LSN_1。在這個例子中,XLOG是一個頭文件和元組實體。
(3) 隨着事務提交,PG建立並寫了一個Xlog到WALbufer(內存中)而後寫到磁盤。LSN變爲1
(4) 隨着第二次插入操做,PG插入一條新的元組,建立和寫入xlog到內存裏,並更新表A的LSN變爲2。
(5) 當事務提交,PG和步驟3同樣。
(6) 假設操做系統失效,全部的內存數據都丟了。
4. pg 恢復的過程
(1) PG讀Xlog而後導入到內存裏。
(2) PG回放XLOG以前,PG會比較XLOG裏的LSN和對應的內存page中的LSN。若是XLOG LSN比頁的LSN要大,那麼XLOG中的數據會插入到內存頁中,而且更新內存頁中的LSN。若是LSN比內存頁中要小,就讀下一個XLOG數據。
(3)PG回放接下來的XLOG。因此redolog 就是xlog。
咱們相信寫XLOG會有必定開銷,可是比起寫整個內存頁,咱們能夠獲得更好的優化。如系統容錯。
5 full-page write
假設表A的數據頁被損壞了。由於操做系統問題,後臺寫進程寫了髒頁進去。Xlog在當前頁就沒法恢復了,因此須要full-page write。
full-page write默認是啓動的,PostgreSQL在每一個檢查點以後的每一個頁面的第一次更改期間將一對標題數據和整個頁面寫爲XLOG記錄;就是說對第一次修改作一個備份。
(1) 檢查點進程開始一個檢查點進程。
(2) 在插入第一條數據,PG操做會寫入整個頁由於是第一次操做。
(3) 隨着事務提交,page會落盤。
(4) 在插入第二條數據後(先日誌後數據)。
(5) 而後PG提交。
(6) 爲了證實full-page的做用,咱們考慮磁盤已經壞死,因爲操做系統失誤。後臺寫進程已經寫到磁盤。
6 數據庫恢復經過備份塊
(1) PG讀取XLOG的日誌到內存裏,而且是有數據的。
(2) 當一個Xlog記錄是全備份,無論他們的lsn是啥,都會覆蓋到內存中。
(3) 因爲有操做日誌信息,能夠恢復B。
7事務日誌和WAL段文件
WAL段文件的文件名是以下規則
第一個WAL段文件是000000010000000000000001,若是第一個已經被寫滿了,那麼就會寫第二個名爲000000010000000000000002。xlog名字都是連續的。0000000100000000000000FF寫完後,000000010000000100000000是下一個。 規則大概是這樣的。
8 wal段文件的內部
一個WAL文件默認是16MB,且內部的頁是8k的。 第一個page有頭部數據,叫
XLogLongPageHeaderData。其餘page頭文件叫作
XLogPageHeaderData.
typedef struct XLogPageHeaderData
{
uint16 xlp_magic;
uint16 xlp_info;
TimeLineID xlp_tli;
XLogRecPtr xlp_pageaddr; /* XLOG address of this page */
uint32 xlp_rem_len; /* total len of remaining data for record */
} XLogPageHeaderData;
{
uint16 xlp_magic;
uint16 xlp_info;
TimeLineID xlp_tli;
XLogRecPtr xlp_pageaddr; /* XLOG address of this page */
uint32 xlp_rem_len; /* total len of remaining data for record */
} XLogPageHeaderData;
兩個結構差很少,就分析這個。
xlp_magic數字用於正確性校驗。由於若是被修改了說明數據不對。
xlp_tli表示該page裏第一條數據的時間線。
xlp_pageaddr這個page的內存地址。
xlp_rem_len page的空餘大小。
9 XLOG 數據記錄的內部
typedef struct XLogRecord
{
uint32 xl_tot_len; /* total len of entire record */ 記錄長度
TransactionId xl_xid; /* xact id */ 事務id
XLogRecPtr xl_prev; /* ptr to previous record in log */ 指針
uint8 xl_info; /* flag bits, see below */
RmgrId xl_rmid; /* resource manager for this record */資源管理器ID號
/* 2 bytes of padding here, initialize to zero */
pg_crc32c xl_crc; /* CRC for this record */ crc碼
}
{
uint32 xl_tot_len; /* total len of entire record */ 記錄長度
TransactionId xl_xid; /* xact id */ 事務id
XLogRecPtr xl_prev; /* ptr to previous record in log */ 指針
uint8 xl_info; /* flag bits, see below */
RmgrId xl_rmid; /* resource manager for this record */資源管理器ID號
/* 2 bytes of padding here, initialize to zero */
pg_crc32c xl_crc; /* CRC for this record */ crc碼
}
其中 info +rmid 都用於 資源管理。
PG10.0目前有如下操做
Operation | Resource manager |
---|---|
Heap tuple operations | RM_HEAP, RM_HEAP2 |
Index operations | RM_BTREE, RM_HASH, RM_GIN, RM_GIST, RM_SPGIST, RM_BRIN |
Sequence operations | RM_SEQ |
Transaction operations | RM_XACT, RM_MULTIXACT, RM_CLOG, RM_XLOG, RM_COMMIT_TS |
Tablespace operations | RM_SMGR, RM_DBASE, RM_TBLSPC, RM_RELMAP |
replication and hot standby operations | RM_STANDBY, RM_REPLORIGIN, RM_GENERIC_ID, RM_LOGICALMSG_ID |
2. 若是是更新操做,xl_info會設置成XLOG_HEAP_UPDATE。heap_xlog_update()會重放記錄。
3. 當事務提交了,xl_rmid 和xl_info 會設置成RM_XACT和XLOG_XACT_COMMIT。恢復時執行xact_redo_commit();
在9.5之後的版本,xl_len已經被移除了。
10. XLOG記錄的數據部分(9.4版本和之前)
主要分爲兩種備份塊和非備份塊。
備份塊,有兩個數據結構和一個數據對象。
1. XLogRecord (頭部)2.
BkpBlock 3.
the entire page apart from its free-space
typedef struct BkpBlock @ include/access/xlog_internal.h { RelFileNode node; /* relation containing block */ ForkNumber fork; /* fork within the relation */ BlockNumber block; /* block number */
// 上面三個屬於鑑別哪一個表 uint16 hole_offset; /* number of bytes before "hole" */ uint16 hole_length; /* number of bytes in "hole" */ //肯定位置和長度 /* ACTUAL BLOCK DATA FOLLOWS AT END OF STRUCT */ } BkpBlock;
非備份塊,一個插入操做會生成兩個數據結構,一個數據對象。
1. XLogRecord (頭部)2.
xl_heap_insert標記插入的tuple。(屬於哪一個表,block位置等)3.數據。
11. XLOG的數據部分(9.5和之後)
9.5之後會劃分爲頭和數據。
頭部分會包括0個或多個
XLogRecordBlockHeaders和0個或1個
XLogRecordDataHeaderShort(或XLogRecordDataHeaderLong)。當記錄有full-page快照(back up block),XLogRecordBlockHeader 包括
XLogRecordBlockImageHeader若是是壓縮的,還包括
XLogRecordBlockCompressHeader。
9.5之後的XLOG 記錄
(a)備份塊。 1. XLogRecord 頭部。 2. XLogRecordBlockHeader等。3. XLogRecordDataHeaderShort 4. 備份塊(數據庫)5. xl_heap_insert (主要數據)
數據結構主要做用是包含數據,進程號,表ID,偏移量。
非備份塊,1. XLogRecord 2. XLogRecordBlockHeader 3. XLogRecordDataHeaderShort 4. an inserted tuple (數據,只有插入的數據沒有整個page)5.
xl_heap_insert(偏移量)
最後說一下檢查點的構造,1.XLogRecord (頭部)2.XLogRecordDataHeaderShort 3.CheckPoint (主要數據)
新的數據結構更適合管理。
XLOG記錄的寫入
INSERT INTO tbl VALUES ('A');
(1) ExtendCLOG()在內存中CLOG中寫狀態置爲"IN_PROGRESS".
(2) heap_insert() 插入一個堆記錄到內存池中,建立XLOG記錄,並觸發XlogInsert。
(3) XLogInsert()寫入XLOG LSN_1而且更新pd_lsn從LSN_1.
(4) finish_xact_command(),提交事務,建立XLOG記錄,而後XLogInsert() 寫入WAL緩存中在LSN_2。
(5)XLogWrite() 寫和刷XLOG從內存中刷到文件裏。若是標記爲"open_sync"或"open_datasync"就異步。若是是fsync就是同步刷。
寫入WAL操做可能會被當即觸發當發生如下狀況,無論事務是否以及提交:
1. 一個正在跑的事務已經被提交或者被取消了。
2. WAL緩存已經被不少許多寫過的元組填滿。
3. 一個WAL寫常常週期性的寫。
理所固然地,DML(數據操做語言)操做寫入XLOG記錄,但非DML操做也是如此。如上所述,提交操做會寫入包含已提交事務的id的XLOG記錄。(好比說create alter drop truncate comment rename 也是會寫xlog的)另外一個示例能夠是用於寫入包含該檢查點的通常信息的XLOG記錄的檢查點動做。此外,SELECT語句在特殊狀況下建立XLOG記錄,但一般不會建立它們。例如,若是在SELECT語句處理期間刪除了沒必要要的元組而且頁面中必要元組的碎片整理由HOT(Heap Only Tuple)發生,則修改頁面的XLOG記錄將寫入WAL緩衝區。(這句話其實我沒有很好地理解。)
12. WAL寫進程
12. WAL寫進程
是一個後臺進程,用於按期檢查WAL緩衝區並將全部未寫入的XLOG記錄寫入WAL段。此過程的目的是避免突發寫入XLOG記錄。若是還沒有啓用此進程,則在一次提交大量數據時,寫入XLOG記錄可能會遇到瓶頸。該進程是默認工做,且不能被禁止。wal_writer_delay 是間隔,默認是200毫秒。
13 檢查點的生成
1. 默認五分鐘作一次檢查點。能夠設置。checkpoint_timeout
2. 在9.4和9.4之前的版本,默認三個段文件作一次檢查點。也能夠設置。checkpoint_segments
3. 在9.5之後的版本是按照文件大小來算的,默認是1G就是64個文件。
4.在PG開啓智能模式或者快速模式下會暫停檢查點。
14 檢查點處理概述
檢查點進程有兩個方面:數據庫恢復的準備和共享緩衝池上的髒頁清除。
(1)檢查點過程開始後,REDO點存儲在內存中; REDO點是在最新檢查點啓動時寫入XLOG記錄的位置,而且是數據庫恢復的起點。
(2)該檢查點的XLOG記錄(即檢查點記錄)被寫入WAL緩衝區。記錄的數據部分由結構CheckPoint定義,結構包含幾個變量,例如存儲在步驟(1)中的REDO點。
(3)全部數據在內存裏被刷到底層存儲。
(4)全部髒頁在共享內存池漸漸地被刷到底層存儲。
(5)全部的PG_control文件被更新。這個文件含有基本的包括檢查點位置等。
爲了從數據庫恢復的角度總結上述描述,檢查點建立包含REDO點的檢查點記錄,並將檢查點位置和更多內容存儲到pg_control文件中。所以,PostgreSQL能夠經過從pg_control文件提供的REDO點(從檢查點記錄得到)重放WAL數據來恢復自身。
15 pg_control file
因爲pg_control文件包含檢查點的基本信息,所以它對於數據庫恢復確定是必不可少的。若是它被破壞或不可讀,則恢復過程沒法啓動以便沒法得到起點。
即便pg_control存了超過40個項目,有三個是必須。
1. state :最新檢查點開始時數據庫服務器的狀態。共有七個狀態:「start up」是系統啓動的狀態; 'shutdown'是系統正常關閉命令正常運行的狀態; 「in production」是系統運行的狀態;等等。
2. Latest checkpoint location : LSN最新檢查點記錄的位置
3. Prior checkpoint location: 上一個LSN的位置,已經被11版本替代了。11版本只存WAL文件,包括了最新的和上一個檢查點。
16 數據恢復
PostgreSQL實現了基於重作日誌的恢復功能。若是數據庫服務器崩潰,PostgreSQL經過從REDO點順序重放WAL段文件中的XLOG記錄來恢復數據庫集羣。
(1) PostgreSQL在啓動時會讀取pg_control文件的全部項目。若是狀態項處於'in production',PostgreSQL將進入恢復模式,由於這意味着數據庫沒有正常中止;若是'close',它將進入正常的啓動模式。
(2)PostgreSQL從相應的WAL段文件中讀取最新的檢查點記錄,該記錄位於pg_control文件中,並從記錄中獲取REDO點。若是最新的檢查點記錄無效,PostgreSQL將讀取它以前的記錄。若是兩個記錄都不可讀,它會自行放棄恢復。
(3)適當的資源管理器從REDO點按順序讀取和重放XLOG記錄,直到它們到達最新WAL段的最後一個點。當重放XLOG記錄而且它是備份塊時,不管其LSN如何,它都將在相應表的頁面上被覆蓋。不然,僅當此記錄的LSN大於相應頁面的pd_lsn時,纔會重放(非備份塊)XLOG記錄。
LSN的比較:
1. PG插入一個元組到表A,寫一條XLOG在LSN_1的位置。
2. 後臺寫進程把表A的頁刷到存儲。此時pd_lsn是1。
3. PG插入一個元組到表A,而且寫一個XLOG記錄到LSN_2.(先寫XLOG文件,數據尚未刷進去)此時馬上掛掉,而後啓動!
(1) PostgreSQL加載第一個XLOG記錄和TABLE_A的頁面,但不重放它,由於該記錄的LSN不大於TABLE_A的LSN(兩個值都是LSN_1)。因此不須要重放。
(2)PostgreSQL重放第二個XLOG記錄,由於此記錄的LSN(LSN_2)大於當前TABLE_A的LSN(LSN_1)。
今後示例中能夠看出,若是非備份塊的重放順序不正確或者屢次重放非備份塊,則數據庫集羣將再也不一致。簡而言之,非備份塊的重作(重放)操做不是冪等的。所以,爲了保留正確的重放順序,當且僅當其LSN大於相應頁面的pd_lsn時,才應重放非備份塊記錄。
17 WAL段文件管理
PostgreSQL將XLOG記錄寫入存儲在pg_xlog子目錄(版本10或更高版本,pg_wal子目錄)中的一個WAL段文件中,若是舊文件滿了,則切換爲新文件。 WAL文件的數量將根據幾個配置參數。
WAL 段文件切換(啥時候換下一個文件)
1. WAL文件寫滿了。
2. pg_switch_xlog函數。
3. archive模式開啓,而且有時間限制時,時間觸發。
WAL段文件管理(9.5及之後)
每當檢查點啓動時,PostgreSQL都會估計並準備下一個檢查點週期所需的WAL段文件數。這種估計是關於先前檢查點週期中消耗的文件數量。而後他會自動刪除WAL。
當wal快沒的時候就會建立下一個wal文件用於寫。當xlog達到max_wal_size,會自動作checkpoint。
WAL段文件管理(9.4及之前)是經過一套公式。
18 持續歸檔和歸檔日誌
連續存檔是一種功能,可在WAL段切換時將WAL段文件複製到存檔區域,並由存檔(後臺)進程執行。複製的文件稱爲存檔日誌。此功能一般用於熱物理備份和PITR。
拷貝的目錄主要是/home/postgres/archives
參數archive_command能夠設置任何Unix命令和工具,所以您能夠經過設置scp命令或任何文件備份工具而不是普通的複製命令將存檔日誌傳輸到其餘主機。