在介紹了BigTable的儲存模型之後,本篇將重點給大家介紹其分布式模型。由於本文大多數內容參考BigTable的論文,如果有些博友已經熟讀這篇論文,可以跳過本文。
綜述
從分布式的角度而言,BigTable會涉及總共五種獨立的構件:
- Client端的庫:一個基於BigTable的應用會根據其所使用語言的不同,而選擇不同的Client端庫來訪問一個BigTable系統。
- Chubby服務:一個高可用、分布式的鎖服務,用於協調整個BigTable的運作。
- Master節點:分配Tablets給Tablet伺服器、檢測新加入的或者到期失效的Table伺服器、並對Tablet伺服器進行負載平衡、以及對儲存在GFS上的檔案進行垃圾收集。除此之外,它還處理與資料庫Schema相關的修改操作,例如建立Table和Column Family。
- Tablet節點: 每個Tablet伺服器都管理一個Tablet的集合(通常每個伺服器有大約數十個至上千個Tablet)。每個Tablet伺服器負責處理它所載入的Tablet的讀寫操作,以及在Tablets過大時,對其進行分割。
- GFS系統:GFS是一個Distributed File System,其主要用於管理和備份那些用於儲存Tablet的SSTable檔案,但是其執行對於BigTable而言是透明的。
雖然Chubby並不是BigTable的一個組成部分,但由於其對BigTable整個分布式的運作非常關鍵,所以下面將首先介紹Chubby。
Chubby的介紹
Chubby的機制
主要可以分為下面這四個方面:
- 在運行機制方面:一個Chubby服務包括5個活動的副本,也就是replica,其中的一個副本被選為Master,讓其來處理請求。只有在大多數副本都是正常啟動並執行,並且彼此之間能夠互相通訊的情況下,Chubby服務才被認為是可用的,而當有一個副本失效的時候,Chubby使用Paxos演算法來保證副本的一致性。
- 在實現機制方面:Chubby主要提供了一個名字空間,裡麵包括了目錄和小檔案。每個目錄或者檔案都可被視為一個鎖,而讀寫這些檔案的操作都是原子的。
- 在與Client端交流方面:Chubby提供對Chubby檔案的一致性緩衝。每個Chubby客戶程式都維護一個與Chubby服務的會話。如果客戶程式不能在租約(Lease)到期的時間內重新簽訂會話的租約,這個會話就到期失效了。當一個會話失效時,它擁有的鎖和開啟的檔案控制代碼都失效了。
Chubby在BigTable的作用
在BigTable中Chubby主要完成下面的幾個任務:
- 確保在任何給定的時間內最多隻有一個活動的Master節點。
- 儲存BigTable資料庫的初始Root Tablet的位置(具體請看下面“如何定位Tablet”這段)
- 為Tablet伺服器提高鎖服務,以及在Tablet伺服器失效時進行善後(具體請看下面“如何分配Tablet”這段)
- 儲存BigTable的schema資訊(和column family相關的)和ACL(存取控制清單)。
假設Chubby服務在長時間內無法被訪問,這將導致BigTable無法正常工作。還有,Chubby也有相關的開源版本,比如Hadoop系列的zookeeper,但兩者在實現機制上面有一定的差別。
如何定位Tablet?
首先,在Master和Tablet節點之間的關係上面,採用了很多Single-Master類型的分布式儲存系統類別似的設計,也就是用戶端讀取的資料都不經過Master伺服器,客戶程式直接和Tablet伺服器通訊進行讀寫操作。由於BigTable的用戶端程式不必通過Master伺服器來擷取Tablet的位置資訊,因此,大多數用戶端程式甚至完全不需要和Master伺服器通訊。在實際應用中,Master伺服器的負載是很輕的,所以一個Master節點能支援上千的Tablet節點。還有,一個BigTable叢集會儲存了很多表,每個表都可以被認為是一個Tablet的集合,而且每個Tablet包含屬於某個Range的行的所有相關資料,在初始狀態下,一個表只有一個Tablet,但隨著表中資料的增長,它會被自動分割成多個Tablet,在預設情況下,每個Tablet的大小在100MB左右。為Tablet的層次圖:
圖1. Tablet的層次圖
總體而言,Tablet的層次是一個三層,類似於B+樹的結構。最上面是一個儲存在Chubby中的檔案,它包含了Root Tablet的位置資訊。Root Tablet包含了一個特殊的METADATA表裡所有的Tablet的位置資訊。METADATA表的每個Tablet包含了一個UserTablet的集合。Root Tablet實際上是METADATA表的第一個Tablet,只不過對它的處理比較特殊,比如,Root Tablet永遠不會被分割,這樣將保證了Tablet的結構最多有三層。在METADATA表裡面,每個Tablet的位置資訊都存放在一個行關鍵字下面,而這個行關鍵字是由Tablet所在的表的標識符和Tablet的最後一行編碼而成的。METADATA的每一行都儲存了大約1KB的記憶體資料。在用戶端使用的BigTable庫會緩衝Tablet的位置資訊。如果用戶端程式沒有緩衝某個Tablet的地址資訊,或者發現它緩衝的地址資訊不正確,用戶端程式就在上面那個樹狀的儲存結構中遞迴的查詢Tablet位置資訊。在支撐的容量方面,一個大小適中的、容量限制為128MB的METADATA Tablet中,假如採用這種三層結構的儲存模式,可以標識2^34個Tablet的地址(如果每個Tablet儲存128MB資料,那麼一共可以儲存 2^61位元組資料)。
如何分配Tablet?
Masater會跟蹤當前有那些活躍的Tablet伺服器和跟蹤Tablet的儲存地方,並將Tablet分配給有空閑空間的Tablet伺服器。BigTable系統使用Chubby服務來記錄Tablet伺服器的狀態。當一個Tablet伺服器啟動時,這個Tablet伺服器會在Chubby的一個指定目錄下建立一個有唯一性名字的檔案,並且擷取該檔案的獨佔鎖。Master伺服器即時監控著這個目錄,而且通過這個手段,Master伺服器因此能夠獲知有那些新的Tablet伺服器加入整個叢集。如果這個Tablet伺服器丟失了Chubby上的獨佔鎖,只要那個檔案還存在,這個伺服器就會試圖重新獲得對該檔案的獨佔鎖;如果檔案不存在了,那麼Tablet伺服器就不能再提供服務了,它會自行退出。當Tablet伺服器終止時,它會嘗試釋放它持有的檔案鎖,這樣一來,Master伺服器就能儘快把Tablet分配到其它的Tablet伺服器。
Master伺服器會檢查一個Tablet伺服器是否已經不再為它的Tablet提供服務了,並且要儘快重新分配它載入的Tablet。 Master伺服器通過輪詢Tablet伺服器檔案鎖的狀態來檢測。如果一個Tablet伺服器報告它丟失了檔案鎖,或者Master伺服器最近幾次嘗試和它通訊都沒有得到響應,Master伺服器就會嘗試擷取該Tablet伺服器檔案的獨佔鎖;如果Master伺服器成功擷取了獨佔鎖,那麼就說明Chubby是正常啟動並執行,而Tablet伺服器要麼是宕機了、要麼是不能和Chubby通訊了,因此,Master伺服器就刪除該Tablet伺服器在Chubby上的伺服器檔案以確保它不再給Tablet提供服務。一旦Tablet伺服器在Chubby上的伺服器檔案被刪除了,Master伺服器就把之前分配給它的所有的Tablet放入未分配的Tablet集合中。為了確保Bigtable叢集在Master伺服器和Chubby之間網路出現故障的時候仍然可以使用,Master伺服器在它的Chubby會話到期後主動退出。總體的來說,Chubby提供了一種高效的機制,利用這種機制,Tablet伺服器能夠在不增加網路負擔的情況下知道它是否還持有鎖。
當BigTable系統啟動了一個Master伺服器之後,Master伺服器首先要瞭解當前Tablet的分配狀態,之後才能夠修改分配狀態。 Master伺服器在啟動的時候執行以下步驟:
- Master伺服器從Chubby擷取一個唯一的Master鎖,用來阻止建立其它的Master伺服器的執行個體。
- Master伺服器掃描Chubby的伺服器檔案鎖儲存目錄,擷取當前正在啟動並執行伺服器列表。
- Master伺服器和所有的正在啟動並執行Tablet表格服務器通訊,擷取每個Tablet伺服器上Tablet的分配資訊,如果發現發現Root Tablet還沒有分配,Master伺服器就把Root Tablet加入到未分配的Tablet集合。這個附加操作確保了Root Tablet會被分配。
- Master伺服器掃描METADATA表擷取所有的Tablet的集合。在掃描的過程中,當Master伺服器發現了一個還沒有分配的Tablet,Master伺服器就將這個Tablet加入未分配的Tablet集合等待合適的時機分配。
由於Root Tablet包括了所有METADATA的Tablet的名字,因此Master伺服器掃描完Root Tablet以後,就得到了所有的METADATA表的Tablet的名字了。
儲存現有Tablet的集合只有在以下事件發生時才會改變,建立了一個新表或者刪除了一箇舊表、兩個Tablet被合并了、或者一個Tablet被分割成兩個小的Tablet。Master伺服器可以追蹤記錄所有這些事件,因為除了最後一個事件外的兩個事件都是由它啟動的。Tablet分割事件需要特殊處理,因為它是由Tablet伺服器啟動。在分割操作完成之後,Tablet伺服器通過在METADATA表中記錄新的Tablet的資訊來提交這個操作;當分割操作提交之後,Tablet伺服器會通知Master伺服器。如果分割操作已提交的資訊沒有通知到Master伺服器(可能兩個伺服器中有一個宕機了),Master伺服器在要求Tablet伺服器裝載已經被分割的子表的時候會發現一個新的Tablet。通過對比METADATA表中Tablet的資訊,Tablet伺服器會發現Master伺服器要求其裝載的Tablet並不完整,因此,Tablet伺服器會重新向Master伺服器發送通知資訊。
本文結束,下篇將關注BigTable的功能集。
參考資料:
- BigTable的論文
- Chubby的論文