重點:HBase的基本數據模型、拓撲結構、部署配置方法,並介紹通過命令行和編程方式使用HBase的基本方法。
HBase:一種列存儲模式與鍵值對相結合的NoSQL軟件,但更多的是使用列存儲模式,底層的數據文件采用HDFS存儲,其文件結構和元數據等由自身維護.
HBase是Hadoop的重要成員,提供了分布式數據表和更高效的數據查詢能力,彌補了HDFS只能進行文件管理以及MapReduce不適合完成實時任務的缺陷.
HBase利用HDFS實現數據分布式存儲,數據分塊以及多副本等,HBase在此基礎上實現了對記錄的更新和刪除.Hbase具有靈活的數據模型,不僅可以基於鍵進行快速查詢,還可以實現基於值、列名等的全文遍歷和檢索。
1、HBase概述
HBase的優點:
- 采用面向列加鍵值對的存儲模式
- 可以實現便捷的橫向擴展,對於元數據管理能力的擴展,可以通過數據分片的方式進行.
- 可以實現自動的數據分片.
- 可以實現嚴格的讀寫一致性和自動的故障轉移
- 可以實現對全文的檢索與過濾
- 支持通過命令行或者java/python等語言來進行操作
HIVE與HBase之間的關系,屬於協作關系:
- 通過ETL工具將數據源抽取到HDFS存儲;
- 通過Hive清洗、處理和計算原始數據;
- HIve清洗處理后的結果,如果是面向海量數據隨機查詢場景的可存入Hbase
- 數據應用從HBase查詢數據;
HIVE |
HBASE |
HIVE數據倉庫:Hive本質將HDFS中已經存儲的文件在Mysql中做了一個雙射關系,以方便使用HQL去管理查詢。(主要用於解決數據處理和計算問題) |
HBASE數據庫:一種面向列存儲的非關系型數據庫(主要用於解決實時數據查詢問題) |
HIVE用於數據分析、清洗:HIVE是適用於離線的數據分析和清洗,延遲較高. |
HBASE用於存儲結構化和非結構化的數據;HBASE適應於單表非關系型數據的存儲,不適合做關聯查詢,類似JOIN等操作。比如:日志明細、交易清單、軌跡行為。 |
HIVE基於HDFS、MapReduce:HIVE存儲的數據依舊在DataNode上,編寫的HQL語句終將是轉換為MapReduce代碼執行 |
HBASE基於HDFS:數據持久化存儲的體現形式是Hfile,存放於DataNode中,被RegionServer以region的形式進行管理。 |
延遲較低,接入在線業務使用:面對大量的企業數據,HBase可以直線單表大量數據的存儲,同時提供了高效的數據訪問數據。 |
2、HBase的數據結構模型
HBase邏輯數據模型:
HBase物理存儲方式,其中StuInfo列族的物理存儲方式:
HBase采用的是一種面向列的鍵值對存儲模式。
表4-1中有2行記錄,行鍵:001和002,其他所有信息均可以看做是行內記錄的字段,或者列。
表中有2個列族(Column Family),列族的名字必是可顯示的字符串。每個列族中含有若干列(Columns)。列族可以看做HBase表結構(Schema)的一部分,需要在建表時預先定義。
//eg,創建表:create'表名','列族名1', '列族名2', '列族名N' create 'table_test001','basic','test001'
對於面向列的存儲模式,列則不屬於表結構,HBase不會預先定義列名及其數據類型和值域等內容。每一條記錄中的每個字段必須記錄自己的列名(也稱列標識符,Column qualifier)以及值(Value)的時間戳(Timestamp)。
這和關系型數據庫有很大的不同,在關系型數據庫中,表結構(Schema)是獨立存儲的。在關系型數據庫中可能會采用以下方式進行記錄:
Hbase並不需要預先設計列的結構,當添加新的列時,只需要在新記錄中記錄這個列名即可,不會對已有的數據產生任何影響。由於Hbase每條記錄都記錄了自己的列名,如果某一行數據不存在某個列,則不會記錄該鍵值對。因此HBase不需要對不存在的數據項記錄null值,使HBase可以支持數以萬計的列名,且並不會在數據稀疏的情況下為NULL值消耗存儲空間。
//eg,新增或修改表的值(數據):put ‘表名’, ‘行鍵’, ‘列族名’, ‘列值’或者 put ‘表名’, ‘行鍵’, ‘列族名:列名’, ‘列值’ put 'table_test001','001','basic','Micheal Jordan',1 put 'table_test001','001','basic:firstname','Kobe'
HBase中其中一個列族basic,列族basic的實際存儲方式:
邏輯上的兩行數據,在實際上被保存為8個鍵值對,或稱為單元格(cell)。單元格是由行鍵、列名、值和時間戳來確定的最小存儲單元。
鍵值對的實際存儲方式:
每一行數據,或者說每一個鍵值對包含了行鍵(Row)、列族名稱(Column Family)和列標識符(Column Qualifier),即列名、時間戳、行鍵類型(Key Type)與值(Value)。
鍵值對結構以兩個固定長度的數值開始,分別表示 Key 的長度和 Value 的長度。緊接着是 Key,Key 以 RowLength 開始,是固定長度的數值,表示 RowKey 的長度;接着是 Row,然后是固定長度的數值 ColumnFamilyLength,表示 Family 的長度;之后是 Family 列族,接着是 Qualifier 列標識符,Key 最后以兩個固定長度的數值 TimeStamp 和 Key Type(Put/Delete) 結束。Value部分沒有這么復雜的結構,就是純粹的二進制數據。
eg:
1)Name Space
命名空間,類似於關系型數據庫的database概念,每個命名空間下有多個表,HBASE有兩個自帶的命名空間,分別是HBASE和default,HBASE中存放的是HBASE內置的表(系統內建表,包含namespace和meta表:存的是用戶表或系統表位置信息),default表是用戶默認的使用的命名空間(用戶建表時未指定namespace的表都創建在此)。
HBase中的數據以表的形式存儲。表名作為HDFS存儲路徑的一部分來使用,在HDFS中可以看到每個表名都作為獨立的目錄結構。
2)Region(表的切片)
Hbase 表的分片,HBase 表會根據 RowKey值被切分成不同的 region 存儲在 RegionServer 中,在一個 RegionServer 中可以有多個不同的 region。
3)行(Row)
在HBase表里,每一行數據代表一個數據對象,每一行都有一個行鍵(Row Key)來進行唯一標識[不可分割的字節數組,且按照字典排序[ASCII碼]由低到高存儲],每一行都有一個rowkey和多個column(列)組成。在HBase中針對行鍵建立索引,提高檢索數據的速度。
scan '表名' //掃描某個列族 scan '表名', {COLUMN=>'列族名'} //掃描某個列族的某個列 scan '表名', {COLUMN=>'列族名:列名'} //查詢同一個列族的多個列 scan '表名', {COLUMNS => [ '列族名1:列名1', 列'族名1:列名2', …]}
4)Column
HBASE中的每個列都由column family(列族)和column qualifier(列限定符)進行限定,例如info:name,info:age。建表時,只需指明列族,而列限定符無需預先定義。列族是列的集合,列族中所有列成員有相同的前綴,列族的名字必須是可顯示的字符串。
5)Store
每一個region有一個或多個store組成,至少是一個store,hbase會把一起訪問的數據放在一個store里面,即為每個ColumnFamily建一個store(即有幾個ColumnFamily,也就有幾個Store)。一個Store由一個memStore、0或多個StoreFile組成。
6)Time Stamp(時間戳)
用於標識數據的不同版本(version),每條數據寫入時,如果不指定時間戳,系統會自動為其加上該字段,其值為寫入HBASE的時間。
7)Cell(單元格)
由{rowkey,column family:column qualifier,time stamp}唯一確定的單元,cell中的數據沒有類型的,全部是字節碼形式存儲。
3、HBase的拓撲結構
HBase采用了主從式的拓撲結構。其主要組件包括一個主節點和若干個從節點(稱為Reginsonserver或Hregionserver)。這里的主從節點都是服務器節點。HBase還需要借助Zookeeper集群來實現節點監控和容錯。
1個Region Server 包含多個Region,每個Region里面包含一個或多個store(存儲的實際數據)。
regionserver的作用:
- 數據的增刪改查
- region的切分和合並,即使master掛掉也不影響查詢數據。
hbase依賴於zookeeper,master的作用:表的增刪改查、管理regionserver。
HBASE底層依賴於hdfs,還依賴於zookeeper,hbasemaster(管理ddl操作)會將某一部分工作交給zookeeper(zookeeper分擔hbasemaster與client的交互,client從zookeeper中獲取表region相關信息)。Regionserver(管理dml操作)維護一個個region,多個HRegion共享HLog(預寫入日志,防止內存中數據丟失,用來做災難恢復)。每一個region里面包含一個或多個store(邏輯上是表的列族,store存儲上是分離的,實際數據存儲在Men store(內存)和store file(磁盤)里面),每個store包含與其對應的MemStore以及一個或多個StoreFile (到達刷寫條件后,從內存到磁盤會刷寫數據,刷寫后就會生成一個store file),hfile是一種文件格式,最后store file 和hlog都要通過hdfs client 交互存到hdfs。
1.Client
Client 包含了訪問 Hbase 的接口,另外 Client 還維護了對應的 cache 來加速 Hbase 的訪問,比如 cache 的.META.元數據的信息。
2.Zookeeper
HBase 通過 Zookeeper 來做 master 的高可用、RegionServer 的監控、元數據的入口以及 集群配置的維護等工作。
具體工作如下:
- 通過 Zoopkeeper 來保證集群中只有 1 個 master 在運行,如果 master 異常,會通過競爭機制產生新的master提供服務
- 通過 Zoopkeeper 來監控 RegionServer 的狀態,當 RegionSevrer 有異常的時候,通過回調的形式通知 Master RegionServer 上下線的信息
- 通過 Zoopkeeper 存儲元數據的統一入口地址
3.HMaster
HMaster的主要功能有:(分配region、管理regionserver)
- 為RegionServer分配Region
- 監控到region失效,並將失效的region分配到正常的regionserver上
- 維護整個集群(HRegionServer)的負載均衡。
- 維護集群的元數據信息
- 當regionserver失效,協調對應的Hlog拆分
注:HMaster沒有單點問題,HBase中可以啟動多個HMaster,通過Zookeeper的Master Election機制保證總有一個Master運行。
4.HRegionServer(維護Hregion處理請求、拆分Hregion)
HregionServer的主要作用:直接對用戶的讀寫請求,功能如下:
- 處理來自客戶端的讀寫請求
- 管理master為其分配的region
- 負責和底層HDFS的交互,存儲數據到HDFS
- 負責region變大以后的拆分
- 負責storefile的合並工作
5.HRegion
Hbase 表的分片,HBase 表會根據 RowKey值被切分成不同的 region 存儲在 RegionServer 中,在一個 RegionServer 中可以有多個不同的 region。
每個HRegion由多個Store構成,每個Store保存一個列族(Columns Family),表有幾個列族,則有幾個Store,每個Store由一個MemStore和多個StoreFile組成,MemStore是Store在內存中的內容,寫到文件后就是StoreFile。StoreFile底層是以HFile的格式保存。
6.HLog
HLog(WAL log):WAL意為write ahead log(預寫日志),用來做災難恢復使用,HLog記錄數據的變更,包括序列號和實際數據,所以一旦region server 宕機,就可以從log中回滾還沒有持久化的數據。
Hlog存儲在HDFS中。
7.Store = memstore + storefile=列族
一個 Store 對應 HBase 表中的一個列族。當一個列族的memstore觸發持久化條件時,整個region里的store會全部進行持久化操作。Store中的數據持久化存儲在HDFS上,其格式為Hfile。
手動持久化操作:flush '表名'
8.Memstore
每個store管理一塊內存memstore,當用戶寫入鍵值對時,最終會將數據寫入memstore,當memstore中的數據達到一定大小,或者一定時間,或者用戶執行flush指令時,regionserver會將memstore中的數據按行鍵進行字典順序排序,並持久化寫入storefile中。
9.Storefile :包含Hfile
當memstore中的數據不斷持久化,形成多個storefile.每個storefile是有序的,但storefile之間是無序的。
10.HFile
這是在磁盤上保存原始數據的實際的物理文件,是實際的存儲文件。StoreFile 是以 Hfile 的形式存儲在 HDFS 的。
HFile 文件是不定長的,長度固定的只有其中的兩塊:Trailer 和 File Info。Trailer 中有指針指向其他數據塊的起始點,File Info 記錄了文件的一些 Meta 信息。每個 Data 塊的大小可以在創建一個 Table 的時候通過參數指定(默認塊大小為 64KB)。每個 Data 塊除了開頭的 Magic 以外就是由一個鍵值對拼接而成的,Magic 內容是一些隨機數字,用於防止數據損壞。
4、水平分區原理
HBase將大數據表水平分割,形成不同的region,並由不同的regionserver管理。原理:一個表剛建立時,只有一個數據分區,隨着數據增多,根據一定規則將表進行水平拆分,形成2個分區或多個分區,而這些region無法存儲到一台機器上時,就會分布存儲在多台機器上。這些分區交給不同的regionserver管理。
分區的拆分是基於行鍵[行鍵按ASCII碼進行排序]進行的,無論分區幾次,屬於哪個列族,相同的行鍵一定在一個region中。HBase的數據文件(HFile)是一種Map文件,即排序后的序列化文件。
HBase中每個Region由三個要素組成,包括Region所屬的表、第一行、最后一行。第一個region沒有首行,最后一個region沒有末行。每個region都有一個regionID來標識它的唯一性,Region標識符就可以表示成:表名+開始行鍵+RegionID.
4.1 Meta表
Meta表記錄各個Regionserver所管理的表和分區。meta表也會隨着數據增多,進行自動分區,每個meta分區記錄一部分用戶表和分區管理情況。
表和分區的分級管理機制:用戶進行讀寫數據時,會根據需要讀寫的表和行鍵,通過如下順序尋找該行鍵對應的分區:Zookeeper->META->Regionserver->Region.
META表的入口地址存儲在Zookeeper集群,表的實體由若干個Regionserver進行管理(持久化在HDFS上)。Meta節點並不負責存儲這些信息,客戶端在尋址之后,可以將信息緩存。
有了Region標識符,就可以唯一標識每個Region。為了定位每個Region所在的位置,可以構建一張映射表[元數據表,又稱為Meta表],包含了關於Region的元數據。映射表:region標識符+region服務器標識符。
4.2 讀流程
首先往hbase寫數據,client put一條數據,會先去zk里面找mete表所在的regionserver位置,假設返回meta表在regionserver102中,client再請求regionserver102返回要put數據的表的regionserver位置(此時客戶端會把元數據緩存下來,下次先找緩存,沒有再找zk)。再假設要put數據對應的表的在regionserver103上,此時client發送請求到regionsever103上,先寫預寫入日志,再寫入內存,此時對於客戶端來說,寫就結束了,不需要等到flush,然后就通知下客戶端寫操作結束。
4.3 數據寫入機制
HBase通過Regionserver來管理寫入。Regionserver負責向對應的表分區和列族中寫入數據,管理緩存和排序,以及實現容錯。
每個Regionserver可能管理多個表和多個分區。Regionserver將用戶請求的數據對應寫到表分區(Hregion)中,每個分區中有一個或多個store,每個store對應當前分區中的一個列族。
比之前多了一個block cache(讀緩存),緩存的是實際數據,client get查詢一條數據,會先去zk里面找mete表所在的regionserver位置,假設返回meta表在regionserver102中,client再請求regionserver102返回要get數據的表的regionserver位置,再假設要get數據對應的表的在regionserver103上,此時client發送get請求到regionsever103上,讀取內存、block cache以及磁盤,先將磁盤中的數據緩存至block cache中,方便下次查詢,再比較時間戳選擇時間戳最新的返回。
//演示: Test表已有中rowkey行info列族name列值為“zhangsan”,先刷寫到磁盤:flush “test” 查看磁盤中hfile:./hbase org.apache.hadoop.hbase.io.hfile.HFile -a -b -e -k -p -f /home/hbase/data/default/test/9cc2c91ace3d7a1d8f88aa95f4867206/info/ 再修改zhangsan為lisi:put "test","rowkey","info:name","lisi",time stamp(小於修改數據的時間戳) 再查看表中數據為張三還是李四:scan “test”。 數據寫入機制的相關配置:通過hbase-site.xml中進行多種配置,可以實現memstore[大小]和持久化[阻塞系統]等機制的管理和優化。
5、數據表的基本設計原則
- 行鍵分布盡量均勻
- 行鍵和列族名盡量短
- 列族盡量少
6、HBase的基本操作(HBase shell)
命名 |
描述 |
語法 |
help '命令名' |
查看命令的使用描述 |
help '命令名' |
whoami |
我是誰 |
whoami |
version |
返回hbase版本信息 |
version |
status |
返回hbase集群的狀態信息 |
status |
table_help |
查看如何操作表 |
table_help |
create |
創建表 |
create '表名', '列族名1', '列族名2', '列族名N' |
alter |
修改列族 |
添加一個列族:alter '表名', '列族名' |
刪除列族: |
||
describe |
顯示表相關的詳細信息 |
describe '表名' |
list |
列出hbase中存在的所有表 |
list |
exists |
測試表是否存在 |
exists '表名' |
put |
添加或修改的表的值 |
put '表名', '行鍵', '列族名', '列值' |
put '表名', '行鍵', '列族名:列名', '列值' |
||
scan |
通過對表的掃描來獲取對用的值 |
scan '表名' |
掃描某個列族: scan '表名', {COLUMN=>'列族名'} |
||
掃描某個列族的某個列: scan '表名', {COLUMN=>'列族名:列名'} |
||
查詢同一個列族的多個列: scan '表名', {COLUMNS => [ '列族名1:列名1', '列族名1:列名2', …]} |
||
get |
獲取行或單元(cell)的值 |
get '表名', '行鍵' |
get '表名', '行鍵', '列族名' |
||
count |
統計表中行的數量 |
count '表名' |
incr |
增加指定表行或列的值 |
incr '表名', '行鍵', '列族:列名', 步長值 |
get_counter |
獲取計數器 |
get_counter '表名', '行鍵', '列族:列名' |
delete |
刪除指定對象的值(可以為表,行,列對應的值,另外也可以指定時間戳的值) |
刪除列族的某個列: delete '表名', '行鍵', '列族名:列名' |
deleteall |
刪除指定行的所有元素值 |
deleteall '表名', '行鍵' |
truncate |
重新創建指定表 |
truncate '表名' |
enable |
使表有效 |
enable '表名' |
is_enabled |
是否啟用 |
is_enabled '表名' |
disable |
使表無效 |
disable '表名' |
is_disabled |
是否無效 |
is_disabled '表名' |
drop |
刪除表 |
drop的表必須是disable的 |
disable '表名' |
||
drop '表名' |
||
shutdown |
關閉hbase集群(與exit不同) |
|
tools |
列出hbase所支持的工具 |
|
exit |
退出hbase shell |
7、什么場景適合HBase
半結構化或非結構化數據:數據結構字段不夠確定或雜亂無章很難按一個概念去進行抽取的數據。
記錄非常稀疏:RDBMS的行有多少列是固定的,為null的列浪費了存儲空間。HBase為null的Column不會被存儲,節省空間的同時又提高了讀性能。
多版本數據:如上文提到的根據Row key 和Column key定位到的Value可以有任意數量的版本值,因此對於需要存儲變動歷史記錄的數據。
超大數據量:RDBMS數據庫撐不住,就出現了讀寫分離策略,通過一個master專門負責寫操作,多個Slave負責讀操作,服務器成本倍增。隨着壓力增加,master撐不住,就需要分庫,把關聯不大的數據分開部署,join查詢用不上,需要借助中間層。隨着數據量的進一步增加,一個表的記錄越來越大,查詢就變得很慢,於是又得搞分表,比如按ID取模分成多個表以減少單個表的記錄數。