關(guān)于log4j2的異步日志輸出方式
log4j2的異步日志輸出方式
使用log4j2的同步日志進(jìn)行日志輸出,日志輸出語句與程序的業(yè)務(wù)邏輯語句將在同一個線程運(yùn)行。
而使用異步日志進(jìn)行輸出時,日志輸出語句與業(yè)務(wù)邏輯語句并不是在同一個線程中運(yùn)行,而是有專門的線程用于進(jìn)行日志輸出操作,處理業(yè)務(wù)邏輯的主線程不用等待即可執(zhí)行后續(xù)業(yè)務(wù)邏輯。
Log4j2中的異步日志實現(xiàn)方式有AsyncAppender和AsyncLogger兩種。
其中:
AsyncAppender
采用了ArrayBlockingQueue來保存需要異步輸出的日志事件;AsyncLogger
則使用了Disruptor框架來實現(xiàn)高吞吐。
第一種實現(xiàn)異步方式AsyncAppender
AsyncAppender直接在log4j2的xml的配置文件中配置,注意下面代碼的注釋位置
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="warn"> <Appenders> <!--正常的Appender配置,此處配置的RollingFile會在下面AsyncAppender被通過name引用--> <RollingFile name="RollingFileError" fileName="${Log_Home}/error.${date:yyyy-MM-dd}.log" immediateFlush="true" filePattern="${Log_Home}/$${date:yyyy-MM}/error-%d{MM-dd-yyyy}-%i.log.gz"> <PatternLayout pattern="%d{yyyy-MM-dd 'at' HH:mm:ss z} %-5level %logger{36} : %msg%xEx%n"/> <ThresholdFilter level="error" onMatch="ACCEPT" onMismatch="DENY"/> <Policies> <TimeBasedTriggeringPolicy modulate="true" interval="1"/> <SizeBasedTriggeringPolicy size="10MB"/> </Policies> </RollingFile> <!--一個Appender配置完畢--> <!--異步AsyncAppender進(jìn)行配置直接引用上面的RollingFile的name--> <Async name="Async"> <AppenderRef ref="MyFile"/> </Async> <!--異步AsyncAppender配置完畢,需要幾個配置幾個--> </Appenders> <Loggers> <Root level="error"> <!--此處如果引用異步AsyncAppender的name就是異步輸出日志--> <!--此處如果引用Appenders標(biāo)簽中RollingFile的name就是同步輸出日志--> <AppenderRef ref="Async"/> </Root> </Loggers> </Configuration>
重點內(nèi)容全在上面代碼的注釋中,AsyncAppender的配置就在xml文件中實現(xiàn),無需單獨引用包來支持.配置AsyncAppender后,日志事件寫入文件的操作將在單獨的線程中執(zhí)行。
AsyncAppender的常用參數(shù)
參數(shù)名 | 類型 | 說明 |
---|---|---|
name | String | Async Appender的名字 |
AppenderRef | String | 異步調(diào)用的Appender的名字,可以配置多個 |
blocking | boolean | 默認(rèn)為true。如果為true,appender將一直等待直到queue中有空閑;如果為false,當(dāng)隊列滿的時候,日志事件將被丟棄。(如果配置了error appender,要丟棄的日志事件將由error appender處理) |
bufferSize | integer | 隊列中可存儲的日志事件的最大數(shù)量,默認(rèn)為128 |
第二種實現(xiàn)異步方式AsyncLogger
Log4j2中的AsyncLogger的內(nèi)部使用了Disruptor框架。
Disruptor簡介
Disruptor是英國外匯交易公司LMAX開發(fā)的一個高性能隊列,基于Disruptor開發(fā)的系統(tǒng)單線程能支撐每秒600萬訂單。
目前,包括Apache Strom、Log4j2在內(nèi)的很多知名項目都應(yīng)用了Disruptor來獲取高性能。
Disruptor框架內(nèi)部核心數(shù)據(jù)結(jié)構(gòu)為RingBuffer,其為無鎖環(huán)形隊列。
Disruptor為什么這么快?
- lock-free-使用了CAS來實現(xiàn)線程安全
- 使用緩存行填充解決偽共享問題
首先在pom單中應(yīng)用相關(guān)的包
<dependency> <groupId>com.lmax</groupId> <artifactId>disruptor</artifactId> <version>3.4.2</version> </dependency>
第二步在log4j2的xml文件中配置AsyncLogger
log4j2.xml配置如下:
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="debug" name="MyApp" packages=""> <Appenders> <Console name="Console" target="SYSTEM_OUT"> <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n" /> </Console> <RollingFile name="RollingFile" fileName="logs/app.log" filePattern="logs/app-%d{yyyy-MM-dd HH}.log"> <PatternLayout> <Pattern>%d %p %c{1.} [%t] %m%n</Pattern> </PatternLayout> <Policies> <SizeBasedTriggeringPolicy size="500MB"/> </Policies> </RollingFile> <RollingFile name="RollingFile2" fileName="logs/app2.log" filePattern="logs/app2-%d{yyyy-MM-dd HH}.log"> <PatternLayout> <Pattern>%d %p %c{1.} [%t] %m%n</Pattern> </PatternLayout> <Policies> <SizeBasedTriggeringPolicy size="500MB"/> </Policies> </RollingFile> </Appenders> <Loggers> <!--上面的配置都和原配置一樣,就是在下方這直接定義AsyncLogger,他的name在java類中被引用即可--> <AsyncLogger name="com.meituan.Main" level="trace" additivity="false"> <appender-ref ref="RollingFile"/> </AsyncLogger> <AsyncLogger name="RollingFile2" level="trace" additivity="false"> <appender-ref ref="RollingFile2"/> </AsyncLogger> <Root level="debug"> <AppenderRef ref="Console"/> <AppenderRef ref="RollingFile"/> </Root> </Loggers> </Configuration>
java代碼如下:
public class Main { public static void main(String args[]) { //引用com.meituan.Main日志輸出器 Logger logger = LogManager.getLogger(Main.class); //引用的名為RollingFile2的異步AsyncLogger Logger logger2 = LogManager.getLogger("RollingFile2"); Person person = new Person("Li", "lei"); logger.info("hello, {}", person); logger2.info("good bye, {}", person); }
上述log4j2.xml中配置了兩個AsyncLogger,名字分別為com.meituan.Main和RollingFile2。
并且,在main方法中分別使用兩個logger來輸出兩條日志。
在加載log4j2.xml的啟動階段,如果檢測到配置了AsyncRoot或AsyncLogger,將啟動一個disruptor實例。
log4j2異步注意事項
log4j2異步類型
1) 使用<Async>標(biāo)簽
示例:
<Async name="asyncKafkaLog"> <AppenderRef ref="Failover" /> </Async>
注意事項: 此類異步隊列是BockingQueue,隊列默認(rèn)大小是128
2) 使用<AsyncLogger>標(biāo)簽
示例:
<AsyncLogger name="kafkaLogger" level="trace" includeLocation="false"> <AppenderRef ref="Failover"/> </AsyncLogger>
注意事項: 此類異步隊列是Disruptor隊列默認(rèn)大小是4096
3) 使用 JVM參數(shù)
示例:
#啟動參數(shù)方式 -DLog4jContextSelector=org.apache.logging.log4j.core.async.AsyncLoggerContextSelector #代碼方式 System.setProperty("Log4jContextSelector", "org.apache.logging.log4j.core.async.AsyncLoggerContextSelector");
注意事項: 此類異步是全量異步,log4j配置文件里所有l(wèi)ogger都自動異步,使用異步隊列為Disruptor,隊列默認(rèn)大小4096
小提示
① Disruptor隊列性能遠(yuǎn)勝于BlockingQueue,這也是log4j2性能提升的重要原因之一
② 如果啟用了全量異步,又使用了<AsyncLogger>會如何?
- log4j2會新建兩個Disruptor隊列,<AsyncLogger>之流使用一個,其他的使用另外一個,所以建議將可能發(fā)生阻塞的logger歸類使用一個Disruptor,畢竟是隊列,一個阻塞了其他的得乖乖等著
③ 如果默認(rèn)隊列長度不足咋辦?
#第一步:加大兩個Disruptor隊列的長度 -DAsyncLogger.RingBufferSize=262144 -DAsyncLoggerConfig.RingBufferSize=262144 #第二步:設(shè)置隊列滿了時的處理策略:丟棄,否則默認(rèn)blocking,異步就與同步無異了 -Dlog4j2.AsyncQueueFullPolicy=Discard
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
SpringMVC加載控制與Postmand的使用和Rest風(fēng)格的引入及RestFul開發(fā)全面詳解
SpringMVC是一種基于Java,實現(xiàn)了Web MVC設(shè)計模式,請求驅(qū)動類型的輕量級Web框架,即使用了MVC架構(gòu)模式的思想,將Web層進(jìn)行職責(zé)解耦?;谡埱篁?qū)動指的就是使用請求-響應(yīng)模型,框架的目的就是幫助我們簡化開發(fā),SpringMVC也是要簡化我們?nèi)粘eb開發(fā)2022-10-10Spring?AOP?后置通知修改響應(yīng)httpstatus方式
這篇文章主要介紹了Spring?AOP?后置通知修改響應(yīng)httpstatus方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-12-12MyBatis insert操作插入數(shù)據(jù)之后返回插入記錄的id
今天小編就為大家分享一篇關(guān)于MyBatis插入數(shù)據(jù)之后返回插入記錄的id,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧2019-03-03Spring?Boot統(tǒng)一接口返回及全局異常處理
這篇文章主要介紹了Spring?Boot統(tǒng)一接口返回及全局異常處理,文章圍繞主題展開相關(guān)資料,具有一定的參考價值需要的小伙伴可以參考一下2022-04-04Mybatis如何根據(jù)List批量查詢List結(jié)果
這篇文章主要介紹了Mybatis如何根據(jù)List批量查詢List結(jié)果,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-03-03Retrofit+Rxjava實現(xiàn)文件上傳和下載功能
這篇文章主要介紹了Retrofit+Rxjava實現(xiàn)文件上傳和下載功能,文中提到了單文件上傳和多文件上傳及相關(guān)參數(shù)的請求,需要的朋友參考下吧2017-11-11