前言
前面的文章初入Hadoop生態系統裡面有涉及到Hbase的一些特點和資料模型,這裡來著重談談Hbase和其中的一些設計策略。
回顧
Hbase是一個分散式的面向列的開源資料庫
rowKey決定Region(區域),columnFamily(列族)決定HFile,並且由於Hbase的多版本性,不同的HFile也有不同的Timestamp區間,所以在查詢時,指定columnFamily將大大提高查詢效率,因為決定了讀取的HFile個數,如果指定Timestamp也可以進一步對HFile進行過濾。
HFile是Hbase中key-value資料的儲存格式。
Hbase的實現包括三個主要功能元件
-
庫函式:
連結到每個客戶端。 -
一個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)設定表中資料的儲存生命期,過期資料將自動被刪除。
關於其它的一些配置效能調優的方式建議檢視相關文案結合實際情況來設定,這裡就不一一闡述了。
效能監控(工具)
- Master Status(自帶):服務埠預設是60010
- Ganglia:是UC Berkeley發起的一個開源叢集監視專案,用於監控系統效能
- OpenTSDB:可以從大規模叢集中獲取相應的metrics(metric就是1個監控項,譬如伺服器的話,會有CPU使用率、記憶體使用率這些metric)並進行儲存、索引及服務
- Ambari:作用就是建立、管理、監視Hadoop叢集
Hbase上構建SQL引擎
- 使用Hive整合HBase,利用兩者對外的API介面互相通訊,注意版本一致性
- Phoenix,由saleforce開源的一個專案,構建在HBase上的一個SQL層,能讓我們用標準的JDBC APIs而不是HBase客戶端APIs來建立表,插入資料和對HBase資料進行查詢。
構建Hbase二級快取
hbase只有一個針對行鍵的索引,訪問只有三種方式;
- 通過單個行鍵訪問
- 通過一個行鍵的區間來訪問(前面說的Rowkey模糊匹配)
- 全表掃描
可以使用其它產品為Hbase行鍵提供索引功能,來提高查詢的效率。
- Redis:redis做客戶端快取,將索引實時更新到redis中,定時更新索引到Hbase的表中
- solr:solr中儲存索引
- Hindex:華為公司研發的,特性是多個表索引、多個列索引、基於部分列值索引
- Coprocessor:Hbase0.92版本之後引入的特性,提供了兩個實現
- Endpoint Coprocessor:相當於關係型資料庫的儲存過程
- Observer Coprocessors:相當於觸發器,Observer允許在記錄put前後做一些處理,因此可以在插入資料時同步寫入索引表,缺點是每插入一條需要向索引表插入資料,因此耗時雙倍,叢集壓力也是雙倍
常用叢集配置
Hbase生產叢集不應該少於10個節點
小型生產叢集(10-20臺伺服器)
一個HbaseMaster,一個Zookeeper就可以了,並且可以部署在一塊
中型(50臺以下)
把NameNode和JobTracker分開部署到不同的機器,建議部署3個Master,3個Zookeeper
大型(50臺以上)
5個Zookeeper,其它和中型方式相同