這才是真正的分布式鎖

2018-09-06 18:04 更新

技術(shù)領(lǐng)域,我覺得了解來龍去脈,了解本質(zhì)原理,比用什么工具實(shí)現(xiàn)更重要

(1)進(jìn)程多線程如何互斥?

(2)一個(gè)手機(jī)上兩個(gè)APP訪問一個(gè)文件如何互斥?

(3)分布式環(huán)境下多個(gè)服務(wù)訪問一個(gè)資源如何互斥?

歸根結(jié)底,是利用一個(gè)互斥方能夠訪問的公共資源來實(shí)現(xiàn)分布式鎖,具體這個(gè)公共資源是redis來setnx,還是zookeeper,相反沒有這么重要。


言歸正傳,今天把昨天文章的緣起講一講,并通過Google Chubby的論文閱讀筆記聊一聊分布式鎖。

一、需求緣起

58到家APP新上線了導(dǎo)入通訊錄好友功能,測試的同學(xué)發(fā)現(xiàn),連續(xù)點(diǎn)擊導(dǎo)入會(huì)導(dǎo)入重復(fù)數(shù)據(jù):

數(shù)據(jù)重復(fù)導(dǎo)入
客戶端同一個(gè)用戶同時(shí)發(fā)出了多個(gè)請(qǐng)求,分布式環(huán)境下,多臺(tái)機(jī)器上部署的多個(gè)service進(jìn)行了并發(fā)操作,故插入了冗余數(shù)據(jù)。

解決思路同一個(gè)用戶同時(shí)只能有一個(gè)導(dǎo)入請(qǐng)求,需要做互斥,最簡易的方案,使用setnx快速解決。
使用setnx解決數(shù)據(jù)重復(fù)

(1)同一個(gè)用戶,多個(gè)service進(jìn)行并發(fā)操作,service需要先去搶鎖

(2)搶到鎖的service,才去數(shù)據(jù)庫操作

具體這個(gè)鎖用setnx,還是zookeeper都不太重要,利用一個(gè)互斥方能夠訪問的公共資源來實(shí)現(xiàn)分布式鎖,這才是《一分鐘實(shí)現(xiàn)分布式鎖》的重點(diǎn)。


二、Google Chubby分布式鎖閱讀筆記

上一篇文章的評(píng)論中,有些朋友提到了zookeeper,會(huì)使用不夠,借著Google Chubby了解下分布式鎖的實(shí)現(xiàn)也是有必要的。


早年Google的四大基礎(chǔ)設(shè)施,分別是GFS、MapReduce、BigTable、Chubby,其中Chubby用于提供分布式的鎖服務(wù)。

1.簡介

Chubby系統(tǒng)提供粗粒度的分布式鎖服務(wù),Chubby的使用者不需要關(guān)注復(fù)雜的同步協(xié)議,而是通過已經(jīng)封裝好的客戶端直接調(diào)用Chubby的鎖服務(wù),就可以保證數(shù)據(jù)操作的一致性。


Chubby具有廣泛的應(yīng)用場景,例如:

(1)GFS選主服務(wù)器;

(2)BigTable中的表鎖;


2.背景

Chubby本質(zhì)上是一個(gè)分布式文件系統(tǒng),存儲(chǔ)大量小文件。每個(gè)文件就代表一個(gè)鎖,并且可以保存一些應(yīng)用層面的小規(guī)模數(shù)據(jù)。用戶通過打開、關(guān)閉、讀取文件來獲取共享鎖或者獨(dú)占鎖;并通過反向通知機(jī)制,向用戶發(fā)送更新信息。


3.系統(tǒng)設(shè)計(jì)

3.1設(shè)計(jì)目標(biāo)

Chubby系統(tǒng)設(shè)計(jì)的目標(biāo)基于以下幾點(diǎn):

(1)粗粒度的鎖服務(wù);

(2)高可用、高可靠;

(3)可直接存儲(chǔ)服務(wù)信息,而無需另建服務(wù);

(4)高擴(kuò)展性;


在實(shí)現(xiàn)時(shí),使用了以下特性:

(1)緩存機(jī)制:客戶端緩存,避免頻繁訪問master;

(2)通知機(jī)制:服務(wù)器會(huì)及時(shí)通知客戶端服務(wù)變化;


3.2整體架構(gòu)
figure 1:system structure

Chubby架構(gòu)并不復(fù)雜,如上圖分為兩個(gè)重要組件:

