HBase進階下
一、HBase的讀寫流程
1.1 HBase讀流程
Hbase讀取資料的流程:
1)是由客戶端發起讀取資料的請求,首先會與zookeeper建立連線
2)從zookeeper中獲取一個hbase:meta表位置資訊,被哪一個regionserver所管理著
hbase:meta表:hbase的後設資料表,在這個表中儲存了自定義表相關的後設資料,包括表名,表有哪些列簇,表有哪些region,每個region儲存的位置,每個region被哪個regionserver所管理,這個表也是儲存在某一個region上的,並且這個meta表只會被一個regionserver所管理。這個表的位置資訊只有zookeeper知道。
3)連線這個meta表對應的regionserver,從meta表中獲取當前你要讀取的這個表對應的regionsever是誰。
當一個表多個region怎麼辦呢?
如果我們獲取資料是以get的方式,只會返回一個regionserver
如果我們獲取資料是以scan的方式,會將所有的region對應的regionserver的地址全部返回。
4)連線要讀取表的對應的regionserver,從regionserver上的開始讀取資料:
讀取順序:memstore-->blockcache-->storefile-->Hfile中
storefile和Hfile對應的是一個檔案
注意:如果是scan操作,就不僅僅去blockcache了,而是所有都會去找。
1.2 HBase寫流程
--------------------------1-4步是客戶端寫入資料的流程-----------------
Hbase的寫入資料流程:
1)由客戶端發起寫資料請求,首先會與zookeeper建立連線
2)從zookeeper中獲取hbase:meta表被哪一個regionserver所管理
3)連線hbase:meta表中獲取對應的regionserver地址 (從meta表中獲取當前要寫入資料的表對應的region所管理的regionserver) 只會返回一個regionserver地址
4)與要寫入資料的regionserver建立連線,然後開始寫入資料,將資料首先會寫入到HLog,然後將資料寫入到對應store模組中的memstore中
(可能會寫多個),當這兩個地方都寫入完成之後,表示資料寫入完成。
-------------------------後面的步驟是伺服器內部的操作-----------------
非同步操作
5)隨著客戶端不斷地寫入資料,memstore中的資料會越來多,當記憶體中的資料達到閾值(128M/1h)的時候,放入到blockchache中,生成新的memstore接收使用者過來的資料,然後當blockcache的大小達到一定閾值(0.85)的時候,開始觸發flush機制,將資料最終重新整理到HDFS中形成小的Hfile檔案。
6)隨著不斷地重新整理,storefile不斷地在HDFS上生成小HFIle檔案,當小的HFile檔案達到閾值的時候(3個及3個以上),就會觸發Compaction機制,將小的HFile合併成一個大的HFile.
7)隨著不斷地合併,大的HFile檔案會越來越大,當達到一定閾值(2.0版本之後最終10G)的時候,會觸發分裂機制(split),將大的HFile檔案進行一分為二,同時管理這個大的HFile的region也會被一分為二,形成兩個新的region和兩個新的HFile檔案,一對一的進行管理,將原來舊的region和分裂之前大的HFile檔案慢慢地就會下線處理。
HBase寫流程的簡單概況
-
開始使用者先往HLOG(主要起到恢復資料的作用,如果資料已經落地到磁碟上,WAL中的資料就會被刪除)中寫日誌
-
memstore相當於記憶體,當其達到128M(閾值)或者一個小時,會將資料放到佇列中,這個佇列所在的容器叫做blockcache
-
在blockcache達到85%或者一個小時的時候,達到閾值,開始往外溢寫,該溢寫檔案在hbase中叫做storefile,但是在HDFS中叫做Hfile
-
在HDFS中隨著溢寫檔案越來越多會生成大的Hfile檔案,條件是三個或者三個以上的小檔案合併成一個大檔案
-
當這個大檔案達到128M時,又開始進行分裂成小檔案,接著小檔案數量增多,又會合併成新的大檔案,此時這個大檔案的閾值則是10G
二、Region的分裂策略
region中儲存的是一張表的資料,當region中的資料條數過多的時候,會直接影響查詢效率。當region過大的時候,region會被拆分為兩個region,HMaster會將分裂的region分配到不同的regionserver上,這樣可以讓請求分散到不同的RegionServer上,已達到負載均衡 , 這也是HBase的一個優點 。
-
ConstantSizeRegionSplitPolicy
0.94版本前,HBase region的預設切分策略
當region中最大的store大小超過某個閾值(hbase.hregion.max.filesize=10G)之後就會觸發切分,一個region等分為2個region。
但是在生產線上這種切分策略卻有相當大的弊端(切分策略對於大表和小表沒有明顯的區分):
- 閾值(hbase.hregion.max.filesize)設定較大對大表比較友好,但是小表就有可能不會觸發分裂,極端情況下可能就1個,形成熱點,這對業務來說並不是什麼好事。
- 如果設定較小則對小表友好,但一個大表就會在整個叢集產生大量的region,這對於叢集的管理、資源使用、failover來說都不是一件好事。
-
IncreasingToUpperBoundRegionSplitPolicy
0.94版本~2.0版本預設切分策略
總體看和ConstantSizeRegionSplitPolicy思路相同,一個region中最大的store大小大於設定閾值就會觸發切分。
但是這個閾值並不像ConstantSizeRegionSplitPolicy是一個固定的值,而是會在一定條件下不斷調整,調整規則和region所屬表在當前regionserver上的region個數有關係.region split閾值的計算公式是:
-
設regioncount:是region所屬表在當前regionserver上的region的個數
-
閾值 = regioncount^3 * 128M * 2,當然閾值並不會無限增長,最大不超過MaxRegionFileSize(10G),當region中最大的store的大小達到該閾值的時候進行region split
例如:
- 第一次split閾值 = 1^3 * 256 = 256MB
- 第二次split閾值 = 2^3 * 256 = 2048MB
- 第三次split閾值 = 3^3 * 256 = 6912MB
- 第四次split閾值 = 4^3 * 256 = 16384MB > 10GB,因此取較小的值10GB
- 後面每次split的size都是10GB了
特點
- 相比ConstantSizeRegionSplitPolicy,可以自適應大表、小表;
- 在叢集規模比較大的情況下,對大表的表現比較優秀
- 對小表不友好,小表可能產生大量的小region,分散在各regionserver上
- 小表達不到多次切分條件,導致每個split都很小,所以分散在各個regionServer上
-
-
SteppingSplitPolicy
2.0版本預設切分策略
相比 IncreasingToUpperBoundRegionSplitPolicy 簡單了一些
region切分的閾值依然和待分裂region所屬表在當前regionserver上的region個數有關係- 如果region個數等於1,切分閾值為flush size 128M
- 否則為MaxRegionFileSize。
這種切分策略對於大叢集中的大表、小表會比 IncreasingToUpperBoundRegionSplitPolicy 更加友好,小表不會再產生大量的小region,而是適可而止。
-
KeyPrefixRegionSplitPolicy
根據rowKey的字首對資料進行分割槽,這裡是指定rowKey的前多少位作為字首,比如rowKey都是16位的,指定前5位是字首,那麼前5位相同的rowKey在相同的region中。
-
DelimitedKeyPrefixRegionSplitPolicy
保證相同字首的資料在同一個region中,例如rowKey的格式為:userid_eventtype_eventid,指定的delimiter為 _ ,則split的的時候會確保userid相同的資料在同一個region中。
按照分隔符進行切分,而KeyPrefixRegionSplitPolicy是按照指定位數切分。 -
BusyRegionSplitPolicy
按照一定的策略判斷Region是不是Busy狀態,如果是即進行切分
如果你的系統常常會出現熱點Region,而你對效能有很高的追求,那麼這種策略可能會比較適合你。它會透過拆分熱點Region來緩解熱點Region的壓力,但是根據熱點來拆分Region也會帶來很多不確定性因素,因為你也不知道下一個被拆分的Region是哪個。
-
DisabledRegionSplitPolicy
不啟用自動拆分, 需要指定手動拆分
三、Compaction操作
注意:在合併的過程中,客戶端是不會進行任何操作的,即使用者是無法對HBase進行增刪改操作的
Minor Compaction:
- 指選取一些小的、相鄰的StoreFile將他們合併成一個更大的StoreFile,在這個過程中不會處理已經Deleted或Expired的Cell。一次 Minor Compaction 的結果是更少並且更大的StoreFile。
Major Compaction:
- 指將所有的StoreFile合併成一個StoreFile,這個過程會清理三類沒有意義的資料:被刪除的資料、TTL過期資料、版本號超過設定版本號的資料。另外,一般情況下,major compaction時間會持續比較長,整個過程會消耗大量系統資源,對上層業務有比較大的影響。因此線上業務都會將關閉自動觸發major compaction功能,改為手動在業務低峰期觸發。
參考文件:https://cloud.tencent.com/developer/article/1488439
同時,HBase是一個面向列儲存的資料庫(列簇機制),當表欄位非常多時,可以把其中一些欄位獨立出來放在一部分機器上,而另外一些欄位放到另一部分機器上,分散儲存,分雜湊查詢。
正由於這樣複雜的儲存結構和分散式的儲存方式,保證了HBase海量資料下的查詢效率。
五、HBase與Hive的整合
HBase與Hive的對比
HBase和Hive的資料最終都儲存在HDFS上,只不過是儲存形式不太一樣。
- Hbase和Hive整合就要求兩者是同一個叢集
hive:
資料倉儲建模工具之一:Hive的本質其實就相當於將HDFS中已經儲存的檔案在Mysql中做了一個雙射關係,以方便使用HQL去管理查詢。
用於資料分析、清洗:Hive適用於離線的資料分析和清洗,延遲較高。
基於HDFS、MapReduce:Hive儲存的資料依舊在DataNode上,編寫的HQL語句終將是轉換為MapReduce程式碼執行。
HBase
- HBase是一種nosql資料庫,它是基於Hadoop分散式檔案系統HDFS構建的分散式資料庫。
- HBase是一種列式資料庫,它以列簇作為儲存單位儲存資料。
資料庫:是一種面向列族儲存的非關係型資料庫。
用於儲存結構化和非結構化的資料:適用於單表非關係型資料的儲存,不適合做關聯查詢,類似JOIN等操作。
基於HDFS:資料持久化儲存的體現形式是HFile,存放於DataNode中,被ResionServer以region的形式進行管理。
延遲較低,接入線上業務使用:面對大量的企業資料,HBase可以直線單表大量資料的儲存,同時提供了高效的資料訪問速度。
在
hive-site.xml
中新增zookeeper的屬性
<property>
<name>hive.zookeeper.quorum</name>
<value>master,node1,node2</value>
</property>
<property>
<name>hive.zookeeper.client.port</name>
<value>2181</value>
</property>
HBase中已經儲存了某一張表,在Hive中建立一個外部表來關聯HBase中的這張表
建立外部表的欄位名要和hbase中的列名一致
前提是hbase中已經有表了
create external table students_hbase
(
id string,
name string,
age string,
gender string,
clazz string
)
stored by 'org.apache.hadoop.hive.hbase.HBaseStorageHandler'
with serdeproperties ("hbase.columns.mapping" = "
:key,
info:name,
info:age,
info:gender,
info:clazz
")
tblproperties("hbase.table.name" = "default:students");
create external table score_hbase2
(
id string,
score_dan string
)
stored by 'org.apache.hadoop.hive.hbase.HBaseStorageHandler'
with serdeproperties ("hbase.columns.mapping" = "
:key,
info:subject_score
")
tblproperties("hbase.table.name" = "default:scores");
關聯後就可以使用Hive函式進行一些分析操作了
六、Phoenix
Hbase適合儲存大量的對關係運算要求低的NOSQL資料,受Hbase 設計上的限制不能直接使用原生的API執行在關聯式資料庫中普遍使用的條件判斷和聚合等操作。Hbase很優秀,一些團隊尋求在Hbase之上提供一種更面向普通開發人員的操作方式,Apache Phoenix即是。
Phoenix 基於Hbase給面向業務的開發人員提供了以標準SQL的方式對Hbase進行查詢操作,並支援標準SQL中大部分特性:條件運算,分組,分頁,等高階查詢語法。
1、Phoenix搭建
Phoenix 5.1.0 HBase 2.2.7 hadoop 3.1.1
1、關閉hbase叢集,在master中執行
stop-hbase.sh
2、上傳解壓配置環境變數
解壓
tar -xvf apache-phoenix-4.15.0-HBase-1.4-bin.tar.gz -C /usr/local/soft/
改名
mv apache-phoenix-4.15.0-HBase-1.4-bin phoenix-4.15.0
3、將phoenix-4.15.0-HBase-1.4-server.jar複製到所有節點的hbase lib目錄下
scp /usr/local/soft/phoenix-4.15.0/phoenix-4.15.0-HBase-1.4-server.jar master:/usr/local/soft/hbase-1.4.6/lib/
scp /usr/local/soft/phoenix-4.15.0/phoenix-4.15.0-HBase-1.4-server.jar node1:/usr/local/soft/hbase-1.4.6/lib/
scp /usr/local/soft/phoenix-4.15.0/phoenix-4.15.0-HBase-1.4-server.jar node2:/usr/local/soft/hbase-1.4.6/lib/
4、啟動hbase , 在master中執行
start-hbase.sh
5、配置環境變數
vim /etc/profile
2、Phoenix使用
1、連線sqlline
sqlline.py master,node1,node2
# 出現
163/163 (100%) Done
Done
sqlline version 1.5.0
0: jdbc:phoenix:master,node1,node2>
2、常用命令
phoneix使用語法注意事項
# 使用注意事項
1、在phoneix內部建立表的時候,表名最後可以使用!table或者show tables命令檢視,並且以大寫的形式展示給我們,但是我們在使用sql語句查詢的時候既可以用大寫也可以用小寫。(列名和表名大小寫無所謂)
2、直接在phoneix內部建立的表,在hbase中可以以大寫的方式檢視到,但是在hbase中建的表,在phoneix中看不到。
3、如何在phoneix中使用hbase原本的資料表呢?
檢視對映:檢視並不是真正意義上的表,而是在phoneix建立一個對映關係,以表的形式將hbase中原本資料對映過來,可以在基礎之上編寫sql語句進行分析,需要注意的是,我們在檢視上sql分析的時候,表名和列名需要加雙引號。刪除檢視不會影響原本hbase中的資料,檢視無法做修改,只能查詢,檢視在phoneix中被看作成一個只讀表。
表對映:建表的語法來說與檢視對映相差一個單詞,其他的沒啥區別。使用上,表對映可以直接在phoneix中對錶資料進行增刪改查。將phoneix中表對映刪了,原來hbase中的表也對應刪除。
4、對映查詢的時候,主鍵可以不用加雙引號,非主鍵的列必須加雙引號
在HBase中建立一張表,在phoenix中是看不到的
但是在phoenix中建立的表可以在HBase中看到
- 注意:
- 在phoenix對錶進行操作,儘管表名是大寫的,在實現對錶的操作時,表名也可以小寫
- 但是在hbase中如果表名時大寫,操作表時表名就必須大寫
# 1、建立表
CREATE TABLE IF NOT EXISTS students_p1 (
id VARCHAR NOT NULL PRIMARY KEY,
name VARCHAR,
age BIGINT,
gender VARCHAR ,
clazz VARCHAR
);
# 2、顯示所有表
!table
# 3、插入資料
upsert into students_p1 values('1500101004','小虎',22,'男','理科一班');
upsert into students_p1 values('1500100005','宣谷芹',24,'男','理科六班');
upsert into students_p1 values('1500100006','羿彥昌',24,'女','理科三班');
upsert into students_p1 values('1500100007','zhangsan',24,'女','理科一班');
# 4、查詢資料,支援大部分sql語法,
select * from STUDENT ;
select * from STUDENT where age=24;
select gender ,count(*) from STUDENT group by gender;
select * from student order by gender;
# 5、刪除資料
delete from STUDENT where id='1500100004';
# 6、刪除表
drop table STUDENT;
# 7、退出命令列
!quit
更多語法參照官網
https://phoenix.apache.org/language/index.html#upsert_select