一、预写日志WAL(Write-Ahead-Log)

HBase的Write Ahead Log (WAL)提供了一种高并发、持久化的日志保存与回放机制。每一个业务数据的写入操作(PUT / DELETE)执行前,都会记账在WAL中。

WAL(Write-Ahead-Log)是HBase的RegionServer在处理数据插入和删除的过程中用来记录操作内容的一种日志。大致过程如下图所示,首先客户端启动一个操作来修改数据,每一个修改都封装到KeyValue对象实例中,并通过RPC调用发送到含有匹配Region的HRegionServer。一旦KeyValue到达,它们就会被发送管理相应行的HRegion实例。数据被写到WAL,然后被放入到实际拥有记录的存储文件的MemStore中。同时还会检查MemStore是否满了,如果满了就会被刷写到磁盘中去。



默认是每个RegionServer有1个WAL,在HBase1.0开始支持多个WALHBASE-5699,这样可以提高写入的吞吐量。配置参数为hbase.wal.provider=multiwal,支持的值还有defaultProvider和filesystem(这2个是同样的实现)。

WAL的持久化的级别有如下几种:

SKIP_WAL:不写wal日志,这种可以较大提高写入的性能,但是会存在数据丢失的危险,只有在大批量写入的时候才使用(出错了可以重新运行),其他情况不建议使用。

ASYNC_WAL:异步写入

SYNC_WAL:同步写入wal日志文件,保证数据写入了DataNode节点。

FSYNC_WAL: 目前不支持了,表现是与SYNC_WAL是一致的

USE_DEFAULT: 如果没有指定持久化级别,则默认为USE_DEFAULT, 这个为使用HBase全局默认级别(SYNC_WAL)

HBase的Write Ahead Log (WAL)提供了一种高并发、持久化的日志保存与回放机制。每一个业务数据的写入操作(PUT / DELETE)执行前,都会记账在WAL中。

如果出现HBase服务器宕机,则可以从WAL中回放执行之前没有完成的操作。

HLog

HLog是实现WAL的类。一个HRegionServer对应一个HLog实例。当HRegion初始化时,HLog将作为一个参数传给HRegion的构造函数。

HLog最核心的是调用doWrite的append() 方法,前面提到的可能对数据改动的操作都就将首先调用这个方法。出于性能的考虑,put(), delete() 和incrementColumnValue()有一个开关函数setWriteToWAL(boolean) , 设为false将禁用WAL。这是为什么上图中向下的箭头是虚线的原因。默认时候当然需要WAL,但是假如你运行一个数据导入的MapReduce Job,你可以通过关闭WAL获得性能上的提升。

另一个重要的特性是HLog将通过“sequence number”追踪数据改变。它内部使用AtomicLong保证线程安全。sequence number的起始值为0,或者是最近一次存入文件系统中sequence number。Region打开存储文件,读取每个HFile中的最大的sequence number,如果该值大于HLog 的sequence number, 就将它作为HLog 的sequence number的值。最后,HLog将得到上次存入文件和继续记log的点。



上图表示了3个不同的region,每一个负责一段rowkey的范围。这些region将共享同一个HLog实例,我们可以看出,从不同region来的数据写入WAL的顺序是不确定的。在后面我们会再详细的介绍。

最后,Hlog利用HMaster恢复和切分一个由一个崩溃的HRegionServery遗留下来的Log。之后,重新部署regions。

HLogKey

WAL使用Hadoop的SequenceFile,它将记录存储为key/values 的数据集。对于WAL,key是一个HLogKey的实例。KeyValue不仅包括row,column family, qualifier, timestamp, value, 还包括“Key Type”—派上用场啦, 这里,可以用Key Type代表一个“put”或“delete”操作。

但是,哪里去存放KeyValue的归属信息,比如region或者表名呢?这些存放在HLogKey中。同时还包括 sequence number,和“写入时间”, 是一个记录数据何时写入到log的时间戳。

LogFlusher

数据以KeyValue形式到达HRegionServer,将写入WAL,之后,写入一个SequenceFile。看过去没问题,但是因为数据流在写入文件系统时,经常会缓存以提高性能。这样,有些本以为在日志文件中的数据实际在内存中。这里,我们提供了一个LogFlusher的类。它调用HLog.optionalSync(),后者根据“hbase.regionserver.optionallogflushinterval”(默认是10秒),定期调用Hlog.sync()。另外,HLog.doWrite()也会根据“hbase.regionserver.flushlogentries”(默认100秒)定期调用Hlog.sync()。Sync() 本身调用HLog.Writer.sync(),它由SequenceFileLogWriter实现。

