接口掛死,你咋辦?

引子

週末本來是可貴愜意的時光,尤爲是晚上,陪家人看看電視啥的再好不過了。不料,晚飯事後不久,手機就傳來 」叮「 的一聲,清脆悅耳,覺得有人發紅包,定眼一看,不妙!—— 線上服務器告警。redis

連忙扒開電腦,準備 」滅火「,根本沒心思看電視。緩存

過程

登上服務器看日誌,發現每隔 2 秒鐘 tomcat 日誌就會打印一次 」Broken pipe「,就是這種:tomcat

似曾相識,以前有位同事作大量數據導出功能,就出現過,很顯然是接口 response 耗時過長致使的。那接口是否是有問題了?服務器

用 postman 測試一下線上接口,點擊 」send「 按鈕後一直loading,等了老白天才有結果返回,耗時 1 min 左右。併發

打開手機端也沒法獲取數據了,一直在加載中。ide

嗯,事情不妙。post

深吸一口氣,冷靜 ~測試

告誡本身再看一遍告警短信:redis 鏈接池異常。難道 redis.pool 配置過小不夠用?請教了一下相關同事,他說 redis 沒問題。idea

我打開 idea , 從新檢查了一遍 redis 相關的配置,定義,使用,該檢查的都檢查了。日誌

心想:既然是接口耗時,那我就把代碼執行過程當中,每個步驟的執行時長先打印出來看看嘛,到底是哪裏」佔坑不拉屎「?

先理一理代碼邏輯:

  1. 從 redis 拿 IdList (大約2萬)
  2. 遍歷 IdList 從 DB 取數據 Entities,並組裝爲 EntityVos(組裝信息較多,需從其餘 rpc 接口獲取)
  3. pageUtils 返回分頁數據

我發現第 2 步耗時特別猛,因而先把組裝的某一項信息註釋掉不去 rpc 拿了,這樣作的依據就是:在我剛纔部署打印日誌以後不久,這個調用 rpc 的服務所有報 time-out。

立刻註釋掉,上線。

嗯,看樣子正常了,時間已經飆到10點多了,洗洗睡去。

晚上躺在牀上在想,其實我能夠對那個 rpc 的調用結果作一層 redis 緩存,減小請求頻次應該會好不少。

次日,興高采烈地來到辦公室,同事直接問候早安——」好像我們的xx沒數據啊,你看看?「

話音未落,個人手機」叮「地一聲,清脆悅耳,這回我知道確定不是紅包了,是」炸藥「 ~

連忙扒開電腦,準備」滅火「,根本沒心思跟別人說早安。

此次告警短信的內容不是 redis 相關的了,而是:JVMFullGC卡頓次數頻繁。

我又重讀了幾遍接口代碼,總以爲哪裏不對。哦~ 耗時的問題我是真的解決了嗎?

因爲打印日誌並未去掉,我仔細分析了下:既然拿 2 萬的實體類進行遍歷組裝,最後分頁只返回 10 條數據,這。。。

假分頁,害死人~

因而把分頁邏輯放到組裝信息以前來作,好比你最終是返回 10 條數據,那就是組裝 10 條了,而不是像以前那樣組裝了 2 萬條。

其實,緣由也顯而易見了:併發高,組裝 vo 時間過長,致使用到 redis 的資源也得不到釋放,new出來的大對象也多,得不到回收,一個請求未響應下一個請求已來,越疊越多,最後掛死。產生的表象就是:接口耗時長,redis 鏈接池異常,JVMFullGC卡頓等。

晚上覆盤,拿到兩張 MinorGC 和 FullGC 總次數的監控圖:

總結

一、其實線上一產生問題,應該先懷疑內存或 CPU 是否佔用過高,我是過小看此次問題了,否則第一時間拿到 dump 就會更順利。 二、雖然改了一點邏輯,但同時順便重構了很多代碼,重構應該發生在每時每刻纔對。

(完)
相關文章
相關標籤/搜索