切面是异步还是同步操作‘_分布式中采用Logback的MDC机制与AOP切面结合串联日志...
導讀:在實際開發中,打印日志是十分重要的。在生產環境中,如果日志打得好可以快速地排查問題,而在分布式的場景下,一個請求會跨越多個節點,既一個業務可能需要多個節點協調配合處理。那么日志將會分散,而為了更好的查看日志,我們需要將它們串聯起來,這樣便會使排查問題變得更佳輕松。
串聯ID在分布式日志打印的好處
舉例一個簡單分布式場景下使用串聯日志的例子。場景如下:一筆支付請求從產品系統發起,期間經歷了核心系統和網關系統最后調用銀行系統實現資金劃轉,并逐步響應結果直到回到產品系統。這里暫且把整個支付流程看作是同步的,當這筆交易在生產環境中因其中某一環境出現異常時,我們需查看日志進行排查,而這筆交易因為流經多個系統,所以日志是分散的。這時候如果有一個唯一標識且能把所有日志串聯起來那么將會方便和提高問題排查的效率。
串連ID的實現方式
串聯的核心要點是把ID做為一個請求必傳參數。常見如采用手動打印日志,既在各個接口服務內多處加上logger打印,打印內容里加上串聯ID,如:
但是,還有另一種更簡便的打印方式,既是MDC ( Mapped Diagnostic Contexts ) + AOP切面結合。MDC它是一個線程安全的存放診斷日志的容器。在處理請求前將請求的唯一標示放到MDC容器中,這個唯一標示會隨著日志一起輸出,以此來區分該條日志是屬于那個請求的。并在請求處理完成之后清除MDC容器。
MDC對外提供的方法
Logback配置
使用Logback的MDC機制,需要在logback.xml日志模板中進行一些設置,在logback.xml中,通過使用 %X{ }來占位,替換到對應的MDC中key的值。MDC容器的key可以多次賦值,每一次賦值會覆蓋上一次的值。
MDC簡單應用例子
往MDC容器中put入鍵值對,在日志打印時,日志會按照我們預先在logback.xml中的格式輸出,而其中占位符會替換上MDC中對應key的value值。打印結果如下:
MDC與AOP切面的結合
如編寫一個切面,被調用的服務在執行操作前,切面會將關鍵信息輸出日志并同時將串聯ID put到容器中,使其能在接下來同一線程內輸出的日志中都包含該串聯ID信息,在將日志串聯起來的同時也方便了日志的打印。
除了自定義切面外,Logback也提供了一個過濾器MDCInsertingServletFilter,感興趣的朋友可以去詳細了解下。
管理每個線程的MDC容器
這里要特別要注意一點的是在主線程上,新起一個子線程,并由 java.util.concurrent.Executors來執行它時,在早期的版本中子線程可以直接自動繼承父線程的MDC容器中的內容,因為MDC在早期版本中使用的是InheritableThreadLocal來作為底層實現。但是由于性能問題被取消了,最后還是使用的是ThreadLocal來作為底層實現。這樣子線程就不能直接繼承父線程的MDC容器。
舉個例子:
例如:支付操作為異步時,網關接收了核心的支付請求后會新開一個線程去處理支付請求,并響應回核心受理成功(注意:這里受理代表接收到支付的請求,而不代表處理成功)。那這樣做就會導致新的子線程MDC并沒有繼承父線程中的東西,導致響應結果時缺失串聯ID信息,不能與支付請求關聯起來。
解決方案
根據以上問題,Logback官方建議父線程新建子線程之前調用MDC.getCopyOfContextMap()方法將MDC內容取出來傳給子線程,子線程在執行操作前先調用MDC.setContextMap()方法將父線程的MDC內容設置到子線程。
最后
以上就是分布式場景下一種較為不錯的日志打印方式,通過結合AOP切面與Logback的MDC機制將多個系統間有關聯的日志串聯起來,有助于問題的排查及信息的查看。如果有其他不錯的日志打印方式也歡迎提出,共同討論學習。
感謝您的閱讀,如果喜歡本文歡迎關注和轉發,本頭條號將堅持原創,持續分享IT技術知識。對于文章內容有其他想法或意見建議等,歡迎提出共同討論共同進步
總結
以上是生活随笔為你收集整理的切面是异步还是同步操作‘_分布式中采用Logback的MDC机制与AOP切面结合串联日志...的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 计算基因组学需要计算机知识吗,生物信息学
- 下一篇: Linux作者批评英特尔指令集,英特尔回