BigTable

Bigtable爲Google設計的一個分佈式結構化數據存儲系統,用來處理Google的海量數據。Google內包括Web索引、Google地球等項目都在使用Bigtable存儲數據。儘管這些應用需求差異很大,但是Bigtable還是提供了一個靈活的、高性能的解決方案。

-----------------------------------------------------------------------------------------------------------------------------------


一、簡介

* 設計目標:可靠的處理PB級別的數據,適用性廣泛、可擴展、高性能和高可用性。

* 很多方面Bigtable和數據庫類似,其也使用了數據庫很多實現策略,但是Bigtable提供了和這些系統完全不同的接口。Bigtable不支持完整的關係數據模型,但爲用戶提供了一種簡單的數據模型,用戶可以動態控制數據的分佈和格式


二、數據模型

* Bigtable是一個稀疏的、分佈式的、持久化存儲的多維排序Map(Key=>Value)。Map的索引(Key)是行關鍵字、列關鍵字和時間戳,Map的值(Value)都是未解析的Byte數組:

    - Key (row:string, col:string, time:int64) => Value (string)

* 下圖是Bigtable存儲網頁信息的一個例子:


    - 行:"com.cn.www"爲網頁的URL

    - 列:"contents:"爲網頁的文檔內容,"anchor:"爲網頁的錨鏈接文本(anchor:爲列族,包含2列cnnsi.com和my.look.ca)

    - 時間戳:t3、t5、t6、t8和t9均爲時間戳

1、行

* 行和列關鍵字都爲字符串類型,目前支持最大64KB,但一般10~100個字節就足夠了

* 對同一個行關鍵字的讀寫操作都是原子的,這裏類似Mysql的行鎖,鎖粒度並沒有達到列級別

* Bigtable通過行關鍵字的字典序來組織數據,表中每行都可以動態分區。每個分區叫做一個"Tablet",故Tablet是數據分佈和負載均衡調整的最小單位。這樣做的好處是讀取行中很少幾列數據的效率很高,而且可以有效的利用數據的位置相關性(局部性原理)

2、列族

* 列關鍵字組成的集合叫做"列族",列族是訪問控制的基本單位,存放在同一列族的數據通常都屬於同一類型。

* 一張表列族不能太多(最多幾百個),且很少改變,但列卻可以有無限多

* 列關鍵字的命名語法:列族:限定詞。

* 訪問控制、磁盤和內存的使用統計都是在列族層面進行的

3、時間戳

* 在Bigtable中,表的每個數據項都可包含同一數據的不同版本,不同版本通過時間戳來索引(64位整型,可精確到毫秒)

* 爲了減輕各版本數據的管理負擔,每個列族有2個設置參數,可通過這2個參數可以對廢棄版本數據進行自動垃圾收集,用戶可以指定只保存最後n個版本數據


三、API

* 在表操作方面,提供建表、刪表、建列族、刪列族,以及修改集羣、表和列族元數據(如訪問權限等)等基本API。一個例子:


* 在數據操作方面,提供寫入、刪除、讀取、遍歷等基礎API。一個例子:


* 根據具體需求,Bigtable還開發出支持一些其他的特性,比如:1 支持單行上的事務處理,2 允許把數據項做整數計數器 3 允許用戶在Bigtable服務器地址空間上執行腳本程序


四、基礎構件

* Bigtable是建立在其他幾個Google基礎構件上的,有GFS、SSTable、Chubby等

1、基礎存儲相關

* Bigtable使用GFS存儲日誌文件和數據文件,集羣通常運行在共享機器池(cloud)中,依靠集羣管理系統做任務調度、資源管理和機器監控等

2、數據文件格式相關

* Bigtable的內部儲存文件爲Google SSTable格式的,SSTable是一個持久化、排序的、不可更改的Map結構

* 從內部看,SSTable是一系列的數據塊,並通過塊索引定位,塊索引在打開SSTable時加載到內存中,用於快速查找到指定的數據塊

3、分佈式同步相關

* Bigtable還依賴一個高可用的、序列化的分佈式鎖服務組件Chubby(類zookeeper)。

* Chubby服務維護5個活動副本,其中一個選爲Master並處理請求,並通過Paxos算法來保證副本一致性。另外Chubby提供一個名字空間,提供對Chubby文件的一致性緩存等

* Bigtable使用Chubby來完成幾個任務,比如:1 確保任意時間只有一個活動Master副本,2 存儲數據的自引導指令位置,3 查找Tablet服務器信息等 4 存儲訪問控制列表等


五、實現

* Bigtable包括3個主要的組件:鏈接到用戶程序的庫,1個Master服務器和多個Tablet服務器。Tablet服務器可根據工作負載動態增減

* Master服務器:爲Tablet服務器分配Tablets,對Tablet服務器進行負載均衡,檢測Tablet服務器的增減等

