CockroachDB是如何實現分布式原子事務的?
作為一個分布式數據庫, CockroachDB 有一個鮮明的特性,就是支持 ACID事務 。近日, Cockroach Labs 團隊成員Matt Tracy 撰文 介紹了CockroachDB如何在不使用鎖的情況下實現原子事務。
CockroachDB的原子事務策略總共包含如下五個基本步驟。
1.“開關(Switch)”:CockroachDB事務記錄
在開始一個事務之前,寫進程首先會創建一個包含如下字段的 事務記錄 :
- 事務唯一標識UUID
- 事務當前狀態,可以有三種取值,其中PENDING為初始狀態,ABORTED或COMMITTED為終止狀態
- 一個Cockroach K/V鍵,指定“開關”在分布式數據存儲中的位置
寫進程會使用一個專門的CockroachDB命令 BeginTransaction() 存儲事務記錄。事務記錄或者開關不能并行訪問,只能嚴格按照順序進行讀/寫操作。事務記錄的PENDING或ABORTED狀態對應開關的“off”狀態,COMMITTED對應“on”。
2.“暫存(Stage)”:Write Intent
寫進程會準備好多個數據庫變更,但并不會覆蓋任何現有值。為了 暫存 一個事務中的變更,CockroachDB使用了一個名為 Write Intent 的結構。任何時候,一個值作為一個事務的一部分寫入到一個鍵,它都會生成一個Write Intent。Write Intent結構中還包含指示事務記錄存儲位置的鍵。
另外,還有一個規則,就是任何鍵都有且僅有一個Write Intent(Matt在此并未考慮事務并發)。
3.“過濾(Filter)”:讀取Write Intent
對于任何有暫存值的鍵,在讀取時都必須檢查事務開關的狀態。如果開關狀態為“off”,則返回該鍵的原值;如果開關狀態為“on”,則返回暫存值。也就是說,如果一個鍵有暫存值,那么對該鍵的所有讀取操作都必須使用開關狀態過濾,具體步驟如下:
- 如果現有Write Intent對應的事務記錄仍然處于PENDING狀態,則將其置為ABORTED狀態。
- “清除(cleanup)”現有的Write Intent。
- 返回該鍵的普通值(即不是Write Intent)。如果之前的事務已經COMMITTED,那么清除操作會將暫存值升級為普通值;否者,返回該鍵的原值。
4.“按開關(Flip)”:提交事務
當寫進程準備好事務中的所有變更后,它會打開開關(即將事務記錄更新成COMMITTED,開關狀態置為“on”)。事務生成的所有Write Intent都會立即生效;之后發生的任何讀取操作在看到事務已經提交后都會返回Write Intent中的暫存值。
另外,將事務記錄的狀態置為ABORTED可以終止事務,之后發生的讀取操作將忽略這個事務生成的Write Intent。
5.“解除暫存(Unstage)”:清除Write Intent
前面4個步驟已經可以提供原子事務;但是,第2步開銷很大,因此,在事務完成后,CockroachDB會盡快清除暫存值。如果事務成功,那么暫存值會取代原值;如果失敗,那么暫存值會被丟棄。總之,如果一個鍵沒有Write Intent,那么讀取操作就無需過濾,也就可以以適當的分布式方式完成。需要注意的是,解除暫存是異步的,并不需要在事務COMMITTED之前完成。
網友RJ Ryan對Matt所謂的“無鎖(lockless)”提出了質疑。他認為,開關和Write Intent看起來跟鎖類似。對此,Matt答復說:
這篇博文談到“鎖”時,是指數據庫記錄鎖,一個修改數據庫某個部分的獨占性許可。
開關(或事務記錄)并不是一個數據庫鎖,因為它沒有阻止其它數據庫操作進行……對開關本身的操作會按順序進行……但它不會阻止任何操作執行。
Write Intent也不是數據庫鎖,因為它不會保證鍵的獨占性訪問;相反,它允許一個事務“發現”其它正在訪問相同鍵的并發事務。當這種情況出現時,其中一個事務必須終止;不過,它并沒有像鎖一樣采用“先來先服務”的策略,而是為每個事務賦予一個數值型的優先級,優先級最高的事務總是會勝出。
Matt指出,如果讀者對CockroachDB的完整事務模型感興趣,可以查看 GitHub上的詳細設計文檔 。 Tobias Schottdorf 也是CockroachDB項目的貢獻者。他在回復網友的評論時指出,雖然CockroachDB的原子事務策略與使用MS-DTC的SQL Server分布式事務處理一樣都是2PC,但它們并不相同。XA有準備和提交兩個階段,提交階段實際上要做大量的工作。但在Cockroach中,“準備”階段就將值寫到了它們最終應該存在的位置,所以“提交”階段只需要對單個鍵執行一次寫操作,幾乎不做什么工作。
另外,在介紹完CockroachDB的原子事務策略后,Matt還特別介紹了CockroachDB的清除操作,感興趣的讀者可以 進一步閱讀 。