1 HBase 淺析
1.1 HBase 是啥
HBase 是一款面向列存儲,用於存儲處理海量數據的 NoSQL 數據庫。它的理論原型是 Google 的 BigTable 論文。你可以認為 HBase 是一個高可靠性、高性能、面向列、可伸縮的分布式存儲系統。
HBase 的存儲是基於HDFS
的,HDFS 有着高容錯性的特點,被設計用來部署在低廉的硬件上,基於 Hadoop 意味着 HBase 與生俱來的超強的擴展性
和吞吐量
。
HBase 采用的時key/value
的存儲方式,這意味着,即使隨着數據量的增大,也幾乎不會導致查詢性能的下降。HBase 又是一個面向列
存儲的數據庫,當表的字段很多時,可以把其中幾個字段獨立出來放在一部分機器上,而另外幾個字段放到另一部分機器上,充分分散了負載的壓力。如此復雜的存儲結構和分布式的存儲方式,帶來的代價就是即便是存儲很少的數據,也不會很快。
HBase 並不是足夠快,只是數據量很大的時候慢的不明顯。HBase主要用在以下兩種情況:
- 單表數據量超過千萬,而且並發量很大。
- 數據分析需求較弱,或者不需要那么實時靈活。
1.2 HBase 的由來
我們知道 Mysql 是一個關系型數據庫,學數據庫的時第一個接觸的就是 MySQL 了。但是 MySQL 的性能瓶頸是很大的,一般單個table行數不宜超過500萬行,大小不宜超過2G。
我們以互聯網公司最核心用戶表為例,當數據量達到千萬甚至億級別時候,盡管你可以通過各種優化來提速查詢,但是對單條數據的檢索耗時還是會超出你的預期!看下這個User表:
假如查詢 id=1 這條數據對應的用戶name,系統會給我們返回aa。但由於MySQL是以行為位單位存儲的,當查 name 時卻需要查詢一整行的數據,連 age 和 email 也會被查出來!如果列非常多,那么查詢效率可想而知了。
我們稱列過多的表為寬表,優化方法一般就是對列進行豎直拆分
:
此時查找 name 時只需要查找 user_basic 表,沒有多余的字段,查詢效率就會很快。如果一張表的行過多
,會影響查詢效率,我們將這樣的表稱之為高表,可以采用水平拆表
的方式提高效率:
這種水平拆分應用比較多的 場景就是日志表
,日志信息每天產生很多,可以按月/按日
進行水平拆分,這樣就實現了高表變矮。
上述的拆分方式貌似可以解決寬表跟高表問題,但是如果有一天公司業務變更,比如原來沒有微信,現在需加入用戶的微信字段。這時候需要改變表的結構信息,該怎么辦?最簡單的想法是多加一列,像這樣:
但是你要知道不是所有用戶都要微信號的,微信號這一列是設置默認值還是采取其他的做法就得權衡一下了。如果需擴展很多列出來,但不是所有的用戶都有這些屬性,那么拓展起來就更加復雜了。這時可以用下JSON格式的字符串,將若干可選擇填寫信息匯總,而且屬性字段可以動態拓展,於是有了下邊做法:至此你可能認為這樣存儲數據它不挺好的嘛,用 HBase 出來干嘛?Mysql 有個致命缺點,就是當數據達到一定的閾值,無論怎么優化,它都無法達到高性能的發揮。而大數據領域的數據,動輒 PB 級數據量,這種存儲應用明顯是不能很好的滿足需求的!並且針對上邊的問題,HBase 都有很好的解決方案~~。
1.3 HBase 設計思路
接着上邊說到的幾個問題:高表、寬表、數據列動態擴展,把提到的幾個解決辦法:水平切分
、垂直切分
、列擴展方法
雜糅在一起。
有張表,你怕它又寬又高跟動態擴展列,那么在設計之初,就把這個表給拆開,為了列的動態拓展
,直接存儲JSON格式:這樣就解決了寬表跟列擴展問題,高表怎么辦呢?一個表按行切分成partition,各存一部分行:
解決了高表、寬表、動態擴展列 的問題后你會發現數據量大了速度不夠快咋辦?用緩存唄,查詢出的數據放緩存中,下次直接從緩存拿數據。插入數據怎么辦呢?也可以這樣理解,我把要插入的數據放進緩存中,再也不用管了,直接由數據庫從緩存拿數據插入到數據庫。此時程序不需要等待數據插入成功,提高了並行工作的效率。
你用緩存的考慮服務器宕機后緩存中數據沒來得及插入到數據庫中造成丟數據咋辦?參考 Redis 的持久化策略,可以插入數據這個操作添加一個操作日志,用於持久化插入操作,宕機重啟后從日志恢復。這樣設計架構就變成了這個樣子:這就是 HBase 實現的大致思路。接下來正式進入 HBase 設計解析。
2 Hbase 簡介
Hbase 官網:http://hbase.apache.org
2.1 HBase 特點
- 海量存儲
HBase適合存儲 PB 級別的海量數據,能在幾十到百毫秒內返回數據。
- 列式存儲
HBase是根據
列族
來存儲數據的。列族下面可以有非常多的列,在創建表的時候列族就必須指定。
- 高並發
在並發的情況下,HBase的單個IO延遲下降並不多,能獲得高並發、低延遲的服務。
- 稀疏性
HBase的列具有靈活性,在列族中,你可以指定任意多的列,在列數據為空的情況下,是不會占用存儲空間的。
- 極易擴展
- 基於 RegionServer 的擴展,通過橫向添加 RegionSever 的機器,進行水平擴展,提升 HBase 上層的處理能力,提升HBase服務更多 Region 的能力。
- 基於存儲的擴展(HDFS)。
2.2 HBase 邏輯結構
邏輯思維層面 HBase的存儲模型如下:
- Table(表):
表由一個或者多個
列族
構成。數據的屬性如name、age、TTL(超時時間)等都在列族里邊定義。定義完列族的表是個空表,只有添加了數據行以后,表才有數據。
- Column (列):
HBase 中的每個列都由 Column Family(列族) 和 Column Qualifier(列限定符)進行限定,例如 info:name、info:age。建表時只需指明列族,而列限定符無需預先定義。
- Column Family(列族):
- 多個列
組合
成一個列族。建表時不用創建列,在 HBase 中列是可增減變化
的!唯一要確定的是列族
,表有幾個列族在開始創建時就定好的。表的很多屬性,比如數據過期時間、數據塊緩存以及是否使用壓縮等都是定義在列族上的。- HBase 會把相同列族的幾個列數據盡量放在同一台機器上。
- Row(行):
一行包含多個列,這些列通過列族來分類。行中的數據所屬的列族從該表所定義的列族中選取。由於HBase是一個面向列存儲的數據庫,所以一個
行中的數據可以分布在不同的服務器上
。
- RowKey(行鍵):
RowKey 類似 MySQL 中的主鍵,在 HBase 中 RowKey 必須有且 RowKey 是按照字典排序的,如果用戶不指定 RowKey 系統會自動生成不重復字符串。查詢數據時只能根據 RowKey 進行檢索,所以 Table 的 RowKey 設計十分重要。
- Region(區域):
- Region 就是若干行數據的集合。HBase 中的 Region 會根據數據量的大小動態分裂,Region是基於HDFS實現的,關於Region的存取操作都是調用HDFS客戶端完成的。同一個行鍵的 Region 不會被拆分到多個 Region 服務器上。
- Region 有一點像關系型數據的分區,數據存放在Region中,當然Region下面還有很多結構,確切來說數據存放在MemStore和HFile中。訪問HBase 時先去HBase 系統表查找定位這條記錄屬於哪個Region ,然后定位到這個Region 屬於哪個服務器,然后就到哪個服務器里面查找對應Region 中的數據。
- RegionServer:
RegionServer 就是存放Region的容器,直觀上說就是服務器上的一個服務。負責管理維護 Region。
2.3 HBase 物理存儲
以上只是一個基本的邏輯結構,底層的物理存儲結構才是重中之重的內容,看下圖
- NameSpace:
命名空間,類似關系型數據庫 DatabBase 概念,每個命名空間下有多個表。HBase有兩個自帶的命名空間,分別是
hbase
和default
,hbase 中存放的是 HBase 內置的表,default 表是用戶默認使用的命名空間。
- TimeStamp:
時間戳,用於標識數據的不同版本(version),每條數據寫入時如果不指定時間戳,系統會自動添加為其寫入 HBase 的時間。並且讀取數據的時候一般只拿出數據的Type符合,時間戳最新的數據。之所以按照Type取數據是因為HBase的底層
HDFS支持增刪查,但不支持改
。
- Cell:
單元格,由 {rowkey, column Family:column Qualifier, time Stamp} 唯一確定的單元。cell 中的數據是
沒有
類型的,全部是字節碼
形式存儲。
3 HBase 底層架構

