逻辑结构和物理结构
命名空间就相当于于库 命名空间下是表
逻辑结构
物理结构
在建表的时候,我们设置的字段其实是上面说的列族,列我们也可以不用。
启动和停止
先启动Zookeeper和Hadoop
启动Hbase
1 | $HBASE_HOME/bin/start-hbase.sh |
停止Hbase
1 | $HBASE_HOME/bin/stop-hbase.sh |
HMaster 的 Web 接口
HRegionServer 的 Web 接口
HBase的操作
下面的操作主要是在hbase的shell中操作的,进入hbase shell
1 | hbase shell |
命名空间
注意
HBase的命名空间 表 列都是区分大小写的。
查看所有namespace
1 | list_namespace |
创建namespace
1 | create_namespace 'ZDB' |
删除namespace
1 | drop_namespace 'ZDB' |
注意
删除命名空间前要删除命名空间下的所有表
删除命名空间下的表
1 | disable 'ZDB:tuser' |
查看namespace
1 | describe_namespace 'ZDB' |
在namespace下创建表
1 | create 'ZDB:tuser','s_name','s_sex','s_age','s_dept','s_course' |
查看namespace下的表
1 | list_namespace_tables 'ZDB' |
表操作
创建表
1 | create 'student','s_name','s_sex','s_age','s_dept','s_course' |
创建命令空间下的表
1 | create 'ZDB:tuser','s_name','s_sex','s_age','s_dept','s_course' |
查看表详情
1 | describe 'student' |
显示所有的表
1 | list |
查看表数据
1 | scan 'student', {LIMIT => 1} |
插入数据
1 | put 'student','95001','s_name','LiYing' |
注意:一次只能为一个表的一行数据的一个列,也就是一个单元格添加一个数据,所以直接用shell命令插入数据效率很低,在实际应用中,一般都是利用编程操作数据。
当运行命令:
put ‘student’,’95001’,’s_name’,’LiYing’
时,即为student表添加了学号为95001,名字为LiYing的一行数据,其行键为95001。
查询数据 HBase中有两个用于查看数据的命令:
- get命令,用于查看表的某一行数据;
- scan命令用于查看某个表的全部数据
示例
1 | get 'student','95001' |
删除数据 在HBase中用delete以及deleteall命令进行删除数据操作,它们的区别是: ① delete用于删除一个数据,是put的反向操作; ② deleteall操作用于删除一行数据。
1 | delete 'student','95001','s_sex' |
修改数据 在添加数据时,HBase会自动为添加的数据添加一个时间戳,故在需要修改数据时,只需直接添加数据,HBase即会生成一个新的版本,从而完成“改”操作,旧的版本依旧保留,系统会定时回收垃圾数据,只留下最新的几个版本,保存的版本数可以在创建表的时候指定。下面是一个操作的例子:
1 | hbase(main):034:0> get 'student','95001' |
删除表 删除表有两步,第一步先让该表不可用,第二步删除表。直接drop未disable的表会失败。
1 | disable 'student' |
查询历史的表
1 | create 'teacher',{NAME=>'username',VERSIONS=>5} |
退出hbase
1 | exit |
授权
具备Create权限的namespace Admin可以对表创建和删除、生成和恢复快照
具备Admin权限的namespace Admin可以对表splits或major compactions
授权命名空间
授权zuser01用户对ZDB下的写权限
1 | grant 'zuser01' 'W' '@ZDB' |
回收zuser01用户对ZDB的所有权限
1 | revoke 'zuser01''@ZDB' |
当前用户:hbase
1 | namespace_create 'ns_hbase' |
授权表
当前用户:zuser02
1 | create 'ns_hbase.tuser01', 'name' |
zuser02创建了两张表tuser01和tuser02,同时成为这两张表的owner,意味着有RWXCA
权限
此时,zuser02团队的另一名成员zuser03也需要获得ns_hbase下的权限,hbase管理员操作如下
如果希望zuser03可以访问已经存在的表,则hbase管理员操作如下
当前用户:hbase
1 | grant 'zuser03', 'RW', 'ns_hbase.tuser01' |
不要只设置写权限
当前用户:hbase
1 | grant 'zuser03', 'W', '@ns_hbase' |
此时zuser03可以在ns_hbase下创建表,但是无法读、写、修改和删除ns_hbase下已存在的表
当前用户:zuser03
1 | scan 'ns_hbase:tuser01' |
报错AccessDeniedException
在HBase中启用授权机制
hbase-site.xml
1 | <property> |
配置完成后需要重启HBase集群
Java操作
添加依赖
1 | <dependency> |
Java代码
1 | package cn.psvmc; |
分页
RowKey + Filter的方式
RowKey一般是必不可少的,但是如果数据量少,几十万数据,就问题不大。很多时候查询都会选择时间,如果能把时间放在RowKey里面,会极大的提升查询的效率。这里有个小技巧:如果Rowkey是按时间戳的方式递增,不要将时间放在二进制码的前面,建议将Rowkey的高位作为散列字段,由程序循环生成,低位放时间字段,这样将提高数据均衡分布在每个Regionserver实现负载均衡的几率。如果没有散列字段,首字段直接是时间信息将产生所有新数据都在一个RegionServer上堆积的热点现象,这样在做数据检索的时候负载将会集中在个别RegionServer,降低查询效率。
HBase的Scan可以通过setFilter方法添加过滤器(Filter),这也是分页、多条件查询的基础。HBase为筛选数据提供了一组过滤器,通过这个过滤器可以在HBase中的数据的多个维度(行,列,数据版本)上进行对数据的筛选操作。通常来说,通过行键,值来筛选数据的应用场景较多。这里简单举个例子,使用SingleColumnValueFilter过滤行,查找数据库中vehicle_speed列是77的数据:
1 | FilterList filterList = new FilterList(); |
Filter是可以加多个的,HBase提供十多种Filter类型。filterList.addFilter(scvf) 就是可以添加多个查询条件,然后调用setFilter函数给Scanner。
这里再简单介绍一下分页的方式:
- client分页,scan查到
N*M
条,过滤掉N*M-M
条,返回M
条。对于M,N
较小时比较适合。 - 自定义Filter,该filter可以传递offset(server端需要过滤的记录条数),在server端分页,注意,跨不同的region时需要重新计算该offset
- 缓存上次分页查询的最后一条,下次分页查询从这条(不包含)开始查。
- 查询条件固定的话,定时任务汇总表
- PageFilter
使用RowKey + Filter的方式只能满足一些查询(数据量少,或者RowKey是必须的参数),包括其分页的实现并不是最优,但这是使用原生的HBase的方法,比较简单。下面介绍的方法更好,但是依赖于其他的组件。
Phoenix
最早由Salesforce.com开源的Apache Phoenix 是一个Java中间层,可以让开发者在Apache HBase上执行SQL查询,目前的版本基本支持常用的操作(分页,排序,Group By,Having,函数,序列等等)。目前的Phoenix是非常成熟的解决方案,阿里、Salesforce、eBay等互联网都在广泛使用。
Phoenix完全使用Java编写,代码位于GitHub上,并且提供了一个客户端可嵌入的JDBC驱动。它查询的实时性非常高,一般查询都在秒级返回,可以应用OLTP的系统中。在用户必须通过Phoenix来建HBase的表,它会映射到HBase的表上。Phoenix可以创建索引来提升提升多条件查询HBase的效率。比如,在查询订单的时候,可以通过订单号、时间、状态等不同的维度来查询,要想把这么多角度的数据都放到RowKey中几乎不可能。而在Phoenix中,你可以针对这几个字段建立索引。在写SQL语句的时候,如果Where语句中使用到了这些条件,Phoenix就会自动判断是否走索引。
Phoenix的索引本质上也是一张HBase的表,它维护了索引和RowKey的关系。在查询的时候,它会从索引表中先找到RowKey,然后再根据RowKey再去HBase原始数据表中获取数据。
ElasticSearch/Solr + HBase
针对HBase使用RowKey访问超高的效率,我们可以把索引数据放在类似于ElasticSearch或者Solr这样的搜索引擎里面。用搜索引擎做二级索引。查询数据的时候先从搜索引擎中查询出RowKey,然后再用RowKey去获取数据。流行的搜索引擎基本可以满足查询的所有需求。
举个例子:
订单数据项有10个,但是用于查询的有5个。当数据插入HBase的同时,也把这5个数据项加上预先生成的RowKey插入搜索引擎,也就是说部分数据存储两份。
选择
当数据量较小几十万,上百万的话可以使用RowKey+Filter的方式实现。
如果数据量到了千万,甚至亿级别,可以尝试Phoenix。
如果数据量到了10亿或者更多则需要选择搜索引擎。
同时方案的系统维护难度和对技术的要求也是逐级递增的。