HBase读取数据的流程
-
从zookeeper找到meta表的region的位置,然后读取meta表中的数据。而meta中又存储了用户表的region信息
-
根据namespace、表名和rowkey根据meta表中的数据找到对应的region信息, 查找对应的region
ZK:/hbase/meta-region-server,该节点保存了meta表的region server数据 -
从MemStore找数据,再去BlockCache中找,如果没有,再到StoreFile上读
-
可以把MemStore理解为一级缓存,BlockCache为二级缓存,但注意scan的时候BlockCache意义不大,因为scan是顺序扫描
HBase存储数据的流程
客户端流程
- 客户端发起写入数据的请求, 首先会先连接zookeeper, 从zookeeper获取 hbase:meta表所在的regionServer的地址
- 连接meta表对应的regionServer, 从meta表获取目标表对应要写入数据的region的地址(基于region的startkey和endKey来确定)
- 连接对应region的regionServer的地址, 开始进行数据的写入
- 首先先将数据写入到这个regionServer的Hlog日志中, 然后在将数据写入到对应的region中store模块的memStore中, 当这个两个地方都写入完成后, 客户端就会认为数据写入完成了
服务器端流程(异步)
- 客户端不断的进行数据的写入工作, memStore数据也会不断的增多, 当memStore中数据达到一定的阈值(128M|1小时)后, 内部最终启动一个flush线程, 将数据刷新到HDFS上, 形成一个storeFile文件
- 随着memStore不断刷新数据到HDFS中, storeFile文件也会越来越多, 当storeFile的文件达到一定的阈值后(3个及以上), 启动compact线程, 将多个文件合并最终合并为一个大文件(Hfile)
- 随着不断的合并, 这个大的Hfile文件也会越来越大, 当这个大的Hfile达到一定的阈值(最终10GB)后, 启动split机制, 将大的Hfile一分为二的操作, 此时region也会进行分割操作, 变成两个新的region, 每个region管理每个分割后新的Hfile文件, 原有旧的region就会被下线
- 随着不断的进行split, 表的region的数量也会越来越多
HBase的memStore溢写合并
说明
- 当MemStore写入的值变多,触发溢写操作(flush),进行文件的溢写,成为一个StoreFile
- 当溢写的文件过多时,会触发文件的合并(Compact)操作,合并有两种方式(major,minor)
触发的条件
- 一旦MemStore达到128M时,则触发Flush溢出(Region级别)
<property>
<name>hbase.hregion.memstore.flush.size</name>
<value>134217728</value>
<source>hbase-default.xml</source>
</property>
- MemStore的存活时间超过1小时(默认),则触发Flush溢写(RegionServer级别)
<property>
<name>hbase.regioinserver.optionalcacheflushinterval</name>
<value>3600000</value>
<source>hbase-default.xml</source>
</property>
In-memory合并
- In-memory合并是HBase2.0之后添加的。它与默认的MemStore的区别:实现了在内存中进行compaction(合并)
- 在CompactingMemStore中,数据是以段(Segment)为单位存储数据的。MemStore包含了多个segment。
- 当数据写入时,首先写入到Active segment中(也就是当前可以写入的segment段)
- 在2.0之前,如果MemStore中的数据量达到指定的阈值时,就会将数据flush到磁盘中的一个StoreFile
- 2.0的In-memory compaction,active segment满了后,将数据移动到pipeline中。这个过程跟以前不一样,以前是flush到磁盘,而现在是将Active segment的数据移动到陈伟pipeline的内存当中。一个pipeline中可以有多个segment。而In-memory compaction会将pipeline的多个segment合并为更大的、更紧凑的segment,这就是compaction。
- HBase会尽量延长CompactingMemStore的生命周期,以达到减少总的IO开销。当需要把CompactingMemStore flush到磁盘时,pipeline中所有的segment会被移动到一个snapshot中,然后进行合并后写入到HFile。
compaction策略
当Active segment flush到pipeline中后,后台会触发一个任务来合并pipeline中的数据。合并任务会扫描pipeline中所有的segment,将segment的索引合并为一个索引。
有三种合并策略:
- basic(基础型)
- Basic compaction策略不清理多余的数据版本,无需对cell的内存进行考核
- basic适用于所有大量写模式
- eager(饥渴型)
- eager compaction会过滤重复的数据,清理多余的版本,这回带来额外的开销
- eager模式主要针对数据大量过期淘汰的场景,例如:购物车、消息队列等
- adaptive(适应型)
- adaptive compaction根据数据的重复情况来决定是否使用eager策略
- 该策略会找出cell个数最多的一个,然后计算一个比例,如果比例超出阈值,则使用eager策略,否则使用basic策略
compaction策略配置
-
可以通过hbase-site.xml来配置默认In Memory Compaction方式
<property> <name>hbase.hregion.compacting.memstore.type</name> <value><none|basic|eager|adaptive></value> </property>
-
在创建表的时候指定方式
create "test_memory_compaction",{NAME => 'C1', IN_MEMORY_COMPACTION => "BASIC"}
HBase的StoreFile合并
- 当MemStore超过阈值的时候,就要flush到HDFS上生成一个StoreFile。因此随着不断写入,HFile的数量将会越来越多,StoreFile数量过多会降低读性能
- 为了避免对读性能的影响,需要对这些StoreFile进行compact操作,把多个HFile合并成一个HFile
- compact操作需要对HBase的数据进行多次的重新读写,因此这个过程会产生大量的IO。可以看到compact操作的本质就是以IO操作换取后续的读性能的提高
minor compaction
minor合并
- minor compaction操作只用来做部分文件的合并操作,包括minVersion=0并且设置ttl的过期版本清理,不做任何删除数据、多版本数据的清理工作
- 小范围合并,默认是3-10个文件进行合并,不会删除其他版本的数据
- minor compaction只会选择数个StoreFile文件compact为一个StoreFile
- minor compact的过程一般较快,而且IO相对较低
minor合并触发条件
-
在打开region或者MemStore时会自动检测是否需要compact(包括minor、major)
-
minFilesToCompact由
hbase.hstore.compaction.min
控制,默认值为3 -
即store下面的StoreFile数量减去正在compaction的数量>=3时,需要做compaction
http://youhosts:16010/conf
<property> <name>hbase.hstore.compaction.min</name> <value>3</value> <final>false</final> <source>hbase-default.xml</source> </property>
major compaction
major合并
- Major compaction操作是对region下的Store中的所有StoreFile执行合并操作,最终的结果是整理合并出一个文件
- 一般手动触发,会删除其它版本的数据(不同时间戳的)
major合并触发条件
-
如果无需进行minor compaction,HBase会继续判断是否需要执行major compaction
-
如果所有的StoreFile中,最老(时间戳最小)的那个StoreFile的世界间隔大于major compaction的时间间隔(hbase.hregion.majorcompaction–默认7天)
<property> <name>hbase.hregion.majorcompaction</name> <value>604800000</value> <source>hbase-default.xml</source> </property>
HBase的split分裂
-
当region中的数据逐渐变大之后,达到某一个阈值,会进行裂变
-
一个region等分为两个region,并分配到不同的RegionServer
-
原本的Region会下线,新split出来的两个Region会被HMaster分配到相应的HRegionServer上,使得原先1个Region的压力得以分流到2个Region上。
<--Region最大文件大小为10G--> <property> <name>hbase.hregion.max.filesize</name> <value>10737418240</value> <final>false</final> <source>hbase-default.xml</source> </property>
-
-
HBase只是增加数据,所有的更新和删除操作,都是在compact阶段做的
-
用户写入操作只需要进入到内存即可立即返回,从而保证I/O高性能读写
自动分区
之前我们在建表的时候,没有涉及过任何关于Region的设置,由HBase来自动进行分区。也就是当Region达到一定大小就会自动进行分区。最小的分裂大小和table的某个region server的region的个数有关,当StoreFile的大小大于如下公式得出的值的时候就会split,公式如下:
Min(R^2 * "hbase.hregion.memstore.flush.size", "hbase.hregion.max.filesize")
R为同一个table中在同一个region server中的region个数。
- 如果初识R=1,那么Min(128MB,10GB)=128MB,也就是说在第一个flush的时候就会触发分裂操作
- 当R=2时,Min(2^2*128MB,10GB)=512MB,当某个StoreFile大小达到512MB的适合,就会触发分裂
- 以此类推,当R=9的时候,StoreFile达到10GB的时候就会分裂,也就是当R>=9的时候,StoreFile达到10GB的时候就会分裂
- split的点都位于Region中row key的中间点
手动分区
在创建表的时候,就可以指定表分为多少个Region。默认一开始的时候系统会只向一个RegionServer写数据,系统不指定startRow和endRow,可以在运行的时候提前split,提高并发写入。
Region的管理
Region分配
- 任何时刻,一个region只能分配给一个region server
- Master记录了当前有哪些可用的region server,以及当前哪些region分配给了哪些region server,哪些region还没有分配。当需要分配新的region,并且有一个region server上有可用空间时,maser就给这个region server发送一个装载请求,把region分配给这个region server。region server得到请求后,就开始对此region提供服务。
region server上线
- Master使用Zookeeper来跟踪region server状态
- 当某个region server启动时
- 首先在Zookeeper上的server目录下建立代表自己的znode
- 由于Master订阅了server目录上的变更消息,当server目录下的文件出现新增或者删除操作时,master可以得到来自Zookeeper的实时通知
- 一旦region server上线,master能马上得到消息。
region server下线
- 当region server下线时,它和Zookeeper的会话断开,Zookeeper会自动释放代表这台server的文件上的独占锁
- Master就可以确定
- region server和Zookeeper之间的网络断开了
- region server挂了
- 无论哪种情况,region server都无法继续为它的region提供服务了,此时master会删除server目录下代表这台region server的znode数据,并将这台region server的region分配给其他还活着的节点
Master工作机制
Master上线
Master启动后进行以下步骤:
- 从Zookeeper上获取唯一一个代表active master的锁,用来阻止其它master成为master;
- 一般hbase集群中总是有一个master在提供服务,还有一个以上的master在等待时机抢占它的位置;
- 扫描Zookeeper上的server父节点,获得当前可用的region server列表
- 和每个region server通信,获取当前已分配的region和region server的对应关系
- 扫描.META.region的集合,计算得到当前还未分配的region,将他们放入待分配region列表
Master下线
- 由于master只维护表和region的元数据,而不参与表数据IO的过程,master下线仅导致所有元数据的修改被冻结
- 无法创建删除表
- 无法修改表的schema
- 无法进行region的负载均衡
- 无法处理region上下线
- 无法进行region的合并
- 唯一例外的是region的split可以正常进行,因为只有region server参与
- 表的数据读写还可以正常进行
- 因此master线下短时间内对整个HBase集群没有影响
- 从上线过程可以看到,master保存的信息全是可以冗余信息(都可以从系统其它地方收集到或者计算出来)