Google的鎖,才是分布式鎖?
早年Google的四大基礎(chǔ)設(shè)施,分別是GFS, MapReduce, BigTable, Chubby,?前三個(gè)比較有名,今天來說說最后一個(gè),Chubby。
Chubby是什么?
Chubby是早年Google四大基礎(chǔ)設(shè)施之一,提供粗粒度的分布式鎖服務(wù)。
Chubby的使用者不需要關(guān)注復(fù)雜的同步協(xié)議,而是通過已經(jīng)封裝好的客戶端直接調(diào)用鎖服務(wù),通過分布式鎖,滿足各種分布式場景下的一致性需求。
Chubby有什么典型的業(yè)務(wù)場景?
Chubby具有廣泛的應(yīng)用場景,例如:
(1)GFS選主;
(2)BigTable中的表鎖;
Chubby的內(nèi)核本質(zhì)是什么?
Chubby本質(zhì)上是一個(gè)分布式文件系統(tǒng),存儲大量小文件。每個(gè)文件就代表一個(gè)鎖,并且可以保存一些應(yīng)用層面的小規(guī)模數(shù)據(jù)。
用戶通過打開、關(guān)閉、讀取文件來獲取共享鎖或者獨(dú)占鎖;并通過反向通知機(jī)制,向用戶發(fā)送更新信息。
Chubby系統(tǒng)設(shè)計(jì)目標(biāo)是什么?
Chubby系統(tǒng)設(shè)計(jì)之初,主要想滿足以下幾點(diǎn):
(1)粗粒度的鎖服務(wù);
(2)高可用、高可靠;
(3)可直接存儲服務(wù)信息,而無需另建服務(wù);
(4)高擴(kuò)展性;
Chubby的整體架構(gòu)是怎么樣的?