(1)Chubby庫:客戶端通過調(diào)用Chubby庫,申請(qǐng)鎖服務(wù),并獲取相關(guān)信息,同時(shí)通過租約保持與服務(wù)器的連接;

(2)Chubby服務(wù)器組:一個(gè)服務(wù)器組一般由五臺(tái)服務(wù)器組成(至少3臺(tái)),其中一臺(tái)master,服務(wù)維護(hù)與客戶端的所有通信;其他服務(wù)器不斷和主服務(wù)器通信,獲取用戶操作。


4.系統(tǒng)實(shí)現(xiàn)

4.1文件系統(tǒng)

Chubby文件系統(tǒng)類似于簡單的unix文件系統(tǒng),但它不支持文件移動(dòng)操作與硬連接。文件系統(tǒng)由許多Node組成,每個(gè)Node代表一個(gè)文件,或者一個(gè)目錄。文件系統(tǒng)使用Berkeley DB來保存每個(gè)Node的數(shù)據(jù)。文件系統(tǒng)提供的API很少:創(chuàng)建文件系統(tǒng)、文件操作、目錄操作等簡易操作。


4.2基于ICE的Chubby通信機(jī)制

一種基于ICE的RPC異步機(jī)制,核心就是異步,部分組件負(fù)責(zé)發(fā)送,部分組件負(fù)責(zé)接收。


4.3客戶端與master的通信

(1)長連接保持連接,連接有效期內(nèi),客戶端句柄、鎖服務(wù)、緩存數(shù)據(jù)均一直有效;

(2)定時(shí)雙向keep alive;

(3)出錯(cuò)回調(diào)是客戶端與服務(wù)器通信的重點(diǎn)。


下面將說明正常、客戶端租約過期、主服務(wù)器租約過期、主服務(wù)器出錯(cuò)等情況。

(1)正常情況

keep alive是周期性發(fā)送的一種消息,它有兩方面功能:延長租約有效期,攜帶事件信息告訴客戶端更新。正常情況下,租約會(huì)由keep alive一直不斷延長。

潛在回調(diào)事件包括:文件內(nèi)容修改、子節(jié)點(diǎn)增刪改、master出錯(cuò)等。


(2)客戶端租約過期

客戶端沒有收到master的keep alive,租約隨之過期,將會(huì)進(jìn)入一個(gè)“危險(xiǎn)狀態(tài)”。由于此時(shí)不能確定master是否已經(jīng)終止,客戶端必須主動(dòng)讓cache失效,同時(shí),進(jìn)入一個(gè)尋找新的master的階段。


這個(gè)階段中,客戶端會(huì)輪詢Chubby Cell中非master的其他服務(wù)器節(jié)點(diǎn),當(dāng)客戶端收到一個(gè)肯定的答復(fù)時(shí),他會(huì)向新的master發(fā)送keep alive信息,告之自己處于“危險(xiǎn)狀態(tài)”,并和新的master建立session,然后把cache中的handler發(fā)送給master刷新。

一段時(shí)間后,例如45s,新的session仍然不能建立,客戶端立馬認(rèn)為session失效,將其終止。當(dāng)然這段時(shí)間內(nèi),不能更改cache信息,以求保證數(shù)據(jù)的一致性。

(3)master租約過期

master一段時(shí)間沒有收到客戶端的keep alive,則其進(jìn)入一段等待期,此期間內(nèi)仍沒有響應(yīng),則master認(rèn)為客戶端失效。失效后,master會(huì)把客戶端獲得的鎖,機(jī)器打開的臨時(shí)文件清理掉,并通知各副本,以保持一致性。


(4)主服務(wù)器出錯(cuò)

master出錯(cuò),需要內(nèi)部進(jìn)行重新選舉,各副本只響應(yīng)客戶端的讀取命令,而忽略其他命令。新上任的master會(huì)進(jìn)行以下幾步操作:

a,選擇新的編號(hào),不再接受舊master的消息;

b,只處理master位置相關(guān)消息,不處理session相關(guān)消息;

c,等待處理“危險(xiǎn)狀態(tài)”的客戶端keep alive;

d,響應(yīng)客戶端的keep alive,建立新的session,同時(shí)拒絕其他session相關(guān)操作;同事向客戶端返回keep alive,警告客戶端master fail-over,客戶端必須更新handle和lock;

e,等待客戶端的session確認(rèn)keep alive,或者讓session過期;

f,再次響應(yīng)客戶端所有操作;

