This page looks best with JavaScript enabled

2 Phase Commit

 ·  ☕ 3 min read

看了 DDIA 第九章 記錄一下

2 phase commit 是用來做 multiple nodes tansaction 時使用的方法

single node transaction

通常都是由 log 與 commit 來達成

postgresql.org/docs/current/wal-intro.html
例如 postgres 的做法就是每個操作都會有一個 write-ahead-log (wal),接著會把資料操作寫進 buffer (記憶體內,速度快),在 commit (寫入 commit record) 之前必須把所有的 wal 都寫入 persistent storage,每隔一陣子資料庫會一次把所有 buffer 內的更動一次寫進 persistent storage

wal 是 sequential write,效率會比每次都把資料寫進 persistent storage 高很多
commit 之後系統如果 crash,也可以用這些已經寫入的 wal 來做恢復
決定這個 transaction 是成功或失敗的因素就是 commit record 在系統 crash 之前是否有被寫入 persistent storage

平時想到 transaction 只會想到是一次更改多筆資料的情況,但其實更改一個物件時也會更改到很多硬碟上的位置(例如有 secondary index),也是有 transaction 的蓋念
單一節點 tansaction 通常是由 db engine 來處理

Multiple nodes transaction

如果只是單純的把它當作每個 db node 上都有一個 transaction 來實作,client 可以在完成時一次發送很多 commit 到各個 node 上,但很有可能某些成功某些失敗,造成資料不一致
如此一來就必須將某些 node 上已經 commit 的 transaction 回朔,但這些 transaction 被 commit 之後就可以被其他 transaction 看見,會有更多 transaction 依賴在這個 commit 上,會出現很多問題

以下是 2 phase commit 的流程圖

圖片來自 DDIA figure 9-9

coordinator 是在 sindle node transaction 內沒有出現的東西,通常都會實作在發 request 的 client library 內,但也可以額外用一個服務來擔任這個角色

以下是比較詳細的 2 pc 流程
首先 coordinator 會在每個 db node 上 init 一個 transaction
當所有所有資料操作結束後會進入 phase 1

coordinator 發送 prepare 給每個 node
只要有任何一個 node 回覆 no 或是 timeout,則在 phase 2 時 coordinator 會請所有 node abort 各自的 transaction
如果所有 node 皆回覆 yes,則在 phase 2 時 coordinator 會請所有 node commit

這邊有兩個 decision points
在 phase 1 時如果一個 node 回覆 yes,代表這個 node 已經自行先檢查所有意外情況(例如 unique constrain conflict 之類),此 node 無論如何一定可以 commit,放棄了自行 abort 的權利,必須等待 phase 2 coordinator 的通知才能進行下一步動作 (在回覆 yes 前都可以自行 abort)
當 coordinator 在 phase 1 做了決定(commit or abort)後,會將這個決定寫入 log,成功後這個決定便不會被更改(single node 是把這兩個動作合在一起 -> commit record)

在 phase 2 時如果有 coordinator 和 node 之間溝通失敗如 timeout 或有 node crash,則會無限次重試直到成功
而 coordinator 如果 crash 了,回答 yes 的 node 也必須要無限時的等待 coordinator 來通知自己接下來到底是要 abort 還是 commit
node 若是在收到通知前擅自 commit,則可能會因為其他參與者在之前回答了 no,其實 coordinator 的決定是 abort
反之,若 node 在收到通知前擅自 abort,其他參與者很有可能已經收到 coordinator 的 commit 決定了

可以看到這個 protocol 中有可能因為 coordinator crash 造成所有 node 都被卡住,所以 2 pc 被稱為 blocking protocol
有人提出了 3pc 要做到 non blocking protocol,而實務上是不太可能做到的,因為它需要一個可以準確得知某個 node 是否 crash 的方法,但網路通訊是 unbounded delay 所以很有可能是 timeout,node 卻活著的情況

以上就是 2pc 的流程
重點大概就是在兩個 decision points 那邊是以前網路看文章比較沒看到的部分

Share on

Marko Peng
WRITTEN BY
Marko Peng
Good man