本文是《YunTable開發日記》的第四篇。
經過這幾天的開發工作,我已經將YunTable所需的一些基本類庫搭建起來,比如記憶體管理,字串處理,I/O處理和基本的資料結構等,由於之前的編程以Java為主,所以在這方面花了一定的時間,導致整個項目的進度偏離了之前的預期,但是我也有很多的收穫,比如我感受到了Java和C之間的異同:異就是Java能通過JVM和JDK提供給程式員一個非常便捷和安全的開發環境,就好象一個溫室那樣,而C語言呢?則是提供一個簡單到以至於簡陋的工具給程式員,但是卻導致其具有非常強大的靈活性,在這方面,有點類似圍棋。而同呢?就是不論寫Java代碼還是C代碼,最核心也是最關鍵的,就是使用優雅的方式將重複的代碼降至最低,從而降低整體的代碼數量和複雜度。在關於語言特性的討論之後,接下來就將介紹本文的核心內容,也就是BigTable的儲存模型,首先是Tablet的運行機制。
Tablet的運行機制
在之前的一篇,我已經給大家介紹了由於一個BigTable需要儲存海量的資料,使得其不得不被分割成多個Tablet,並且儲存在多個的伺服器上,下面就給大家介紹一下Tablet的運行機制。
圖1. Tablet的運行機制(源自BigTable的論文)
當一個寫的請求傳遞給一個Tablet時,它首先會將這個操作提交給Redo日誌,也就是圖1的tablet log,接著,在這些已經提交的寫操作中,最新提交的那些會被放置在記憶體的一個被排序的緩衝中,稱為“memtable”,而較早的更新則會被flush到用於儲存資料的SSTable中。而當一個讀操作傳遞給一個Tablet的時候,這個讀操作會根據一個有一系列的SStable和memtable合并的視圖來查詢資料,並且由於SSTable和memtable是按字典排序的資料結構,因此可以高效產生這個合并視圖。下面將介紹用於儲存資料的SSTable。
SSTable的介紹
簡單而言,SSTable是一個用於排序儲存Key-Value對的檔案格式,並且是不可變動的(immutable),也就是寫了之後,只能將其更新附加至其之後,而不能直接進行修改,這樣是為了讓系統能執行disk所擅長的順序訪問,而不是隨機訪問。由於關於SSTable的內部實現和格式是不公開的,所以在這裡選擇SSTable開源複製HFile作為介紹的樣板。HBase本來使用Hadoop的檔案格式MapFile作為其隱藏檔的格式,但由於效率等原因,HBase的開發組在HBase的0.20版中引入了SSTable的開源版本HFile,並且隨著HFile不斷成熟,而且有可能在今後也成為Hadoop預設的檔案格式,為HFile的格式:
圖2. HFile的格式
在格式方面,HFile主要可以被分為兩個部分:其一是Metadata部分,其包括檔案的資訊,資料與Metadata的索引和Trailer等,Trailer主要用於隱藏檔中每個模組的位移值(offset),以便於系統訪問和使用這個HFile檔案。其二則是Data部分,其主要有一系列儲存Key-Value對的Block組成,每個Block的大小大概在64KB左右,但是可以根據儲存資料的大小來進行調整,比如當儲存的資料比較小時,可以通過將Block的大小設為16KB,使得減少每個Block儲存的資料量,從而減少Block內部的查詢。
在大小方面,64MB是HFile比較常見的大小,也可以將HFile擴大至GB級,但是越大HFile需要更多記憶體以保持其Index被裝載至記憶體中,以減少磁碟的Seek操作。同時HFile也像SSTable那樣,對壓縮有很好的支援,特別是對LZO演算法支援,因為通過這個演算法不僅能將資料壓至原有的1/4大小,而且運行效率很高,從而能提升整個系統的運行效率。
本篇結束,下篇日記將主要講解BigTable的分布式模型。
參考資料:
- Bigtable的論文(中文版)
- HFile: A Block-Indexed File Format to Store Sorted Key-Value Pairs