Large-scale incremental processing using distributed transactions and notifications 論文閱讀筆記
主要有2點:
- 事務提交細節(lock列,write列),相當於用 SI+鎖 實現一致性(注意 Write Skew)
- 2PC 細節,故障恢復
需求:海量數據,隨機讀寫,跨行事務(強一致性),高吞吐量,延遲無所謂
爲什麼 MapReduce 不能增量更新
參考 Ref[1]
原因是有些操作不可結合不可交換,需要計算的中間結果,不能增量更新,所以 MapReduce 要重新計算一遍整個 repo
這有個改進版 MapReduce:Incoop: MapReduce for incremental computations
設計
提供兩種方式:事務 和 觀察者機制(用於組織增量計算)
事務
Percolator爲每行記錄都新增了一些隱藏列,這些列保證了事務的正確執行或者回滾。
- lock列:記錄此行的寫鎖
- write列:記錄數據提交時間戳
因爲要求強一致性,所以用 SI+鎖(注意要防止 Write Skew)
- prewrite 階段:拿到所有的寫鎖
- 獲得開始時間戳
start_ts
- 對於所有需要寫入的 cell,在lock列標記時間戳爲
start_ts
(指定其中有一個爲 primary,其他爲 secondary,指向 primary)(之後會阻塞讀,這樣做避免了 Write Skew) - 拿寫鎖時的衝突檢測
- 如果write列的時間戳 > 自己的
start_ts
,說明別人先提交了,自己 abort(保證強一致性) - 如果lock列中有時間戳,那麼說明另一個寫還沒有提交,或者提交了沒有清理鎖,那麼自己 abort(或者另一個事務 crash,檢查 primary lock)(解決寫衝突,這裏不存在什麼 first-writer-wins)
- 如果write列的時間戳 > 自己的
- 執行事務
- 對於讀操作:如果lock列上的時間戳 < 自己的
start_ts
,那麼阻塞(阻塞讀操作,這樣做避免了 Write Skew) - 對於寫操作:已經持有鎖,直接寫
- 對於讀操作:如果lock列上的時間戳 < 自己的
- 獲得開始時間戳
- commit 階段:用提交時間戳替換鎖
- 獲得提交時間戳
commit_ts
- 順序從 primary 開始
- 更新write列爲
commit_ts
- 釋放鎖,即清空lock列(只要 primary lock 被清空,就認爲事務成功提交)
- 更新write列爲
- 獲得提交時間戳
Failover
參考 Ref[2]
如果事務 crash,必須要正確維護lock列和write列信息,採用lazy模式,由之後的事務來觸發。
- prewrite 階段 crash
- 拿鎖時 crash:清理部分lock列的鎖
- 執行時 crash:清空lock列
- commit 階段 crash
- 如果 primary lock 還在,說明事務未被提交,清空lock列,回滾(GC??)
- 如果 primary lock 不在,說明事務已經成功提交,清除剩下的lock列,並且補上write列的信息
通知機制
通知機制組織了增量計算的任務。
Observer 註冊一個列和對應的回調函數,回調函數觸發下游的 Observer 任務。
當改變發生時,並不會立即通知 Observer,而是通過 worker 線程異步掃描來通知。
Reference
- 經典論文翻譯導讀之《Large-scale Incremental Processing Using Distributed Transactions and Notifications》
- Google Percolator 分佈式事務實現原理解讀
- Google Percolator事務
- Percolator論文閱讀筆記
- Percolator 論文筆記
- percolator-and-txn.md - PingCAP
- Google Percolator 的事務模型
- Percolator簡單翻譯與個人理解
- 分佈式事務實現-Percolator
- Percolator Google的海量數據增量處理系統
- My reading of Percolator architecture: a Google search engine component
- Implementing Distributed Transactions the Google Way: Percolator vs. Spanner
- 學習 TLA+ - Percolator Transaction