Java開源日志框架大比拼
譯文
應(yīng)用系統(tǒng)中,日志是不可缺少的重要組成部分,所有的應(yīng)用的出錯(cuò)信息等都應(yīng)該能在日志文件中查找到,有的應(yīng)用系統(tǒng)日志可能數(shù)量很小,有的龐大的應(yīng)用系統(tǒng)的日志是相當(dāng)龐大,同時(shí)日志文件必須是方便用戶定制和查找的,要具備很高的性能,否則會(huì)影響應(yīng)用系統(tǒng)的性能。
由 于日志通常涉及到IO讀寫磁盤(或者是阻塞或者是異步),這都要耗費(fèi)時(shí)間。當(dāng)在大型系統(tǒng)中有大量數(shù)據(jù)的時(shí)候,日志所耗費(fèi)的時(shí)間就會(huì)顯現(xiàn)。在本文中,將深入 探討目前Java開源世界中領(lǐng)先的五個(gè)日志框架,在各個(gè)方面進(jìn)行比較,要指出的是,本文并不是探究哪個(gè)日志框架是***秀的,而只是列出各自的優(yōu)缺點(diǎn)。
我們選取的五個(gè)日志框架分別為:
1. Log4J
2. Log4J2
3. Logback
4. SLF4J Simple Logging (SLF4J SL)
5. Java Util Logging (JUL)
我們想對(duì)比下這些日志框架對(duì)于基本的日志記錄活動(dòng)的性能如何,每一個(gè)日志操作包括時(shí)間戳和其上下文的進(jìn)程ID。我們進(jìn)行如下四個(gè)方面的測(cè)評(píng):
1.記錄字符串常量
2. Logging the .toString() value of a POJO 對(duì)POJO使用.toString()方法
3. Logging a throwable object 記錄throwable對(duì)象4 只測(cè)試.toString()方法
我們決定為每種場(chǎng)景進(jìn)行五次的評(píng)測(cè),通過(guò)衡量完成日紙記錄的操作次數(shù),以決定哪一個(gè)有***的成績(jī)。在每次測(cè)試中讓日志引擎在一分鐘內(nèi)使用10個(gè)線程去執(zhí)行,并且剔除***的2次偏差,將余下的三次進(jìn)行平均。
在每一個(gè)單獨(dú)的日志記錄操作中,我們讓CPU在日志記錄的時(shí)候都執(zhí)行一些操作(如檢查是否一個(gè)隨機(jī)數(shù)是否素?cái)?shù))。這些評(píng)測(cè)的日志引擎都使用各自的默認(rèn)配置通過(guò)SLF4J來(lái)運(yùn)行。評(píng)測(cè)是在Amazon m1.large EC2實(shí)例上進(jìn)行的。
在 Log4j2的剛開始的測(cè)試中,我們?cè)O(shè)置了%C的布局參數(shù)(參考:http://logging.apache.org/log4j/2.x /manual/layouts.html),這增加了其開銷,在@RemkoPopma的建議下,我們更新了設(shè)置為%c(日志的名稱)以符合其他的配 置,這給Log4j2一個(gè)性能相當(dāng)大的提升,在下面兩個(gè)圖中,值得注意的是記錄上下文的性能開銷。
使用%C的設(shè)置:
使用%C的設(shè)置:
完整的測(cè)試結(jié)果集參考這個(gè)鏈接:https://docs.google.com/spreadsheet/ccc?key=0Alceaf46X4GPdHBoLTdYQ29nRDh6V1dRY00zT1FwWWc&usp=sharing
下面對(duì)基于4個(gè)場(chǎng)景的測(cè)試結(jié)果進(jìn)行具體分析:
一 字符串常量
在 這輪比拼中,需要日志引擎使用線程和時(shí)間戳上下文去記錄字符串常量。Log4j是冠軍,比JUL能多寫270%的日志行,比logback多12.5%, 比SLF4J SL多52%。有趣的是在我們改變log4j2的配置前,它寫的行數(shù)能是比改變后的1/4左右,在更改配置后,性能排在第三位,只比logback記錄的 行數(shù)少30%。
二.toString()
在 這輪比拼中記錄的是POJO(使用其.toString方法),同樣使用的是線程和時(shí)間戳。結(jié)果中,對(duì)于Log4j2來(lái)說(shuō),和***回合差不多,但相比 SLF4J SL有25%的性能提升。Log4j和Logback是并駕齊驅(qū)的,位居第三,其吞吐量是SLF4J SL的88%。
三.Throwable
在這輪比拼中,日志引擎記錄異常的對(duì)象和相關(guān)的描述信息。其中Log4j2是位居首位,其性能比SLF4J SL高3倍,SLF4J SL位于第五位。
而Log4j和Logback也是只能排在此輪的冠軍之后,記錄的行數(shù)只大概有冠軍的一半,而第二位的反而是JUL,能記錄冠軍Log4j2的日志量的大概82%。
四.toString()方法比拼
當(dāng) 處理服務(wù)器日志的時(shí)候,每一個(gè)日志項(xiàng)的上下文(例如線程ID,類的相關(guān)上下文,時(shí)間戳等等)都是和日志內(nèi)容一樣重要。在之前的測(cè)試中,使用的是在大多數(shù)日 志文件中常見(jiàn)的標(biāo)志――線程ID號(hào)和時(shí)間戳。接下來(lái)我們認(rèn)為值得去分析單純?cè)谌罩局惺褂?toString()方法的性能。
這個(gè)時(shí)候,Log4j2是贏家(如果改變配置,能獲得180%的性能提升),贏出Logback和JUL 大概25%。SL4FJ SL則落敗。在每輪的五次測(cè)試中,SLF4J SL在啟用appenders的時(shí)候性能比不啟用要好。
Log4j在吞吐量上有15%的增加。JUL在這輪比拼中比不上Log4j和Log4j2,其結(jié)果和不使用上下文數(shù)據(jù)是一樣的。
本文的測(cè)試代碼可以在https://github.com/takipi/the-logging-olympics中下載。