一 Hbase的搭建与安装
1.1 安装
1.准备好文件,上传到Linux上
2.解压文件 tar zxvf hbase-2.2.7-bin.tar.gz -C ../
../是解压到的路径
1.2 配置文件
1.配置环境变量 去etc/profile目录下
export HBASE_HOME=/usr/local/soft/hbase-2.2.7
export PATH=$PATH:$HBASE_HOME/bin
2.修改hbase-site.xml文件
<!--指定 zookeeper 服务器 -->
<property>
<name>hbase.zookeeper.quorum</name>
<value>master,node1,node2</value>
</property>
<!--指定 hbase 根路径 -->
<property>
<name>hbase.rootdir</name>
<value>hdfs://master:9000/hbase</value>
</property>
<!--将 hbase 设置为分布式部署。 -->
<property>
<name>hbase.cluster.distributed</name>
<value>true</value>
</property>
<!-- 避免出现启动错误。 -->
<property>
<name>hbase.unsafe.stream.capability.enforce</name>
<value>false</value>
</property>
2.修改hbase-env.sh文件
export HBASE_MANAGES_ZK=false
export JAVA_HOME=/usr/local/soft/jdk1.8.0_171
3.修改regionservers文件
node1
node2
4.同步一份给子节点
scp -r hbase-2.2.7 node2:`pwd`
1.3启动
1.hbase启动顺序:
zk-->hadoop-->hbase
2.命令
a、启动zk 三台机器都要输入
zkServer.sh start
b、启动Hadoop集群
start-all.sh
c、启动Hbase
start-hbase.sh
1.4 进入客户端
hbase xhell
1.5 进入网页端
http://master:16010/
1.6 退出进程的顺序
1.先退hbase
stop-hbase.sh
这里注意 关闭这个的时候最好 flush一下 将操作客户端的表都刷一下,最最好 每次操作一下表就flush ‘表名’ 一下
2. 再退Hadoop集群
stop-all.sh
3 关闭zk
三台机器都要关闭
zkServer.sh stop
二 Hbase的相关概念
2.1 hbase的概述
1.HBase 是一个高可靠性、高性能、面向列、可伸缩的分布式存储系统,用于存储海量的结构化或者半结构化,非结构化的数据(底层是字节数组做存储的)
2.HBase是Hadoop的生态系统之一,是建立在Hadoop文件系统(HDFS)之上的分布式、面向列的数据库,通过利用Hadoop的文件系统提供容错能力。如果需要进行实时读写或者随机访问大规模的数据集的时候,会考虑使用HBase。
2.2 HBase处理数据
1.虽然Hadoop是一个高容错、高延时的分布式文件系统和高并发的批处理系统,但是它不适用于提供实时计算;
HBase是可以提供实时计算的分布式数据库,数据被保存在HDFS分布式文件系统上,由HDFS保证期高容错性;
但是再生产环境中,HBase是如何基于hadoop提供实时性呢?
HBase上的数据是以StoreFile(HFile)二进制流的形式存储在HDFS上block块儿中;
但是HDFS并不知道的HBase用于存储什么,它只把存储文件认为是二进制文件,也就是说,HBase的存储数据对于HDFS文件系统是透明的。
2.3 hbase与hadoop
2.4 数据模型
1.列簇:一个HBase表被分组成许多“列族”的集合,它是基本的访问控制单元。
2.行:每个表由若干行组成,每个行有一个行键作为这一行的唯一标识。访问表中的行只有三种方式:通过单个行键进行查询、通过一个行键的区间来访问、全表扫描。
3.列修饰符(列限定符):列族里的数据通过列限定符(或列)来定位
4.单元格:在HBase表中,通过行、列族和列限定符确定一个“单元格”(cell),单元格中存储的数据没有数据类型,总被视为字节数组byte[]
5.时间戳:每个单元格都保存着同一份数据的多个版本,这些版本采用时间戳进行索引
2.5 数据坐标
2.6 区域
1.HBase自动把表水平划分为区域(Region),每个区域都是有若干连续行构成的,一个区域由所属的表、起始行、终止行(不包括这行)三个要素来表示。
2.一开始,一个表只有一个区域,但是随着数据的增加,区域逐渐变大,等到它超出设定的阈值(128M)大小,就会在某行的边界上进行拆分,分成两个大小基本相同的区域。然后随着数据的再增加,区域就不断的增加,如果超出了单台服务器的容量,就可以把一些区域放到其他节点上去,构成一个集群。也就是说:集群中的每个节点(Region Server)管理整个表的若干个区域。所以,我们说:区域是HBase集群上分布数据的最小单位
三 Hbase的架构
3.1 组件
1.HBase由三种类型的服务器以主从模式构成:
-
Region Server:负责数据的读写服务,用户通过与Region server交互来实现对数据的访问。
-
HBase HMaster:负责Region的分配及数据库的创建和删除等操作。
-
ZooKeeper:负责维护集群的状态(某台服务器是否在线,服务器之间数据的同步操作及master的选举等)。
HDFS的DataNode负责存储所有Region Server所管理的数据,即HBase中的所有数据都是以HDFS文件的形式存储的。出于使Region server所管理的数据更加本地化的考虑,Region server是根据DataNode分布的。HBase的数据在写入的时候都存储在本地。但当某一个region被移除或被重新分配的时候,就可能产生数据不在本地的情况。这种情况只有在所谓的compaction之后才能解决。
2.Zookeeper
保证任何时候,集群中只有一个master
存贮所有Region的寻址入口。
实时监控Region server的上线和下线信息。并实时通知Master
存储HBase的schema和table元数据的meta信息
3.Master
为Region server分配region
负责Region server的负载均衡
发现失效的Region server并重新分配其上的region
管理用户对table的增删改操作
4.RegionServer
Region server维护region,处理对这些region的IO请求
Region server负责切分在运行过程中变得过大的region
5.HLog(WAL log):
HLog文件就是一个普通的Hadoop Sequence File,Sequence File 的Key是 HLogKey对象,HLogKey中记录了写入数据的归属信息,除了table和 region名字外,同时还包括sequence number和timestamp,timestamp是” 写入时间”,sequence number的起始值为0,或者是最近一次存入文件系 统sequence number。
HLog SequeceFile的Value是HBase的KeyValue对象,即对应HFile中的 KeyValue
6.Region
HBase自动把表水平划分成多个区域(region),每个region会保存一个表里面某段连续的数据;每个表一开始只有一个region,随着数据不断插 入表,region不断增大,当增大到一个阀值的时候,region就会等分会两个新的region(裂变);
当table中的行不断增多,就会有越来越多的region。这样一张完整的表被保存在多个Regionserver上。
7.Memstore 与 storefile
一个region由多个store组成,一个store对应一个CF(列簇)
store包括位于内存中的memstore和位于磁盘的storefile写操作先写入 memstore,当memstore中的数据达到某个阈值,hregionserver会启动 flashcache进程写入storefile,每次写入形成单独的一个storefile
当storefile文件的数量增长到一定阈值后,系统会进行合并(minor、 major compaction),在合并过程中会进行版本合并和删除工作 (majar),形成更大的storefile。
当一个region所有storefile的大小和超过一定阈值后,会把当前的region 分割为两个,并由hmaster分配到相应的regionserver服务器,实现负载均衡。
客户端检索数据,先在memstore找,找不到再找storefile
HRegion是HBase中分布式存储和负载均衡的最小单元。最小单元就表 示不同的HRegion可以分布在不同的HRegion server上。
HRegion由一个或者多个Store组成,每个store保存一个columns family。
每个Strore又由一个memStore和0至多个StoreFile组成。
如图:StoreFile 以HFile格式保存在HDFS上。
3.2 理解
1、flush刷新在HDFS上呈现究竟是怎么刷新的呢??
我们目前刚刚学习的时候,添加数据,都是一条一条的put进去,而我们在put的数据比较少(小于128M)的时候,我们put完去HDFS上并未查看到我们put的文件,这是因为数据还在内存中,也就是还在memStore中,所以要想在HDFS中查看到,我们必须手动刷新到磁盘中,这是将memStore的数据刷新到StoreFile中去,这样我们在HDFS中就可以查看到了。
2、为什么Hbase不可以使用像Mysql那样进行查询??
首先,我们应该可以感受到,我们在插入的时候,每行数据,有多少列,列名叫什么完全是我们自己定义的,之所以不支持像MySql那样对列进行查询和操作,因为不确定列的个数和名称。
3、数据最后存在HDFS上的,HDFS不支持删改,为什么Hbase就可以呢??
这里有个思想误区,的确,数据是以HFile形式存在HDFS上的,而且HDFS的确是不支持删改的,但是为什么Hbase就支持呢?首先,这里的删除并不是真正意义上的对数据进行删除,而是对数据进行打上标记,我们再去查的时,就不会查到这个打过标记的数据,这个数据Hmaster会每隔1小时清理。修改是put两次,Hbase会取最新的数据,过期数据也是这个方式被清理。
四 hbase shell
4.1 help
1.可以通过 help '命名名称'
来查看命令行的具体使用,包括命令的作用和用法。 通过help ‘hbase’ 命名来查看hbase shell 支持的所有命令,hbase将命令进行分组,其中ddl、dml使用较多。
4.2 general 类
4.2.1 显示集群状态status
4.2.2 查询数据库版本version
4.2.3 显示当前用户与组 whoami
4.2.4 查看操作表的命令table_help
4.2.5 退出HBase Shell exit
4.3 DDL
4.3.1. 创建表create
1.创建表时只需要指定列族名称,不需要指定列名。
2.语法
create '表名', {NAME => '列族名1'}, {NAME => '列族名2'}, {NAME => '列族名3'}
# 此种方式是上上面的简写方式,使用上面方式可以为列族指定更多的属性,如VERSIONS、TTL、BLOCKCACHE、CONFIGURATION等属性
create '表名', '列族名1', '列族名2', '列族名3'
create '表名', {NAME => '列族名1', VERSIONS => 版本号, TTL => 过期时间, BLOCKCACHE => true}
3.示例
create 'tbl_user', 'info', 'detail'
create 't1', {NAME => 'cf1', VERSIONS => 2}
4.3.2 修改(添加、删除)表结构Schema alter
1 添加一个列簇
语法 alter '表名', '列族名'
2.删除一个列簇
语法:alter '表名', {NAME=> '列族名', METHOD=> 'delete'}
示例:alter 't1',{NAME => 'cf2', METHOD => 'delete'}
3. 修改列簇属性
可以修改列族的VERSIONS、IN_MEMORY
alter 't1', NAME => 'f1', VERSIONS => 5
4.3.3 获取表的描述describe
1.语法
describe '表名'
4.3.4 列举所有表list
1.查看的是所有命名空间的表
4.3.5 表是否存在exists
语法:exists '表名'
4.3.6 启用表enable和禁用表disable
1.通过enable和disable来启用/禁用这个表,相应的可以通过is_enabled和is_disabled来检查表是否被禁用。
2.语法:
enable '表名'
is_enabled '表名'
disable '表名'
is_disabled '表名'
4.3.7 启用 禁用满足正则表达式的所有表enable_all
1.相关概念
-
.
匹配除“\n”和"\r"之外的任何单个字符 -
*
匹配前面的子表达式任意次
2.语法
# 匹配以t开头的表名
disable_all 't.*'
# 匹配指定命名空间ns下的以t开头的所有表
disable_all 'ns:t.*'
# 匹配ns命名空间下的所有表
disable_all 'ns:.*'
4.3.8删除表drop
1.需要先禁用表,然后再删除表,启用的表是不允许删除的
2.语法:
disable '表名'
drop '表名'
4.3.9 获取某个表赋值给一个变量 get_table
1.通过 var = get_table ‘表名’ 赋值给一个变量对象,然后对象.来调用,就像面向对象编程一样,通过对象.方法来调用,这种方式在操作某个表时就不必每次列举表名了。
4.3.10 获取rowKey所在的区 locate_region
4.3.11 显示hbase所支持的所有过滤器show_filters
1.过滤器用于get和scan命令中作为筛选数据的条件,类型关系型数据库中的where的作用
4.4 namespace
hbase中没有数据库的概念 , 可以使用namespace来达到数据库分类别管理表的作用
4.4.1 列举命名空间 list_namespace
4.4.2 获取命名空间描述 describe_namespace
1.语法 describe_namespace '命名空间'
4.4.3 查看命名空间下的所有表 list_namespace_tables
4.4.4 创建命名空间create_namespace
4.4.5 删除命名空间drop_namespace
4.5 DML
4.5.1 插入或者修改数据put
1.语法:
当列族中只有一个列时'列族名:列名'使用'列族名'
put '表名', '行键', '列族名', '列值'
put '表名', '行键', '列族名:列名', '列值'
2.他写入是一行写入的
# 第一行数据
put 'users', 'rk1001', 'info:id', '1'
put 'users', 'rk1001', 'info:name', '张三'
put 'users', 'rk1001', 'info:age', '28'
put 'users', 'rk1001', 'detail:birthday', '1990-06-26'
put 'users', 'rk1001', 'detail:email', 'abc@163.com'
put 'users', 'rk1001', 'detail:create_time', '2019-03-04 14:26:10'
put 'users', 'rk1001', 'address', '上海市'
# 第二行数据
put 'users', 'rk1002', 'info:id', '2'
put 'users', 'rk1002', 'info:name', '李四'
put 'users', 'rk1002', 'info:age', '27'
put 'users', 'rk1002', 'detail:birthday', '1990-06-27'
put 'users', 'rk1002', 'detail:email', 'xxx@gmail.com'
put 'users', 'rk1002', 'detail:create_time', '2019-03-05 14:26:10'
put 'users', 'rk1002', 'address', '北京市'
# 第三行数据
put 'users', 'rk1003', 'info:id', '3'
put 'users', 'rk1003', 'info:name', '王五'
put 'users', 'rk1003', 'info:age', '26'
put 'users', 'rk1003', 'detail:birthday', '1990-06-28'
put 'users', 'rk1003', 'detail:email', 'xyz@qq.com'
put 'users', 'rk1003', 'detail:create_time', '2019-03-06 14:26:10'
put 'users', 'rk1003', 'address', '杭州市'
4.5.2 全表扫描scan
1.语法
scan '表名'
2.扫描整个列簇
# 语法
scan '表名', {COLUMN=>'列族名'}
# 示例
scan 'users', {COLUMN=>'info'}
3.扫描整个列簇的某个列
# 语法
scan '表名', {COLUMN=>'列族名:列名'}
# 示例
scan 'users', {COLUMN=>'info:age'}
4.限制查几行
语法
scan '表名',{LIMIT=>1}
意思是查一行
4.5.3 获取数据get
1.可以获取某一行,也可以获取应该单元格
# 语法
get '表名', '行键'
# 示例
get 'users', 'xiaoming'
2.建表的时候确定了几个版本的值,那么获取的时候页可以获取几个版本的值
例如 create 'test1', {NAME => 'cf1', VERSIONS => 4} 建表语句
get '表名','行名',{COLUMN=>'列簇',VERSIONS=>4}
4.5.4 删除某个列族中的某个列delete
1.语法 delete '表名', '行键', '列族名:列名'
2.删除的是最新的那一列
4.5.5 删除某行数据deleteall
1.语法 deleteall '表名', '行键'
4.5.6 清空整个表的数据truncate
1.语法 truncate '表名'
4.5.7 自增incr
1.语法 incr '表名', '行键', '列族:列名', 步长值
2.
# 示例
# 注意:incr 可以对不存的行键操作,如果行键已经存在会报错,如果使用put修改了incr的值再使用incr也会报错
# ERROR: org.apache.hadoop.hbase.DoNotRetryIOException: Field is not a long, it's 2 bytes wide
incr 'tbl_user', 'xiaohong', 'info:age', 1
4.5.8 计数器get_counter
create 'counters', 'daily', 'weekly', 'monthly'
incr 'counters', '20240415', 'daily:hits', 1
get_counter 'counters', '20240415', 'daily:hits' 获取计数器的值
4.5.9 修饰词
1.修饰词
# 语法
scan '表名', {COLUMNS => [ '列族名1:列名1', '列族名1:列名2', ...]}
# 示例
scan 'tbl_user', {COLUMNS => [ 'info:id', 'info:age']}
2.TIMESTAMP 指定时间戳
scan '表名',{TIMERANGE=>[timestamp1, timestamp2]}
# 示例
scan 'tbl_user',{TIMERANGE=>[1551938004321, 1551938036450]}
区间是左闭右开的
3.VERSIONS
默认情况下一个列只能存储一个数据,后面如果修改数据就会将原来的覆盖掉,可以通过指定VERSIONS时HBase一列能存储多个值。
create 'tbl_test', 'columnFamily1'
describe 'tbl_test'
# 修改列族版本号
alter 'tbl_test', { NAME=>'columnFamily1', VERSIONS=>3 }
put 'tbl_test', 'rowKey1', 'columnFamily1:column1', 'value1'
put 'tbl_test', 'rowKey1', 'columnFamily1:column1', 'value2'
put 'tbl_test', 'rowKey1', 'columnFamily1:column1', 'value3'
# 默认返回最新的一条数据
get 'tbl_test','rowKey1','columnFamily1:column1'
# 返回3个
get 'tbl_test','rowKey1',{COLUMN=>'columnFamily1:column1', VERSIONS=>3}
# 返回2个
get 'tbl_test','rowKey1',{COLUMN=>'columnFamily1:column1', VERSIONS=>2}
4、STARTROW
ROWKEY起始行。会先根据这个key定位到region,再向后扫描
scan '表名', { STARTROW => '行键名'}
# 示例
scan 'users', { STARTROW => 'rk1002'}
5、STOPROW :截止到STOPROW行,STOPROW行之前的数据,不包括STOPROW这行数据
# 语法
scan '表名', { STOPROW => '行键名'}
5.ENDROW :截止到ENDROW 行,ENDROW 行之前的数据,不包括ENDROW 这行数据
scan '表名', {ENDROW => '行键名'}
6、LIMIT 返回的行数
# 语法
scan '表名', { LIMIT => 行数}
# 示例
scan 'tbl_user', { LIMIT => 2 }
4.5.10 FILTER条件过滤器
过滤器之间可以使用AND、OR连接多个过滤器。
1、ValueFilter 值过滤器
# 语法:binary 等于某个值
scan '表名', FILTER=>"ValueFilter(=,'binary:列值')"
scan 'users',FILTER=>"ValueFilter(=,'binary:张三')"
取出张三的所有信息
# 语法 substring:包含某个值
scan '表名', FILTER=>"ValueFilter(=,'substring:列值')"
scan 'users',FILTER=>"ValueFilter(=,'substring:2019')"
取里面包含2019的所有列
2、ColumnPrefixFilter 列名前缀过滤器
# 语法 substring:包含某个值
scan '表名', FILTER=>"ColumnPrefixFilter('列名前缀')"
scan 'users', FILTER=>"ColumnPrefixFilter('a')"
取出所有包含a的列的所有信息
3、rowKey字典排序
Table中的所有行都是按照row key的字典排序的