前面的文章初入Hadoop生態系統裏面有涉及到Hbase的一些特色和數據模型,這裏來着重談談Hbase和其中的一些設計策略。git
回顧
Hbase是一個分佈式的面向列的開源數據庫 rowKey決定Region(區域),columnFamily(列族)決定HFile,而且因爲Hbase的多版本性,不一樣的HFile也有不一樣的Timestamp區間,因此在查詢時,指定columnFamily將大大提升查詢效率,由於決定了讀取的HFile個數,若是指定Timestamp也能夠進一步對HFile進行過濾。 HFile是Hbase中key-value數據的存儲格式。github
Hbase的實現包括三個主要功能組件redis
庫函數:
連接到每一個客戶端。數據庫
一個Master主服務器:
主要負責均衡。 管理用戶對Table的增刪改查等操做
管理RegionServer的負載均衡,調整Region分佈
在Region Split後負責新的Region的分配 RegionServer停機後,負責失效RegionServer上的Region遷移緩存
多個Region服務器:
負責存儲和維護分配給本身的Region,處理客戶端的讀寫。性能優化
客戶端不須要經過Master,直接經過Zookeeper來得到Region位置信息,而後直接從Region服務器獲取數據,這種設計方式使得Master負載小。服務器
Region開始只有一個,後面不斷分裂、拆分很是快,緣由是拆分時只須要修改指向配置,直到後臺啓動合併過程把存儲文件異步寫到獨立文件以後,纔會讀取新文件。是由Master來完成。網絡
Hbase架構 架構
客戶端讀寫數據的過程
用戶寫入數據時,被分配到相應Region服務器去執行,首先先寫入到Memstore和HLog中,只有寫入到HLog以後commit()調用纔會將其返回給客戶端。 用戶取數據時,Region服務器會首先訪問Memstore緩存,若是找不到,再取磁盤上面的StoreFile中尋找。負載均衡
緩存的刷新
系統週期性把Memstore緩存裏的內容寫到磁盤的StoreFile文件中,清空緩存,並在HLog裏面寫入一個標記,每次刷新都生產新的StoreFile文件,每一個Store包含多個StoreFile文件。 每一個Region服務器都有一個本身的HLog文件,每次啓動都檢查文件,肯定最新操做,如發生更新,先寫入Memstore,再刷寫到StoreFile,最後刪除舊的HLog文件,開始爲用戶提供服務。
StoreFile的合併
每次刷寫都生成一個新的StoreFile,數量太多影響查找速度,調用Store.compact()把多個合併成一個,合併操做比較耗費資源,只有數量達到一個閥值才啓動合併。
Store
Store是Region服務器的核心,多個StoreFile合併成一個,單個StoreFile過大時又觸發分裂操做。
HLog
分佈式環境必需要考慮系統出錯,Hbase採用HLog保證系統恢復,每一個Region服務器配置一個,共享日誌的優勢可以提升對錶的寫操做性能,缺點是恢復時須要拆分日誌。
BlockCache
HBase中最小的數據存儲單元Block,默認爲64K,BlockCache也稱爲讀緩存,HBase會將一次文件查找的Block塊緩存到Cache中,以便後續同一請求或者鄰近數據查找請求直接從內存中獲取,避免昂貴的IO操做。 BlockCache有兩種實現機制:LRUBlockCache(基於LRU作了分層設計)和BucketCache
數據恢復
Zookeeper實時監測每一個Region服務器的狀態,當某個發生故障時,Zookeeper會通知Master,Master首先處理該故障Region服務器上面遺留的HLog文件,這個文件包含了來自多個Region對象的日誌記錄,系統會根據每條日誌記錄所屬的Region對象對HLog數據進行拆分,放到相應Region對象的目錄下,再將失效的Region從新分配到可用的Region服務器中,並將該Region相關日誌記錄HLog也發送給相應的Region服務器,Region服務器領取到分配的Region與之相關的HLog日誌記錄後會從新作一遍日誌記錄中的各類操做寫入MemStore緩存,刷新到StoreFile文件中,完成數據恢復。
Hbase中特殊的兩張Table
-ROOT-:
記錄.META.表的Region信息,只有一個區域(Region).META.:
記錄用戶表的Region信息,能夠有多個區域(Region)目前Region最佳大小建議1GB-2GB,每一個Region服務10-1000個Region。
客戶端與Hbase交互步驟
屢次的網絡操做,客戶端會作Cache緩存,加速尋址,如圖:
表的設計
Hbase主要有兩種表設計風格
Flat-Wide表:
一行中有不少列 hbase只能在行的邊界作split,因此行不可拆分,因此設計細節在於列族。Tall-Narrow表:
列不多,行不少 原子性更弱,由於全部數據不在同一行,因此設計的細節在於行。若是查詢模式以scan(掃描)爲主能夠把表設計成Tall-Narrow類型,若是查詢模式以get爲主能夠把表設計成Flat-Wide類型
scan:
掃描整表,如上所述,若是是Tall-Narrow表,能夠考慮在rowkey的設計上考慮,由於scan是能夠模糊匹配的。 get:
獲取數據,若是是Flat-Wide類型,獲取的數據基本上是根據列族來分類的,get能夠指定到某個列族以及還能夠細化到Timestamp。
行的設計
由於Hbase只能在行鍵上創建索引,行鍵結構很重要,因此應該基於預期的訪問模式來爲行鍵建模。Hbase表是有序特性,行鍵是按照字典序存儲的,因此基於IO的考慮在設計的時候從兩個方面入手
爲寫優化:
犧牲讀模式的效率,把數據分散到多個Region上,在大量數據寫入的時候,就不會致使像使用時間戳作行鍵那樣遭遇單個Region的熱點問題。
散列:使用MD5等提供隨機分佈的散列函數。
salting:時間戳前面加上一個隨機數前綴,能夠用RegionServer的數量取模來生產隨機salt數。(salt方法,就是加點「佐料」)
爲讀優化:
可使用倒序時間戳(long.Max_value-時間戳),而後附上用戶ID來構成行鍵,這樣就能夠基於用戶ID掃描N行就能找到用戶須要的n條最新信息了。
列族的設計
列族儘可能少:
最好不超過三個,每一個列族存在一個獨立的HFile裏,flush和compaction操做都是針對一個Region進行的,當數據不少的列族須要flush的時候,其它列族即便數據不多也須要flush,這樣就產生大量沒必要要的io操做。
flush,compaction主要起的幾個做用是: 合併文件--清除過時多餘版本的數據--提升讀寫效率。
多列族時:
注意各列族數據的數量級要一致,若是相差太大,會使數量級少的列族的數據掃描效率低。
針對查詢:
將常常查詢和不常常查詢的數據放在不一樣的列族,根據實際狀況來劃分,也體現Hbase的反規範化。
取名:
儘量短,列族和列的名字會存在Hbase的每一個cell中。 cell:經過row和columns肯定的爲一個存儲單元稱爲cell。每一個cell都保存着同一份數據的多個版本。版本經過時間戳來索引。時間戳的類型是64位整型。
性能優化
前面有提到關於針對表、行、列族的設計優化規範,下面講講一些其它設計的優化方式;
In Memory:
建表時,經過HColumnDescriptor.setInMemory(true)將表放到RegionServer的緩存中,保證在讀取的時候被cache命中。Max Version:
建表時,經過HColumnDescriptor.setMaxVersions(int maxVersions)設置表中數據的最大版本,若是隻須要保存最新版本的數據,那麼能夠設置setMaxVersions(1)。Time To Live:
建表時,經過HColumnDescriptor.setTimeToLive(int timeToLive)設置表中數據的存儲生命期,過時數據將自動被刪除。關於其它的一些配置性能調優的方式建議查看相關文案結合實際狀況來設置,這裏就不一一闡述了。
性能監控(工具)
Hbase上構建SQL引擎
構建Hbase二級緩存
hbase只有一個針對行鍵的索引,訪問只有三種方式;
可使用其它產品爲Hbase行鍵提供索引功能,來提升查詢的效率。
經常使用集羣配置
Hbase生產集羣不該該少於10個節點
小型生產集羣(10-20臺服務器)
一個HbaseMaster,一個Zookeeper就能夠了,而且能夠部署在一塊
中型(50臺如下)
把NameNode和JobTracker分開部署到不一樣的機器,建議部署3個Master,3個Zookeeper
大型(50臺以上)
5個Zookeeper,其它和中型方式相同