背景介紹
在2023年4月,google的網頁索引更新實現了實時更新,在今年的osdi大會上,google首次公布了有關這一技術的**。
在此之前,google的索引更新,採用的的批處理的方式(map/reduce),也就是當增量資料達到一定規模之後,把增量資料和全量索引 庫join,得到最新的索引資料。採用新的索引更新系統之後,資料的生命週期縮短了50%,所謂的資料生命週期是指,資料從網頁上爬下來,到展現在搜尋結 果中這段時間間隔,但是正如google所強調的,這一系統僅僅是為增量更新所建立的,並沒有取代map/reduce的批量作業處理模式。
架構overview
google的新一代增量索引更新 – percolator,是建立在bigtable之上,提供的api也盡量接近bigtable的方式,所以整個架構大致是如下的樣子:
事務(transaction)和鎖(lock)有區別嗎?
在關聯式資料庫領域,二者還是有很大區別的,但是對percolator而言,transaction = lock,所以我們這裡討論的分布式鎖,也可以說是分布式事務,所以下面提到的鎖或者事務,指的都是同一件事。
percolator利用bigtable原有的行鎖,再加上自己的一些巧妙的做法,實現了分布式鎖服務,這就意味著,google可以實時的 更新pb級別的索引庫。最近我們發現google的搜尋結果時效性很好,剛寫好的文章,幾分鐘之後,google就可以檢索到,原因就在google的 crawler在抓到新的網頁之後,不用再等待一定的時間批量更新索引,而是實時的更新,資料生命週期大大縮短。
percolator支援跨行,跨表的事務,充分利用了bigtable本身已經有的行事務、備份機制。
簡單的示例
在分析percolator的細節之前,先看乙個簡單的例子,對percolator有乙個大概的認識,有利於後面的理解。
下面的這個例子是把usera的人氣分減掉10,加到userb的人氣分上,key表示每一行的key,data,lock,write是列名字,data儲存資料,lock儲存鎖狀態,write表示事務提交後的資料位置引用.
初始狀態:usera有100個人氣分,userb有50個人氣分
最終狀態:usera有90個人氣分,userb有60個人氣分
step0(初始狀態)
keydata
lock
write
usera
100:t1
userb
50:t2
step1(從usera中拿出10個人氣分)
keydata
lock
write
usera
90:t2100:t1
primary lock:t2
t2userb
50:t2
step2(把userb的人氣分加10)
keydata
lock
write
usera
90:t2100:t1
primary_lock:t2
t2userb
60:t350:t2
primary_lock:usera@data
t3step3(事務提交)
a:先提交primary(移除鎖,寫入新的timestamp,在write列寫入新資料的位置引用)
keydata
lock
write
usera
t390:t2100:t1
t3:data:t2t2
userb
60:t350:t2
t3 b:再提交非primary(步驟同上)
keydata
lock
write
usera
t390:t2100:t1
t3:data:t2t2
userb
t460:t350: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機制介紹的比較簡單,感興趣的請參考**原文
《large-scale incremental processing using distributed transactions and notifications》
分類:
解讀Google分布式鎖服務
背景介紹 在2010年4月,google的網頁索引更新實現了實時更新,在今年的osdi大會上,google首次公布了有關這一技術的 在此之前,google的索引更新,採用的的批處理的方式 map reduce 也就是當增量資料達到一定規模之後,把增量資料和全量索引 庫join,得到最新的索引資料。採...
分布式 分布式鎖
本質是利用redis的setnx 方法的特性來加鎖,setnx 即key不存在則設定key,否則直接返回false,要求在分布式系統中使用同乙個redis服務,以下提供兩種解決方案 1 直接使用redistemplate 這其實並不能完全保證高併發下的安全問題,因為可能在鎖過期之後該執行緒尚未執行完...
分布式專題 分布式鎖
在傳統的單體應用架構中,遇到併發安全性問題時我們可以通過同步鎖synchronized,同步 塊,reentrantlock等方式都可以解決,但隨著業務的發展,單體應用架構不能滿足龐大的使用者請求量,於是分布式系統應用而生,在分布式系統中,由於每個系統都執行在不同的伺服器上,有著不同的jvm,所以j...