wal日志即write ahead log預寫式日志,簡稱wal日志。wal日志可以說是PostgreSQL中十分重要的部分,相當於oracle中的redo日志。
當數據庫中數據發生變更時:
change發生時:先要將變更后內容計入wal buffer中,再將變更后的數據寫入data buffer;
commit發生時:wal buffer中數據刷新到磁盤;
checkpoint發生時:將所有data buffer刷新的磁盤。
可以想象,如果沒有wal日志,那么數據庫中將會發生什么?
首先,當我們在數據庫中更新數據時,如果沒有wal日志,那么每次更新都會將數據刷到磁盤上,並且這個動作是隨機i/o,性能可想而知。並且沒有wal日志,關系型數據庫中事務的ACID如何保證呢?
因此wal日志重要性可想而知。其中心思想就是:先寫入日志文件,再寫入數據。
說到checkpoint,我們再來看看哪些情況會觸發數據庫的checkpoing:
1.手動執行CHECKPOINT命令;
2.執行需要檢查點的命令(例如pg_start_backup 或pg_ctl stop|restart等等);
3.達到檢查點配置時間(checkpoint_timeout);
4.max_wal_size已滿。
其中1和2兩點都和數據庫的配置無關,我們暫時先不看,這里先介紹下checkpoint_timeout和max_wal_size兩個參數。
checkpoint_timeout:
自動 WAL 檢查點之間的最長時間,以秒計。合理的范圍在 30 秒到 1 天之間。默認是 5 分鍾(5min)。增加這個參數的值會增加崩潰恢復所需的時間。
bill@bill=>show checkpoint_timeout ; checkpoint_timeout -------------------- 30min (1 row)
max_wal_size:
在自動 WAL檢查點之間允許WAL 增長到的最大尺寸。這是一個軟限制,在特殊的情況 下 WAL 尺寸可能會超過max_wal_size, 例如在重度負荷下、archive_command失敗或者高的 wal_keep_segments設置。默認為 1 GB。增加這個參數可能導致崩潰恢復所需的時間。
bill@bill=>show max_wal_size ; max_wal_size -------------- 2GB (1 row)
和max_wal_size相對應的還有個min_wal_size,這里簡單介紹下:
只要 WAL 磁盤用量保持在這個設置之下,在檢查點時舊的 WAL文件總是被回收以便未來使用,而不是直接被刪除。
可能對oracle熟悉的人會覺得wal日志和redo還是有些不同,沒錯,oracle中redo是固定幾個redo日志文件,然后輪着切換去寫入,因此我們常常會在io高的數據庫中看到redo切換相關的等待事件。
而在pg中wal日志是動態切換,從pg9.6開始采用這種模式。和oracle不同的是,pg中這種動態wal切換步驟是這樣的:單個wal日志寫滿(默認大小16MB,編譯數據庫時指定)繼續寫下一個wal日志,直到磁盤剩余空間不足min_wal_size時才會將舊的 WAL文件回收以便繼續使用。
但是這種模式有一個弊端就是如果在checkpoint之前產生了大量的wal日志就會導致發生checkpoint時對性能的影響巨大,因此pg中還有一個參數checkpoint_completion_target來進行調整。
checkpoint_completion_target:
指定檢查點完成的目標,作為檢查點之間總時間的一部分。默認是 0.5。
什么意思呢,假如我的checkpoint_timeout設置是30分鍾,而wal生成了10G,那么設置成0.5就允許我在15分鍾內完成checkpoint,調大這個值就可以降低checkpoint對性能的影響,但是萬一數據庫出現故障,那么這個值設置越大數據就越危險。
總結:
大多數檢查點應該是基於時間的,即由checkpoint_timeout觸發。
性能(不頻繁檢查點)與恢復所需時間(頻繁檢查點)之間需要抉擇:
值在15-30分鍾之間是比例合適的,但到1小時不是什么壞事。
在決定checkpoint_timeout后,通過估計WAL的數量選擇max_wal_size。
設置checkpoint_completion_target以便內核將數據刷新到磁盤的時間足夠(但不是太多)。
