大對象出沒,內存不夠了

作者簡介:大廠一線 技術管理者。從crud開發到資深開發,再到研究員兼技術經理。《資深開發講技術》 從一線實戰中總結有故事,有背景的案例,希望帶給大家一系列技術盛宴,歡迎關注,轉發,討論。

幾年前我剛才從學校畢業,進入第一家公司去哪兒網,走出校門時只聽過java,c語言到是挺熟的。感謝去哪兒網脫產培訓3個月,培訓的導師,都是一線的資深開發或者負責人,他們給我們講了很多案例以及基礎,當然也有很多作業。

雖然我在去哪兒網待的時間並不長,但是這些年過去了,我一直心存感激。


為什麼我要提我上面的這段經歷呢,因為有些東西,已經深入到我的骨髓中了。以至於我覺得很普通,很常見的東西,一些同學竟然不知道或者不重視。當然大家的經歷不同,認知肯定會有差距。

今天我就講下,查詢數據大對象的問題。


背景

前段時間業務方反饋,我們負責的推薦服務數據不準確。我在家裡遠程和公司的一位同事緊急開始排查。需要說明一下,此業務剛剛移交給我們團隊,共涉及到三個項目。

出問題的服務線上部署4個容器,負責數據管理,每個容器配置有安全檢查,如果服務不健康的話,隔一段時間就會重啟服務。

我們緊急請教了之前負責的同事,他告訴我們第一個容器CPU太高了。


排查上半場

登陸到一個有問題的容器,下載了一個arthas,試圖去分析一下cpu的原因,但是很遺憾嚴重卡死了,根本綁不上進程,我試圖是執行jstack,也是無果。(我記得上一次出現這個現象的是redis服務,由於異常流量過高,dba也反饋過此現象)

幸運的是此時日誌可以打開,雖然很慢看了下日誌,慘不忍睹,各種報錯,但是分析了幾個錯誤,不能夠解釋cpu過高的原因。

大對象出沒,內存不夠了


然後日誌也看不到了,容器不健康被殺死了重啟了。其他容器cpu並不高!!!很遺憾。我們只能下載日誌去排查,可是日誌量很大,windows根本打不開。

我和公司的開發商量如何分析日誌的時候,發現其他容器也出現unhealth,而且基本上發現不到10分鐘,一個容器就會掛掉,然後重啟。

發現這樣的規律後就好說了,我們在一臺容器上,部署好了arthas等著問題復現,看下到底是那個線程出現了問題。

可以發現cpu佔比最高的一直都是arthas,最高的線程佔比大約5%到20%之間波動,解釋不通啊。

排查中場

容器還在不斷的kill然後重啟,一頓折騰1個多小時過去了。期間我們緊急處理,數據已經恢復正常。但是問題還沒有定位到。


突然我的同事告訴我,可能是fullgc引起的,他反饋每次fullgc失敗和服務重啟時間也差不多這個時候附近,之前我們的精力很停留在為啥cpu佔用過高上

我們看了下gc日誌,發現頻繁fullgc,gc後依然申請不到內存。

我同事dump下了內存,使用MAT查看了,MAT直接顯示內存洩漏。一個對象中有幾十萬個對象。而且定位到的方法和cpu過高的方法吻合。


我們基本確定了問題後,內存擴大了一倍,觀察了下服務穩定,此時已經凌晨了。

排查後半場

第二天早上,主要看下了gc日誌,發現頻繁的從survivor中,固定的申請450M的內存。我們看了下出問題的那塊代碼,頻繁的類似從mongo庫中直接findAll,每次取出來幾十萬的對象,放在list中,然後循環處理。

這個task其實已經上線很長時間了,我理解不應該之前沒有問題,最近才出現。我把我的疑慮告訴了,我們的開發。

我們先上線,優化了此處的問題,發現服務不會掛了,但是依舊還是比較吃內存。陸陸續續又發現了好幾處,查詢大對象的問題,解決後此服務暫時穩定。

總結

查詢數據庫的時候,特別是findAll,一定要問下自己,數據量是不是很大。

超過1千條,我建議走分頁查詢。

這是我在上家公司,培訓的時候學到的。現在分享給你們。希望大家少故障,生活更美好


分享到:


相關文章: