Zookeeper源码分析(二) ----- zookeeper日志
zookeeper
源码分析系列文章:
- Zookeeper源码分析(一) ----- 源码运行环境搭建
原创博客,纯手敲,转载请注明出处,谢谢!
既然我们是要学习源码,那么如何高效地学习源代码呢?答案就是跟踪日志。说到zookeeper
日志,小编觉得非常的重要,如果没有日志文件,后期的zookeeper
事务处理基本上不能玩。因此,我将zookeeper
日志放在源码分析系列的第二部分,也是在能够运行zookeeper
的基础上,进行日志分析。
一、zookeeper
日志类型
zookeeper
中有两类日志,分别是:
- 1、事务日志
log
- 2、快照日志
snapshot
事务日志 :
顾名思义,就是用于存放事务执行的相关信息,如zxid
、cxid
等。至于什么是zookeeper
事务,放到后面的文章中讲。
快照日志 : ``zookeeper
数据节点数据是运行在内存中的,当然内存保存这些结点的数据不可能无限大,而且数据节点的内容是动态变化的,因此zookeeper
提供一中奖数据节点持久化的机制,每隔一段时间,zookeeper
会将内存中的数据节点DataTree
序列到磁盘中,因此就形成了我们的快照日志。
在zookeeper
源码调试的过程中,诸如服务端的启动日志、客户端的启动日志、请求的相关日志,由于zookeeper
采用log4j
进行日志打印,因此log4j
必须在类路径下查找log4j.properties
文件,如果启动的过程中找不到该文件,则报错如下:
log4j:WARN No appenders could be found for logger (org.apache.log4j.jmx.HierarchyDynamicMBean).
log4j:WARN Please initialize the log4j system properly.
log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.
复制代码
因此,必须将log4j.properties
放到类路径下,那么对于可恶的ant
工程,类路径在哪里呢?我也不清楚,于是我直接在eclipse
右键工程Build Path
->Configure build path
找到类路径为%baseDir%\src\java\main
,具体如下图:
所以将conf
目录下的log4j.properties
拷贝一份至上图的目录中即可!
二、zookeeper
日志可视化
上面说到zookeeper
中有两种日志类型,但很遗憾,上面的日志你都无法直接看到,因为都是采用二进制进行保存的。查看zookeeper
源代码也可以知道,zookeeper
日志输出体现在FileTxnLog.java
文件的append()
方法中,具体如下:
// 写日志文件,采用log. + 哈希值的命名形式保存文件
logFileWrite = new File(logDir, ("log." + Long.toHexString(hdr.getZxid())));
// 文件输出流
fos = new FileOutputStream(logFileWrite);
// 采用BufferedOutputStream包裹fos成缓冲输出流
logStream=new BufferedOutputStream(fos);
// 这是重点,这里采用org.apache.jute.BinaryOutputArchive二进制构件对logStream进行包裹,输出二进制数据
oa = BinaryOutputArchive.getArchive(logStream);
复制代码
对应的文件系统的文件如下图:
既然是二进制日志文件,那么我们直接打开该文件肯定是乱码嘛!怎么办呢?下面提供两种方法,这两种方法都是基于zookeeper
提供的LogFormatter.java
工具类来实现的。
- 1、在
eclipse
中开该类,然后运行该类的main
方法的同时传入你想查看的日志文件路径即可 - 2、采用命令行
java -classpath xxx.jar org.apache.zookeeper.server.LogFormatter logFilePath
的形式进行查看
第一种方式:
这里假设我的日志文件存放路径为E:\\resources\\zookeeper-3.4.11\\conf\\log\\version-2\\log.1
,当我在eclipse
中运行main
方法时,设置传入的参数即可,如下图:
然后就可以在控制台输出日志了,输出样例如下:
ZooKeeper Transactional Log File with dbid 0 txnlog format version 2
18-4-30 下午08时39分23秒 session 0x100022b44190000 cxid 0x0 zxid 0x1 createSession 3000018-4-30 下午08时39分55秒 session 0x100022b44190000 cxid 0x0 zxid 0x2 closeSession null
EOF reached after 2 txns.
复制代码
第二种方式:
- 1、在任意目录下新建一个临时目录,随便命名为
logSee
,将slf4j-api-1.6.1.jar
和zookeeper-3.4.11.jar
两个文件放到该目录下,然后打开命令行,执行java -classpath .;slf4j-api-1.6.1.jar;zookeeper-3.4.11.jar org.apache.zookeeper.server.LogFormatter E:\\resources\\zookeeper-3.4.11\\conf\\log\\version-2\\log.1
其中两个jar
包之间采用分号;
分隔而不是冒号,org.apache.zookeeper.server.LogFormatter
表示LogFormatter.java
的全路径命名(即包全名+类名
),E:\\resources\\zookeeper-3.4.11\\conf\\log\\version-2\\log.1
表示你想查看的日志文件。
输出如下:
三、zookeeper
日志清理机制
zookeeper
是将日志以文件的形式存放在磁盘中,久而久之,磁盘的文件就越来越多,zookeeper
提供了一种定期清理日志和快照文件的机制。
QuorumPeerMain.java
是zookeeper
的启动类,在zookeeper
启动之前会创建一个DatadirCleanupManager
对象进行数据清理任务,DatadirCleanupManager
会根据你配置文件的配置决定是否清理以及每隔多久进行清理,其底层原理采用JDK
的Timer
定时器实现,下面将对其实现机制从源码的角度进行分析:
先看QuorumPeerMain
类,在其initializeAndRun()
方法执行时会创建一个DatadirCleanupManager
对象,并将zoo.cfg
配置文件的相关配置传递给该对象,源码如下:
protected void initializeAndRun(String[] args)throws ConfigException, IOException{QuorumPeerConfig config = new QuorumPeerConfig();if (args.length == 1) {config.parse(args[0]);}// 启动数据目录清理定时任务,传递的参数有数据目录DataDir,日志目录LogDir,以及快照保留数量count,默认>3,最后一个是每个多长时间进行清理DatadirCleanupManager purgeMgr = new DatadirCleanupManager(config.getDataDir(), config.getDataLogDir(), config.getSnapRetainCount(), config.getPurgeInterval());purgeMgr.start();if (args.length == 1 && config.servers.size() > 0) {runFromConfig(config);} else {LOG.warn("Either no config or no quorum defined in config, running "+ " in standalone mode");// there is only server in the quorum -- run as standaloneZooKeeperServerMain.main(args);}}
复制代码
你可以在配置文件zoo.cfg
文件中增加两个配置,分别是autopurge.snapRetainCount
和autopurge.snapRetainCount
。autopurge.purgeInterval
就是设置多少小时清理一次。而autopurge.snapRetainCount
是设置保留多少个快照文件snapshot
,之前的多有都删除。
有一点性能问题就是,一般zookeeper
是运行在集群中,业务会比较繁忙,如果每隔多久去清理势必会影响性能,我们会想能否有一种在集群不繁忙的时候去执行清理操作,比如在每晚的12点。但是很遗憾,zookeeper
并没有提供相应的实现,zookeeper
采用Timer
的方式去实现,而不是像quartz
,Spring
一样提供cron
表达式配置。但注意,并不是说Timer
不能实现指定时间执行,而是说zookeeper
没有实现而已。因为quartz
,Spring
底层还是使用Timer
和Executors
去实现的嘛!
再来看看DatadirCleanupManager
的start()
方法:
public void start() {if (PurgeTaskStatus.STARTED == purgeTaskStatus) {LOG.warn("Purge task is already running.");return;}// Don't schedule the purge task with zero or negative purge interval.if (purgeInterval <= 0) {LOG.info("Purge task is not scheduled.");return;}// 创建TIMERtimer = new Timer("PurgeTask", true);// 创建定时任务TimerTask task = new PurgeTask(dataLogDir, snapDir, snapRetainCount);// 每隔多少小时执行timer.scheduleAtFixedRate(task, 0, TimeUnit.HOURS.toMillis(purgeInterval));purgeTaskStatus = PurgeTaskStatus.STARTED;}
复制代码
现在原理一目了然了,日志源码分析就先到这了,同时你也阅读完了,非常棒!欢迎评论区留言,多多交流!
Zookeeper源码分析(二) ----- zookeeper日志相关推荐
- zookeeper源码分析之恢复事务日志
zookeeper源码分析之恢复事务日志 前言 源码分析 查看事务日志命令 总结 前言 本文是基于zookeeper集群启动过程分析(https://blog.csdn.net/weixin_4244 ...
- zookeeper源码分析之四服务端(单机)处理请求流程
上文: zookeeper源码分析之一服务端启动过程 中,我们介绍了zookeeper服务器的启动过程,其中单机是ZookeeperServer启动,集群使用QuorumPeer启动,那么这次我们分析 ...
- zookeeper源码分析之五服务端(集群leader)处理请求流程
leader的实现类为LeaderZooKeeperServer,它间接继承自标准ZookeeperServer.它规定了请求到达leader时需要经历的路径: PrepRequestProcesso ...
- zookeeper源码分析之三客户端发送请求流程
znode 可以被监控,包括这个目录节点中存储的数据的修改,子节点目录的变化等,一旦变化可以通知设置监控的客户端,这个功能是zookeeper对于应用最重要的特性,通过这个特性可以实现的功能包括配置的 ...
- SpringBoot源码分析(二)之自动装配demo
SpringBoot源码分析(二)之自动装配demo 文章目录 SpringBoot源码分析(二)之自动装配demo 前言 一.创建RedissonTemplate的Maven服务 二.创建测试服务 ...
- 【Android 事件分发】ItemTouchHelper 源码分析 ( OnItemTouchListener 事件监听器源码分析 二 )
Android 事件分发 系列文章目录 [Android 事件分发]事件分发源码分析 ( 驱动层通过中断传递事件 | WindowManagerService 向 View 层传递事件 ) [Andr ...
- gSOAP 源码分析(二)
gSOAP 源码分析(二) 2012-5-24 flyfish 一 gSOAP XML介绍 Xml的全称是EXtensible Markup Language.可扩展标记语言.仅仅是一个纯文本.适合用 ...
- Android Q 10.1 KeyMaster源码分析(二) - 各家方案的实现
写在之前 这两篇文章是我2021年3月初看KeyMaster的笔记,本来打算等分析完KeyMaster和KeyStore以后再一起做成一系列贴出来,后来KeyStore的分析中断了,这一系列的文章就变 ...
- 【投屏】Scrcpy源码分析二(Client篇-连接阶段)
Scrcpy源码分析系列 [投屏]Scrcpy源码分析一(编译篇) [投屏]Scrcpy源码分析二(Client篇-连接阶段) [投屏]Scrcpy源码分析三(Client篇-投屏阶段) [投屏]Sc ...
最新文章
- UI:UITableView表视图
- java子网划分_子网划分讲解及练习(二)
- Python Django列表渲染for的使用
- C# asp:Repeater DataSource ListT
- 如何容器化你的 ASP.Net Core
- mysql数据库安全机制研究意义_MySQL数据库的安全机制
- c 语言 realloc 源码,C语言,realloc
- oracle4030,oracle ora-4030错误求解
- mysql vs连不上_vs2015下配置MySQL,使之能使用c++连接完美运行
- Python入门--第三方模块的安装与使用,pip,import
- 获取公网ip,获取用户城市地址
- 26.leetcode160_intersection_of_two_linked_lists
- 电大计算机应用基础实训任务1-4,计算机应用基础本形考任务1
- scrapy运行报错: Overridden settings XXX
- Magento(CE1.X)自带模块解析七
- java开发人员的小习惯
- Spring boot 中使用 Thymeleaf
- vgg16_weights_tf_dim_ordering_tf_kernels_notop.h5
- 学习 Python Django
- c语言 字符金字塔问题
热门文章
- 分布式开放消息系统(RocketMQ)的原理与实践
- git rebase -i 汇合提交
- C++ MFC常用函数(转)
- OpenCV之gpu 模块. 使用GPU加速的计算机视觉:GPU上的相似度检测(PNSR 和 SSIM)
- Coursera课程Python for everyone:Quiz: Single-Table SQL
- Coursera课程Python for everyone:chapter3
- 图像代数运算:平均值去噪,减去背景
- C语言中 if 和 else if 的区别
- leetcode 697 Degree of an Array
- 【RegExp】JavaScript中正则表达式判断匹配规则以及常用方法