天天看点

hbase源码系列(七)Snapshot的过程

直接进入主题吧,上代码。

从代码上看得出来,启用的表和被禁用的表走的是两个不同的方法。

先看snapshotenabledtable方法吧,看看在线的表是怎么备份的。

这里就两步,先去看看snapshot前的准备工作吧,f3进入preparetotakesnapshot方法。这个方法里面也没干啥,就是检查一下是否可以对这个表做备份或者恢复的操作,然后就会重建这个工作目录,这个工作目录在.hbase-snapshot/.tmps下面,每个snapshot都有自己的目录。

在snapshottable里面把就线程提交一下,让handler来处理了。

这些都不是重点,咱到handler那边去看看吧,enabledtablesnapshothandler是继承takesnapshothandler的,prepare方法和process方法都一样,区别在于snapshotregions方法被重写了。

看prepare方法还是检查表的定义文件在不在,我们直接进入process方法吧。

1、写一个.snapshotinfo文件到工作目录下

2、把表的定义信息写一份到工作目录下,即.tabledesc文件

3、查找和表相关的region server和机器

4、开始备份

5、检验snapshot的结果

6、确认没问题了,就把临时目录rename到正式目录

  

我们直接到备份这一步去看吧,方法在enabledtablesnapshothandler里面,重写了。

这里用到一个分布式事务,这里被我叫做分布式事务,我也不知道它是不是事务,但是procedure这个词我真的不好翻译,叫过程也不合适。

我们进入procedurecoordinator的startprocedure看看吧。

先创建procedure,然后提交它,这块没什么特别的,继续深入进去submitprocedure方法也找不到什么有用的信息,我们得回到procedure类里面去,它是一个callable的类,奥秘就在call方法里面。

从sendglobalbarrierstart开始看吧,里面就一句话。

再追杀下去。

1、首先是检查abortnode ,什么是abortnode ?每个procname在zk下面都有一个对应的节点,比如snapshot,然后在procname下面又分了acquired、reached、abort三个节点。检查abort节点下面有没有当前的实例。

2、在acquired节点为该实例创建节点,创建实例节点的时候,把snapshotdescription的信息(在enabledtablesnapshothandler类里面通过this.snapshot.tobytearray()传进去的)放了进去,创建完成之后,在该实例节点下面监控各个region server的节点。如果发现已经有了,就更新procedure中的acquiringmembers列表和inbarriermembers,把节点从

acquiringmembers中删除,然后添加到inbarriermembers列表当中。

3、到这一步服务端的工作就停下来了,等到所有rs接收到指令之后通过实例节点当中保存的表信息找到相应的region创建子过程,子过程在acquired节点下创建节点。

4、收到所有rs的回复之后,它才会开始在reached节点创建实例节点,然后继续等待。

5、rs完成任务之后,在reached的实例节点下面创建相应的节点,然后回复。

6、在确定所有的rs都完成工作之后,清理zk当中的相应proname节点。

<b>注意:</b>在这个过程当中,有任务的错误,都会在abort节点下面建立该实例的节点,rs上面的子过程一旦发现abort存在该节点的实例,就会取消该过程。

 snapshot这块在region server是由regionserversnapshotmanager类里面的procedurememberrpcs负责监测snapshot下面的节点变化,当发现acquired下面有实例之后,启动新任务。

这块折叠起来,不是咱们的重点,让大家看看而已。我们直接进入subprocedure这个类里面看看吧。

insidebarrier的实现在flushsnapshotsubprocedure这个类里面,调用了flushsnapshot(),这个方法给每个region都开一个线程去提交。

我们接下来看看regionsnapshottask的call方法。

在对region操作之前,先上锁,不让读了。然后就flushcache,这个方法很大,也好难懂哦,不过我们还是要迎接困难上,我折叠起来吧,想看的就看,不想看的就看我下面的写的步骤吧。

1、获取wal日志的flushid(要写入到hfile当中,以后恢复的时候,要拿日志的flushid和hfile的flushid对比,小于hfile的flushid的就不用恢复了)

2、给memstore的做snapshot,从kvset集合转移到snapshot集合

3、同步日志,写入到硬盘

5、上一步的生成的文件是保存在临时目录中的,转移到正式的目录当中

6、更新memstore当中的大小

好,我们继续看addregiontosnapshot方法,好累啊,尼玛,这么多步骤。

在工作目录在.hbase-snapshot/.tmps/snapshotname/region/familyname/下面给hfile创建引用文件。在创建引用文件的时候,还要先判断一下这个所谓的hfile是不是真的hfile,还是它本身就是一个引用文件了。

如果已经是引用文件的话,把旧的引用文件里面的内容写入到新的引用文件当中。

如果是一个正常的hfile的话,就创建一个空的引用文件即可,以后我们可以通过它的名字找到它在snapshot下面相应的文件。

okay,到这里,每个rs的工作都完成了。

完成执行分布式事务,就是备份split过的region了,把之前的代码再贴一次吧,折叠起来,需要的自己看。

备份启用的表,现在已经结束了,但是备份禁用的表吧,前面说了区别是snapshotregions方法,但是方法除了做一些准备工作之外,就是snapshotdisabledregion。。。。所以snapshot到这里就完了,下面我们<b>再回顾一遍吧</b>。

1、进行snapshot之前的准备,创建目录,复制一些必要的信息文件等。

2、对于启用的表,启动分布式事务,rs接到任务,flush掉wal日志和memstore的数据,写入文件。

3、为hfile创建引用文件,这里的引用文件居然是空的文件,而且名字一样,它不是真的备份hfile,这是什么回事呢?这个要到下一章,从snapshot中恢复,才能弄明白了,这个和hbase的归档文件机制有关系,hbase删除文件的时候,不是直接删除,而是把它先放入archive文件夹内。

继续阅读