* Tablet服務器:管理一個Tablets集合(十到上千個Tablet),並負責它們的讀寫操作。與一般Single-Master類型的分佈式存儲系統類似,客戶端可直接和Tablet服務器通信並進行讀寫,故Master的負載並不大

* 初始情況下,每個表只含一個Tablet,隨着表數據的增長,它會被自動分割成多個Tablet,使得每個Table一般爲100~200MB

1、Tablet的位置信息

* 我們使用三層的、類B+樹的結構存儲Tablet的位置信息,如下圖所示:


* 第一層爲存儲於Chubby中的Root Tablet位置信息。Root Tablet包含一個MetaData表,MetaData表每個Tablet包含一個用戶Tablet集合

* 在MetaData表內,每個Tablet的位置信息都存儲在一個行關鍵字下,這個行關鍵字由Tablet所在表的標識符和最後一行編碼而成

* MetaData表每一行都存儲約1KB內存數據,即在一個128MB的MetaData表中,採用這種3層存儲結構,可標識2^32個Tablet地址

* 用戶程序使用的庫會緩存Tablet的位置信息,如果某個Tablet位置信息沒有緩存或緩存失效,那麼客戶端會在樹狀存儲結構中遞歸查詢。故通常會通過預取Tablet地址來減少訪問開銷

2、Tablet的分配

* 在任何時刻,一個Tablet只能分配給一個Tablet服務器,這個由Master來控制分配(一個Tablet沒分配,而一個Tablet服務器用足夠空閒空間,則Master會發給該Tablet服務器裝載請求)

* Bigtable通過Chubby跟蹤Tablet服務器的狀態。當Tablet服務器啓動時,會在Chubby註冊文件節點並獲得其獨佔鎖,當Tablet服務器失效或關閉時,會釋放這個獨佔鎖

* 當Tablet服務器不提供服務時,Master會通過輪詢Chubby上Tablet服務器文件鎖的狀態檢查出來,確認後會刪除其在Chubby註冊的節點,使其不再提供服務。最後Master會重新分配這個Tablet服務器上的Tablet到其他未分配的Tablet集合內

* 當集羣管理系統啓動一個Master服務器之後,這個Master會執行以下步驟:

    - 1 從Chubby獲取一個唯一的Master鎖,保證Chubby只有一個Master實例

    - 2 掃描Chubby上的Tablet文件鎖目錄,獲取當前運行的Tablet服務器列表

    - 3 和所有Tablet服務器通信,獲取每個Tablet服務器上的Tablet分配信息

    - 4 掃描MetaData表獲取所有Tablet集合,如果發現有還沒分配的Tablet,就會將其加入未分配Tablet集合等待分配

3、Tablet的服務


* 如圖所示,Tablet的持久化狀態信息保存在GFS上。更新操作會提交Redo日誌,更新操作分2類:

    - 最近提交的更新操作會存放在一個排序緩存中,稱爲memtable

    - 較早提交的更新操作會存放在SSTable中,落地在GFS上

* Tablet的恢復:Tablet服務器從MetaData中讀取這個Tablet的元數據,元數據裏面就包含了組成這個Tablet的SSTable和RedoPoint,然後通過重複RedoPoint之後的日誌記錄來重建(類似Mysql的binlog)

* 對Tablet服務器寫操作:首先檢查操作格式正確性和權限(從Chubby拉取權限列表)。之後有效的寫記錄會提交日誌,也支持批量提交,最後寫入的內容插入memtable內

* 對Tablet服務器讀操作:也首先檢查格式和權限,之後有效的讀操作在一系列SSTable和memtable合併的視圖內執行(都按字典序排序,可高效生成合並視圖)

4、Compactions

* 當memtable增大達到一個門限值時,這個memtable會轉換爲SSTable並創建新的memtable,這個過程稱爲Minor Compaction。

* Minor Compaction過程爲了減少Tablet服務器使用的內存,以及在災難恢復時減少從提交日誌讀取的數據量

* 如果Minor Compaction過程不斷進行下去,SStable數量會過多而影響讀操作合併多個SSTable,所以Bigtable會定期合併SStable文件來限制其數量,這個過程稱爲Major Compaction。

* 除此之外,Major Compaction過程生產的新SStable不會包含已刪除的數據,幫助Bigtable來回收已刪除的資源


六、優化

1、局部性羣族

* 用戶可將多個列族組合成一個局部性羣族,Tablet中每個局部性羣族都會生產一個SSTable,將通常不會一起訪問的分割成不同局部性羣族,可以提高讀取操作的效率

* 此外,可以局部性羣族爲單位專門設定一些調優參數,如是否存儲於內存等

2、壓縮

* 用戶可以控制一個局部性羣族的SSTable是否壓縮

* 很多用戶使用”兩遍可定製“的壓縮方式:第一遍採用Bentley and Mcllroy(大掃描窗口內常見長字符串壓縮),第二遍採用快速壓縮算法(小掃描窗口內重複數據),這種方式壓縮速度達到100~200MB/s,解壓速度達到400~1000MB/s,空間壓縮比達到10:1

