3-1 HBase写流程
HBase是通过zookeeper集群协调进行数据的写入,Client客户端首先会访问Zookeeper,从Zookeeper中获取表的相关信息以及表的Region相关信息,根据我们要插入数据的rowkey,获取指定RegionServer的信息。如果是批量提交,会把rowkey根据HRegionLocal进行分组,当我们得到了需要访问的RegionServer后Client会向对应的RegionServer发起写请求并把数据发送给RegionServer,当这个RegionServer收到请求之,首先会执行各种检查操作比如说这个RegionServer是不是处于只读状态,memorystore大小是不是超过了blocksize的大小,检查完成之后,就会进入真正的写入操作RegionServer依次将数据写入memstore和Hlog,只有这两者都写入成功,此次写入才算成功。这个过程比较复杂,写入memorystore和hlog都会获取相关的锁,要么全部成功,要么全部失败。当memStore的大小达到我们设置的阈值时,将memStore中的数据flush成store file文件。当store file增加到一定数量,会触发Compare合并机制,会将多个store file 合并成一个大的storefile文件 。如果单个store file 达到了一定的阈值,会触发split机制,将RegionServer一分为二 ,然后HMaster给两个RegionServer分配相应的RegionServer进行管理,从而分担压力。
HBase写流程总结如下:
- Client会先访zookeeper,得到对应的 Regionserver 地址;
- Client 对 Regionserver 发起写请求, Regionserver接受数据写入内存;
- 当 Memstore 的大小达到一定的值后, flush到StoreFIle并存储到 HDFS;
RegionServer处理数据的输入输出请求,RegionServer管理多个region,每个region都有对应的Hlog实例,region是数据存储单元,数据都存储在region中。每一个region,存储一个column family数据,而且只是这个列族的一部分,当这个region达到某个阈值之后,会根据rowkey的排序,划分为多个region,每个region中又包含多个store对象,每一个store中包含一个memstore和一个或者多个Store file,memstore就是数据的实体,一般是有序的,当有数据写入的时候,会先写入memstore,当memstore达到上限之后,store会创建Store File(HFile的一层封装),HBase依赖于HDFS,HFile存储在HDFS之上,所以memstore中的数据,最终就会写入HFile中。
HBase保证数据不丢的关键是HLog,HLog就是WAL(预写日志,事务中常见的一种实现方式)的一种实现,每个RegionServer都有一个HLog实例,RegionServer会将更新操作记录在memstore,然后写入到HLog中,只有当HLog更新成功之后,这个数据才算真正写入。这样即使memstore中的数据丢失了,还是可以根据HLog找到的。这里要注意一下,一般的WAL预写日志,都是先写入WAL再写入内存的,HBase是先写入内存,在写入日志。
3-2 HBase读流程
以RowKey读取为例,客户端client想要读取数据,必须先去访问ZooKeeper,然后通过访问meta RegionServer的节点信息,将HBase的meta表缓存到本地,通过缓存的表,获取要访问的表的相对应的RegionServer的信息,当client知道要访问的表的RegionServer信息之后,client就像对应的RegionServer发起读请求,RegionServer收到读请求之后,RegionServer先扫描自己的MemStore,如果没有找到数据,再扫描blockCache(加速读的缓冲区),如果还没有找到,就从StoreFile中查找数据,然后将这条数据返回给client,将数据返回给客户端。
- Client会先访问zookeeper,得到对应的Regionserver地址
- Client对Regionserver 发起读请求
- 当Regionserver收到client 的读请求后,先扫描自己的 Memstore,再扫描BlockCache(加速读内容缓存区)如果还没找到则StoreFIIe中读取数据,然后将数据返回给Client
通过HBase的读和写我们了解到,HBase的读写操作和HMaster没有任何关系,客户端请求数据的时候,只需要知道zookeeper的地址,和HMaster没有关系,也不需要提前知道RegionServer的IP,原因是HMaster在启动的过程中,会把Meta的信息表的加载到zookeeper,这个表存储了HBase的所有的表,所有region的详细信息,例如region开始的key,结束的key,所在RegionServer的地址,HBase的meta表就相当于一个目录,通过这个表可以快速的定位到数据的实际位置,所以读写操作只需要与zookeeper和对应的RegionServer进行交互。HMaster只负责维护table和meta的元数据信息,协调各个RegionServer,所以HMa的负载就小了很多。
3-3 HBase模块的协作
HMaster不参与数据的读写,RegionServer负责管理region,参与数据的读写。客户端要访问数据的信息,只需要知道zookeeper的地址就可以了。
下面我们来探讨三个问题,进一步加深HBase模块之间的协作
- HBase启动,发生了什么
Hamster启动的时候,首先将自己注册到backup Master节点(原因是可能会有很多master节点, 最终的activity master节点可能为了抢占锁,所以默认都先把自己写入到backup maser节点,如果抢占锁成功,成为activity master,就会将自己从backup master节点删除,然后实例化一些相关的类,比如MasterFileSystem,ServerManager,TableStateManager等等),然后注册到Zookeeper,等待RegionServer节点汇报。
此时RegionServer会注册到Zookeeper,并向HMaster汇报。
HMaster收集到RegionServer的信息后,对各个RegionServer(包括失效的)的数据进行整理,分配Region和meta信息。然后将这张表交个zookeeper。其他的backup master就会定期的从activity master保持数据的更新,以保证自己的meta数据是最新的。RegionServer启动正式注册到集群之后,会设置WAL预写日志,定期的刷新memstore,保证数据最终写入到HFile文件,以及client通过zookeeper发起的请求等。
- 当RegionServer失效后,会发生什么,如何保证数据的可读可写?
zookeeper会向HMaster汇报,HMaste在meta表中将该失效的RegionServer删除,并将其上的Region分配到其他的节点。然后将更新之后的meta表交给zookeeper。
- 当HMaster失效后,会发生什么,如果我们配置了高可用,那么集群将会怎样?如果没有配置高可用,那么集群会不会宕机?
如果集群配置了高可用,当HMaster失效后,backup Master会通过zookeeper选举出一个activity master。如果没有配置高可用,数据能正常读写,但是因为涉及到meta表的更新,不能创建删除表,不能更改表结构。
3-4 HBase的shell命令
Hbase常见的命令
hbase shell命令 | 描述 |
alter | 修改列族(column family)模式 |
count | 统计表中行的数量 |
create | 创建表 |
describe | 显示表相关的详细信息 |
delete | 删除指定对象的值(可以为表,行,列对应的值,另外也可以指定时间戳的值) |
deleteall | 删除指定行的所有元素值 |
disable | 使表无效 |
drop | 删除表 |
enable | 使表有效 |
exists | 测试表是否存在 |
exit | 退出hbase shell |
get | 获取行或单元(cell)的值 |
incr | 增加指定表,行或列的值 |
list | 列出hbase中存在的所有表 |
put | 向指向的表单元添加值 |
tools | 列出hbase所支持的工具 |
scan | 通过对表的扫描来获取对用的值 |
status | 返回hbase集群的状态信息 |
shutdown | 关闭hbase集群(与exit不同) |
truncate | 重新创建指定表 |
version | 返回hbase版本信息 |
shell命令例子
进入Hbase cli的命令是hbase shell
# HBase shell中的帮助命令非常强大,使用help获得全部命令的列表,使用help ‘command_name’获得某一个命令的详细信息
help 'status'
# 查询服务器状态
status
# 查看所有表
list
# 创建一个表
create 'FileTable','fileInfo','saveInfo'
# 获得表的描述
describe 'FileTable'
# 添加一个列族
alter 'FileTable', 'cf'
# 删除一个列族
alter 'FileTable', {NAME => 'cf', METHOD => 'delete'}
# 插入数据
put 'FileTable', 'rowkey1','fileInfo:name','file1.txt'
put 'FileTable', 'rowkey1','fileInfo:type','txt'
put 'FileTable', 'rowkey1','fileInfo:size','1024'
put 'FileTable', 'rowkey1','saveInfo:path','/home'
put 'FileTable', 'rowkey1','saveInfo:creator','tom'
put 'FileTable', 'rowkey2','fileInfo:name','file2.jpg'
put 'FileTable', 'rowkey2','fileInfo:type','jpg'
put 'FileTable', 'rowkey2','fileInfo:size','2048'
put 'FileTable', 'rowkey2','saveInfo:path','/home/pic'
put 'FileTable', 'rowkey2','saveInfo:creator','jerry'
# 查询表中有多少行
count 'FileTable'
# 获取一个rowkey的所有数据
get 'FileTable', 'rowkey1'
# 获得一个id,一个列簇(一个列)中的所有数据
get 'FileTable', 'rowkey1', 'fileInfo'
# 查询整表数据
scan 'FileTable'
# 扫描整个列簇
scan 'FileTable', {COLUMN=>'fileInfo'}
# 指定扫描其中的某个列
scan 'FileTable', {COLUMNS=> 'fileInfo:name'}
# 除了列(COLUMNS)修饰词外,HBase还支持Limit(限制查询结果行数),STARTROW(ROWKEY起始行。会先根据这个key定位到region,再向后扫描)、STOPROW(结束行)、TIMERANGE(限定时间戳范围)、VERSIONS(版本数)、和FILTER(按条件过滤行)等。比如我们从RowKey1这个rowkey开始,找下一个行的最新版本
scan 'FileTable', { STARTROW => 'rowkey1', LIMIT=>1, VERSIONS=>1}
# Filter是一个非常强大的修饰词,可以设定一系列条件来进行过滤。比如我们要限制名称为file1.txt
scan 'FileTable', FILTER=>"ValueFilter(=,'name:file1.txt’)"
# FILTER中支持多个过滤条件通过括号、AND和OR的条件组合
scan 'FileTable', FILTER=>"ColumnPrefixFilter('typ') AND ValueFilter ValueFilter(=,'substring:10')"
# 通过delete命令,我们可以删除某个字段,接下来的get就无结果
delete 'FileTable','rowkey1','fileInfo:size'
get 'FileTable','rowkey1','fileInfo:size'
# 删除整行的值
deleteall 'FileTable','rowkey1'
get 'FileTable',’rowkey1'
# 通过enable和disable来启用/禁用这个表,相应的可以通过is_enabled和is_disabled来检查表是否被禁用
is_enabled 'FileTable'
is_disabled 'FileTable'
# 使用exists来检查表是否存在
exists 'FileTable'
# 删除表需要先将表disable
disable 'FileTable'
drop 'File