g,一段時(shí)間后,檢查是否有臨時(shí)文件,以及是否存在一些lock沒有handle;如果臨時(shí)文件或者lock沒有對(duì)應(yīng)的handle,則清除臨時(shí)文件,釋放lock,當(dāng)然這些操作都需要保持?jǐn)?shù)據(jù)的一致性。


4.4服務(wù)器間的一致性操作

這塊考慮的問題是:當(dāng)master收到客戶端請(qǐng)求時(shí)(主要是寫),如何將操作同步,以保證數(shù)據(jù)的一致性。

(1)節(jié)點(diǎn)數(shù)目

一般來說,服務(wù)器節(jié)點(diǎn)數(shù)為5,如果臨時(shí)有節(jié)點(diǎn)被拿走,可預(yù)期不久的將來就會(huì)加進(jìn)來。


(2)關(guān)于復(fù)制

服務(wù)器接受客戶端請(qǐng)求時(shí),master會(huì)將請(qǐng)求復(fù)制到所有成員,并在消息中添加最新被提交的請(qǐng)求序號(hào)。member收到這個(gè)請(qǐng)求后,獲取master處被提交的請(qǐng)求序號(hào),然后執(zhí)行這個(gè)序列之前的所有請(qǐng)求,并把其記錄到內(nèi)存的日志里。如果請(qǐng)求沒有被master接受,就不能執(zhí)行。


各member會(huì)向master發(fā)送消息,master收到>=3個(gè)以上的消息,才能夠進(jìn)行確認(rèn),發(fā)送commit給各member,執(zhí)行請(qǐng)求,并返回客戶端。

如果某個(gè)member出現(xiàn)暫時(shí)的故障,沒有收到部分消息也無礙,在收到來自master的新請(qǐng)求后,主動(dòng)從master處獲得已執(zhí)行的,自己卻還沒有完成的日志,并進(jìn)行執(zhí)行。

最終,所有成員都會(huì)獲得一致性的數(shù)據(jù),并且,在系統(tǒng)正常工作狀態(tài)中,至少有3個(gè)服務(wù)器保持一致并且是最新的數(shù)據(jù)狀態(tài)。

4.5Chubby系統(tǒng)鎖機(jī)制

客戶端和服務(wù)器除了要保存lease對(duì)象外,服務(wù)器和客戶端還需要保存另一張表,用于描述已經(jīng)加鎖的文件及相關(guān)信息。由于Chubby系統(tǒng)所使用鎖是建議性而非強(qiáng)制性的,這代表著如果有多個(gè)鎖請(qǐng)求,后達(dá)的請(qǐng)求會(huì)進(jìn)入鎖等待隊(duì)列,直到鎖被釋放。


5.Chubby使用例子(重點(diǎn))

5.1選master

(1)每個(gè)server都試圖創(chuàng)建/打開同一個(gè)文件,并在該文件中記錄自己的服務(wù)信息,任何時(shí)刻都只有一個(gè)服務(wù)器能夠獲得該文件的控制權(quán);

(2)首先創(chuàng)建該文件的server成為主,并寫入自己的信息;

(3)后續(xù)打開該文件的server成為從,并讀取主的信息;


5.2進(jìn)程監(jiān)控

(1)各個(gè)進(jìn)程都把自己的狀態(tài)寫入指定目錄下的臨時(shí)文件里;

(2)監(jiān)控進(jìn)程通過閱讀該目錄下的文件信息來獲得進(jìn)程狀態(tài);

(3)各個(gè)進(jìn)程隨時(shí)有可能死亡,因此指定目錄的數(shù)據(jù)狀態(tài)會(huì)發(fā)生變化;

(4)通過事件機(jī)制通知監(jiān)控進(jìn)程,讀取相關(guān)內(nèi)容,獲取最新狀態(tài),達(dá)到監(jiān)控目的;


6.總結(jié)

Google Chubby提供粗粒度鎖服務(wù),它的本質(zhì)是一個(gè)松耦合分布式文件系統(tǒng);開發(fā)者不需要關(guān)注復(fù)雜的同步協(xié)議,直接調(diào)用庫來取得鎖服務(wù),并保證了數(shù)據(jù)的一致性。


最后要說明的是,最終Chubby系統(tǒng)代碼共13700多行,其中ice自動(dòng)生成6400行,手動(dòng)編寫約8000行,這就是Google牛逼的地方:強(qiáng)大的工程能力,快速穩(wěn)定的實(shí)現(xiàn),然后用來解決各種業(yè)務(wù)問題。


以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)