記一次線上頻繁fullGc的排查解決過程

發生背景

最近上線的一個項目幾乎全是查詢業務,並且都是大表的慢查詢,sql優化是做了一輪又一輪,前幾天用戶反饋頁面加載過慢還時不時的會timeout,但是我們把對應的sql都優化一遍過後,前臺響應還是很慢,數據庫測試sql運行時間在3s以內但響應的時候要麼500要麼就超時了,這時猜測可能是服務器出了問題,於是讓運維監測了下GC情況,結果令人喫驚,近15小時發生了237次FGC,每次耗時近4000秒;於是我就讓他把內存快照dump給我了

通過MAT分析內存快照

常用名詞介紹

  • Leak Suspects
    相當於一個總覽,通過餅圖的方式展示了可能造成內存溢出或泄露的對象使用的內存大小,並且會分析是哪個類加載器加載的哪個類佔用了多少字節;如圖:
  • Dominator Tree
    列出了對象與其自身的引用關係,並且倒序列出了對象佔用的內存大小以及百分比;通過這些能很清晰的定位到佔用內存的對象
  • shallow heap
    淺堆;對象沒有引用其他對象時自身的大小
  • retained heap
    深堆;對象自身的大小加其引用對象的大小,即對象被回收時垃圾回收器能回收到的內存大小

快照分析

通過Leak Suspects分析得出佔用內存最大的是DruidDataSourceWrapper實例,這是連接池的類竟然不是業務代碼,然後通過Dominator Tree 觀察到底是哪個對象佔用的內存較大,如圖:

發現竟然是軟引用佔用了大量內存空間,此時瞄了一眼DruidDataSourceWrapper的源碼就短短數行並沒有什麼可能造成溢出的因素,奈何又沒看過mybatis和連接池的源碼,只能結合這個軟引用猜測,軟引用一般被用在緩存的場景,而我們每次查詢的結果集都是5w以上的數據量,直接放內存就算會OOM的話應該也不會用到緩存,於是猜測mybatis的xml裏是否用到了fetchSize,全局搜索果然發現了有使用fetchSize,值竟然是一萬,於是將fetchSize改爲500發佈後問題解決

記一次印象深刻的SQL優化

上面也提到了,這次問題排查對很多查詢sql進行了優化,下面舉個實例以作備忘;有一張六千多萬的數據表T1,其共有45列數據,有a,b,c,d四個列涉及到查詢,查詢sql爲:

  select b,c,d,count(1) from T1 where a=123 group by b,c,d

優化時執行sql響應時間大概在20多秒左右,檢查索引情況發現a、b、c、d均建立了普通索引,通過執行計劃分析發現只命中了a的索引,於是考慮將b、c、d建立一個聯合索引,但是查詢速度依然不理想,於是考慮利用稀疏索引的原理來創建一個a、b、c、d的聯合索引,結果發現查詢結果直接0點幾秒,全結果集掃描共4萬多條記錄也只用了五秒左右,優化完成

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