概述
HBase是基于Bigtable論文的面向列的分布式存儲系統,其存儲設計是基于Memtable/SSTable的。 其它如 Cassandra 都是采用的該設計。
整個存儲分為兩部分,一部分為內存中的 MemStore(Memtable) ,另外一部分為磁盤 ( 這里是 HDFS) 上的 HFile(SSTable) 。下面分別講述兩種類型的存儲分別的實現:
MemStore 中最重要的變量是:
volatile KeyValueSkipListSet kvset;
這里的 KeyValueSkipListSet 里面實際是這樣的:
private final ConcurrentNavigableMap<KeyValue, KeyValue> delegatee;
換句話說,其實就是一個放內存的 Map 存放著 kv 。
?
HFile 是 HBase 實際的文件存儲格式,它是基于 TFile 的文件格式,替換了早期的 MapFile ,改進了性能。
然后 HBase 會進行控制,當 MemStore 寫滿了以后進行刷磁盤操作。
而HLog是HBase的日志格式實現,主要是在寫入的時候進行write-ahead-log,主要為recovery而做。
HFile
HFile 是 HBase 中實際存數據的文件,為 HBase 提供高效快速的數據訪問。它是基于 Hadoop 的 TFile ,模仿 Google Bigtable 架構中的 SSTable 格式。之前的 Hadoop 的 MapFiles 已經被證明性能不能到達我們的期望。文件格式如下:
?
?
文件是變長的,唯一固定的塊是 File info 和 Trailer ,如圖所示, Trailer 有指向其它塊的指針,這些指針也寫在了文件里, Index 塊記錄了 data 和 meta 塊的偏移量, data 和 meta 塊都是可選的。
塊的大小是由表創建時的 HColumnDescriptor 指定的,如下是 master web interface 上看到的一個例子:
{NAME => 'docs', FAMILIES => [{NAME => 'cache', COMPRESSION => 'NONE', VERSIONS => '3', TTL => '2147483647', BLOCKSIZE => '65536', IN_MEMORY => 'false', BLOCKCACHE => 'false'}, {NAME => 'contents', COMPRESSION => 'NONE', VERSIONS => '3', TTL => '2147483647', BLOCKSIZE => '65536', IN_MEMORY => 'false', BLOCKCACHE => 'false'}, ...
默認的大小是 64KB ,下面是一段關于 HFile 的解釋:
“最小的塊大小。我們建議通常將其設置為 8KB 到 1MB 之間,如果經常進行基于 primary key 的順序訪問,可以設置更大的塊大小,但是這樣會帶來低效的隨機訪問效率(更多的數據需要被解壓縮)。更小的塊大小將帶來更好的隨機訪問效率,但是會耗費更多的內存去維持索引,并且在創建的時候會比較慢,因為需要 flush 壓縮流,這將導致一個 FS I/O flush 。由于內部的壓縮 codec 的緩存,最小的塊大小可以為 20-30KB ”
?
?
?
上圖是 HFile 中每個 KeyValue 的格式,和普通的 key-value 沒有太大的區別。
?
HLog
源碼中的實現類是 HLog 。每個 HRegionServer 會對應一個 HLog , HRegion 在初始化的時候 HRegionServer 會將該 HLog 的實例作為構造函數傳入其中。 HLog 的核心函數是其 append() 函數。
在 HLog 中,會維持一個 Sequence Number ,是一個 AtomicLong 型,當一個 Region 啟動的時候會從 HFile 的 Meta field 里面讀出當前的 Sequence Number 。
如圖所示,由于 HLog 是 Region 之間共享的,因此, log 的順序是不定的,這一點后面會提到。當一個 HRegionServer 崩潰掉后, HMaster 會讓 HRegionServer 重啟的時候根據日志進行恢復。
當前的 WAL 使用的是 Hadoop 下的 SequenceFile 格式,其 key 是 HLogKey 實例,它包括以下內容:
private byte [] encodedRegionName; private byte [] tablename; private long logSeqNum; // Time at which this edit was written. private long writeTime; private byte clusterId;
?
由于操作系統處理批量的數據要塊過單個單個的處理,因此,需要進行 flush 日志。 LogFlusher 實現了該功能,它調用了 HLog.optionalSync() ,它將檢查是否到了 hbase.regionserver.optionallogflushinterval ,默認是 10 秒。
???????? 日志的大小會有一個限制,這是用 hbase.regionserver.logroll.period 參數控制的,默認是 1 個小時。到點以后 LogRoller 會觸發操作,檢查當前的 Sequence Number ,看小于它的所有日志是否完整。
?
參考文獻
http://www.larsgeorge.com/
主要參考自larsgeorge的hbase系列文章
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
