HBase是一个基于HDFS、低延迟的列式数据库,它支持随机访问和更改HDFS上的数据,但HDFS中的文件是只能附加的,并且一旦创建后是不能改变的,那么HBase是怎么做到低延迟读写的?该文主要介绍了HBase的写路径(Write Path),即HBase中的数据是怎么更改的?
Write Path
写路径(Write Path)实际就是HBase中put或delete数据的流程,是怎么put、delete数据的。写路径开始于客户端,然后到region server,最后数据写到HBase的数据文件(HFile)中。
HBase中的表主要由三类server负责托管和管理:
- 一个master server:负责集群状态的管理、负载均衡等,不提供数据的存储服务
- 一个或多个备份 master server:master server的备份
- 多个region server:负责存储数据、数据处理服务
由于HBase的表比较大,通常会将他们按一定的大小比例切分,切分的每一个部分称为region,这些region会被分发到相应的region server上,每一个region server可以有多个region。
HBase组织数据的形式类似于排序的map集合(sort map),按key排序,然后分发到不同的region。客户端可以通过put或delete命令来修改表中的数据,当客户端发送一个更改请求,该请求将被路由到一个region server。另外,也可以通过编码的方式将这些请求缓存到客户端,然后批量提交这些操作。
当客户端发送一个put或delete请求,首先会根据row key (行健)从ZooKeeper集群中找到含有-ROOT- region的region server,然后从含有root region的server上再找到含有-META- region的region server,最后从含有-META- region的region server上查找实际的region server。在找到实际的region server后,会将行健实际对应的region server的地址缓存起来,因为这个查找的过程是比较昂贵的操作。如果缓存的地址无效了,将会从新查找并更新缓存。
当请求到达相应的region server后,并不会立即更改HFile文件中的数据,因为HFile文件中的数据都是按key排序的。而是先保存到内存中的一个称为memstore地方,在memstore中的数据也是有序的,同HDFile文件中的排序方式一样。当memstore中的数据累积到足够大时,将会被刷写到HDFS上一个新的HFile文件中。
整个过程如下:
将修改直接保存到memstore中,存在一定的风险,如果当前的region server崩溃,那么其memstore中的数据将会丢失,所以为了降低风险,HBase在将修改操作保存到memstore之前,先将其保存到一个预写日志文件(write-ahead log,, WAL)中,这样,如果一个region server发生故障,可以通过回放(replay)WAL文件中的内容来恢复数据。
WAL文件中的数据不同于HFile文件,它包含一个edit列表,每一个eidt表示一个put或delete操作,并且还有相应的region server信息。edit是按时间顺序写入的。
随着WAL文件的增长,当达到指定的阈值就会被关闭,并创建一个新的文件来接收edit操作,这称为“滚动(rolling)”WAL文件,一旦WAL文件滚动,老的WAL文件将不在改变。
默认,WAL文件大小达到块大小的95%时就会发生滚动(roll),当然可以通过hbase.regionserver.logroll.multiplier参数和hbase.regionserver.hlog.blocksize参数配置。另外,还可以通过配置“hbase.regionserver.logroll.period”参数定期的滚动日志,默认为1小时。
一个region server含有多个region,这些region共享一个WAL文件。因为WAL文件是滚动的,所以每个region server会有许多WAL文件,值得注意的是在任意时刻只有一个WAL文件是可用的。
WAL文件中的每一个edit都有一个唯一的sequence ID,这个ID是递增的,当WAL文件滚动时,下一个sequence ID和老的日志文件名将会被保存到一个map集合中,这样做主要是为了跟踪每个WAL文件的最大sequence ID,在刷写memstore中的数据到磁盘上,可以较容易的找出哪些文件需要归档 (通过检查写入到存储文件中的最大序列号是多少,因为小于或等于这个序列号的所有修改都已经保存了。还要检查是不是有日志文件的序列号小于这个序列号,如果有,就会将这些文件移动到.oldlogs文件夹中,留下其余的日志)
每个region中的edit和它的sequence ID是唯一的,任何时候一个edit添加到WAL文件中,同时它的sequence ID也会作为最后的sequence ID被写入。当将memstore中的数据刷写到磁盘时,如果写到磁盘上的最后sequence ID和WAL文件中的最大的sequence ID相同,表明WAL文件中的所有edit都已经写入到了磁盘上,那么这个文件就可以关闭了,并可以进行归档。