關於Mysql com.mysql.jdbc.StatementImpl$CancelTask記憶體流失問題及解決辦法,mysqljdbc

來源:互聯網
上載者:User

關於Mysql com.mysql.jdbc.StatementImpl$CancelTask記憶體流失問題及解決辦法,mysqljdbc

近來在負責公司簡訊網關的維護及建設,隨著公司業務發展對簡訊依賴越來越嚴重了,簡訊每天發送量也比以前每天40多w發送量暴增到每天達到200w發送量。因為是採用Java做發送底層,壓力遞增情況下不可避免的面對記憶體問題。在發送量接近200w情況下,出現記憶體泄露問題了。

經過對系統運行檢查發現:

        1)每次重啟系統3-4個小時後,均發現一點不穩定;

        2)在3-4個小時後,出現out of memory的錯誤:java.lang.OutOfMemoryError: GC overhead limit exceeded

發現這個問題後,直接通過JMS擷取監控日誌,發現系統的記憶體回收存在異常,gc壓力非常大而且存在明顯記憶體積壓。




然後直接把系統的記憶體down下來分析,發現的確存在記憶體積壓情況:


這個是mysql的一個定時任務的,這個定時任務主要作用是在用於做查詢逾時的。簡單舉個例子,系統在執行一個sql查詢情況下,jdbc會給你一個逾時時間。為了保證逾時時間後,可以關閉statement,會開啟一個保護關閉的定時任務。如果逾時情況下,sql還沒響應執行,cancel task就會執行關閉任務。因為c3p0的預設設定的逾時時間為25s(<setting name="defaultStatementTimeout" value="25000" />),意味這個25s內,在執行大量sql情況下,cancel task積壓到了一定程度,就會造成系統不穩定。(最後發現這個並不是根本原因,只是表象)

但是系統本身就有通過mysql做發送隊列的,本身對mysql操作非常多,如果只是對代碼層面下最佳化基本杯水車薪。

在時間緊迫的情況下,短時間內穩定業務才是最重要的任務。被逼根據以上現狀採用了臨時方案解決。


臨時方案

        通過以上判斷,基本可以判定cancel task在某組線程執行應該會形成一個峰值,撐爆了JVM的堆。但是現在無法在停止業務運行做過多調試,所以當機立斷,對JVM的記憶體擴大一倍以上,希望系統可以跨過一波記憶體峰值。結果把JVM的記憶體調整為故障時候的2倍時候,系統的記憶體又恢複到正常運作,不過cancel task最高值會佔用到記憶體2G以上。雖然也是會回收,但是一直擴記憶體不是很好的辦法。


解決方案

系統採用的mysql jdbc 5.1.6的版本,立刻反編譯mysql代碼,發現以下問題。因為cancel task的timer在connection中靜態存放,意味statement如果正常查詢出結構,業務無法把cancel task記憶體回收才是故障根本原因。


明確問題在mysql jdbc上面後,根本解決辦法應該查詢mysql jdbc是否解決了這個bug。

在5.1.11版本中找到這個bug的修複,更新後,記憶體流失故障得到解決。http://dev.mysql.com/doc/relnotes/connector-j/en/news-5-1-11.html


感謝國波與銳康的討論及協助,使故障得以完滿解決!

相關文章

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.