3.1 Client
Client 包含了訪問 Hbase 的接口,另外 Client 還維護了對應的 cache 來加速 Hbase 的訪問,比如緩存元數據的信息。
3.2 Zookeeper
HBase 通過 Zookeeper 來做 Master 的高可用、RegionServer 的監控、元數據的入口以及集群配置的維護等工作。Zookeeper 職責如下:
- 通過Zoopkeeper來保證集群中只有1個Master 在運行,如果Master 發生異常會通過競爭機制產生新的Master 來提供服務。
- 通過 Zoopkeeper 來監控 RegionServer 的狀態,當RegionSevrer有異常的時候,通過回調的形式通知MasterRegionServer上下線的信息。
- 通過 Zoopkeeper 存儲元數據 hbase:meata 的統一入口地址。
3.3 Master
Master 在 HBase 中的地位比其他類型的集群弱很多!數據的讀寫操作與他沒有關系,它掛了之后,集群照樣運行。但是Master 也不能宕機太久,有很多必要的操作,比如創建表、修改列族配置等DDL跟Region的分割與合並都需要它的操作。
- 負責啟動的時候分配Region到具體的 RegionServer。
- 發現失效的 Region,並將失效的 Region 分配到正常的 RegionServer 上。
- 管理HRegion服務器的負載均衡,調整HRegion分布。
- 在HRegion分裂后,負責新HRegion的分配。
HBase 中可以啟動多個Master,通過 Zookeeper 的 Master Election 機制保證總有一個 Master 運行。
3.4 RegionServer
HregionServer 直接對接用戶的讀寫請求,是真正的干活的節點。它的功能概括如下:
- 管理Master為其分配的Region。
- 處理來自客戶端的讀寫請求。
- 負責和底層HDFS的交互,存儲數據到HDFS。
- 負責Region變大以后的拆分。
- 負責StoreFile的合並工作。
ZooKeeper 會監控 RegionServer 的上下線情況,當 ZK 發現某個 HRegionServer 宕機之后會通知 Master 進行失效備援。下線的 RegionServer 所負責的 Region 暫時停止對外提供服務,Master 會將該 RegionServer 所負責的 Region 轉移到其他 RegionServer 上,並且會對 下線RegionServer 上存在 MemStore 中還未持久化到磁盤中的數據由 WAL重播進行恢復。
3.5 WAL
WAL (Write-Ahead-Log) 預寫日志是 HBase 的 RegionServer 在處理數據插入和刪除的過程中用來記錄操作內容的一種日志。每次Put、Delete等一條記錄時,首先將其數據寫入到 RegionServer 對應的HLog文件中去。只有當WAL日志寫入成功的時候,客戶端才會被告訴提交數據成功。如果寫WAL失敗會告知客戶端提交失敗,這其實就是數據落地的過程。
WAL是保存在HDFS上的持久化文件。數據到達 Region 時先寫入WAL,然后被加載到MemStore中。這樣就算Region宕機了,操作沒來得及執行持久化,也可以再重啟的時候從WAL加載操作並執行。跟Redis的AOF類似。
- 在一個 RegionServer 上的所有 Region 都 共享一個 HLog,一次數據的提交先寫入WAL,寫入成功后,再寫入MenStore之中。當MenStore的值達到一定的時候,就會形成一個個StoreFile。
- WAL 默認是開啟 的,也可以手動關閉它,這樣增刪改操作會快一點。但是這樣做犧牲的是數據的安全性。如果不想關閉WAL,又不想每次都耗費那么大的資源,每次改動都調用HDFS客戶端,可以選擇 異步的方式寫入WAL(默認間隔1秒寫入)
- 如果你學過 Hadoop 中的 Shuffle(edits文件) 機制的就可以猜測到 HBase 中的 WAL 也是一個滾動的日志數據結構,一個WAL實例包含多個WAL文件,WAL被觸發滾動的條件如下。
- WAL的大小超過了一定的閾值。
- WAL文件所在的HDFS文件塊快要滿了。
- WAL歸檔和刪除。
3.5 Region
每一個 Region 都有起始 RowKey 和結束 RowKey,代表了存儲的Row的范圍。從大圖中可知一個Region有多個Store,一個Store就是對應一個列族的數據,Store 由 MemStore 和 HFile 組成的。
3.6 Store
Store 由 MemStore 跟 HFile 兩個重要的部分。
3.6.1 MemStore
每個 Store 都有一個 MemStore 實例,數據寫入到 WAL 之后就會被放入 MemStore 中。MemStore是內存的存儲對象,當 MemStore 的大小達到一個閥值(默認64MB)時,MemStore 會被 flush到文件,即生成一個快照。目前HBase 會有一個線程來負責MemStore 的flush操作。
3.6.2 StoreFile
MemStore 內存中的數據寫到文件后就是StoreFile,StoreFile底層是以 HFile 的格式保存。HBase以Store的大小來判斷是否需要切分Region。
3.6.3 HFile
在Store中有多個HFile,每次刷寫都會形成一個HFile文件落盤在HDFS上。HFile文件也會動態合並,它是數據存儲的實體。
這里提出一點疑問:操作到達Region時,數據進入HFile之前就已經被持久化到WAL了,而WAL就是在HDFS上的,為什么還要從WAL加載到MemStore中,再刷寫成HFile呢?
- 由於HDFS支持文件創建、追加、刪除,但不能修改!但對數據庫來說,數據的順序非常重要!
- 第一次WAL的持久化是為了保證數據的安全性,無序的。
- 再讀取到MemStore中,是為了排序后存儲。
- 所以MemStore的意義在於維持數據按照RowKey的字典序排列,而不是做一個緩存提高寫入效率。
3.7 HDFS
HDFS 為 HBase 提供最終的底層數據存儲服務,HBase 底層用HFile格式 (跟hadoop底層的數據存儲格式類似) 將數據存儲到HDFS中,同時為HBase提供高可用(Hlog存儲在HDFS)的支持,具體功能概括如下:
- 提供元數據和表數據的底層分布式存儲服務
- 數據多副本,保證的高可靠和高可用性
4 HBase 讀寫
在HBase集群中如果我們做 DML 操作是不需要關心 HMaster 的,只需要從 ZooKeeper 中獲得hbase:meta 數據地址,然后從RegionServer中增刪查數據即可。
4.1 HBase 寫流程

- Client 先訪問 zookeeper,訪問 /hbase/meta-region-server 獲取 hbase:meta 表位於哪個 Region Server。
- 訪問對應的 Region Server,獲取 hbase:meta 表,根據讀請求的 namespace:table/rowkey,查詢出目標數據位於哪個 Region Server 中的哪個 Region 中。並將該 table 的 Region 信息以及 meta 表的位置信息緩存在客戶端的 meta cache,方便下次訪問。
- 與目標 Region Server 進行通訊。
- 將數據順序寫入(追加)到 WAL。
- 將數據寫入對應的 MemStore,數據會在 MemStore 進行排序。
- 向客戶端發送 ack,此處可看到數據不是必須落盤的。
- 等達到 MemStore 的刷寫時機后,將數據刷寫到 HFile
- 在web頁面查看的時候會隨機的給每一個Region生成一個隨機編號。
4.2 HBase 讀流程

- Client 先訪問 ZooKeeper,獲取 hbase:meta 表位於哪個 Region Server。
- 訪問對應的 Region Server,獲取 hbase:meta 表,根據讀請求的 namespace:table/rowkey, 查詢出目標數據位於哪個 Region Server 中的哪個 Region 中。並將該 table 的 region 信息以 及 meta 表的位置信息緩存在客戶端的 meta cache,方便下次訪問。
- 與目標 Region Server 進行通訊。
- 分別在 Block Cache(讀緩存),MemStore 和 Store File(HFile)中查詢目標數據,並將 查到的所有數據進行合並。此處所有數據是指同一條數據的不同版本(time stamp)或者不同的類型(Put/Delete)。
- 將從文件HFile中查詢到的數據塊(Block,HFile 數據存儲單元,默認大小為 64KB)緩存到 Block Cache。
- 將合並后的最終結果,然后返回時間最新的數據返回給客戶端。
4.2.1 Block Cache
HBase 在實現中提供了兩種緩存結構 MemStore(寫緩存) 和 BlockCache(讀緩存)。寫緩存前面說過不再重復。
- HBase 會將一次文件查找的 Block塊 緩存到 Cache中,以便后續同一請求或者鄰近數據查找請求,可以直接從內存中獲取,避免昂貴的IO操作。
- BlockCache是Region Server級別的,
- 一個Region Server只有一個Block Cache,在 Region Server 啟動的時候完成 Block Cache 的初始化工作。
- HBase對Block Cache的管理分為如下三種。
- LRUBlockCache 是最初的實現方案,也是默認的實現方案,將所有數據都放入JVM Heap中,交給JVM進行管理。
- SlabCache 實現的是堆外內存存儲,不再由JVM管理數據內存。一般跟第一個組合使用,單它沒有改善 GC 弊端,引入了堆外內存利用率低。
- BucketCache 緩存淘汰不再由 JVM 管理 降低了Full GC 發生的頻率。
重點:
讀數據時
不要理解
為先從 MemStore 中讀取,讀不到再讀 BlockCache 中,還讀不到再從HFile中讀取,然后將數據寫入到 BlockCache 中。因為如果人為設置導致磁盤數據new,內存數據old。你讀取的時候會出錯的!
結論:
HBase 把磁盤跟內存數據一起讀,然后把磁盤數據放到 BlockCache中,BlockCache 是磁盤數據的緩存。HBase 是個讀比寫慢的工具。
4.3 HBase 為什么寫比讀快
- HBase 能提供實時計算服務主要原因是由其架構和底層的數據結構決定的,即由 LSM-Tree(Log-Structured Merge-Tree) + HTable(Region分區) + Cache決定的。
- HBase 寫入速度快是因為數據並不是真的立即落盤,而是先寫入內存,隨后異步刷入HFile。所以在客戶端看來,寫入速度很快。
- HBase 存儲到內存中的數據是有序的,內存數據刷寫到HFile時也是有序的。並且多個有序的HFile還會進行 歸並排序生成更大的有序HFile。性能測試發現順序讀寫磁盤速度比隨機讀寫磁盤快至少三個數量級!
- 讀取速度快是因為它使用了 LSM樹型結構,因為磁盤尋址耗時遠遠大於磁盤順序讀取的時間,HBase的架構設計導致我們可以將磁盤尋址次數控制在性能允許范圍內。
- LSM 樹原理把一棵大樹拆分成N棵小樹,它首先寫入內存中,隨着小樹越來越大,內存中的小樹會flush到磁盤中,磁盤中的樹定期可以做merge操作來合並成一棵大樹,以優化讀性能。
4.3.1查詢舉例
- 根據RowKey能快速找到行所在的Region,假設有10億條記錄,占空間1TB。分列成了500個Region,那讀取2G的記錄,就能找到對應記錄。
- 數據是按照列族存儲的,假設分為3個列族,每個列族就是666M, 如果要查詢的東西在其中1個列族上,1個列族包含1個或者多個 HStoreFile,假設一個HStoreFile是128M, 該列族包含5個HStoreFile在磁盤上. 剩下的在內存中。
- 內存跟磁盤中數據是排好序的,你要的記錄有可能在最前面,也有可能在最后面,假設在中間,我們只需遍歷2.5個HStoreFile共300M。
- 每個HStoreFile(HFile的封裝),是以鍵值對(KV)方式存儲,只要遍歷一個個數據塊中的key的位置,並判斷符合條件可以了。一般key是有限的長度,假設KV比是1:19,最終只需要15M就可獲取的對應的記錄,按照磁盤的訪問100M/S,只需0.15秒。加上Block Cache 會取得更高的效率。
- 大致理解讀寫思路后你會發現如果你在讀寫時設計的足夠巧妙當然讀寫速度快的很咯。
5 HBase Flush
5.1 Flush
對於用戶來說數據寫到 MemStore 中就算OK,但對於底層代碼來說只有數據刷到硬盤中才算徹底搞定了!因為數據是要寫入到WAL(Hlog)中再寫入到MemStore中的,flush有如下幾個時機。
- 當 WAL 文件的數量超過設定值時 Region 會按照時間順序依次進行刷寫,直到 WAL 文件數量小於設定值。
- 當Region Server 中 MemStore 的總大小達到堆內存40%時,Region 會按照其所有 MemStore 的大小順序(由大到小)依次進行阻塞刷寫。直到Region Server中所有 MemStore 的總大小減小到上述值以下。當阻塞刷寫到上個參數的0.95倍時,客戶端可以繼續寫。
- 當某個 MemStore 的大小達到了128M時,其所在 Region 的所有 MemStore 都會阻塞刷寫。
- 到達自動刷寫的時間也會觸發 MemStore 的 flush。自動刷新的時間間隔默認1小時。
5.2 StoreFile Compaction
由於 MemStore 每次刷寫都會生成一個新的 HFile,且同一個字段的不同版本(timestamp) 和不同類型(Put/Delete)有可能會分布在不同的 HFile 中,因此查詢時需要遍歷所有的 HFile。為了減少 HFile 的個數跟清理掉過期和刪除的數據,會進行 StoreFile Compaction。
Compaction 分為兩種,分別是 Minor Compaction 和 Major Compaction。
- Minor Compaction會將臨近的若干個較小的 HFile 合並成一個較大的 HFile,但不會清理過期和刪除的數據。
- Major Compaction 會將一個 Store 下的所有的 HFile 合並成一個大 HFile,並且會清理掉過期和刪除的數據。

5.3 Region Split
每個 Table 起初只有一個 Region,隨着不斷寫數據 Region 會自動進行拆分。剛拆分時,兩個子 Region 都位於當前的 Region Server,但出於負載均衡的考慮, HMaster 有可能會將某個 Region 轉移給其他的 Region Server。
Region Split 時機:
- 0.94 版本之前:
當 1 個 Region 中的某個 Store 下所有 StoreFile 的總大小超過 hbase.hregion.max.filesize(默認10G), 該 Region 就會進行拆分。
- 0.94 版本之后:
當 1 個 Region 中的某個 Store 下所有 StoreFile 的總大小超過 Min(R^2 * “hbase.hregion.memstore.flush.size=128M”,hbase.hregion.max.filesize"),該 Region 就會進行拆分,其 中 R 為當前 Region Server 中屬於該 Table 的個數。
舉例:
- 第一次的閾值是128,切分后結果64 , 64。
- 第二次閾值512M,64,512 ⇒ 54 + 256 + 256
- 最后會形成一個 64M…10G 的這樣Region隊列,會產生數據傾斜問題。
- 解決方法: 提前做好Region組的規划,0-1k,1k-2k,2k-3k這樣的。
官方不建議用多個列族,比如有CF1,CF2,CF3,但是 CF1數據很多而CF2跟CF3數據很少,那么當觸發了region切分的時候,會把CF2跟CF3分成若干小份,不利於系統維護。
6 HBase 常見面試題
6.1 Hbase 中 RowKey 的設計原則
- RowKey 長度原則
二進制碼流RowKey 最大長度 64Kb,實際應用中一般為 10-100bytes,以 byte[] 形式保存,一般設計定長。建議越短越好,因為HFile是按照KV存儲的Key太大浪費空間。
- RowKey 散列原則
RowKey 在設計時候要盡可能的實現可以將數據均衡的分布在每個 RegionServer 上。
- RowKey 唯一原則
RowKey 必須在設計上保證其唯一性,RowKey 是按照字典順序排序存儲的,因此設計 RowKey 時可以將將經常讀取的數據存儲到一塊。
6.2 HBase 在大數據體系位置
其實就簡單的把HBase當成大數據體系下的DataBase來用就行,任何可以分析HBase的引擎比如MR、Hive、Spark等框架連接上HBase都可以實現控制。比如你可以把Hive跟HBase進行關聯,Hive中數據不再由HDFS存儲而是存儲到HBase中,並且關聯后Hive中添加數據在HBase中可看到,HBase中添加數據Hive也可看到。
6.3 HBase 優化方法
6.3.1 減少調整
HBase中有幾個內容會動態調整,如Region(分區)、HFile。通過一些方法可以減少這些會帶來I/O開銷的調整。
- Region
沒有預建分區的話,隨着Region中條數的增加,Region會進行分裂,這將增加I/O開銷,所以解決方法就是根據你的RowKey設計來進行預建分區,減少Region的動態分裂。
- HFile
MemStore執行flush會生成HFile,同時HFilewe年過多時候也會進行Merge, 為了減少這樣的無謂的I/O開銷,建議估計項目數據量大小,給HFile設定一個合適的值。
6.3.2 減少啟停
數據庫事務機制就是為了更好地實現批量寫入,較少數據庫的開啟關閉帶來的開銷,那么HBase中也存在頻繁開啟關閉帶來的問題。
- 關閉 Compaction。
HBase 中自動化的Minor Compaction和Major Compaction會帶來極大的I/O開銷,為了避免這種不受控制的意外發生,建議關閉自動Compaction,在閑時進行compaction。
6.3.3 減少數據量
- 開啟過濾,提高查詢速度
開啟BloomFilter,BloomFilter是列族級別的過濾,在生成一個StoreFile同時會生成一個MetaBlock,用於查詢時過濾數據
- 使用壓縮
一般推薦使用Snappy和LZO壓縮
6.3.4 合理設計
HBase 表格中 RowKey 和 ColumnFamily 的設計是非常重要,好的設計能夠提高性能和保證數據的准確性。
- RowKey設計
- 散列性:散列性能夠保證相同相似的RowKey聚合,相異的RowKey分散,有利於查詢
- 簡短性:RowKey作為key的一部分存儲在HFile中,如果為了可讀性將rowKey設計得過長,那么將會增加存儲壓力.
- 唯一性:rowKey必須具備明顯的區別性。
- 業務性:具體情況具體分析。
- 列族的設計
- 優勢:HBase中數據是按列進行存儲的,那么查詢某一列族的某一列時就不需要全盤掃描,只需要掃描某一列族,減少了讀I/O。
- 劣勢:多列族意味這一個Region有多個Store,一個Store就有一個MemStore,當MemStore進行flush時,屬於同一個Region的Store中的MemStore都會進行flush,增加I/O開銷。
6.4 HBase 跟關系型數據庫區別
指標 | 傳統關系數據庫 | HBase |
---|---|---|
數據類型 | 有豐富的數據類型 | 字符串 |
數據操作 | 豐富操作,復雜聯表查詢 | 簡單CRUD |
存儲模式 | 基於行存儲 | 基於列存儲 |
數據索引 | 復雜的多個索引 | 只有RowKey索引 |
數據維護 | 新覆蓋舊 | 多版本 |
可伸縮性 | 難實現橫向擴展 | 性能動態伸縮 |
6.5 HBase 批量導入
- 通過 HBase API進行批量寫入數據。
- 使用 Sqoop工具批量導數到HBase集群。
- 使用 MapReduce 批量導入。
- HBase BulkLoad的方式。
- HBase 通過 Hive 關聯導入數據。
大數據導入用 HBase API 跟 MapReduce 寫入效率會很低,因為請求RegionServer 將數據寫入,這期間數據會先寫入 WAL 跟 MemStore,MemStore 達到閾值后會刷寫到磁盤生成 HFile文件,HFile文件過多時會發生Compaction,如果Region大小過大時也會發生Split。
BulkLoad 適合初次數據導入,以及HBase與Hadoop為同一集群。BulkLoad 是使用 MapReduce 直接生成 HFile 格式文件后,Region Servers 再將 HFile 文件移動到相應的Region目錄下。
7 參考
- BlockCache講解:https://blog.51cto.com/12445535/2363376?source=dra
- LSM 原理:https://www.zhihu.com/question/19887265
- HBase教程:http://c.biancheng.net/view/6499.html
原文:https://my.oschina.net/u/4511602/blog/4916109