HBase是一種構建在HDFS之上的分布式、面向存儲列的存儲系統。在需要實時讀寫、隨機訪問超大規模訪問數據采集的時候,可以使用HBase。
盡管現在已經有很多數據存儲和訪問的策略和實現方法,但是事實上大多數解決方案,特別是一些關系類型的,在構建時並沒有考慮超大規模和分布式的特點。許多商家通過復制和分區的方法來擴充數據庫使其突破單個節點的界限,但這些功能通常都是事后增加的,安裝和維護都很復雜。同時,也會影響RDBMS的特定功能,例如聯接、復雜的查詢、觸發器、視圖和外鍵約束這些操作在大型的RDBMS上的代價相當高,甚至根本無法實現。
HBase從另一個角度處理伸縮性的問題。它通過線性方式從下到上增加節點來進行擴展。HBase不是關系型數據庫,也不支持SQL,但是他有自己的特長,這是RDBMS不能處理的,HBase巧妙的將稀疏的表放在商用的服務器的集群上。
HBase 是Google Bigtable 的開源實現,與Google Bigtable利用GFS作為文件存儲系統類似,HBase利用Hadoop HDFS 作為文件存儲系統,Google 運行MapReduce 來處理Bigtable中的海量數據,HBase 同樣利用Hadoop MapReduce來處理HBase的海量數據,Google Bigtable 利用Chubby作為協同服務。HBase利用Zookepper作為對應。
HBase的特點
- 大:一個表可以有上億行,上百萬列。
- 面向列:面向列表(簇)的存儲和權限控制,列(簇)獨立檢索。
- 稀疏:對於為空(NULL)的列,並不占用存儲空間,因此,表可以設計的非常稀疏。
- 無模式:每一行都有一個可以排序的主鍵和任意多的列,列可以根據需要動態增加,同一張表中不同的行可以有截然不同的列。
- 數據多版本:每個單元中的數據可以有多個版本,默認情況下,版本號自動分配,版本號就是單元格插入時的時間戳。
- 數據類型單一:HBase中的數據都是字符串,沒有類型。
HBase的高並發和實時處理數據
hadoop是一個高容錯,高延時的文件分布式系統和高並發的批處理系統,不適用實時計算。HBase是可以提供實時計算的分布式數據庫。數據被保存到HDFS分布式文件系統上。由HDFS保證期高容錯性。但是在生產環境中。HBase是如何基於hadoop提供實時性呢? HBase上的數據是以StoreFile(HFile)二進制流的形式存儲在HDFS上block塊兒中;但是HDFS並不知道hbase存入的是什么,它只把存儲文件是為二進制文件,也就是說。hbase的存儲數據對於HDFS文件系統是透明的。hbase的存儲數據對於HDFS文件系統是透明的。
HBase HRegion servers集群中的所有的region的數據在服務器啟動時都是被打開的,並且在內存初始化一些memstore,相應的這就在一定的程度上加快的系統的響應。而Hadoop中的block中的數據文件默認是關閉的,只有在需要的時候打開。處理完數據后就關閉。這在一定的程度上就增加了響應時間。
從根本上來說。HBase能提供實時計算的服務的主要原因是由架構和底層數據結構決定的。即由LSM-Tree + HTable(region分區) + Cache決定——客戶端可以直接定位到要查數據所在的HRegion server服務器,然后直接在服務器的一個region上查找要匹配的數據,並且這些數據部分是經過cache緩存的。具體查詢流程如下圖所示:
具體數據訪問流程如下:
- 1.Client會通過內部緩存的相關的-ROOT-中的信息和.META.中的信息直接連接與請求數據匹配的HRegion server;
- 2.然后直接定位到該服務器上與客戶請求對應的Region,客戶請求首先會查詢該Region在內存中的緩存——Memstore(Memstore是一個按key排序的樹形結構的緩沖區);
- 3.如果在Memstore中查到結果則直接將結果返回給Client;
- 4.在Memstore中沒有查到匹配的數據,接下來會讀已持久化的StoreFile文件中的數據。前面的章節已經講過,StoreFile也是按 key排序的樹形結構的文件——並且是特別為范圍查詢或block查詢優化過的,;另外HBase讀取磁盤文件是按其基本I/O單元(即 HBase Block)讀數據的。
具體過程就是:
如果在BlockCache中能查到要造的數據則這屆返回結果,否則就讀去相應的StoreFile文件中讀取一block的數據,如果還沒有讀到要查的數據,就將該數據block放到HRegion Server的blockcache中,然后接着讀下一block塊兒的數據,一直到這樣循環的block數據直到找到要請求的數據並返回結果;如果將該 Region中的數據都沒有查到要找的數據,最后接直接返回null,表示沒有找的匹配的數據。當然blockcache會在其大小大於一的閥值(heapsize * hfile.block.cache.size * 0.85)后啟動基於LRU算法的淘汰機制,將最老最不常用的block刪除。
HBase數據模型
HBase 以表的形式存儲數據。表由行和列組成。列划分為若干個列族(row family),如下圖所示。
HBase的邏輯數據模型:
HBase的物理數據模型(實際存儲的數據模型):
邏輯數據模型中空白cell在物理上是不存儲的,因為根本沒有必要存儲,因此若一個請求為要獲取t8時間的contents:html,他的結果就是空。相似的,若請求為獲取t9時間的anchor:my.look.ca,結果也是空。但是,如果不指明時間,將會返回最新時間的行,每個最新的都會返回
Row Key
與 NoSQL 數據庫一樣,Row Key 是用來檢索記錄的主鍵。訪問 HBase table 中的行,只有三種方式:
- 通過單個 Row Key 訪問。
- 通過 Row Key 的 range 全表掃描。
- Row Key 可以使任意字符串(最大長度是64KB,實際應用中長度一般為 10 ~ 100bytes),在HBase 內部,Row Key 保存為字節數組。
在存儲時,數據按照* Row Key 的字典序(byte order)排序存儲*。設計 Key 時,要充分排序存儲這個特性,將經常一起讀取的行存儲到一起(位置相關性)。
注意 字典序對 int 排序的結果是 1,10,100,11,12,13,14,15,16,17,18,19,20,21,…, 9,91,92,93,94,95,96,97,98,99。要保存整形的自然序,Row Key 必須用 0 進行左填充。
行的一次讀寫是原子操作(不論一次讀寫多少列)。這個設計決策能夠使用戶很容易理解程序在對同一個行進行並發更新操作時的行為。
列族
HBase 表中的每個列都歸屬於某個列族。列族是表的 Schema 的一部分(而列不是),必須在使用表之前定義。列名都以列族作為前綴,例如 courses:history、courses:math 都屬於 courses 這個列族。
訪問控制、磁盤和內存的使用統計都是在列族層面進行的。在實際應用中,列族上的控制權限能幫助我們管理不同類型的應用, 例如,允許一些應用可以添加新的基本數據、一些應用可以讀取基本數據並創建繼承的列族、
一些應用則只允許瀏覽數據(甚至可能因為隱私的原因不能瀏覽所有數據)。
時間戳
HBase 中通過 Row 和 Columns 確定的一個存儲單元稱為 Cell。每個 Cell 都保存着同一份數據的多個版本。 版本通過時間戳來索引,時間戳的類型是 64 位整型。時間戳可以由HBase(在數據寫入時自動)賦值,
此時時間戳是精確到毫秒的當前系統時間。時間戳也 可以由客戶顯示賦值。如果應用程序要避免數據版本沖突,就必須自己生成具有唯一性的時間戳。每個 Cell 中,不同版本的數據按照時間倒序排序,即最新的數據排在最前面。
為了避免數據存在過多版本造成的管理(包括存儲和索引)負擔,HBase 提供了兩種數據版本回收方式。 一是保存數據的最后 n 個版本,二是保存最近一段時間內的版本(比如最近七天)。用戶可以針對每個列族進行設置。
Cell
Cell 是由 {row key,column(=< family> + < label>),version} 唯一確定的單元。Cell 中的數據是沒有類型的,全部是字節碼形式存儲。
HBase物理存儲
Table 在行的方向上分割為多個HRegion,每個HRegion分散在不同的RegionServer中。
每個HRegion由多個Store構成,每個Store由一個memStore和0或多個StoreFile組成,每個Store保存一個Columns Family
StoreFile以HFile格式保存在HDFS上。HFile的格式為:
Trailer部分的格式:
HFile分為六個部分:
- Data Block 段–保存表中的數據,這部分可以被壓縮
- Meta Block 段 (可選的)–保存用戶自定義的kv對,可以被壓縮。
- File Info 段–Hfile的元信息,不被壓縮,用戶也可以在這一部分添加自己的元信息。
- Data Block Index 段–Data Block的索引。每條索引的key是被索引的block的第一條記錄的key。
- Meta Block Index段 (可選的)–Meta Block的索引。
- Trailer–這一段是定長的。保存了每一段的偏移量,讀取一個HFile時,會首先 讀取Trailer,Trailer保存了每個段的起始位置(段的Magic Number用來做安全check),然后,DataBlock Index會被讀取到內存中,這樣,當檢索某個key時,不需要掃描整個HFile,而只需從內存中找到key所在的block,通過一次磁盤io將整個 block讀取到內存中,再找到需要的key。DataBlock Index采用LRU機制淘汰。
HFile的Data Block,Meta Block通常采用壓縮方式存儲,壓縮之后可以大大減少網絡IO和磁盤IO,隨之而來的開銷當然是需要花費cpu進行壓縮和解壓縮。目標HFile的壓縮支持兩種方式:Gzip,Lzo。
HLog(WAL log)
WAL 意為Write ahead log(http://en.wikipedia.org/wiki/Write-ahead_logging),類似mysql中的binlog,用來 做災難恢復只用,Hlog記錄數據的所有變更,一旦數據修改,就可以從log中進行恢復。
每個Region Server維護一個Hlog,而不是每個Region一個。這樣不同region(來自不同table)的日志會混在一起,這樣做的目的是不斷追加單個 文件相對於同時寫多個文件而言,可以減少磁盤尋址次數,因此可以提高對table的寫性能。帶來的麻煩是,如果一台region server下線,為了恢復其上的region,需要將region server上的log進行拆分,然后分發到其它region server上進行恢復。
HLog文件就是一個普通的Hadoop Sequence File,Sequence File 的Key是HLogKey對象,HLogKey中記錄了寫入數據的歸屬信息,除了table和region名字外,同時還包括 sequence number和timestamp,timestamp是”寫入時間”,sequence number的起始值為0,或者是最近一次存入文件系統中sequence number。HLog Sequece File的Value是HBase的KeyValue對象,即對應HFile中的KeyValue,可參見上文描述。