事故代碼
直入主題,生產環境日誌級別爲warn,請看如下這行代碼:
LOGGER.info("the DTO info: {}", JSON.toJSONString(DTO));
先做個小調查,你覺得這段代碼會不會有問題。
如果你的答案爲“有問題”,並且你有充足的理由,那麼這篇文章已經沒有往下看的必要了,因爲你已經掌握了筆者此文要傳達的知識點。如果你的答案爲“沒有問題”或者“無法分辨”,那麼,請繼續往下看。
原因分析
這段代碼主要有兩個需要注意的地方:
-
日誌級別爲info,而線上環境是warn級別。我們可以得出結論,線上環境肯定不會輸出這行日誌。 -
打印日誌的行爲中有JSON序列化動作。
第二點是此文的關鍵。我們假設DTO是一個很小的對象,JSON序列化時間以及開銷可以忽略不計,那麼這行代碼依然沒有問題。但是,如果DTO是一個很大的對象,比如10k,甚至100k,即使快如fastjson,其耗時依然高達數百毫秒,並且非常消耗CPU。如果是在高併發的系統中,這麼大的開銷完全不可接受,甚至可能就會拖垮整個系統。
public void info(String format, Object arg);
解決方案
如何解決這個問題?很簡單,在輸入日誌時加個級別判斷(需要說明的是,這種規範很容易被忽略,比如項目成員更替時,很容易引入有問題的代碼。所以筆者寫了一段腳本:掃描所有Java代碼,如果logger.info()中有JSON序列化動作,那麼必須判斷優先級後才能輸出日誌。即可以簡單的認爲它的前一行代碼必須是logger.isInfoEnabled()。如果你的項目有CICD環境,那麼把這段腳本集成到掃描規範中,纔是解決這個問題最完美的方案):
if(LOGGER.isInfoEnabled()) {
LOGGER.info("the DTO info: {}", JSON.toJSONString(DTO));
}
String reqId = "...";
String msg = "...";
LOGGER.info("the DTO info: {}", msg);
- END -
往期推薦
關注我回復「加羣」,加入Spring技術交流羣
本文分享自微信公衆號 - 程序猿DD(didispace)。
如有侵權,請聯繫 [email protected] 刪除。
本文參與“OSC源創計劃”,歡迎正在閱讀的你也加入,一起分享。