HBase读取数据的流程

  1. 从zookeeper找到meta表的region的位置,然后读取meta表中的数据。而meta中又存储了用户表的region信息
  2. 根据namespace、表名和rowkey根据meta表中的数据找到对应的region信息, 查找对应的region
    ZK:/hbase/meta-region-server,该节点保存了meta表的region server数据
  3. 从MemStore找数据,再去BlockCache中找,如果没有,再到StoreFile上读
  4. 可以把MemStore理解为一级缓存,BlockCache为二级缓存,但注意scan的时候BlockCache意义不大,因为scan是顺序扫描

hbase用的什么协议 hbase的工作原理_xml

HBase存储数据的流程

客户端流程

  1. 客户端发起写入数据的请求, 首先会先连接zookeeper, 从zookeeper获取 hbase:meta表所在的regionServer的地址
  2. 连接meta表对应的regionServer, 从meta表获取目标表对应要写入数据的region的地址(基于region的startkey和endKey来确定)
  3. 连接对应region的regionServer的地址, 开始进行数据的写入
  4. 首先先将数据写入到这个regionServer的Hlog日志中, 然后在将数据写入到对应的region中store模块的memStore中, 当这个两个地方都写入完成后, 客户端就会认为数据写入完成了

服务器端流程(异步)

  1. 客户端不断的进行数据的写入工作, memStore数据也会不断的增多, 当memStore中数据达到一定的阈值(128M|1小时)后, 内部最终启动一个flush线程, 将数据刷新到HDFS上, 形成一个storeFile文件
  2. 随着memStore不断刷新数据到HDFS中, storeFile文件也会越来越多, 当storeFile的文件达到一定的阈值后(3个及以上), 启动compact线程, 将多个文件合并最终合并为一个大文件(Hfile)
  3. 随着不断的合并, 这个大的Hfile文件也会越来越大, 当这个大的Hfile达到一定的阈值(最终10GB)后, 启动split机制, 将大的Hfile一分为二的操作, 此时region也会进行分割操作, 变成两个新的region, 每个region管理每个分割后新的Hfile文件, 原有旧的region就会被下线
  4. 随着不断的进行split, 表的region的数量也会越来越多

HBase的memStore溢写合并

hbase用的什么协议 hbase的工作原理_hbase_02

说明

  • 当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策略配置

  1. 可以通过hbase-site.xml来配置默认In Memory Compaction方式
<property>
	<name>hbase.hregion.compacting.memstore.type</name>
  <value><none|basic|eager|adaptive></value>
</property>
  1. 在创建表的时候指定方式
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启动后进行以下步骤:

  1. 从Zookeeper上获取唯一一个代表active master的锁,用来阻止其它master成为master;
  2. 一般hbase集群中总是有一个master在提供服务,还有一个以上的master在等待时机抢占它的位置;
  3. 扫描Zookeeper上的server父节点,获得当前可用的region server列表
  4. 和每个region server通信,获取当前已分配的region和region server的对应关系
  5. 扫描.META.region的集合,计算得到当前还未分配的region,将他们放入待分配region列表

Master下线

  • 由于master只维护表和region的元数据,而不参与表数据IO的过程,master下线仅导致所有元数据的修改被冻结
  • 无法创建删除表
  • 无法修改表的schema
  • 无法进行region的负载均衡
  • 无法处理region上下线
  • 无法进行region的合并
  • 唯一例外的是region的split可以正常进行,因为只有region server参与
  • 表的数据读写还可以正常进行
  • 因此master线下短时间内对整个HBase集群没有影响
  • 从上线过程可以看到,master保存的信息全是可以冗余信息(都可以从系统其它地方收集到或者计算出来)