HBase是谷歌BigTble的開源實現。谷歌的三篇論文拉開了大數據江湖的序幕,鑄就了現在以Hadoop為主的大數據技術生態圈。而HBase是開源的大數據數據庫,和傳統的行式數據庫不同的是,HBase是列式數據庫。列式數據的特點是開源橫向擴展,將一張表的數據存儲在hadoop集群的不同datanode中,一張表的存儲量可以達到T級別。這是行式關系型數據庫無法實現的。本文主要講解HBase的基本概念,只有概念清楚了才能更好的在我們的系統中使用HBase。
核心組件介紹
Table:可理解為傳統數據庫中的一個表,但因為SchemaLess的設計,它較之傳統數據庫的表而言,在設計上更加靈活。
Region:將表橫向切割為一個個子表,子表在HBase中被稱之為Region。
RegionServer:數據服務進程,Region必須部署在某一個RegionServer上才可以提供讀寫服務。
HFile:HBase數據庫在底層分布式文件系統中的文件組織形式。
Column Family:一些列的集合。不同的Column Family數據被存儲在不同的路徑中。
MemStore:用來在內存中緩存一定大小的數據,達到設定的閾值后批量寫入到底層文件系統中。數據是有序的。
下圖清晰的展示了Table,Region,RegionServer,HFile,MemStore,Column Family在HBase的邏輯關系。
下圖顯示了HBase集群中的關鍵進程
Zookeeper:HBase集群的調度器,可以用於將HBase RegionServer信息注冊到zookeeper中,查詢HBase RegionServer狀態信息,HMaster啟動時會將HBase系統表-ROOT-加載到zookeeper集群中,通過zookeeper集群可以獲取當前系統表.META.的存儲所對應的RegionServer信息
。
Master,通過jps命令顯示的進程名稱是HMaster,在負責表管理操作,Region到各個RegionServer的分配以及RegionServer Failover的處理等。
RegionServer進程提供數據讀寫服務。
NameNode,Hadoop進程,處理來自Master的請求,H管理DFS文件系統的命名空間NameSpace。
DataNode,Hadoop數據節點進程,HBase的所有數據都存在Hadoop的DataNode中。
KeyValue數據存儲結構
HBase所存儲的數據是以KeyValue形式存放的,KeyValue有特定的數據結構,如下圖所示,一個KeyValue可以理解成HBase表中的一個列,當一行存在多個列時,將包含多個KeyValue,同一行的KeyValue有可能存儲在不同的文件中,但在讀取時,會按需合並在一起返回給客戶端。
用戶寫數據時,需要定義用戶數據的RowKey,指定每一列所存放的Column Family,並且為其定義相應的Qualifier(列名),Value部分存放用戶數據。Hbase中每一行可擁有不同的KeyValues,這就是HBase Schema-less的特點。
HBase中支持數據的多版本,通過帶有不同時間戳的多個KeyValue版本來實現的,如下圖所示。
HBase所保存的版本數據是可配置的,默認存放3個版本。在普通的讀取流程中,舊版本的數據時不可見的,但通過制定版本數或者版本號的讀取,可以獲取舊版本數據。下圖是普通讀取劉恆與多版本讀取流程的對比。
靈活的列定義
用戶數據存入到HBase表中時,需要進行Qualifier(KeyValue/列)設計。一個最簡單的設計是保持HBase的列與用戶數據的列一致,如下圖1的設計。這種設計,基本上與關系型數據庫的設計是一致的,但這種設計會帶來較大的數據冗余(KeyValue結構開銷)。但HBase基於KeyValue的接口,決定了這種設計可以是非常靈活的,例如,我們也可以考慮為HBase的每一行只設置兩個列,其中,Name為一個列,其他內容合並到一個列中,如下圖2所示。
盡管我們在使用HBase表存放數據的時候,需要預先做好列的設計。但這個設計僅僅由應用層感知,HBase並沒有存放任何的Schema信息來描述這個設計。也就是說,應用層需要知道為每一個表/每一行設計了什么樣的列(KeyValue),然后在地區的時候做相應的解析。既然HBase中並沒有Schema信息,name,每一行中的列,也可以是任意添加的。如下圖所示,綠色背景的KeyValue為后續增加的。
Column Family
假設為表設置了兩個列族,而且,定義了每一個列簇中要存放的列,如下圖所示:
{Name} -> Column Family - A, {City,Phone,Gender} -> Column Familly-B。不同列簇的數據會被存儲在不同的路徑中。即,設置多個列簇時一行數據可能存在於兩個路徑中。整行讀取的時候,需要將兩個路徑中的數據合並在一起蔡可以獲取完整的一行記錄。但如果僅僅讀取Name一列的話,只需要讀取Column Family-A即可。