問題描述:
最近已經有兩個項目因為日志打印問題而引發了故障,可以說是血的教訓了。兩次故障的原因也是非常的相似,都是由於其他業務系統調用了另外一個老系統的接口,但是由於傳遞的參數不正確,而老系統會因為參數不正確而打印日志。當錯誤的請求量增大,打印日志會造成當前線程阻塞,容易使機器機器負載升高,產生性能問題
排查方法:
1. 直接查看機器上日志大小
2. 還可以通過Jstack查看 占用cpu最多的線程,多查看幾次,如果每次都是打印日志的線程,那基本上也可以確定是打印日志的問題
解決方案:
1. 提前校驗參數,如果參數有問題應該拋出異常
2. 在logback的AsyncAppender中配置<neverBlock>true</neverBlock> 避免業務線程的阻塞
<!-- 異步輸出 --> <appender name ="STDOUT_ASYNC" class= "ch.qos.logback.classic.AsyncAppender"> <discardingThreshold >0</discardingThreshold> <queueSize>512</queueSize> <includeCallerData>false</includeCallerData> <neverBlock>true</neverBlock> <appender-ref ref ="stdout"/> </appender>
Logback的neverBlock原理:
由於logback相當於是生產者-消費者模式,當時我們在系統中ogger.info()或者ogger.error()時,是把日志信息加入到logback的隊列中,默認是調用隊列的put方法,而當隊列滿了之后,就會阻塞當前的線程。而設置了neverBlock后,則會調用offer方法,如果隊列滿了,則丟棄。可以查看源碼: