解讀Google分佈式鎖服務

背景介紹

在2010年4月,Google的網頁索引更新實現了實時更新,在今年的OSDI大會上,Google首次公佈了有關這一技術的論文。 html

在此以前,Google的索引更新,採用的的批處理的方式(map/reduce),也就是當增量數據達到必定規模以後,把增量數據和全量索引庫Join,獲得最新的索引數據。採用新的索引更新系統以後,數據的生命週期縮短了50%,所謂的數據生命週期是指,數據從網頁上爬下來,到展示在搜索結果中這段時間間隔,可是正如Google所強調的,這一系統僅僅是爲增量更新所創建的,並無取代map/reduce的批量做業處理模式。 sql

架構Overview

Google的新一代增量索引更新 – Percolator,是創建在Bigtable之上,提供的API也儘可能接近Bigtable的方式,因此整個架構大體是以下的樣子: 數據庫

事務(Transaction)和鎖(Lock)有區別嗎? 架構

在關係數據庫領域,兩者仍是有很大區別的,可是對Percolator而言,Transaction = Lock,因此咱們這裏討論的分佈式鎖,也能夠說是分佈式事務,因此下面提到的鎖或者事務,指的都是同一件事。 oracle

Percolator利用Bigtable原有的行鎖,再加上本身的一些巧妙的作法,實現了分佈式鎖服務,這就意味着,Google能夠實時的更新PB級別的索引庫。最近咱們發現Google的搜索結果時效性很好,剛寫好的文章,幾分鐘以後,Google就能夠檢索到,緣由就在Google的Crawler在抓到新的網頁以後,不用再等待必定的時間批量更新索引,而是實時的更新,數據生命週期大大縮短。 nosql

Percolator支持跨行,跨表的事務,充分利用了Bigtable自己已經有的行事務、備份機制。 分佈式

簡單的示例

在分析Percolator的細節以前,先看一個簡單的例子,對Percolator有一個大概的認識,有利於後面的理解。 google

下面的這個例子是把UserA的人氣分減掉10,加到UserB的人氣分上,key表示每一行的key,data,lock,write是列名字,data存儲數據,lock存儲鎖狀態,write表示事務提交後的數據位置引用. spa

初始狀態:UserA有100我的氣分,UserB有50我的氣分 .net

最終狀態:UserA有90我的氣分,UserB有60我的氣分

Step0(初始狀態)

Key Data Lock Write
UserA 100:t1
UserB 50:t2

Step1(從UserA中拿出10我的氣分)

Key Data Lock Write
UserA 90:t2100:t1 Primary Lock:t2 t2
UserB 50:t2

Step2(把UserB的人氣分加10)

Key Data Lock Write
UserA 90:t2100:t1 primary_lock:t2 t2
UserB 60:t350:t2 Primary_lock:UserA@data t3

Step3(事務提交)

A:先提交primary(移除鎖,寫入新的timestamp,在write列寫入新數據的位置引用)

Key Data Lock Write
UserA t390:t2

100:t1

t3:data:t2t2
UserB 60:t350:t2 Primary_lock@UserA.data t3

B:再提交非primary(步驟同上)

Key Data Lock Write
UserA t390:t2

100:t1

t3:data:t2t2
UserB t460:t3

50:t2

t4:data:t3t3

事務結束了,UserA有90我的氣分,timestamp是t3,Userb有60我的氣分,timestamp是t4。(至於鎖的寫法和write列爲何那樣寫,後面再詳細解釋)

事務的執行過程

Percolator鎖分爲兩種,primary和non-primary,在事務提交的過程當中,先提交primary鎖,不管是跨行仍是跨表,primary鎖都是沒有區別的。

事務的提交

事務的提交的過程分兩步,以UserA爲例:

首先,在write列寫入新數據的位置引用,注意不是數據,是引用(理解成指針會更形象),上面step3A 中t3:data:t2表示在t3時刻提交的數據,最新的數據在data列的t2 timestamp

而後,移除lock列的內容。

由於Bigtable支持行鎖定,因此上述兩步都是在一個Bigtable事務內完成的。

讀操做

當一個client在發起讀操做以後,首先會向oracle server申請time stamp,接下來Percolator會檢查lock列,若是lock列不空,那麼讀操做試圖移除(修復)這個lock或者等待,在後續鎖衝突處理詳細介紹如何修復。

補充:oracle發放time stamp是嚴格遞增的,並且不是一次發放一個,而是採起批量的方式。

寫操做

當一個client發起寫操做以後,首先會向oracle server申請time stamp,Percolator會檢查write列,若是write列的timestamp大於當前client的timestamp,那麼寫失敗(不能覆蓋新的數據 write-write conflict);若是lock列有鎖存在,說明當前行正在被另外的client鎖定,client要麼寫失敗,要麼試圖修復(lock conflict)!

Notify機制

Percolator定義了一系列的Observer(相似於數據庫的trigger),位於Bigtable的tablet server上,Observer會監視某一列或者某幾列,當數據發生變化就會觸發Observer,Observer執行完以後,又會建立或者通知後續的Observer,從而造成一個通知的傳遞。

鎖衝突的處理

當一個client在事務提交階段,crash掉了,那麼鎖還保留,這樣後續的client訪問就會被阻止,這種狀況叫作鎖衝突,Percolator提供了一種簡單的機制來解決這個問題。

每一個client按期向Chubby Server寫入token,代表本身還活着,當某個client發現鎖衝突,那麼會檢查持有鎖的client是否還活着,若是client是working狀態,那麼client等待鎖釋放。不然client要清除掉當前鎖。

Roll  forward & roll  back

Client先檢查primary lock是否存在,由於事務提交先從primary開始,若是primary不存在,那麼說明前面的client已經提交了數據,因此client執行roll forward操做:把non-primary對應的數據提交,而且清除non-primary lock;若是primary存在,說明前面的client尚未提交數據就crash了,此時client執行roll back操做:把primary和non-primary的數據清除掉,而且清除lock。

小結

Google的分佈式鎖服務很好了支持了增量索引的實時更新,縮短了數據的生命週期。本文對notify機制介紹的比較簡單,感興趣的請參考論文原文

相關文章
相關標籤/搜索