热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

(十五)Zookeeper原理源码分析之数据日志文件归档

文章目录1.日志文件概述1.1作用说明1.2日志文件格式1.2.1事务日志文件解析1.2.2快照日志文件解析2.日志文件序列化2.1日志路径配置2.2序列化时机2.3日志文件的管理


文章目录

  • 1. 日志文件概述
    • 1.1 作用说明
    • 1.2 日志文件格式
      • 1.2.1 事务日志文件解析
      • 1.2.2 快照日志文件解析
  • 2. 日志文件序列化
    • 2.1 日志路径配置
    • 2.2 序列化时机
    • 2.3 日志文件的管理


1. 日志文件概述


1.1 作用说明

  ZK框架不依赖于我们所理解的常规数据库,但服务器运行时需要记录处理过的客户端请求,ZK的处理方式则是将请求信息序列化到文件中。ZK将日志请求分为两种:


  • 事务日志:用于记录接收过的每个客户端请求,里面会保存接收时间、cxid值、zxid值、操作类型、操作路径和请求数据;事务日志文件的核心作用有两个:
    1. 根据日志文件可快速查阅在什么时间点服务端处理过什么操作,方便排查问题;
    2. ZK服务器启动时,会将事务日志中zxid大于最新快照的zxid的请求再处理一遍,防止请求遗漏。
  • 快照日志:在ZK服务器运行了一定的时间后或处理了一定的请求后,将ZK服务器当前状态记录并保存到文件中,形成快照文件,因此快照文件的数据就是某一时刻ZK服务器的数据记录;其作用在于ZK服务器重启时,可以读取最新的快照文件,恢复到上次停止时的状态。

  上面一些名词的简单说明:


  • cxid值:客户端每次请求cxid都会+1,初始值为1,在客户端的属性名为xid;
  • zxid值:事务唯一ID,ZK服务端的全局变量,能够保证请求事务的唯一性。

1.2 日志文件格式

  如果要看事务日志文件的内容,ZK官方提供了对应的可执行Main函数类LogFormatterSnapshotFormatter,其中LogFormatter针对的是ZK的事务日志文件,SnapshotFormatter则是针对ZK的快照日志文件。

  若想要直接使用Idea编译器来查看日志文件,以事务日志文件为例,只需要进入到类LogFormatter中,点击执行按钮,在弹窗的Program arguments一栏中填入需要查看的事务日志文件的路径即可,如下图:

运行设置

  一般而言直接执行会因为事务日志的内容太多,而导致Idea的控制台无法全部展示,此时只需要再配置控制台的输出重定向就可以了,如下图:

控制台日志重定向

  ZK的事务日志文件需要从ZK的服务器日志目录拉取,经过上面两种配置就可以顺利把ZK的事务日志文件读取并输出到对应的本地文件中了。

  如果要解析快照日志文件,只需要进入SnapshotFormatter再重复上述两个步骤即可,但最好重定向的文件名不要一致。


1.2.1 事务日志文件解析

  先从事务日志文件的命名格式开始说起,事务日志的文件名是 log.+事务日志文件中第一个请求事务的zxid,解析重定向到本地文件中格式如下:

{time}" session 0x"{clientId}" cxid 0x"{cxid}" zxid 0x"{zxid}" "{type}" "{txnContent}

  以下为真实数据内容:

ZooKeeper Transactional Log File with dbid 0 txnlog format version 2
22-1-21 下午09时57分00秒 session 0x37c82be90ee01c9 cxid 0x2642ac zxid 0x22000595ba create '/XXXX/XXXX/X/XX/X,,v{s{31,s{'world,'anyone}}},T,43304022-1-21 下午09时57分00秒 session 0x37c82be90ee01c9 cxid 0x2642b8 zxid 0x22000595bc delete '/XXXX/XXXX/X/XX/X22-1-21 下午09时58分44秒 session 0x17dbd96b867001a cxid 0x263b2 zxid 0x22000595ce setData '/XX/XXXXX/XXX/X,XXXXXXX,52086

  第一行用来标识本ZK事务日志文件所支持的jar包版本,避免不同事务格式日志文件混用报错。从日志文件内容可以得到sessionclientIdcxidzxid和操作类型,都是16进制,具体的txnContent内容每个请求都各不相同。根据本日志文件可以得到具体时间点的具体操作及内容,从而实现生产问题排查。

  在ZK重启时,会根据事务日志文件名的zxid判断具体应该读取哪个事务日志文件,读取出来后再使用zxid去过滤已经处理过的请求,从而实现恢复到ZK停止前的状态。


1.2.2 快照日志文件解析

  快照日志文件名的格式为:snapshot.+服务器最新的zxid,事务日志的格式如下:

ZNode Details (count={nodeCount}):
----
/cZxid = {cZxid}ctime = {ctime}mZxid = {mZxid}mtime = {mtime}pZxid = {pZxid}cversion = {cversion}dataVersion = {dataVersion}aclVersion = {aclVersion}ephemeralOwner = {ephemeralOwner}dataLength = {dataLength}
----
/
省略N个被序列化的快照节点信息
----
Session Details (sid, timeout, ephemeralCount):
{sessionId}, {timeout}, {ephemeralCount}
以下忽略N个session的超时信息

  快照日志的信息看起来信息很多,但实际上基本都是DataNode中的StatPersisted stat成员属性,接下来挨个分析一下各个属性的代表含义:


  1. nodeCount:快照文件中所包含的节点数量;
  2. cZxid:创建该节点请求的zxid;
  3. ctime:创建该节点的请求时间;
  4. mZxid:最后修改节点的请求zxid;
  5. mtime:最后修改节点的请求时间;
  6. pZxid:增加删除节点时,操作父节点与当前节点的请求zxid值,因此如果有父子关系,则节点的pZxid会一致,且子节点的cZxid会与pZxid一致;
  7. cversion:节点创建版本值,取值为父节点的cversion+1,因此子节点的值一定是比父节点要大的;
  8. dataVersion:数据节点版本,主要由客户端控制;
  9. aclVersion:如果为新增节点,值为0,如果为客户端发送的setAcl请求,则取决于客户端传值;
  10. ephemeralOwner:是否是临时节点, 如果不是则值为0,是则为某个客户端的sessionId值;
  11. dataLength:节点成员属性byte[] data数组的长度;
  12. sessionId:与客户端一一对应的唯一值,初始值为0,每当一个新的客户端连接进来,则+1,在集群中能够代表具体哪台客户端机器;
  13. timeout:客户端的失效时间;
  14. ephemeralCount:客户端下有多少个临时节点的数量值;

  一共14个不同的参数,有几个参数的值内容值得推敲,实际快照日志文件内容如下:

ZNode Details (count={nodeCount}):
----
/kafka1/brokers/topics/X.XX.XXX/partitions/11cZxid = 0x00002200053b0fctime = Thu Jan 20 10:16:29 CST 2022mZxid = 0x00002200053b0fmtime = Thu Jan 20 10:16:29 CST 2022pZxid = 0x00002200053b2ccversion = 1dataVersion = 0aclVersion = 0ephemeralOwner = 0x00000000000000no data
----
/kafka1/brokers/topics/X.XX.XXX/partitions/11/statecZxid = 0x00002200053b2cctime = Thu Jan 20 10:16:29 CST 2022mZxid = 0x00002200053b2cmtime = Thu Jan 20 10:16:29 CST 2022pZxid = 0x00002200053b2ccversion = 0dataVersion = 0aclVersion = 0ephemeralOwner = 0x00000000000000dataLength = 72
----
Session Details (sid, timeout, ephemeralCount):
0x17c82be90e20023, 10000, 1
0x17c82be90e20024, 40000, 25

  从上面的简单例子便可以看出,可以通过cZxidpZxid确认第一个节点是第二个节点的父节点,因为第一个节点cZxidpZxid不一致,但是第二个节点两个属性的值是一致的。


2. 日志文件序列化


2.1 日志路径配置

  如果要说日志文件的序列化,那首先是需要搞定出文件要被序列化在哪里并从哪里读取反序列化。ZK启动前可在properties配置文件中配置dataDirdataLogDir属性来确定事务、快照日志文件路径。除了配置properties文件中的路径属性,也可以以参数传入,参数传入则只能有三个参数,第二个参数为路径属性,且dataDir=dataLogDir

  其中会先加载dataDir路径文件,再去加载dataLogDir路径文件,需要注意:dataDir=snapLog,dataLogDir=txnLog。所以实际上是先加载快照日志文件,再去加载事务日志文件,先从快照日志文件获取ZK停机前最新的zxid(如果有的话),再使用获取到的zxid去过滤事务日志文件中已经被处理过的请求,防止重复消费。


2.2 序列化时机

  前面确定了ZK日志文件的存储位置,那么问题来了,ZK是如何判断当前应该进行写文件及归档呢?总不可能让请求信息一直无限制增加吧?所以肯定ZK会有个阈值,超过这个阈值后就进行一次归档,且最好要是可配的。

  ZK也确实是这样做的,ZK服务器可配置zookeeper.snapCount属性,用来控制快照文件的数量,默认值大小为100000。服务器设置归档的范围是[0,snapCount/2] + snapCount/2,如果要保证可以有数字随机,其值最低只能为2,如果是1,随机的范围就只有0了,不符合随机要求。

  只要看过前面ZK源码的小伙伴,就会知道ZK服务器在处理客户端的请求时,一定会经过SyncRequestProcessor处理器,这个处理器就是用来统计已处理的请求数量并判断是否超过阈值需要进行归档。判断流程图如下:

归档阈值判断

  流程中有以下几点需要注意:


  • randRoll在每个归档周期内都会重新设置随机值,随机范围[0,snapCount/2],其目的在于动态伸缩ZK的日志归档大小。这样做的原因在于ZK会向集群内的所有机器同步请求,如果归档大小都是一样的,一段时间内所有的机器都在进行归档,占用IO,从导致集群在这一段时间的性能降低;如果归档时间不一样,就可以保证集群总体而言性能不会由于IO使用而降低太多;
  • SyncRequestProcessor请求接收到requestOfDeath固定请求,则说明ZK由于某种原因需要关闭,此时将会退出死循环,否则将一直运行下去,即使轮询不到请求;
  • 要添加到事务日志文件中,TxnHeader必须不为空,一般而言除了ping操作,其它的正常操作诸如creategetsetdelete等,都是可以成功添加到事务日志中的;
  • randRoll随机范围是[0,snapCount/2],事务日志的阈值范围是[snapCount/2,snapCount],每当有一个事务请求添加到事务日志中,logCount将会+1;
  • 在超过事务日志阈值前,事务请求都是被保存在BufferedOutputStream缓存中的,只要超过阈值后,事务日志才会写到文件中,且快照日志进行归档,logCount清零;
  • 一台机器同时只会操作一个快照日志文件,如果上一次的文件还没写入完成,则下次快照归档会跳过;

  除了上面几点外,还需要特别注意toFlush集合,该集合需要注意两点:


  1. 事务请求添加到toFlush集合的情况:
    1. 当事务请求添加到事务文件成功时;
    2. 添加到事务文件失败且toFlush集合不为空;
  2. 清空toFlush集合事务请求,并将里面的事务请求交给下个RequestProcessor处理的情况:
    1. toFlush集合不为空,且无新的请求进入SyncRequestProcessor处理器时;
    2. 新的toFlush请求进入,添加到事务日志文件失败且toFlush集合为空,直接交给下个RequestProcessor处理;
    3. 当事务请求添加到toFlush集合成功,且集合数量大于1000时,主动清空集合,并将里面的请求全部交给下个RequestProcessor处理。

  对于toFlush集合的操作,结合流程图应该大致能搞懂里面的逻辑,如果觉得很绕,结合源码再来看这些注意点就能够很轻松的搞懂了。


2.3 日志文件的管理

  进行归档时会实例化一个ZooKeeperThread类型的线程对象,执行takeSnapshot()方法生成快照日志文件,而事务日志文件只需要将BufferedOutputStream缓存中的刷到文件中即可。

  ZK往复执行上面的归档流程,如果没有对日志文件进行管理的机制,那就肯定是需要人工定时维护的,从3.4.X版本开始,支持配置两个属性来定时清理日志文件,如下:


  1. 可在properties属性文件中配置autopurge.purgeInterval属性,用来设置间隔多久进行清理,单位小时h,默认值0,即不清理,所以如果要配最小清理间隔为1h;
  2. 配置autopurge.snapRetainCount属性用来控制需要保留的快照文件数量snapRetainCount属性,默认值为3,最小值可配为3,配了之后将会保留最新的snapRetainCount个快照日志文件;

  注:上述的autopurge.snapRetainCount属性只控制快照日志文件,事务请求文件会清理比快照文件zxid最小还要小的。以下面为例:

假设现在快照文件共有6个,事务日志文件共有6个:


序号快照日志文件名事务日志文件名
1snapshot.1log.1
2snapshot.3log.2
3snapshot.5log.4
4snapshot.7log.5
5snapshot.9log.7
6snapshot.10log.8

  假设autopurge.snapRetainCount属性为默认的3,清理后的日志文件为:


序号快照日志文件名事务日志文件名
1--
2--
3--
4snapshot.7-
5snapshot.9log.7
6snapshot.10log.8

  因为快照日志文件最小的zxid7,因此事务日志文件名的zxid小于7的都要删除。


