<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    Sky's blog

    我和我追逐的夢

    常用鏈接

    統計

    其他鏈接

    友情鏈接

    最新評論

    蹊蹺的ThreadDeath,令人郁悶的glassfish

         上周遇到的一個bug,ThreadDeath error,從而導致系統的每個請求都失敗。能夠讓系統的每個traffic請求都失敗的bug,這個嚴重程度不言而喻。看看是怎么回事吧?

        其實問題的表現很簡單:在請求處理過程中,拋出了一個ThreadDeath 的error:

    Caused by: java.lang.ThreadDeath
            at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:
    1413)
            at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:
    320)
            at se.ericsson.nrg.ws.realms.nrgcommonentities.service._ApplicationServiceSubscriptionRemote_DynamicStub.searchBySpIdAndAppIdAndScPk

    (se
    /ericsson/nrg/ws/realms/nrgcommonentities/service/_ApplicationSe
    rviceSubscriptionRemote_DynamicStub.java)
            at se.ericsson.nrg.ws.realms.nrgcommonentities.service.ApplicationServiceSubscriptionDAORemoteImpl.searchBySpIdAndAppIdAndScPk(ApplicationServiceSubscriptionDAORemoteImpl.java:
    104)
            ...
    74 more


        坦白說,每次看到ThreadDeath這個error,我都有種一頭撞死的感覺, ^0^,誰取的這名字!由于之前遇到過類似的問題,因此倒是不特別緊張,先看看請求處理的過程:首先是一個webapp接收請求,然后請求被交給一個EJB的模塊處理,ThreadDeath error就是在這里拋出。從ThreadDeath的exception trace上看到,

        at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1413)

        說明當前線程是試圖用webapp的classloader來裝載類,然后遭遇ThreadDeath,隨即在日志文件中查找到這樣的內容:


    [#
    |2010-05-24T15:19:26.702+0800|INFO|sun-glassfish-comms-server2.0|org.apache.catalina.loader.WebappClassLoader|_ThreadID=47;_ThreadName=httpWorkerThread-48080WorkerThread-8080-337;|PWC1635: Illegal access: this web application instance has been stopped already (the eventual following stack trace is caused by an error thrown for debugging purposes as well as to attempt to
    terminate the thread which caused the illegal access, and has no functional impact)
    |#]

        "this web application instance has been stopped already",進一步證實了我們的猜測,這個是最常見的ThreadDeath 的發生場景了,簡單描述一下:

        1. 工作線程執行webapp的請求,webapp的classloader被保存在thread
            類似Thread.setContextClassLoader(WebappClassLoader)這樣的方式
        2. webapp被restart/redeploy ,但是由于某些原因上面的工作線程中保留的webapp的classloader并沒有被清理

        3. 這個工作線程繼續處理請求,由于他使用的classloader是restart/redeploy前的webapp的,現在這個webapp已經不復存在,因此出現ThreadDeath 錯誤

        有關ThreadDeath的類似錯誤,glassfish上有個wiki特地描述了這個問題。

    http://wiki.glassfish.java.net/Wiki.jsp?page=FaqWebAppStoppedIllegalAccessError

        正在我們以為找到問題準備繼續查找看是哪里的Thread.setContextClassLoader()方法出現問題時,被另外一個發現擊倒!我們發現上述的ThreadDeath 在重新啟動之后居然可以立即重現!很暈,按照上面的推斷邏輯,如果我們關閉glassfish,即關閉jvm,退出進程,然后重啟啟動,ThreadDeath 就應該消失才是,因為出問題的Thread隨jvm一起退出了。新jvm中啟動的Thread不再有殘余的classloader來導致ThreadDeath。

        這個證據直接推翻前面的推斷,看來問題不是這個簡單了。

        隨后進行了大量的查找,推斷和嘗試,過程不敘述了。最后發現在日志中有一個異常,坦白說我們的日志有點多,有點亂,不是很好查找問題:

    javax.servlet.ServletException: java.lang.ClassCastException: java.lang.Long cannot be cast to java.lang.Integer
     at se.ericsson.nrg.ws.service.http.SIGAuthenticationFilter.init(SIGAuthenticationFilter.java:
    162)
     at org.apache.catalina.core.ApplicationFilterConfig.getFilter(ApplicationFilterConfig.java:
    273)
     at org.apache.catalina.core.ApplicationFilterConfig.setFilterDef(ApplicationFilterConfig.java:
    385)
     at org.apache.catalina.core.ApplicationFilterConfig.
    <init>(ApplicationFilterConfig.java:119)
     at org.apache.catalina.core.StandardContext.filterStart(StandardContext.java:
    4521)
     at org.apache.catalina.core.StandardContext.start(StandardContext.java:
    5369)
     at com.sun.enterprise.web.WebModule.start(WebModule.java:
    345)
     at com.sun.enterprise.web.LifecycleStarter.doRun(LifecycleStarter.java:
    58)
     at com.sun.appserv.management.util.misc.RunnableBase.runSync(RunnableBase.java:
    304)
     at com.sun.appserv.management.util.misc.RunnableBase.run(RunnableBase.java:
    341)
     at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:
    441)
     at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:
    303)
     at java.util.concurrent.FutureTask.run(FutureTask.java:
    138)
     at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:
    886)
     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:
    908)
     at java.lang.Thread.run(Thread.java:
    619)

        webapp中定義有一個filter,現在這個filter在init()方法中出現異常,而我們編碼的時候會包裝這個異常然后以ServletException的方式拋給容器。

        init()方法中出現的異常是一個配置項的類型不正確,做強制類型轉換時失敗導致。由于出現這個配置問題的腳本偶爾才運行,因此過去這個錯誤發生的幾率極低。隨即修復了這個配置項,重啟glassfish后驗證成功,ThreadDeath 錯誤消失,系統工作正常。

        OK,問題找到并得到確認。

        可是這里依然有一個巨大的疑問:為什么一個filter拋出的ServletException,會導致glassfish出現"判斷失誤"從而認定webapp是"stopped"狀態以致最后以ThreadDeath的形式來體現錯誤?

        這個案例比較迷惑人的地方是,filter拋出的ServletException后,這個webapp是可以正常接收請求也可以正常將請求轉交后面的業務處理模塊,控制臺上也看不到這個webapp的任何狀態異常。

        特地找了一下j2ee5規范,沒有發現有對filter的詳細要求,隨即找到了j2ee 5的 API,在API文檔中發現以下內容:

    void init(FilterConfig filterConfig)
              
    throws ServletException
    Called by the web container to indicate to a filter that it is being placed into service. The servlet container calls the init method exactly once after instantiating the filter. The init method

    must complete successfully before the filter is asked to 
    do any filtering work.
     
    The web container cannot place the filter into service 
    if the init method either
    1.Throws a ServletException
    2.Does not return within a time period defined by the web container

        這里可以看到,當發生ServletException 異常時,“The web container cannot place the filter into service”,既這個filter應該不能生效才是。而且也沒有任何其他說明說ServletException會導致其他問題比如webapp不能啟動,不能工作之類的。

        當時實際上,我們在檢查ThreadDeath的調用信息時,發現有下面的調用

    at se.ericsson.nrg.ws.service.http.SIGAuthenticationFilter.doFilter(SIGAuthenticationFilter.java:89)

        說明這個出現init()錯誤的filter還是被glassfish正常調用去執行doFilter()方法,這里和j2ee API的要求是不符合的。有點奇怪的是,glassfish一向是以嚴格遵循j2ee規范而著稱,居然在這里一反常態。

        而更令人 郁悶的是,glassfish在處理這個有filter初始化出現ServletException異常的webapp時的前后表現:首先這個webapp的啟動沒有問題,狀態正常。filter也被認為可以正常工作并加入了filter鏈。webapp中的功能正常,可以正常的接收請求并轉發給內容業務處理模塊。從這些跡象看這個webapp基本沒有問題。但是后面glassfish卻莫名其妙的認定,“this web application instance has been stopped already”,從而以ThreadDeath這種非常規的error來報錯。

        這個做法令人比較難于接收,如果filter初始化出現ServletException異常會導致webapp的狀體異常,那么glassfish應該在第一時間直接給出這個判斷,比如直接讓webapp就啟動失敗之類的,這樣不至于將這個錯誤推遲到一個非常遙遠的地方才被暴露,而且filter ServletException異常 -》 ThreadDeath 的這種因果關系未免有點牽強,查錯時根本沒有可能直接聯系上,導致查錯的難度大增。

        不得不再次批評一下glassfish,從產品質量上看,glassfish和weblogic的差距還真是不小。
       

    posted on 2010-05-25 11:38 sky ao 閱讀(3677) 評論(0)  編輯  收藏 所屬分類: ejb

    主站蜘蛛池模板: 精品国产免费人成电影在线观看| 成年人在线免费观看| 好爽…又高潮了毛片免费看| 亚洲人成网站18禁止一区| 亚洲国产高清人在线| 亚洲aⅴ无码专区在线观看| 免费一区二区无码东京热| 最新仑乱免费视频| 亚洲av中文无码乱人伦在线r▽| 亚洲色中文字幕在线播放| 伊人免费在线观看| 日本午夜免费福利视频| 91亚洲自偷手机在线观看| 黄页网站在线免费观看| 久久久久久久久久国产精品免费| 国产美女无遮挡免费网站| 亚洲精品高清视频| 全部一级一级毛片免费看| 久久久久久久91精品免费观看| 国产亚洲精品不卡在线| 亚洲欧美日韩久久精品| 日本xxxx色视频在线观看免费| 全黄性性激高免费视频| 亚洲午夜久久久久久尤物| aa级女人大片喷水视频免费| 日韩成人免费视频播放| 亚洲色图.com| 国产午夜无码片免费| 四虎影院永久免费观看| 亚洲国产精品久久久久秋霞影院| 国产激情久久久久影院老熟女免费 | 亚洲精品无码永久中文字幕 | 亚洲福利秒拍一区二区| 有码人妻在线免费看片| 毛色毛片免费观看| 久久久久亚洲AV无码网站| 中文字幕版免费电影网站| 免费又黄又硬又爽大片| 中文字幕无码精品亚洲资源网久久 | 国产高清视频免费在线观看| 国产高清免费观看|