• ZooKeeper学习之文件系统的布局和格式


    本文来谈谈快照文件,事务日志文件在文件系统中是如何存放的。

    写事务日志是事务处理的关键步骤,所以高度建议在一个独立的磁盘上存储。快照不需要在独立的磁盘存储,因为它们是由一个后台线程以懒汉式的(lazily)方式产生的。

    存储快照的路径是由DataDir参数指定的,事务日志的路径则是由DataLogDir参数指定的。首先来看看事务日志的目录。如果你查看目录的内容,你会看到一个名为version-2的文件夹。对于日志和快照现在只有一种格式,如果有别的版本的格式,像这样按照格式的版本把数据隔离开来,对于日后不同版本的数据迁移会比较方便。

    事务日志

    在执行一些测试之后,看一下目录的情况,只有两个事务日志文件:


    -rw-r--r--  1 breed 67108880 Jun 5 22:12 log.100000001
    -rw-r--r--  1 breed 67108880 Jul 15 21:37 log.200000001

    来观察一下,首先,它们有些大,每个文件大约有6M,执行的测试其实挺少。第二,文件名的后缀的那个数字很大。

    ZK为文件预分配了相当大的块(chunk)来避免每次写文件带来的元数据的管理开销。如果你用16进制dump这些文件的话,会看到都是一些null字符(字符),除了文件开头的一些数据二进制数据之外。当server跑了一段时间后,这些null字符会被实际的日志数据取代。

    文件名后缀的那个数字是zxid,可以很容易的进行recovery并能快速查找,这个zxid是日志文件的第一个zxid,并且是16进制的。之所以用16进制是因为可以容易的看到epoch和counter。所以第一个文件属于epoch 1,第二个属于epoch 2。

    如果能看到文件内部的数据当然更好了,这在需要定位问题的时候很有必要的。开发人员需要花很多时间去调查为何ZK丢失了znode的数据,只有通过查看事务日志,才能知道是不是被client删除了。

    我们可以用下面的命令查看第二个日志文件:

    [java] view plain copy
     
    1. java -cp $ZK_LIBS org.apache.zookeeper.server.LogFormatter version-2 log.200000001  

    输出如下:


    7/15/13... session 0x13...00  cxid 0x0 zxid 0x200000001 createSession 30000
    7/15/13... session 0x13...00  cxid 0x2 zxid 0x200000002 create
    '/test,#22746573746 ...
    7/15/13... session 0x13...00  cxid 0x3 zxid 0x200000003 create
    '/test/c1,#6368696c ...
    7/15/13... session 0x13...00  cxid 0x4 zxid 0x200000004 create
    '/test/c2,#6368696c ...
    7/15/13... session 0x13...00  cxid 0x5 zxid 0x200000005 create
    '/test/c3,#6368696c ...
    7/15/13... session 0x13...00  cxid 0x0 zxid 0x200000006 closeSession null

    每一个事务都以人类可读的方式打印出来。因为在事务中只有change操作,所以你不会看到read操作。

    快照

    快照的命名模式跟事务日志的模式类似。这是配合事务日志的一个例子:


    -rw-r--r-- 1 br33d 296 Jun 5 07:49 snapshot.0
    -rw-r--r-- 1 br33d 415 Jul 15 21:33 snapshot.100000009

    快照文件没有进行预分配,所以size正确的反映了实际的数据量。使用的后缀反映了当快照开始时当前的zxid。前面的文章说过,快照文件实际上是fuzzy的。快照数据只有在对应的事务日志重放后才是正确的。为了恢复数据,必须重放一个快照文件后缀之后的事务日志。

    快照文件是使用二进制的形式存储,这儿有另一个工具来解析快照文件:

    [java] view plain copy
     
    1. java -cp ZK_LIBS org.apache.zookeeper.server.SnapshotFormatter version-2 snapshot.100000009  

     
    输出如下:
    ----
    /
    cZxid = 0x00000000000000
    ctime = Wed Dec 31 16:00:00 PST 1969
    mZxid = 0x00000000000000
    mtime = Wed Dec 31 16:00:00 PST 1969
    pZxid = 0x00000100000002
    cversion = 1
    dataVersion = 0
    aclVersion = 0
    ephemeralOwner = 0x00000000000000
    dataLength = 0
    ----
    /sasd
    cZxid = 0x00000100000002
    ctime = Wed Jun 05 07:50:56 PDT 2013
    mZxid = 0x00000100000002
    mtime = Wed Jun 05 07:50:56 PDT 2013
    pZxid = 0x00000100000002
    cversion = 0
    dataVersion = 0
    aclVersion = 0
    ephemeralOwner = 0x00000000000000
    dataLength = 3
    ----
    只dump出每个znode的元数据。这可以让管理员找出那些znode的数据被改变过,那些znode占用了大量内存。不幸的是,znode的数据和ACL不会打印。还要记得定位问题时,一定要使用快照和它对应的日志文件的合并后的数据。

    Epoch文件

    此外还有2个小文件来构成ZK状态的持久化。有2个epoch文件,分别是acceptedEpoch和currentEpoch。这两个文件分别反映了指定的server进程已经看到的和参与的epoch number。尽管这些文件不包含任何应用级别的数据,但他们对于数据一致性来说很重要,所以在你对数据文件进行备份时,不要漏掉这2个文件。

    使用ZK的数据

    无论是standalone模式还是集群模式,都是用同样的方式来存储数据的。我们刚才只提到如果通过合并快照和日志来得到正确的数据。你可以拷贝日志文件和快照文件到另外一个机器上,比如你的笔记本电脑,把它们放到一个standalone模式下的干净的数据目录,并启动server,数据就会在这个server上重现。这可以让你看到近似于生产环境的服务上的数据。这也意味着你可以简单的拷贝文件来轻松的备份。如果你选择这种做法需要注意一些事情。首先,ZK得分布式部署,这样数据就会有冗余。做备份的时候,只需要备份其中一个server的数据即可。

    一定要记住当一个ZK server ack一个事务时,之后它会承诺记住当时的状态。所以如果你使用一份老的备份数据恢复一台server时,你就使得这个server违反了它的承诺。如果你刚遭受了一个全局性的数据丢失的话这并不是大问题,但如果你在正常工作的集群中一台server放入老的数据,这可能会导致其他的server丢失状态。

    如果你想对所有server或者大多数server做数据恢复,最好的做法就是获取最新的状态(从存活的机器中取得的最新(up-to-date)的数据),在启动每个server之前拷贝到对应的数据目录下。

  • 相关阅读:
    运输装备(codevs 1669)
    考前复习(codevs 2837)
    2014编程之美初赛第一场
    51系列小型操作系统精髓 简单实现
    数学----有趣的扑克牌《一》
    hadoop编程:分析CSDN注冊邮箱分布情况
    [动态规划]UVA437
    Swift学习笔记四:数组和字典
    [动态规划]UVA10285
    freemarker中的left_pad和right_pad
  • 原文地址:https://www.cnblogs.com/seaspring/p/6227381.html
Copyright © 2020-2023  润新知