推荐阅读
  • 本文介绍了在sqoop1.4.*版本中,如何实现自定义分隔符的方法及步骤。通过修改sqoop生成的java文件,并重新编译,可以满足实际开发中对分隔符的需求。具体步骤包括修改java文件中的一行代码,重新编译所需的hadoop包等。详细步骤和编译方法在本文中都有详细说明。 ... [详细]
  • Java在运行已编译完成的类时,是通过java虚拟机来装载和执行的,java虚拟机通过操作系统命令JAVA_HOMEbinjava–option来启 ... [详细]
  • 原文地址:https:www.cnblogs.combaoyipSpringBoot_YML.html1.在springboot中,有两种配置文件,一种 ... [详细]
  • 本文介绍了在Linux下安装和配置Kafka的方法,包括安装JDK、下载和解压Kafka、配置Kafka的参数,以及配置Kafka的日志目录、服务器IP和日志存放路径等。同时还提供了单机配置部署的方法和zookeeper地址和端口的配置。通过实操成功的案例,帮助读者快速完成Kafka的安装和配置。 ... [详细]
  • Jboss的EJB部署描述符standardjaws.xml配置步骤详解
    本文详细介绍了Jboss的EJB部署描述符standardjaws.xml的配置步骤,包括映射CMP实体EJB、数据源连接池的获取以及数据库配置等内容。 ... [详细]
  • 本文总结了初学者在使用dubbo设计架构过程中遇到的问题,并提供了相应的解决方法。问题包括传输字节流限制、分布式事务、序列化、多点部署、zk端口冲突、服务失败请求3次机制以及启动时检查。通过解决这些问题,初学者能够更好地理解和应用dubbo设计架构。 ... [详细]
  • 安装mysqlclient失败解决办法
    本文介绍了在MAC系统中,使用django使用mysql数据库报错的解决办法。通过源码安装mysqlclient或将mysql_config添加到系统环境变量中,可以解决安装mysqlclient失败的问题。同时,还介绍了查看mysql安装路径和使配置文件生效的方法。 ... [详细]
  • XML介绍与使用的概述及标签规则
    本文介绍了XML的基本概念和用途,包括XML的可扩展性和标签的自定义特性。同时还详细解释了XML标签的规则,包括标签的尖括号和合法标识符的组成,标签必须成对出现的原则以及特殊标签的使用方法。通过本文的阅读,读者可以对XML的基本知识有一个全面的了解。 ... [详细]
  • 本文介绍了Web学习历程记录中关于Tomcat的基本概念和配置。首先解释了Web静态Web资源和动态Web资源的概念,以及C/S架构和B/S架构的区别。然后介绍了常见的Web服务器,包括Weblogic、WebSphere和Tomcat。接着详细讲解了Tomcat的虚拟主机、web应用和虚拟路径映射的概念和配置过程。最后简要介绍了http协议的作用。本文内容详实,适合初学者了解Tomcat的基础知识。 ... [详细]
  • 本文介绍了通过ABAP开发往外网发邮件的需求,并提供了配置和代码整理的资料。其中包括了配置SAP邮件服务器的步骤和ABAP写发送邮件代码的过程。通过RZ10配置参数和icm/server_port_1的设定,可以实现向Sap User和外部邮件发送邮件的功能。希望对需要的开发人员有帮助。摘要长度:184字。 ... [详细]
  • C++字符字符串处理及字符集编码方案
    本文介绍了C++中字符字符串处理的问题,并详细解释了字符集编码方案,包括UNICODE、Windows apps采用的UTF-16编码、ASCII、SBCS和DBCS编码方案。同时说明了ANSI C标准和Windows中的字符/字符串数据类型实现。文章还提到了在编译时需要定义UNICODE宏以支持unicode编码,否则将使用windows code page编译。最后,给出了相关的头文件和数据类型定义。 ... [详细]
  • 本文由编程笔记#小编为大家整理,主要介绍了StartingzookeeperFAILEDTOSTART相关的知识,希望对你有一定的参考价值。下载路径:https://ar ... [详细]
  • centos安装Mysql的方法及步骤详解
    本文介绍了centos安装Mysql的两种方式:rpm方式和绿色方式安装,详细介绍了安装所需的软件包以及安装过程中的注意事项,包括检查是否安装成功的方法。通过本文,读者可以了解到在centos系统上如何正确安装Mysql。 ... [详细]
  • MySQL数据库锁机制及其应用(数据库锁的概念)
    本文介绍了MySQL数据库锁机制及其应用。数据库锁是计算机协调多个进程或线程并发访问某一资源的机制,在数据库中,数据是一种供许多用户共享的资源,如何保证数据并发访问的一致性和有效性是数据库必须解决的问题。MySQL的锁机制相对简单,不同的存储引擎支持不同的锁机制,主要包括表级锁、行级锁和页面锁。本文详细介绍了MySQL表级锁的锁模式和特点,以及行级锁和页面锁的特点和应用场景。同时还讨论了锁冲突对数据库并发访问性能的影响。 ... [详细]
  • 深入解析Linux下的I/O多路转接epoll技术
    本文深入解析了Linux下的I/O多路转接epoll技术,介绍了select和poll函数的问题,以及epoll函数的设计和优点。同时讲解了epoll函数的使用方法,包括epoll_create和epoll_ctl两个系统调用。 ... [详细]
author-avatar
程橙屋04_kc275_938
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有