3、緩存

* Tablet服務器使用二級緩存策略來提高讀操作性能。兩級的緩存針對性不同:

* 第一級緩存爲掃描緩存:緩存Tablet服務器通過SSTable接口獲取的Key-Value對(時間局部性)

* 第二季緩存爲塊緩存:緩存從GFS讀取的SSTable塊(空間局部性)

4、布隆過濾器

* 一個讀操作必須讀取構成Tablet狀態的所有SSTable數據,故如果這些SSTable不在內存便需多次訪問磁盤

* 我們允許用戶使用一個Bloom過濾器來查詢SStable是否包含指定的行和列數據,付出少量Bloom過濾器內存存儲代價,換來顯著減少訪問磁盤次數

5、Commit日誌實現

* 如果每個Tablet操作的Commit日誌單獨寫一個文件,會導致日誌文件數過多,寫入GFS會產生大量的磁盤Seek操作而產生負面影響

* 優化:設置爲每個Tablet服務器寫一個公共的日誌文件,裏面混合了各個Tablet的修改日誌。
* 這個優化顯著提高普通操作性能,卻讓恢復工作複雜化。當一臺Tablet服務器掛了,需要將其上面的tablet均勻恢復到其他Tablet服務器,則其他服務器都得讀取完整的Commit日誌。爲了避免多次讀Commit日誌,我們將日誌按關鍵字排序(table, row, log_seq),讓同一個Tablet的操作日誌連續存放

6、Tablet恢復提速

* Master轉移Tablet時,源Tablet服務器會對這個Tablet做一次Minor Compaction,減少Tablet服務器日誌文件沒有歸併的記錄,從而減少了恢復時間

7、利用不變性

* 在使用Bigtable時,除了SSTable緩存外其他部分產生的SSTable都是不變的,可以利用這個不變性對系統簡化


七、性能評估

* 實驗設計:N臺Tablet服務器集羣(N=1、50、250、500...),每臺Tablet服務器1G內存,數據寫入一個含1786臺機器的GFS集羣。使用N臺Client產生工作負載,這些機器都連入一個兩層樹狀網絡,根節點帶寬約100~200Gbps。

* 一共有6組基準測試:序列寫、隨機寫、序列讀、隨機讀、隨機讀(內存)和掃描,測試結果如下圖所示:


測試均爲讀/寫1000字節value的數據,圖1顯示了1/50/250/500臺Tablet服務器,每臺服務器的每秒操作次數,圖2曲線顯示隨着Tablet服務器數量增加,所有服務器的每秒操作次數總和

* 對於圖1單個Tablet服務器性能維度,有下面幾個特點:

    - 隨機讀性能最慢,這是因爲每個隨機讀操作都要通過網絡從GFS集羣拉回64KB(1塊)數據到Tablet服務器

    - 隨機讀(內存)性能很快,因爲這些讀操作的數據都從Tablet服務器的內存讀取
    - 序列讀性能好於隨機讀,因爲每次從GFS取出64KB數據,這些數據會緩存,序列讀很多落到同個塊上而減少GFS讀取次數

    - 寫操作比讀操作高,因爲寫操作實質上爲Tablet服務器直接把寫入內容追加到Commit日誌文件尾部(隨機寫和序列寫性能相近的原因),最後再採用批量提交的方式寫入GFS

    - 掃描的性能最高,因爲Client的每一次RPC調用都會返回大量value數據,抵消了RPC調用消耗

* 對於圖2Tablet服務器集羣性能維度,有下面幾個特點:

    - 隨着Tablet服務器的增加,系統整體吞吐量有了夢幻般的增加,之所以會有這樣的性能提升,主要是因爲基準測試的瓶頸是單臺Tablet服務器的CPU

    - 儘管如此,性能的增加也不是線性的,這是由於多臺Tablet服務器間負載不均衡造成的

    - 隨機讀的性能提升最小,還是由於每個1000字節value的讀操作都會導致一個64KB塊的網絡傳輸,消耗了網絡的共享帶寬


八、實際應用

* 截止到2006年,Google內部一共運行了388個非測試的Bigtable集羣,約24500臺Tablet服務器,這些應用以及應用數據大致如下:


* 如上圖所示,可以瞭解到Google分析,Google地圖,Google個性化查詢等應用的Bigtable使用情況


九、經驗教訓

* 很多類型的錯誤都會導致大型分佈式系統受損,而不僅僅是網絡中斷等“常規”錯誤。我們使用修改協議來解決這些問題(容錯性),如在RPC機制中加入Checksum等

* 需要在徹底瞭解一個新特性如何使用後,再決定添加這個新特性是否是重要的。

* 系統級的監控對Bigtable非常重要,能有效跟蹤集羣狀態、檢查引發集羣高時延的潛在因素等

* 簡單的設計和編碼給維護和調試帶來了巨大的好處

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章