Zookeeper源码分析(二) ----- zookeeper日志
zookeeper源碼分析系列文章:
- Zookeeper源碼分析(一) ----- 源碼運行環(huán)境搭建
原創(chuàng)博客,純手敲,轉(zhuǎn)載請注明出處,謝謝!
既然我們是要學習源碼,那么如何高效地學習源代碼呢?答案就是跟蹤日志。說到zookeeper日志,小編覺得非常的重要,如果沒有日志文件,后期的zookeeper事務(wù)處理基本上不能玩。因此,我將zookeeper日志放在源碼分析系列的第二部分,也是在能夠運行zookeeper的基礎(chǔ)上,進行日志分析。
一、zookeeper日志類型
zookeeper中有兩類日志,分別是:
- 1、事務(wù)日志log
- 2、快照日志snapshot
事務(wù)日志 : 顧名思義,就是用于存放事務(wù)執(zhí)行的相關(guān)信息,如zxid、cxid等。至于什么是zookeeper事務(wù),放到后面的文章中講。
快照日志 : ``zookeeper數(shù)據(jù)節(jié)點數(shù)據(jù)是運行在內(nèi)存中的,當然內(nèi)存保存這些結(jié)點的數(shù)據(jù)不可能無限大,而且數(shù)據(jù)節(jié)點的內(nèi)容是動態(tài)變化的,因此zookeeper提供一中獎數(shù)據(jù)節(jié)點持久化的機制,每隔一段時間,zookeeper會將內(nèi)存中的數(shù)據(jù)節(jié)點DataTree序列到磁盤中,因此就形成了我們的快照日志。
在zookeeper源碼調(diào)試的過程中,諸如服務(wù)端的啟動日志、客戶端的啟動日志、請求的相關(guān)日志,由于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日志輸出體現(xiàn)在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二進制構(gòu)件對logStream進行包裹,輸出二進制數(shù)據(jù) oa = BinaryOutputArchive.getArchive(logStream); 復制代碼對應(yīng)的文件系統(tǒng)的文件如下圖:
既然是二進制日志文件,那么我們直接打開該文件肯定是亂碼嘛!怎么辦呢?下面提供兩種方法,這兩種方法都是基于zookeeper提供的LogFormatter.java工具類來實現(xiàn)的。
- 1、在eclipse中開該類,然后運行該類的main方法的同時傳入你想查看的日志文件路徑即可
- 2、采用命令行java -classpath xxx.jar org.apache.zookeeper.server.LogFormatter logFilePath的形式進行查看
第一種方式:
這里假設(shè)我的日志文件存放路徑為E:\\resources\\zookeeper-3.4.11\\conf\\log\\version-2\\log.1,當我在eclipse中運行main方法時,設(shè)置傳入的參數(shù)即可,如下圖:
然后就可以在控制臺輸出日志了,輸出樣例如下:
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兩個文件放到該目錄下,然后打開命令行,執(zhí)行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啟動之前會創(chuàng)建一個DatadirCleanupManager對象進行數(shù)據(jù)清理任務(wù),DatadirCleanupManager會根據(jù)你配置文件的配置決定是否清理以及每隔多久進行清理,其底層原理采用JDK的Timer定時器實現(xiàn),下面將對其實現(xiàn)機制從源碼的角度進行分析:
先看QuorumPeerMain類,在其initializeAndRun()方法執(zhí)行時會創(chuàng)建一個DatadirCleanupManager對象,并將zoo.cfg配置文件的相關(guān)配置傳遞給該對象,源碼如下:
protected void initializeAndRun(String[] args)throws ConfigException, IOException{QuorumPeerConfig config = new QuorumPeerConfig();if (args.length == 1) {config.parse(args[0]);}// 啟動數(shù)據(jù)目錄清理定時任務(wù),傳遞的參數(shù)有數(shù)據(jù)目錄DataDir,日志目錄LogDir,以及快照保留數(shù)量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就是設(shè)置多少小時清理一次。而autopurge.snapRetainCount是設(shè)置保留多少個快照文件snapshot,之前的多有都刪除。
有一點性能問題就是,一般zookeeper是運行在集群中,業(yè)務(wù)會比較繁忙,如果每隔多久去清理勢必會影響性能,我們會想能否有一種在集群不繁忙的時候去執(zhí)行清理操作,比如在每晚的12點。但是很遺憾,zookeeper并沒有提供相應(yīng)的實現(xiàn),zookeeper采用Timer的方式去實現(xiàn),而不是像quartz,Spring一樣提供cron表達式配置。但注意,并不是說Timer不能實現(xiàn)指定時間執(zhí)行,而是說zookeeper沒有實現(xiàn)而已。因為quartz,Spring底層還是使用Timer和Executors去實現(xiàn)的嘛!
再來看看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;}// 創(chuàng)建TIMERtimer = new Timer("PurgeTask", true);// 創(chuàng)建定時任務(wù)TimerTask task = new PurgeTask(dataLogDir, snapDir, snapRetainCount);// 每隔多少小時執(zhí)行timer.scheduleAtFixedRate(task, 0, TimeUnit.HOURS.toMillis(purgeInterval));purgeTaskStatus = PurgeTaskStatus.STARTED;} 復制代碼現(xiàn)在原理一目了然了,日志源碼分析就先到這了,同時你也閱讀完了,非常棒!歡迎評論區(qū)留言,多多交流!
總結(jié)
以上是生活随笔為你收集整理的Zookeeper源码分析(二) ----- zookeeper日志的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: JavaScript中的原型(proto
- 下一篇: SpringBoot webmvc项目导