iT邦幫忙

2023 iThome 鐵人賽

DAY 9
1
Software Development

CRUD仔的一生(上集)系列 第 10

[ACID] Postgres WAL機制

  • 分享至 

  • xImage
  •  

預寫日誌 Write Ahead Log (Wal)

前情提要

還記得學生時期老師在教課時,一邊學習一邊抄筆記個樣子嗎?

買了一本精美的筆記,裡面寫力與美的字體,調理清晰的交代老師說了什麼,回家複習也是賞心悅目,一切就如同上了軌道般的輕鬆自在。

但老師越講越快,你就變成這個樣子

無法一個字一個字好好地寫完,
於是寫起來就變成只有自己能看懂的樣子了

至少有了草稿,而且腦中也有老師剛剛上課的內容,
下課後再把剛剛寫很亂的草稿,慢慢的把筆記做好,寫成精美的筆記

昨天介紹了如何將 records 寫入 table,使用正確的方式存進設定好的資料結構中,這種完整的寫入在 I/O 上會有時間差,完全無法應付 record 進來的速度
今天來介紹資料庫的寫入草稿 write-ahead log(WAL),好好地存入 table 我們可以比擬成寫成精美的筆記,WAL 就是我們上課所寫只有自己看得懂的鬼畫符啦~

WAL 機制

就如同前情提要的概念一樣,先把修改的操作都先以日誌的方式存起來,等到比較不忙時,在將日誌回放(Replay),處理 index,FSM...的,正確的存到 Table 之中。
當我們在操作 SQL 指令完成後,會下 Commit,會希望資料庫能快點回應我們 Committed,因此導入了 WAL log 的機制,步驟大致如下

  1. Client commit
  2. DB write WAL log
  3. 修改 shared_buffers
  4. 寫進硬碟後
  5. DB reply Committed

後續的查詢因 shared_buffers 已經修改好了,所以後續得查詢自然可以查詢的到我們已經 committed 的資料。

WAL

在 PostgreSQL 上面,WAL 以 16MB 為單位切割成 segment,WAL 也是寫到硬碟之中不是 memory 喔,,他只是非常單純的寫下 O(1)而已,所以會比存到 Table 中 O(logN)快上許多。

shared_buffers

基本上就是 DB 的 in memory cache,當你要 CRUD 時,都會先變更 Cache 成想要的樣子。
等到 DB 有空時,在將 shared_buffers 的資料正確的落到 Disk 中,這樣就完成了一次的完整寫入,並且標註上(Checkpoint)這裡都可以在硬碟之中找到。
in memory 最怕的就是主機突然 Crash 等意外。
雖然 shared_buffers 中的所有資料都不見了,但我們還是可以透過最後一個 Checkpoint 開始還原到一個基準點,
然後在透過 WAL 回放(Redo,roll-forward recovery)一直到 shared buffers 內的資料恢復到正確的樣子,經得起查詢為止。

Checkpoint

觸發 checkpoint 的時機點就是 DB 將 shared_buffers 的內容安全的寫入硬碟之中,這時就可以使用 checkpoint,所以我們就不需要這個 checkpoint 之前的 WAL 紀錄了。最後 checkpoint 也會建立一筆 WAL 紀錄。

原子性 Atomic

前面我們使用 8 的篇幅來講解 ACID 的 I(isolation),終於要講解 A(Atomic) 了。
先來了解一下 Atomic 是什麼意思,

Atomicity 原子性:
每次的操作都是全部成功,或是全部失敗滾回,沒有其他選項。

重點在於不論 tx 中間做了哪些事情,只要需要 rollback,都可以順利的回復到原本的樣子。
那麼一個 tx 可能有許許多多的 sql command,而 db 是如何達到全部成功或失敗的呢?其實也跟 WAL 有關係
我們知道 pg 的 Write 操作都會建立一筆新的資料,在透過 clog 來判別是否需要顯示,所以

  • 當 commit 時, 就將 clog 由 TRANSACTION_STATUS_IN_PROGRESS 改為 TRANSACTION_STATUS_COMMITTED, 並且開始寫入 wal。
    所以在 tx 過程中發生了任何意外或者錯誤 clog 都還沒改變成 TRANSACTION_STATUS_COMMITTED,自然的我們會是他為整筆失敗。
  • 當 rollback 時, 就將 clog 由 TRANSACTION_STATUS_IN_PROGRESS 改為 TRANSACTION_STATUS_ABORTED
    因 Pg 是真實的 mvcc,所以在 delete 與 rollback 等操作下,還是會有殘留的資料,可透過 vacuum 來做清除,vacuum 將會在後續單元介紹。
Remark: BigO(1)的資料操作,不代表是 Atomic,單純代表該操作中沒有 loop。

持久性 Durability

再來講解 ACID 的 D(durability),先來了解一下 Atomic 是什麼意思,

事務完成之後, 對系統的修改是永久性的。

重點在於 commit 時就算還沒寫完硬碟中途 crash 也救的回來。

  • 當 commit 時, dbms 會開始將操作寫入 WAL,代表這些都是已經 commit 了,如果中途發生 crash,我們還是可以透過 Checkpoint+WAL 來恢復資料,因此資料完全避免掉了可能遺失的機會,永久(持久)的存在 db 中了。

Replication

我們知道了 WAL 寫下了在進入 table 之前的所有資料變更,並且使用了只有自己能看懂的方式交代。
資料庫剛好可以透過 預寫日誌(Write Ahead Log,WAL)的可讀複製(PITR),將 WAL 使用異步的方式,提供主從複製(Master-Slave Replication)。
透過複製 Master 的 WAL 到 Slave,讓 Slave 只需要將 WAL 的變更正確的存入 Table 內即可。
將 WAL 從 Master 傳輸到 Slave Server,然後在 Slave 上回放(Replay)出預寫日誌中記錄改動,從而實現主從複製。
PostgreSQL 使用了兩種方式傳輸預寫日誌:存檔式(archive)和流式(streaming)。

存檔式(archive)

我喜歡叫他 Polling,原理大概是 Master 主動將 WAL 複製到一個安全的位置,Slave 定期去抓回來回放。

流式(streaming)

就是所謂的串流傳輸,Master 直接透過 TCP 協議來將 WAL 傳送到 Slave 中。

結語

前面我們使用 8 的篇幅來講解 ACID 的 isolation,
這裡我們使用講解了 WAL,並且使用 wal 來完成 A(atomic)D(durability)。
當如果想要做讀寫分離,也可以使用 wal 來實作流式(streaming)與存檔式(archive)的複製。

參考資料

PostgreSQL 基於預寫日誌的複製
Postgres 筆記 – Write Ahead Log (WAL)
PostgreSQL 特性介紹- WAL & checkpoint


上一篇
[ACID] 樂觀鎖(MySQL RR Problem)
下一篇
[ACID] Mysql WAL機制
系列文
CRUD仔的一生(上集)32
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言