Chubby架構(gòu)并不復(fù)雜,如上圖所示,其核心是這兩個(gè)重要組件:
(1)Chubby客戶端:以庫的方式提供,可以通過相應(yīng)API接口,申請鎖服務(wù),獲取數(shù)據(jù)信息,同時(shí)保持與服務(wù)端的連接;
(2)Chubby服務(wù)端:服務(wù)端集群,一般由5個(gè)節(jié)點(diǎn)組成(至少3個(gè)節(jié)點(diǎn)),其中一臺主節(jié)點(diǎn)(master),維護(hù)與客戶端的所有通信;其他節(jié)點(diǎn)不斷和主節(jié)點(diǎn)通信,獲取用戶操作;
在系統(tǒng)實(shí)現(xiàn)時(shí),還使用了以下特性:
(1)客戶端緩存,以減少對主節(jié)點(diǎn)的訪問;
(2)反向通知機(jī)制,鎖變化時(shí),會反向通知客戶端;
Chubby的實(shí)現(xiàn)關(guān)鍵點(diǎn)有哪些?
其一,文件系統(tǒng)。
Chubby文件系統(tǒng)類似于簡單的unix文件系統(tǒng)。
文件系統(tǒng)由許多Node組成,每個(gè)Node代表一個(gè)文件,或者一個(gè)目錄。文件系統(tǒng)使用Berkeley DB來保存每個(gè)Node的數(shù)據(jù)。文件系統(tǒng)提供的API很少:創(chuàng)建文件系統(tǒng)、文件操作、目錄操作等簡易操作。
其二,基于ICE的通信機(jī)制。
Chubby基于ICE的通信機(jī)制,核心就是異步,部分組件負(fù)責(zé)發(fā)送,部分組件負(fù)責(zé)接收。
其三,客戶端與主節(jié)點(diǎn)通信。
(1)使用長連接,連接有效期內(nèi),鎖服務(wù)、客戶端緩存數(shù)據(jù)均一直有效;
(2)定時(shí)雙向keepalive;
(3)出錯(cuò)回調(diào);
下面將說明正常、客戶端租約過期、主節(jié)點(diǎn)租約過期、主節(jié)點(diǎn)出錯(cuò)等情況。
(1)正常情況
keepalive會周期性發(fā)送,它有兩方面功能:
一來,延長租約有效期,攜帶事件信息告訴客戶端更新。
二來,執(zhí)行回調(diào),例如文件內(nèi)容修改、子節(jié)點(diǎn)增刪改、主節(jié)點(diǎn)出錯(cuò)等。
(2)客戶端租約過期
客戶端沒有收到主節(jié)點(diǎn)的keepalive,租約隨之過期,將會進(jìn)入一個(gè)“危險(xiǎn)狀態(tài)”。由于此時(shí)不能確定主節(jié)點(diǎn)是否已經(jīng)終止,客戶端必須主動(dòng)讓本地緩存失效,同時(shí),進(jìn)入一個(gè)尋找新的主節(jié)點(diǎn)的階段。
這個(gè)階段中,客戶端會輪詢服務(wù)集群,訪問非主節(jié)點(diǎn)的其他節(jié)點(diǎn),當(dāng)客戶端收到一個(gè)肯定的答復(fù)時(shí),他會向新的主節(jié)點(diǎn)發(fā)送keepalive信息,告之自己處于“危險(xiǎn)狀態(tài)”,并和新的主節(jié)點(diǎn)建立會話,然后把本地緩存中的信息刷新。
(3)主節(jié)點(diǎn)租約過期
主節(jié)點(diǎn)一段時(shí)間沒有收到客戶端的keepalive,會進(jìn)入一段等待期,此期間內(nèi)客戶端仍沒有響應(yīng),則主節(jié)點(diǎn)認(rèn)為客戶端失效。失效后,主節(jié)點(diǎn)會把客戶端獲得的鎖,打開的臨時(shí)文件清理掉,并通知各副本節(jié)點(diǎn),以保持一致性。
(4)主服務(wù)器出錯(cuò)
主節(jié)點(diǎn)出錯(cuò),需要內(nèi)部進(jìn)行重新選舉,各副本節(jié)點(diǎn)只響應(yīng)客戶端的讀取命令,而忽略寫命令。
其四,服務(wù)器集群間的一致性操作。
這里需要解決的問題是,當(dāng)主節(jié)點(diǎn)收到客戶端請求時(shí)(主要是寫),如何將操作同步到其他服務(wù)器節(jié)點(diǎn),以保證數(shù)據(jù)的一致性。
(1)節(jié)點(diǎn)數(shù)目
一般來說,節(jié)點(diǎn)數(shù)為5,至少要是3。
(2)關(guān)于復(fù)制
收到客戶端請求時(shí),主節(jié)點(diǎn)會將請求復(fù)制到所有成員,并在消息中添加最新被提交的請求序號。副本節(jié)點(diǎn)收到這個(gè)請求后,獲取主節(jié)點(diǎn)處被提交的請求序號,然后執(zhí)行這個(gè)序列之前的所有請求,并把其記錄到內(nèi)存的日志里。
各副本節(jié)點(diǎn)會向主節(jié)點(diǎn)回復(fù)消息,主節(jié)點(diǎn)收到半數(shù)以上的消息(集群包含5個(gè)節(jié)點(diǎn)時(shí),至少要收到3個(gè)節(jié)點(diǎn)),才能夠進(jìn)行確認(rèn),執(zhí)行請求,并返回客戶端。
畫外音:半數(shù)以上確認(rèn),才認(rèn)為成功。
如果某個(gè)副本節(jié)點(diǎn)出現(xiàn)暫時(shí)的故障,沒有收到部分消息也沒關(guān)系,副本節(jié)點(diǎn)重新啟動(dòng)后,主動(dòng)從主節(jié)點(diǎn)處獲得已執(zhí)行的,自己卻還沒有完成的日志,并進(jìn)行執(zhí)行。
畫外音:像不像MySQL的binlog。
最終,所有成員都會獲得一致性的數(shù)據(jù),正常情況下,至少有3個(gè)節(jié)點(diǎn)包含一致,且最新的數(shù)據(jù)。
最后,舉幾個(gè)Chubby使用場景的例子。
例子一,集群選主
(1)集群中每個(gè)節(jié)點(diǎn)都試圖創(chuàng)建/打開同一個(gè)文件,并在該文件中記錄自己的服務(wù)信息,任何時(shí)刻,肯定只有一個(gè)服務(wù)器能夠獲得該文件的控制權(quán);
(2)首先創(chuàng)建該文件的節(jié)點(diǎn)成為主,并寫入自己的信息;
(3)后續(xù)打開該文件的節(jié)點(diǎn)成為從,并讀取主的信息;
畫外音:是不是很巧妙?
?
例子二,進(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)會發(fā)生變化;
(4)通過事件機(jī)制通知監(jiān)控進(jìn)程,讀取相關(guān)內(nèi)容,獲取最新狀態(tài),達(dá)到監(jiān)控目的;
總結(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ù)問題。
近期被罰了,原創(chuàng)功能被關(guān)了,申訴也失敗了:
