201207.24.bops操作者id丟失問題排查過程

背景:

    運營反饋在進入頁面操作時,修改會員密碼等操作會提示操作者id丟失等問題。


代碼實現原理:

    查看代碼,發現是從cookie中獲取的操作者id通過log4j的MDC進行上下文傳遞,寫入時正常,但是獲取時出現信息丟失。


技術背景:

  MDC的實現原理是threadlocal獲取上下文,所以在非誤操作情況下,在這個線程中的信息是不會丟失的


分析過程:

    1.模擬運營操作:發現部分操作成功,部分操作失敗;很容易讓人聯想到是因爲個別會員導致的,也是一開始被迷惑了(線上是一個集羣),走了不少彎路

    2.模擬環境:單獨啓動一個應用,發現沒有失敗過,從cookie到MDC的寫入以及讀出,完全正確,現場無法模擬,實在難以追蹤,中斷一段時間

    後來有位wlb同事剛好搭建了環境,必現這個問題,開始着手排查

    3.模擬異常請求:分析請求過程,發現cookie到MDC正常,但是讀取失敗,想必是代碼問題。

    4.綜上幾個,初步定論,該實現與代碼部署相關,在特定一些機器下部署,代碼不會出現問題且運行正常;但是在其他機器下部署,必然出現問題。

       這種問題比較可能是跟類加載有關。

    5.分析整體代碼結構:

     調用點: 

  

     

     實現:

   


說明下:

代碼自己封裝了jakarta.commons.logging.xxx.jar,getFactory()就是通過jakarta.commons.logging的實現去知道具體的log,然後又由自定義的Logger去包裝了一下Log(只包裝非log4j實現,MDC依賴log4j)。自己封裝logger爲了暴露MDC和NDC的接口,至於爲什麼要這麼風封裝,這裏不深糾了,畢竟代碼比較古來。(個人不太喜歡這種封裝,完全可以直接用jakarta.commons.logging)。

再來看下getFactory()實現,這個直接關係到具體的代碼。網上能找到一些說明,查找具體Factory實現的類,順序:

    讀取:commons-logging.properties 的org.apache.commons.logging.LogFactory

    系統傳入的org.apache.commons.logging.LogFactory屬性

    類路徑下的META-INF/services/org.apache.commons.logging.LogFactory文件

    默認實現org.apache.commons.logging.impl.LogFactoryImpl

系統沒有傳入任何東西,默認是使用的是第三種,分析代碼,類似路徑的jar包有三個,並且都在war的lib下,具體如下:

META-INF/services/org.apache.commons.logging.LogFactory:

jmemory-1.0-SNAPSHOT.jar
    com.alibaba.common.logging.spi.GenericLoggerFactory
toolkit.common.logging-1.0.jar
    com.alibaba.common.logging.spi.GenericLoggerFactory
org.slf4j.jcl104-over-slf4j-1.5.6.jar
    org.apache.commons.logging.impl.SLF4JLogFactory

前兩個還好實現是兩套代碼,但代碼一模一樣,咳

但是第三個的實現完全不同,實現是SLF4JLogFactory工廠。

jvm在類加載階段讀取具體的配置,由於lib下讀取的順序是jboss控制,並且和機器有關,導致讀取時有些讀取到GenericLoggerFactory,產生的log爲log4j,能獲取到MDC,有些SLF4JLogFactory,產生的log爲org.apache.commons.logging.impl.SLF4JLocationAwareLog,該log並非log4j實現,在封裝logger時,採用了LoggerWrapper,裏面的MDC實現爲空實現,導致信息沒有記錄。


 

直接誘因:odin引入的

      <groupId>com.xxxxx.external</groupId>
      <artifactId>org.slf4j.jcl104-over-slf4j</artifactId>

 

解決:

   1.逐出org.slf4j.jcl104-over-slf4j,直接但不徹底

    2. bops由於日誌系統太多,有log4j(web),slf4j(task),但是包打成一個,在加載時會出現一些不可預期的結果,建議梳理bops。

   最好能把MDC全部替換爲threadlocal,這樣不依賴於任何日誌系統,原先的使用方式已經不適合了


   









   


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章