CockroachDB事務剖析-第二篇
本篇主要是講述一些事務實現過程中的細節補充,比較瑣碎,很多時候需要結合程式碼才能理解。
KV GC
CockroachDB後臺任務定期掃描store的kv,MVCC資料最多保留25hour(預設配置,可以調整),不過最新的一條記錄一定會儲存不受這個限制。未push的TXN記錄最多保留1hour,未提交的write intent最多保留2hour。
cockroachDB的事務記錄中並不儲存事務的提交記錄,因此GC的時候分別處理這兩個邏輯,同時也意味著cockroachDB的事務沒有明顯的條目限制。
Timestamp cache
timestamp cache快取最近讀寫的key和以及其事務記錄資訊,用於事務衝突檢查。timestamp cache有大小限制,內部採用page輪轉的方式淘汰old的page。
timestamp cache存在一個低水位線和高水位線,HLC.time低於低水位線的key會被丟棄,不會快取。高水位線用來修正dumped的事務的提交時間戳。
lease holder發生lease切換的時候,需要重置timestamp cache的低水位線。
Latch manager
核心作用是具有重疊操作區間的讀寫併發控制,它允許讀操作的併發,寫操作是序列進行的。
每次讀寫操作的時候都需要申請一個看門狗,來保證在操作完成以前,如果本操作是寫操作,那麼阻塞一切操作,如果本操作是讀操作,阻塞寫操作。
Range Lease
range副本存在兩個邏輯上獨立的角色lease holder, leader holder.其中leader holder是raft leader所在的副本,它具備唯一的提交raft log的權利。lease holder的存在主要是解決以下幾個問題:
1. 管理range的分裂,合併
2. 本地讀寫,降低網路開銷
CockroachDB中會保證lease
holder和leader holder是同一個節點,這通過兩個流程保證,一個是當發生lease轉移的時候,如果新的lease holder不是leader holder會主動發起transferLeader,另一個是在提交raft log的時候,發現lease holder不是leader holder的時候會主動設定成候選人狀態,發起選舉。保證提交一定是本地提交。
Lease holder對寫操作會先在本地完成,然後才提交raft。這樣做的好處就是如果本地執行失敗,那麼無需raft,直接返回給客戶端即可。
在副本應用raft log的時候,會檢查是否是當前lease holder提交的日誌,如果是,那麼不需要再次執行。
另一個好處就是read本地讀取是安全的。不會因為當lease holder和leader holder不是同一個副本的時候,出現不能滿足快照讀。
3. 解決腦裂問題
參閱通過 raft 的 leader lease 來解決叢集腦裂時的 stale read 問題
CockroachDB為什麼放棄SI隔離級別
問題來源於一個PRstorage: SNAPSHOT isolation violation with write timestamp cache #26460
舉例來說,如下場景:
併發的發起以下三個事務
INSERT INTO kv VALUES ($1, 1) ON CONFLICT DO UPDATE SET v = v+1 DELETE FROM kv SELECT * FROM kv
那麼存在這樣一種執行順序
1. Read for INSERT 2. DELETE 3. Write for INSERT. The WriteTooOld flag is set and the transaction restarts. 4. Read for INSERT, seeing the outcome of the delete. 5. Write for INSERT
問題出在第三步,insert的時候檢查timestamp cache發現有一個更大的提交時間戳導致insert事務需要restart。事務restart的時候會重置事務的提交時間戳(也是事務中讀操作使用的時間戳)為這個衝突的時間戳+1,因此事務重試的時候讀取到了後來發生的delete的記錄,破壞了快照隔離。
筆者個人認為這個問題是cockroachDB自己設計的問題,應該是受限與固有的邏輯框架,修改起來比較費力,幸運的是SSI隔離級別不受影響,因此暫時擱置了。