[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
一些配置参数说明:
hbase.hregion.max.filesize
10737418240
Maximum HStoreFile size. If any one of a column families' HStoreFiles has
grown to exceed this value, the hosting HRegion is split in two.
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执行操作的。
一些配置属性的说明如下:
hbase.hstore.compactionThreshold
3
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.
hbase.server.compactchecker.interval.multiplier
1000
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.
hbase.hregion.majorcompaction
604800000 7天
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.
hbase.hstore.blockingStoreFiles
10
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.
hbase.hstore.compaction.max
10
Max number of HStoreFiles to compact per 'minor' compaction.
MemStore
注意:在memstore写的过程中,必须不能是多线程的(并行)调用的,hstore在调用的过程中必须持有一个读锁和写锁
在写的过程中,预先数据在memstore中进行排序,因为数据最终是有序存放,当memstore中的数据量超过阈值之后就会刷新到磁盘文件storefile中。
配置参数如下:
hbase.hregion.memstore.flush.size
134217728
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.
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中去找,如果有,则直接取出>>>
如果没有,则就去在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数据库一样,比较方便。