一次Tomcat假死的問題尋找

運行環境:Linux CentOS 7 JDK8 Tomcat8 MYSQL SpringMVC, 8G內存,Tomcat不定時的假死,假死時GC線程都是接近100%,根據網上排查假死的方法,jstatck、jmap、jvisualVM,MAT都查了個遍,能定位到相關的地方,但是看代碼覺得沒有任何問題,最好還是加上了MAP、LIST等類型在使用完成後賦值爲null,強制爲垃圾以便回收,但是沒有效果。後來琢磨着假死時還是看下SQL運行語句吧,使用mysql的指令show full processList,發現一條只有日期字段而沒有記錄數限制的SQL的執行狀態是Sending Data,正常而言,該SQL語句的數據不多的,過了幾秒後再執行,發現那個語句L的執行狀態是Sending Data,估計是這個語句引起的,將該語句複製出來改爲統計記錄數後執行,發現居然大於150萬,就是它了,這裏巨量的數據要返回給前端,必死無疑。其實該語句也會出現在druid-slow-sql.log文件中,只是自己沒有留意而已。

下面來分析下過程:第一個表:表A是股票交易所的當天分時指數,每個交易所每分鐘一條數據,一般而言,一個交易所一天就是幾百條記錄。第二個表:表B是股票交易所的最近一週的分時指數,當時爲了提高當天分時指數的速度,表A只保留一天的數據,由第三方負責插入,表B的數據是本程序每天將表A的數據複製一份到表B,然後清除一週前的數據。從邏輯看起來沒問題,問題是在於複製時沒有根據當天日期進行復制,而是認爲表A的數據就是當天的,所以複製時造成了表B數據的重複,並且表A的數據由於第三方的原因,好久沒有更新,這樣長期累計下來,在表B中的同一天的數據就很多了。一般情況下,用戶不查詢周線指數時,系統正常,一旦查詢周線指數,必然出現假死,由於這個操作時間的不確定,所以假死是沒有規律的。

最後修復方法包括:1)直接在指數查詢語句限制記錄數,這個可以快速更新代碼,就算數據有錯,也不至於系統假死而造成系統無法使用;2)修改表B的複製處理邏輯,嚴格按照當天日期進行。

經過這個事情,得出的結論:1)不要偷懶,代碼邏輯要編寫嚴謹;2)不要假設第三方提供的服務和數據不存在問題,你要假設它存在的問題,然後自己提供方法保證不會影響到自己編寫的模塊功能。

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