LogRoller

Log的大小通过$HBASE_HOME/conf/hbase-site.xml 的“hbase.regionserver.logroll.period”限制,默认是一个小时。所以每60分钟,会打开一个新的log文件。久而久之,会有一大堆的文件需要维护。首先,LogRoller调用HLog.rollWriter(),定时滚动日志,之后,利用HLog.cleanOldLogs()可以清除旧的日志。它首先取得存储文件中的最大的sequence number,之后检查是否存在一个log所有的条目的“sequence number”均低于这个值,如果存在,将删除这个log。

Replay

当HRegionServer启动,打开所管辖的region,它将检查是否存在剩余的log文件,如果存在,将调用Store.doReconstructionLog()。重放一个日志只是简单地读入一个日志,将日志中的条目加入到Memstore中。最后,flush操作将Memstore中数据flush到硬盘中。

旧日志往往由region server 崩溃所产生。当HMaster启动或者检测到region server 崩溃,它将日志文件拆分为多份文件,将其存储在region所属的文件夹。之后,根据上面提到的方法,将日志重放。需要指出的是,崩溃的服务器中的region只有在日志被拆分和拷贝之后才能被重新分配。拆分日志利用HLog.splitLog()。旧日志被读入主线程内存中,之后,利用线程池将其写入所有的region文件夹中,一个线程对应于一个region。

问题

为什么要一个RegionServer 对应于一个HLog。为什么不是一个region对应于一个log file?

如果我们每一个“tablet”(对应于HBase的region)都提交一个日志文件,会需要并发写入大量的文件到GFS,这样,根据每个GFS server所依赖的文件系统,写入不同的日志文件会造成大量的磁盘操作。

HBase依照这样的原则。在日志被回滚和安全删除之前,将会有大量的文件。如果改成一个region对应于一个文件,将会不好扩展,迟早会引发问题。

二、WAL的写入

与WAL相关的几个主要类:

  1. WALKey: wal日志的key,包括 regionName: 日志所属的region tablename:日志所属的表,writeTime:日志写入时间,clusterIds:cluster的id,在数据复制的时候会用到。
  2. WALEdit: 在hbase的事务日志中记录一系列的修改的一条事务日志。另外WALEdit实现了Writable接口,可用于序列化处理。
  3. FSHLog: WAL的实现类,负责将数据写入文件系统

对每个wal的写入使用的是多生产者单消费者的模式,这里使用到了disruptor框架,将WALKey和WALEdit信息封装为FSWALEntry,然后通过RingBufferTruck放入RingBuffer中。

接下来看hlog的写入流程,分为以下3步:

日志写入缓存:由rpcHandler将日志信息写入缓存ringBuffer.

缓存数据写入文件系统:每个FSHLog有一个线程负责将数据写入文件系统(HDFS)

