Percolator 和 TiDB 事務演算法

qiuyesuifeng發表於2016-11-24

本文先概括的講一下 Google Percolator 的大致流程。Percolator 是 Google 的上一代分散式事務解決方案,構建在 BigTable 之上,在 Google 內部 用於網頁索引更新的業務,原始的論文在此。原理比較簡單,總體來說就是一個經過優化的二階段提交的實現,進行了一個二級鎖的優化。TiDB 的事務模型沿用了 Percolator 的事務模型。 總體的流程如下:

### 讀寫事務

1) 事務提交前,在客戶端 buffer 所有的 update/delete 操作。 2) Prewrite 階段:

首先在所有行的寫操作中選出一個作為 primary,其他的為 secondaries。

PrewritePrimary: 對 primaryRow 寫入 L 列 (上鎖),L 列中記錄本次事務的開始時間戳。寫入 L 列前會檢查:

  1. 是否已經有別的客戶端已經上鎖 (Locking)。
  2. 是否在本次事務開始時間之後,檢查 W 列,是否有更新 [startTs, +Inf) 的寫操作已經提交 (Conflict)。

在這兩種種情況下會返回事務衝突。否則,就成功上鎖。將行的內容寫入 row 中,時間戳設定為 startTs。

將 primaryRow 的鎖上好了以後,進行 secondaries 的 prewrite 流程:

  1. 類似 primaryRow 的上鎖流程,只不過鎖的內容為事務開始時間及 primaryRow 的 Lock 的資訊。
  2. 檢查的事項同 primaryRow 的一致。

當鎖成功寫入後,寫入 row,時間戳設定為 startTs。

3) 以上 Prewrite 流程任何一步發生錯誤,都會進行回滾:刪除 Lock,刪除版本為 startTs 的資料。

4) 當 Prewrite 完成以後,進入 Commit 階段,當前時間戳為 commitTs,且 commitTs> startTs :

  1. commit primary:寫入 W 列新資料,時間戳為 commitTs,內容為 startTs,表明資料的最新版本是 startTs 對應的資料。
  2. 刪除 L 列。

如果 primary row 提交失敗的話,全事務回滾,回滾邏輯同 prewrite。如果 commit primary 成功,則可以非同步的 commit secondaries, 流程和 commit primary 一致, 失敗了也無所謂。

### 事務中的讀操作

  1. 檢查該行是否有 L 列,時間戳為 [0, startTs],如果有,表示目前有其他事務正佔用此行,如果這個鎖已經超時則嘗試清除,否則等待超時或者其他事務主動解鎖。注意此時不能直接返回老版本的資料,否則會發生幻讀的問題。
  2. 讀取至 startTs 時該行最新的資料,方法是:讀取 W 列,時間戳為 [0, startTs], 獲取這一列的值,轉化成時間戳 t, 然後讀取此列於 t 版本的資料內容。

由於鎖是分兩級的,primary 和 seconary,只要 primary 的行鎖去掉,就表示該事務已經成功 提交,這樣的好處是 secondary 的 commit 是可以非同步進行的,只是在非同步提交進行的過程中 ,如果此時有讀請求,可能會需要做一下鎖的清理工作。

原文連結

更多原創文章乾貨分享,請關注公眾號
  • Percolator 和 TiDB 事務演算法
  • 加微信實戰群請加微信(註明:實戰群):gocnio

相關文章