hbase写入数据时,为了提升写入效率,先写入缓存memory store,默认为128M,缓存满了会触发flush落盘,写入hfile文件。

但这种方式并不安全,如果缓存未满之前region server挂掉,还未来得及落盘的数据就会丢失。

hbase提供的解决方案是在写入缓存之前写入hlog日志文件。

每个region server管理多个region,这些region共享一个hlog,即一个region server上只有一个hlog,准确的说,只有一个可以写入的hlog,因为hlog达到指定大小后,会滚动生成一个新的hlog接收新的日志数据。

hbase 建表如何设置备份数 hbase如何保证数据不丢失_log日志

结合hlog的作用,有下面两个问题,需要搞清楚:

  • 第一,随着hbase大量的写入,日志必然会越来越多,永久保存会浪费大量存储空间,hbase规定hlog超出一定数量后要删除最老的日志文件,如何确定一个文件能不能删除呢,如果最老的文件不能删除,hbase的机制是什么?
  • 第二,hlog存在的作用是为了保证数据的高可靠,防止数据丢失,那么当region server宕机之后,如果根据hlog恢复数据呢?

sequenceId就是这几个问题的答案。

记入hlog的每一条日志都有一个sequenceId,写入memory store的数据也包含sequenceId,并且是一一对应的。

sequenceId是什么呢?

sequenceId是一个hlog维护的自增id,每个region维护一个,同一个region的sequenceId不会重复。

除此之外,hlog还维护着另外一个变量oldestUnflushedSequenceId,这个变量指向一个sequenceId,这个sequenceId之前的记录已经全部落盘了。

假设某个region server上有两个region,其hlog的逻辑图如下:

hbase 建表如何设置备份数 hbase如何保证数据不丢失_hbase 建表如何设置备份数_02

此时有两个hlog,hlog1已经写满,注意此时oldestUnflushedSequenceId的指向:

region1的oldestUnflushedSequenceId指向sequenceId的值是3,说明3之前的数据已经落盘。

region2的oldestUnflushedSequenceId指向sequenceId的值是6,说明6之前的数据已经落盘。

从图上可以直观的看出,两个region的oldestUnflushedSequenceId指向的sequenceid都在hlog2上,说明hlog1上所有的日志对应的数据都已经落盘,此时hlog1可以被删除。

如果是下面这种情况:

hbase 建表如何设置备份数 hbase如何保证数据不丢失_缓存_03


region1的oldestUnflushedSequenceId指向了hlog1,说明hlog1上对应数据还没有落盘,假设系统设置的最大hlog文件数是2,则不能再创建新的hlog文件,必须要删除一个hlog文件,但最老的hlog1还没有全部落盘,不能直接删除。

这种情况下,hbase会强制hlog1对应的数据flush落盘,使得hlog可以删除。

搞清楚了这个机制,宕机之后的数据恢复也就比较容易理解了。

宕机之后,hbase会找到对应的hlog日志,将oldestUnflushedSequenceId之后的数据恢复出来,写入缓存,数据就得到了恢复。