HBase筆記整理(二)
阿新 • • 發佈:2018-03-23
大數據 HBase [TOC]
HBase筆記整理(二)
邏輯結構
RowKey第一位
ColumnFamily
ColumnQuiauer
value(TimeStamps)
Cell
物理結構
HMaster ----->NameNode
管理節點,用於管理HBase中的Table和Region的結構操作,比如用戶增、刪、修改表的操作。 在HBase集群中,可以啟動多個HMaster,但是只能有一個HMaster屬於Active的狀態,通過ZooKeeper和其它standby狀態的HMaster進程完成,一個狀態的切換,或者選舉。 我們可以使用HMaster的shutdown放關閉整個集群,在關閉整個集群的時候,需要向通知HRegionServer進行關閉,並反饋給HMaster,HMaster才自行關閉。
HRegionServer----->DataNode
存放Region的服務器,需要在HMaster進行註冊,如此才能在HMaster中對其進行管理,在HBase集群中,可以部署多個HRegionServer
Region
存儲的是一張表的一個特定的Region數據,包含了一部分行的所有的列,region通過table和對應行健rowkey來定義,在region級別
添加一個鎖的唯一的目的,就是擋在執行其它操作的時候,阻止region被關閉,以及split。每一行的操作,都需要在執行過程中獲得一個row所和region的讀鎖。
HRegion
存放hbase中數據的一個概念,可以簡單的理解為表的一個分區,存放一張表中的一部分數據,當該region中的數據超過一定量的時候,會自動進行分裂, 分裂成兩個region(一分為二),從這個角度上而言,Region是對hbase中表的一個橫向的劃分。 每一個HRegion有多個HStore組成,每一個HRegion是一張表中所有的列做成部分數據(也就是說部分記錄),每一個region都有一個startKey和endKey
一些配置參數說明:
<property> <name>hbase.hregion.max.filesize</name> <value>10737418240</value> <description> Maximum HStoreFile size. If any one of a column families‘ HStoreFiles has grown to exceed this value, the hosting HRegion is split in two.</description> </property> hregion最大的大小,當一個region中的storeFile增長到10G的時候,split一分為二 手動將一個表今次那個region的切分,使用命令split ‘table‘/‘region‘, ‘splitKey‘
startKey和endKey
假設,我一張表裏面有100條記錄,我要把它分別存放到10個region裏面,又因為存放在hbase裏面的數據都是有序的,是能夠進行一個高速隨機讀寫的,
也就是說有序能夠保證我的快讀,就需要能夠通過rowkey,快速的定位到當前記錄在哪一個region裏面,然後當定位到region之後,再去掃描當前region,獲取數據,
為了滿足於此,我們就對這些region進行劃分,編號,也是為了方便管理。這裏每一個region的範圍:[startKey, endKey),需要註意一定最後一個region的endkey是需要被包含進去的。
region 0 [null, 10)
region 1 [10, 20)
region 2 [20, 30)
region ... ...
region 9 [90, null]
將HRegion數據從memstore中手動刷新到磁盤中,使用命令flush ‘table‘/‘region‘
手動將一個表今次那個region的切分,使用命令split ‘table‘/‘region‘, ‘splitKey‘
HStore
每一個HRegion由多一個HStore來組成,一個HStore對應HRegion中的一個列族,一個HStore有一個MemStore和一個系列StoreFiles組成。
HStore級別不會持有鎖,以及事務,鎖和事務在更高一個級別或者說HRegion持有的,
HStore最核心的一個service就是合並memstore刷新到到磁盤裏面的storefiles,
把多個storefiles合並成為一個storefile,寫到hdfs裏面,寫到hdfs裏面的文件稱之為hfile。
在寫的過程中,唯一設計到hlog的部分就是關於hlog日誌的重建的過程,當hstore將用戶提交的數據最終寫到了hdfs之後,會反饋給hlog,
將hlog裏面冗余的數據刪除掉。
hbase.hstore.compactionThreshold=3,當hstore個數超過3個之後就要開啟hstore合並的工作
Compaction:
minor compaction(小合並):
就是將多個HFile合並成為一個大的HFile,然後對之前的HFile做清除處理。
常見的會在執行刪除數據的動作、以及達到hbase.hstore.compactionThreshold觸發條件的時候發生,
刪除數據:不會立即刪除,做一個標記(標記刪除),等到執行合並操作的時候,才進行數據的處理。
major compaction(大合並):
將一個列族中的所有的HFile合並成為一個HFile,然後對之前的HFile做清除處理。
大合並非常消耗性能,非常耗時,不建議操作,當然是直接可以在shell執行操作的。
一些配置屬性的說明如下:
<property>
<name>hbase.hstore.compactionThreshold</name>
<value>3</value>
<description>
If more than this number of HStoreFiles in any one HStore
(one HStoreFile is written per flush of memstore) then a compaction
is run to rewrite all HStoreFiles files as one. Larger numbers
put off compaction but when it runs, it takes longer to complete.
</description>
</property>
<property>
<name>hbase.server.compactchecker.interval.multiplier</name>
<value>1000</value>
<description>The number that determines how often we scan to see if compaction is necessary.
Normally, compactions are done after some events (such as memstore flush), but if
region didn‘t receive a lot of writes for some time, or due to different compaction
policies, it may be necessary to check it periodically. The interval between checks is
hbase.server.compactchecker.interval.multiplier multiplied by
hbase.server.thread.wakefrequency.
</description>
</property>
<property>
<name>hbase.hregion.majorcompaction</name>
<value>604800000</value> 7天
<description>The time (in miliseconds) between ‘major‘ compactions of all
HStoreFiles in a region. Default: Set to 7 days. Major compactions tend to
happen exactly when you need them least so enable them such that they run at
off-peak for your deploy; or, since this setting is on a periodicity that is
unlikely to match your loading, run the compactions via an external
invocation out of a cron job or some such.</description>
</property>
<property>
<name>hbase.hstore.blockingStoreFiles</name>
<value>10</value>
<description>
If more than this number of StoreFiles in any one Store
(one StoreFile is written per flush of MemStore) then updates are
blocked for this HRegion until a compaction is completed, or
until hbase.hstore.blockingWaitTime has been exceeded.</description>
</property>
<property>
<name>hbase.hstore.compaction.max</name>
<value>10</value>
<description>Max number of HStoreFiles to compact per ‘minor‘ compaction. </description>
</property>
MemStore
註意:在memstore寫的過程中,必須不能是多線程的(並行)調用的,hstore在調用的過程中必須持有一個讀鎖和寫鎖
在寫的過程中,預先數據在memstore中進行排序,因為數據最終是有序存放,當memstore中的數據量超過閾值之後就會刷新到磁盤文件storefile中。
配置參數如下:
<property>
<name>hbase.hregion.memstore.flush.size</name>
<value>134217728</value>
<description>
Memstore will be flushed to disk if size of the memstore
exceeds this number of bytes. Value is checked by a thread that runs
every hbase.server.thread.wakefrequency.</description>
</property>
StoreFile
最終保存HStore數據的文件,數據是由MemStore不斷向磁盤刷新過程中產生的,當storefile達到一定量的時候,會將這些storefile組成一個storefiles。
這個storefiles有可能持有其他store裏面的storefile。
HFile
在hdfs上存放數據之前的一個物理結構,用於接收從客戶端提交過來的數據。
HFile中的數據都Key-Value鍵值對兒的方式存儲,並且key和value都是字節數組。並且因為數據已經在memstore中排序過了,在hfile中也是有序的。
hfile同時是由一個個的block來組成的,最終k-v實際上是在這一個個的block中的,block的推薦的大小在8k~1M之間,默認大小65536byte-->16kb。
每一個block都有索引,沒有hfile有由索引
官方建議:
blocksize在8k~1M之間,默認是64k
如果執行順序讀的操作,建議將blocksize調大一點點,這個會影響隨機訪問的效率
如果執行隨機讀的操作,建議將blocksize調小一點點,用默認就可以了
在掃描全表數據的時候,一定要指定start key和end key,不然容易操作OOM異常
總結
HRegionServer
|---一個HLog
|---多個HRegion(一張表對應多個HRegion,是對hbase表的一個橫向的劃分)
|---多個HStore(一個HStore對應一個列族,反之一個列族對應多個HStore,列族是對HBase表的縱向的劃分)
|--一個MemStore
|--多個StoreFile
HFile
|---多個data block
HBase如何做到高速隨機讀?
rowkey---->region
先到memstore中去找,如果有,則直接取出<rowkey, <cf, <col, <ts, value>>>>
如果沒有,則就去在hfile中找,通過索引定位到具體的block,然後遍歷該block塊,找到相應的數據
--------------------------------------------------------------------------
把在想memstore寫數據的過程中,同時向hlog中寫數據的這種解決問題的方式稱之為SLM-Tree(Structure Log merge tree)
這種數據結構和B-Tree有些類似,也是引自於Google BigTable
行健的設計問題
行健的熱點問題
是由於行健相似、連續且數據量過大操作成單region的數據量過大,進而影響讀寫效率
行健應該盡量的隨機、不要出現連續行健。
常見的行健設計就是,比如手機號碼倒置+時間戳,比如隨機前綴+關系型數據庫中的主鍵(以存放在mr中電信日誌案例為例)
因為hbase提供的查詢內容非常非常low,但是所有關於hbase的查詢只能通過rowkey,所以
在設計行健的時候,應該考慮將盡量多的查詢條件放到rowkey中去,形成的行健就成為復合鍵
列族的設計
cf1----->"maxRowLength"
cf2----->"mrl"
建議hbase表是高表,不建議寬表,因為寬表擁有的列族很多,操作並跨越的文件(HFile)就很多,效率會有相應影響,
反之建議使用高表,列族不宜過多。
在設計表的時候,各個列/列族名稱不宜過長,因為hbase需要對這些數據在內存中做緩存,做索引,進而影響內存容量,
所以建議不易過長,以便能夠在內存中容納更多的數據。至於閱讀性,有項目文檔搞定。
Hive整合HBase
啟動hive,進入hive的終端:
/home/uplooking/app/hive/bin/hive --auxpath /home/uplooking/app/hive/lib/hive-hbase-handler-2.1.0.jar,/home/uplooking/app/hive/lib/zookeeper-3.4.6.jar --hiveconf hbase.master=uplooking01:16010 --hiveconf hbase.zookeeper.quorum=uplooking01,uplooking02,uplooking03
在Hive裏面操作HBase
創建一張表:
hbase不存在該表的情況
如果hbase中不存在該表我們只能在hive中使用創建內部表的方式,來創建一張表,同會在hbase中也會創建相關的表。
eg.
create table h2hb_1(
id int,
name string,
age int
)row format delimited
fields terminated by ‘,‘
stored by ‘org.apache.hadoop.hive.hbase.HBaseStorageHandler‘ with serdeproperties (
"hbase.columns.mapping" = ":key,cf:name,cf:age",
"hbase.table.name" = "t"
);
在hive中創建了一張表h2hb_1,有三列內容id, name,age,同時映射到hbase中的表t,其中id對應行健
name對應hbase中列族cf中的name,age同理
嘗試向表中導入數據,會報下面的錯誤:
hive (mydb1)> load data local inpath ‘stu.txt‘ into table h2hb_1;
FAILED: SemanticException [Error 10101]: A non-native table cannot be used as target for LOAD
所以創建了一張臨時表並導入數據:
hive (mydb1)> create temporary table tmp(
> id int,
> name string,
> age int)row format delimited
> fields terminated by ‘,‘;
OK
Time taken: 0.104 seconds
hive (mydb1)> load data local inpath ‘stu.txt‘ into table tmp;
Loading data to table mydb1.tmp
OK
Time taken: 0.408 seconds
最後通過查詢的方式向其插入數據:
hive (mydb1)> insert into h2hb_1 select * from tmp;
...
2018-03-24 01:09:47,267 Stage-0 map = 0%, reduce = 0%
2018-03-24 01:09:59,883 Stage-0 map = 100%, reduce = 0%, Cumulative CPU ...
Time taken: 32.315 seconds
可以看到會啟動一個MR的任務。
hbase存在該表的情況
如果使用上述建表語句創建的時候,則會報錯,因為在hbase中已經存在了一張表為t,所以這時只能創建外部表去映射hbase中的一張表。
create external table h2hb_2
(id int,
name string,
age int
)row format delimited
fields terminated by ‘,‘
stored by ‘org.apache.hadoop.hive.hbase.HBaseStorageHandler‘ with serdeproperties (
"hbase.columns.mapping" = ":key,cf:name,cf:age",
"hbase.table.name" = "t"
);
Phoenix整合HBase
安裝Phoenix
約定安裝到/home/uplooking/app目錄下面
解壓:
[uplooking@uplooking01 ~]$ tar -zxvf soft/phoenix-4.7.0-HBase-1.1-bin.tar.gz -C app/
重命名 [uplooking@uplooking01 ~]$ mv app/phoenix-4.7.0-HBase-1.1-bin/ app/phoenix
拷貝lib目錄下面jar包到regionserver機器的lib($HBASE_HOME/lib)目錄
[uplooking@uplooking01 phoenix]$ scp *.jar uplooking@uplooking02:/home/uplooking/app/hbase/lib/
[uplooking@uplooking01 phoenix]$ scp *.jar uplooking@uplooking03:/home/uplooking/app/hbase/lib/
重啟regionserver
hbase-daemon.sh stop regionserver
hbase-daemon.sh start regionserver
將phoenix中的client拷貝到hbase的client中,重啟master
p[uplooking@uplooking01 phoenix]$ cp phoenix-4.7.0-HBase-1.1-client.jar /home/uplooking/app/hbase/lib/
hbase-daemon.sh stop master
hbase-daemon.sh start master
官網測試案例:
http://phoenix.apache.org/Phoenix-in-15-minutes-or-less.html
./psql.py uplooking01:2181 us_population.sql us_population.csv us_population_queries.sql
在cli中使用Phoenix
./sqlline.py uplooking01:2181:/hbase
查詢操作:
0: jdbc:phoenix:uplooking01:2181:/hbase> !tables
+------------+--------------+----------------+---------------+----------+------------+---------------------------+
| TABLE_CAT | TABLE_SCHEM | TABLE_NAME | TABLE_TYPE | REMARKS | TYPE_NAME | SELF_REFERENCING_COL_NAME |
+------------+--------------+----------------+---------------+----------+------------+---------------------------+
| | SYSTEM | CATALOG | SYSTEM TABLE | | | |
| | SYSTEM | FUNCTION | SYSTEM TABLE | | | |
| | SYSTEM | SEQUENCE | SYSTEM TABLE | | | |
| | SYSTEM | STATS | SYSTEM TABLE | | | |
| | | US_POPULATION | TABLE | | | |
+------------+--------------+----------------+---------------+----------+------------+---------------------------+
0: jdbc:phoenix:uplooking01:2181:/hbase> select * from US_POPULATION;
+--------+---------------+-------------+
| STATE | CITY | POPULATION |
+--------+---------------+-------------+
| AZ | Phoenix | 1461575 |
| CA | Los Angeles | 3844829 |
| CA | San Diego | 1255540 |
| CA | San Jose | 912332 |
| IL | Chicago | 2842518 |
| NY | New York | 8143197 |
| PA | Philadelphia | 1463281 |
| TX | Dallas | 1213825 |
| TX | Houston | 2016582 |
| TX | San Antonio | 1256509 |
+--------+---------------+-------------+
10 rows selected (0.138 seconds)
創建表與插入數據:
0: jdbc:phoenix:uplooking01:2181:/hbase> create table p1(id integer not null primary key, name varchar(20), age integer);
No rows affected (2.351 seconds)
0: jdbc:phoenix:uplooking01:2181:/hbase> !tables
+------------+--------------+----------------+---------------+----------+------------+---------------------------+
| TABLE_CAT | TABLE_SCHEM | TABLE_NAME | TABLE_TYPE | REMARKS | TYPE_NAME | SELF_REFERENCING_COL_NAME |
+------------+--------------+----------------+---------------+----------+------------+---------------------------+
| | SYSTEM | CATALOG | SYSTEM TABLE | | | |
| | SYSTEM | FUNCTION | SYSTEM TABLE | | | |
| | SYSTEM | SEQUENCE | SYSTEM TABLE | | | |
| | SYSTEM | STATS | SYSTEM TABLE | | | |
| | | P1 | TABLE | | | |
| | | US_POPULATION | TABLE | | | |
+------------+--------------+----------------+---------------+----------+------------+---------------------------+
0: jdbc:phoenix:uplooking01:2181:/hbase> !describe p1;
+------------+--------------+-------------+--------------+------------+------------+--------------+--------------+
| TABLE_CAT | TABLE_SCHEM | TABLE_NAME | COLUMN_NAME | DATA_TYPE | TYPE_NAME | COLUMN_SIZE | BUFFER_LENGT |
+------------+--------------+-------------+--------------+------------+------------+--------------+--------------+
| | | P1 | ID | 4 | INTEGER | null | null |
| | | P1 | NAME | 12 | VARCHAR | 20 | null |
| | | P1 | AGE | 4 | INTEGER | null | null |
+------------+--------------+-------------+--------------+------------+------------+--------------+--------------+
0: jdbc:phoenix:uplooking01:2181:/hbase> upsert into p1 values(1, ‘zhangsan‘,13);
1 row affected (0.13 seconds)
0: jdbc:phoenix:uplooking01:2181:/hbase> upsert into p1 values(2, ‘lisi‘,14);
1 row affected (0.019 seconds)
0: jdbc:phoenix:uplooking01:2181:/hbase> select * from p1;
+-----+-----------+------+
| ID | NAME | AGE |
+-----+-----------+------+
| 1 | zhangsan | 13 |
| 2 | lisi | 14 |
+-----+-----------+------+
2 rows selected (0.066 seconds)
可以看到,我們創建的表p1,在實際創建時,會變成大寫的P1,在hbase中查看:
hbase(main):004:0> scan ‘P1‘
ROW COLUMN+CELL
\x80\x00\x00\x01 column=0:AGE, timestamp=1521827542938, value=\x80\x00\x00\x0D
\x80\x00\x00\x01 column=0:NAME, timestamp=1521827542938, value=zhangsan
\x80\x00\x00\x01 column=0:_0, timestamp=1521827542938, value=x
\x80\x00\x00\x02 column=0:AGE, timestamp=1521827553065, value=\x80\x00\x00\x0E
\x80\x00\x00\x02 column=0:NAME, timestamp=1521827553065, value=lisi
\x80\x00\x00\x02 column=0:_0, timestamp=1521827553065, value=x
2 row(s) in 0.0410 seconds
可以看到列族也默認為0,可以嘗試下面的方式來創建表:
0: jdbc:phoenix:uplooking01:2181:/hbase> create table "p2"(id varchar(100000) primary key, "cf"."name" varchar(20), "cf"."age" varchar(100));
No rows affected (1.288 seconds)
0: jdbc:phoenix:uplooking01:2181:/hbase> !tables
+------------+--------------+----------------+---------------+----------+------------+---------------------------+
| TABLE_CAT | TABLE_SCHEM | TABLE_NAME | TABLE_TYPE | REMARKS | TYPE_NAME | SELF_REFERENCING_COL_NAME |
+------------+--------------+----------------+---------------+----------+------------+---------------------------+
| | SYSTEM | CATALOG | SYSTEM TABLE | | | |
| | SYSTEM | FUNCTION | SYSTEM TABLE | | | |
| | SYSTEM | SEQUENCE | SYSTEM TABLE | | | |
| | SYSTEM | STATS | SYSTEM TABLE | | | |
| | | P1 | TABLE | | | |
| | | US_POPULATION | TABLE | | | |
| | | p2 | TABLE | | | |
+------------+--------------+----------------+---------------+----------+------------+---------------------------+
0: jdbc:phoenix:uplooking01:2181:/hbase> upsert into "p2" values(‘1‘,‘zhangsan‘,‘13‘);
1 row affected (0.061 seconds)
0: jdbc:phoenix:uplooking01:2181:/hbase> upsert into "p2" values(‘2‘,‘lisi‘,‘14‘);
1 row affected (0.015 seconds)
0: jdbc:phoenix:uplooking01:2181:/hbase> select * from "p2";
+-----+-----------+------+
| ID | name | age |
+-----+-----------+------+
| 1 | zhangsan | 13 |
| 2 | lisi | 14 |
+-----+-----------+------+
2 rows selected (0.055 seconds)
這樣創建的表就為小寫的了,同時在hbase中查看也可以看到列族:
hbase(main):006:0> scan ‘p2‘
ROW COLUMN+CELL
1 column=cf:_0, timestamp=1521827723448, value=x
1 column=cf:age, timestamp=1521827723448, value=13
1 column=cf:name, timestamp=1521827723448, value=zhangsan
2 column=cf:_0, timestamp=1521827735556, value=x
2 column=cf:age, timestamp=1521827735556, value=14
2 column=cf:name, timestamp=1521827735556, value=lisi
2 row(s) in 0.0390 seconds
Phoenix客戶端工具操作
安裝squirrel-sql-3.7-standard.jar
java -jar squirrel-sql-3.7-standard.jar
然後就可以進行安裝。
添加HBase驅動
使用squirrel-sql添加一個驅動,其屬性值可為如下:
Name:hbase
Example URL:jdbc:phoenix:uplooking01,uplooking02,uplooking03:2181
Class Name:org.apache.phoenix.jdbc.PhoenixDriver
驅動可以到phoenix目錄下找到:phoenix-4.7.0-HBase-1.1-client.jar,然後添加即可
創建連接
選擇驅動為前面創建的驅動,然後用戶名和密碼都為uplooking
這樣之後就可以像使用navicat管理MySQL數據庫一樣,比較方便。
HBase筆記整理(二)