类似于MySQL的binary log,WAL存储了对数据的所有更改,这使得服务器崩溃的时候,可以有效地回放日志,是数据得以恢复到崩溃以前。这也就意味着如果将记录写入到WAL失败时,整个操作也可以认为是失败的。
WAL就像日志中心一样,它被同一个region server中的所有region共享。
当客户端启动一个操作来修改数据,该操作便会被封装成一个KeyValue对象实例中,并通过RPC调用发送出去。这些调用成批的发送给含有匹配region的HRegionServer。一旦KeyValue到达,它们会被发送到管理相应行的HRegion对象实例。数据便被写入到WAL,然后放入到实际拥有记录的存储文件的MemStore中。
最后当memstore达到一定的大小或者经历一个特定时间之后,数据就会异步地连续写入到文件系统中。在写入的过程中,数据以一种不稳定的状态存放在内容中,即使在服务器完全崩溃的情况下,WAL也能够保证数据不丢失,因为实际的日志存储在HDFS上。其他服务器可以打开日志然后回放这些修改。
实现了WAL的类叫做HLog。当HRegion被实例化时,HLog实例会被当作一个参数传入到HRegion的构造器中,当一个region接收到一个更新操作时,它可以直接将数据保存到一个共享的WAL实例中去。
HLog的另一个特性是追踪修改,这个特性可以通过使用序列号来实现。
WAL当前使用的是Hadoop的SequenceFile,这种文件格式按照键/值集合的方式存储记录
对WAL来说,Value仅仅是客户端发送的修改请求,Key则是HLogKey实例。由于KeyValue仅仅代表行健、列族、列限定词、时间戳、类型以及值,所以要有一个地方来存储KeyValue的归属,即region和表名,这个信息存储在HLogKey中。
客户端发送的每一个修改都会被封装到一个WALEdit类。它通过日志级别来管理原子性。
表的描述符允许用户设置延迟日志刷写(deffered log flush)的标志,默认是false,意味着每一次编辑都被发送到服务器时,它都会调用写日志的sync()方法。这个调用强迫写入日志的更新都会被文件系统确认,所以用户获得了持久化的保证。
目前sync()的实现是管道写,意味着当修改被写入时,它会被发送到第一个DataNode进行存储。一旦成功,第一个DataNode就会把修改发送到另一个Data Node来进行相同的工作。只有3个DataNode都已经确认了写操作,客户端才被会允许继续进行。
写入操作被同时发送到3台主机,当所有主机都确认了写操作之后,客户端才可以继续。
日志的写入是有大小限制的。LogRoller类会作为一个后台线程运行,并且在特定的时间间隔内滚动日志。
master和region服务器需要配合起来精确地处理日志文件,特别是需要从服务器失效中恢复的时候,WAL用来保持数据更新的安全,而回放则是一个使用系统恢复到一致性状态的更加复杂的过程。
考虑到同时写入太多文件,且需要保留滚动的日志会影响系统的扩展性,因此所有的数据更新都会被写入到region服务器中的一个基于HLog的日志文件中。
有两种日志文件需要被回放的情况:集群启动时或服务失败时。当master启动的时候(包括备用的master接管系统的时候),它会检查文件系统中HBase根目录的.log
文件夹下是不是有日志文件,以及这些文件又没有分配的region服务器。
日志的名字不仅包含服务器的名字,还包含服务器的启动码(start code)。这个数字会在每次region服务器重启的时候重置。master可以通过这个数字来检查日志是否被遗弃了。
在日志中的数据改动被回放之前,日志需要单独放在每个region对应的单独的日志文件中。
读取混在一起的日志,并且所有的条目都按照它所归属的region来分组。这些分组的修改记录被存放在一个紧挨着目标region的文件中以供接下来的数据恢复过程使用。这个过程叫做日志拆分。
日志拆分版本已经经过多次变更,见HBase Log Splitting。
.corrupt
文件夹包括所有不能解析的日志文件。这种情况可以通过hbase.hlog.split.skip.errors
属性来改变。默认情况下设置为true,表示所有不可以从文件中读出来的数据更改都会使整个日志文件被移动到.corrupt
文件夹中。
注意日志拆分和region拆分的区别。
当集群启动,或region从一个region server移动到另一个region server中时,region都会被打开,且此时region会首先检查recovered.edits目录是否存在,如果该目录存在,它就会打开该目录的文件,并开始读取文件所包含的数据更改记录。又由于文件是按照序列ID的文件名排序的,region便可以按照序列ID的数据来恢复数据。
一旦recovered.edits目录中的文件都被处理完,且其中的数据更改也都被写入到硬盘后,该目录便会被删除。当出现文件不可读的情况时,hbase.skip.errors
属性决定了接下来系统的行为。
HBase原理-RegionServer宕机数据恢复
HBase会检测当前的Hadoop库是否支持syncFS()或hflush()。如果写入日志的时候触发sync(),则HBase会在内部调用以上两种方法之一。