数据同步:如果操作的持久化级别为(SYNC_WAL或者USE_DEFAULT 则需进行数据同步处理

各类线程是如何配合来实现这几步操作的:

rpcHandler线程负责将日志信息(FSWALEntry)写入缓存RingBbuffer,在操作日志写完后,rpcHandler会调用wal的sync方法,进行数据同步,其实际处理为写入一个SyncFuture到RingBuffer,然后blocking一直到syncFuture处理完成。

wal线程从缓存RingBuffer中取数据,如果为日志(FSWALEntry)就调用Writer将数据写入文件系统,如果为SyncFuture,则由专门的同步线程来进行同步处理。

三、相关博文

CSDN(Kuzury):HBase WAL 解析

博客园( Yijian):HBase的Write Ahead Log (WAL) —— 整体架构、线程模型

简书(牦牛sheriff):05. HBase WAL解析

HBase的Write Ahead Log (WAL)的更多相关文章

  1. HBase的Write Ahead Log (WAL) —— 整体架构、线程模型

    解决的问题 HBase的Write Ahead Log (WAL)提供了一种高并发.持久化的日志保存与回放机制.每一个业务数据的写入操作(PUT / DELETE)执行前,都会记账在WAL中. 如果出 ...

  2. HBase的Write Ahead Log (WAL) —— 整体架构、线程模型【转】

    转自:http://www.cnblogs.com/ohuang/p/5807543.html 解决的问题 HBase的Write Ahead Log (WAL)提供了一种高并发.持久化的日志保存与回 ...

  3. HBase的Write Ahead Log (WAL) —— API与基本概念

    HBase的数据写入操作,会先记录到HLog中,再真正写入到MemStore中.前者是对写入友好的格式,后者是对查询友好的格式.所以前者吞吐量更高,写入成功率大,提高了系统的可靠性,“基本”可以实现宕 ...

  4. RocksDB 之Write Ahead Log(WAL)

    Overview RocksDB 中有三个基本的数据结构概念:memtable, sstfile 和 logfile memtable 是个内存数据结构,新写入会插入memtable 切回选择性地写入 ...

  5. SparkStreaming “Could not read data from write ahead log record” 报错分析解决

    # if open wal org.apache.spark.SparkException: Could not read data from write ahead log record FileB ...

  6. HBase源码分析之WAL

    WAL(Write-Ahead Logging)是数据库系统中保障原子性和持久性的技术,通过使用WAL可以将数据的随机写入变为顺序写入,可以提高数据写入的性能.在hbase中写入数据时,会将数据写入内 ...

  7. Hbase记录-Hbase shell使用命令

    1.进入hbase shell  执行./bin/hbase shell 2.进入后,help  帮助信息,如可以使用help 'create' 3.创建表:create 'test','cf'  表 ...

  8. hbase官方文档(转)

    FROM:http://www.just4e.com/hbase.html Apache HBase™ 参考指南  HBase 官方文档中文版 Copyright © 2012 Apache Soft ...

  9. HBase 官方文档

    HBase 官方文档 Copyright © 2010 Apache Software Foundation, 盛大游戏-数据仓库团队-颜开(译) Revision History Revision ...

随机推荐

  1. Docker 网络及命令

    Docker常用命令 docker version #查看版本 docker search centos #搜索可用docker镜像 docker images 查看当前docker所有镜像 dock ...

  2. sqlite嵌入式数据库简介及特性

    p.p1 { margin: 0; font: 12px "Helvetica Neue"; color: rgba(69, 69, 69, 1) } p.p2 { margin: ...

  3. Centos7 安装Teamviewer

    参考:链接1  链接2  链接3 由于工作原因,需要再Centos7.6下安装Teamviewer,流程如下: 下载 TeamViewer下载 链接 wget https://download.tea ...

  4. Linux下Oracle19c离线rpm安装

    一.基础环境配置 1.关闭系统防火墙 systemctl stop firewalld syustemctl disable firewalld 2.关闭selinux vim /etc/selinu ...

  5. Sql Server Sum函数的特殊使用

    利用Sql Server的Sum函数开窗得到累计值 具体详解https://www.cnblogs.com/zhaoshujie/p/9594676.html 个人示例例子 DECLARE @Sale ...

  6. LeetCode844 比较含退格的字符串

    题目描述: 给定 S 和 T 两个字符串,当它们分别被输入到空白的文本编辑器后,判断二者是否相等,并返回结果. # 代表退格字符. 示例 1: 输入:S = "ab#c", T = ...

  7. Redis-4.X 版本 Redis Cluster集群 (一)

    一 创建redis cluster 集群前提条件: 1 ) 每个redis node 节点采用相同的硬件配置,相同的密码. 2 ) 每个节点必须开启的参数: cluster-enabled yes # ...

  8. 我们NetCore下日志存储设计

    日志的分类 首先往大的来说,日志分2种 ①业务日志: 即业务系统需要查看的日志, 常见的比如谁什么时候修改了什么. ②参数日志: 一般是开发人员遇到问题的时候定位用的, 一般不需要再业务系统里展示. ...

  9. memcached+magent的集群部署详细过程

    问题描述 Memcached在实现分布集群部署时, Memcached服务端的之间是没有通讯的,服务端是伪分布式,实现分布式是由客户端实现的,客户端实现了分布式算法把数据保存到不同的Memcached ...

  10. 分布式系统:分布式任务调度xxl-job较深入使用

    目录 系统关键概念介绍 执行器 任务 任务配置项描述 阻塞策略 路由策略 日志问题 客户端日志 服务端日志 框架目前发现的缺点以及存在的问题 xxl-job是一个分布式定时任务调度框架,功能强大,底层 ...