笑了,面試官問我遇到過線上問題沒有?

不知道面試的時候,面試官問你遇到過線上性能問題沒有?
GC頻繁,CPU飆高,任務(wù)隊列積壓,線程池任務(wù)拒絕等等,對于看重項目經(jīng)驗的面試官,這種問題基本是標(biāo)配。
問線上問題處理的經(jīng)過,問題定位,排查的思路,怎么做的業(yè)務(wù)快速止血。
一方面考察候選人項目的真實性,一般遇到線上問題大部分時候是系統(tǒng)主要負(fù)責(zé)人著手處理的,所以如果你處理過線上問題,也從側(cè)面反映你的重要性。
另外還能知道面試者是不是真的從原理上掌握了問題的根本原因,對技術(shù)的熱忱等。
另外建議大家處理完線上問題,排查了原因之后不要停,把排查過程和問題原因記錄下來,一方面以后遇到類似問題可以基于已有的經(jīng)驗快速反應(yīng),另外就是一定讓自己的知識體系化,怎么體系化呢?
就需要把日常的技術(shù)問題做歸類總結(jié)。
這篇文章主要是給大家一個參考,講講安琪拉遇到的線上問題以及排查思路。
問題描述
一個在普通不過的周末,手機突然收到線上告警短信,嚇得我一激靈,趕緊從床上爬起來打開電腦。
起因: ?消息隊列積壓了十幾萬消息,第一反應(yīng),什么情況...

趕緊穿衣服,對待線上問題要嚴(yán)肅。
如下圖,【待處…】 那一列就是指隊列中“待處理的”消息。
消息積壓,指的是消息的消費速度跟不上生產(chǎn)的速度,消息在消息隊列中。

可以看到有好幾個分區(qū)已經(jīng)積壓了上萬條消息。
問題排查
立即開始問題排查,遇到線上問題,一定是保證最快速度止血,降低對業(yè)務(wù)的影響。
然后才是排查原因,當(dāng)然有的問題也需要快速找到原因。
第一反應(yīng)是不是入口流量太大,處理消息的線程池核心線程數(shù)滿了,任務(wù)都在排隊,但是看了入口流量并沒有尖刺。
看監(jiān)控的消息消費任務(wù)耗時,如下圖:

可以看到耗時在不斷增加。那就需要看處理耗時增加原因了,為什么處理任務(wù)的耗時上漲了。
查看消息日志,如下:

發(fā)現(xiàn)有很多網(wǎng)絡(luò)接口超時的異常:

排查到這里,大致得出結(jié)論:
消息處理任務(wù)依賴下游系統(tǒng)接口,連接下游接口超時,連接下游接口設(shè)置的超時時間不算短,為什么下游接口如此多SocketTimeOut呢?

恰好下游系統(tǒng)也是我負(fù)責(zé)的系統(tǒng),非常熟悉。
于是重點開始看下游的系統(tǒng)監(jiān)控,發(fā)現(xiàn)相關(guān)的接口調(diào)用的單機耗時時間極不規(guī)律,如下圖所示:

對比一下日常這個接口的耗時時間,如下圖,日常都沒有超過 100ms 的:

初步猜測這個地方是出現(xiàn)了問題,查看下游系統(tǒng)的監(jiān)控大盤,發(fā)現(xiàn)了問題:

老年代 GC 次數(shù)暴漲,而且 GC 耗時都到了秒級別,1 分鐘 5~10 秒的 stop the world,太恐怖了。
分析GC問題找一臺機器,把GC回收dump下來分析,使用mat查看,如下圖所示:

一共七百多M空間,一個對象就占了640M空間,找到原因了,大對象!
這個對象為什么會這么大呢?
我們用 MAT 分析一波。從 GC Roots 最短路徑如下:

解釋下,上面主要有三列:
- 第一列是內(nèi)存對象的類。
- 重點在二,三列,Shallow Heap 指的是對象本身占據(jù)的內(nèi)存大小,Retained Heap = 本身本身占據(jù)內(nèi)存大小 + 當(dāng)前對象可直接或間接引用到的對象的大小總和。說人話就是當(dāng)前對象如果被回收,能夠回收的內(nèi)存大小。
繼續(xù)看,第一步,查看誰引用了這個對象,找到自己代碼中的類:

第二步,查看這個對象 TaggedMetricRegistry 都引用了誰,為什么會占用這么大的內(nèi)存空間,如下圖所示:

找到罪魁禍?zhǔn)琢?,metrics 這個 ?ConcurrentHashMap 占了 671M 內(nèi)存。
現(xiàn)在開始可以看下代碼,找到 ?TaggedMetricRegistry 繼承自 MetricRegistry ,metrics 是 MetricRegistry 的成員變量,如下圖:


那為什么這個 ConcurrentHashMap 占了這么大的內(nèi)存空間,并且 GC 也回收不掉呢?
我們繼續(xù)看 MAT ,分析 ConcurrentHashMap ?占有的詳細(xì)內(nèi)存分布:

從上圖我們可以發(fā)現(xiàn) ConcurrentHashMap 有幾個 Node 節(jié)點特別大。
于是繼續(xù)追下去:

看到這個 key ,對應(yīng)在代碼中的位置:

這段代碼就是萬惡之源。
那么這段代碼是干嘛的呢?
它的作用是統(tǒng)計接口每次的執(zhí)行時間,它內(nèi)部 update 的源碼如下:

這個方法是統(tǒng)計接口的耗時、調(diào)用次數(shù)的。
它內(nèi)部有一個 measurements 的跳躍表,存放時間戳和統(tǒng)計指標(biāo)(耗時、調(diào)用次數(shù))的鍵值對。
設(shè)置的時間窗口是 1 分鐘,也就是它會存放 1 分鐘的統(tǒng)計數(shù)據(jù)在內(nèi)存中。
當(dāng)然這里面有個采樣比,不是 1 分鐘的全量數(shù)據(jù)。
可以看到采樣比是 COLLISION_BUFFER 決定的,然后 1 分鐘上報一次內(nèi)存數(shù)據(jù)到遠端。
問題就出現(xiàn)在這,因為這個耗時統(tǒng)計的函數(shù)的 QPS 非常高,1 分鐘有數(shù)據(jù)頻繁產(chǎn)生的時候,會導(dǎo)致在一個時間窗口(1分鐘)measurements 極速增長,導(dǎo)致內(nèi)存占用快速增長,但是因為有強引用,GC 的時候也不會把這個回收掉,所有才出現(xiàn)了上面的那個情況。
why哥說
前面就是公眾號[安琪拉的博客]的號主安琪拉給大家分享的一個線上問題排查的實操案例。
首先建議大家關(guān)注一波安琪拉,是個大佬,大廠 offer 收割了個遍。在公眾號里面分享的文章也很硬核。
然后基于他分享的這個案例,我也想簡單的分享一點自己的看法。
第一點就是監(jiān)控預(yù)警系統(tǒng)的重要性。
文中的案例中的監(jiān)控系統(tǒng)就是 CAT。
CAT 是什么?
我從 github 上給大家截個圖:
https://github.com/dianping/cat

除了 CAT 之外,why哥知道的比較知名的監(jiān)控系統(tǒng)還有:
- Skywalking,專注于鏈路和性能監(jiān)控,國產(chǎn)開源,埋點無侵入,UI功能較強。能夠加入Apache孵化器,設(shè)計思想及代碼得到一定認(rèn)可,后期應(yīng)該也會有更多的發(fā)展空間及研發(fā)人員投入。目前使用廠商最多。版本更新較快。
- Pinpoint,專注于鏈路和性能監(jiān)控,韓國研發(fā)團隊開源,埋點無侵入,UI功能較強。
- zipkin 由Twitter開源,調(diào)用鏈分析工具,基于 spring-cloud-sleuth 得到廣泛使用,非常輕量,使用部署簡單。
監(jiān)控預(yù)警系統(tǒng),就是系統(tǒng)的眼睛。
所以why哥在上家公司的時候有幸深度參與了自研的監(jiān)控系統(tǒng),取名就叫做:眼睛蛇。
我取的。
第二點就是日志收集。
文中的案例,日志收集使用的是 ELK 體系。
不管是什么日志收集手段吧。
日志收集的意義是非常重大的。
現(xiàn)在大家都是微服務(wù)化部署,一個應(yīng)用部署到幾十個服務(wù)器上去。
如果需要登錄到每個服務(wù)器上去查詢?nèi)罩?,將是一件非常低效且耗時的事情。
而日志收集,就是一把利器,用順手了,事半功倍。
第三點也就是最重要的一點:敬畏生產(chǎn)。
我的領(lǐng)導(dǎo)曾經(jīng)不止一次的給我說過:
遇到生產(chǎn)問題,第一件事千萬不要想著排查問題,而是想著怎么恢復(fù)業(yè)務(wù)。
其實上面這句話我也感覺很矛盾,不把問題排查出來了,怎么去解決問題然后恢復(fù)業(yè)務(wù)呢?
其實,我們常見的一個手段就是先保留現(xiàn)場,然后立即回滾版本。
有問題,拿到測試環(huán)境、預(yù)發(fā)布環(huán)境、災(zāi)備環(huán)境去定位,而不要在生產(chǎn)定位問題。
比如在這個案例中。
當(dāng)我們定位到是 GC 導(dǎo)致的問題時,就應(yīng)該當(dāng)機立斷的先對應(yīng)用進行重啟,然后對消息進行消費。
能爭取一點時間就算一點時間。
而我們根據(jù)保留的現(xiàn)場,繼續(xù)定位到是這個監(jiān)控統(tǒng)計功能的問題,且這個功能確實是需要這么多的內(nèi)存的時候。
我們知道重啟是解決不了根本問題的,需要發(fā)布緊急版本,把這個統(tǒng)計功能關(guān)閉掉。
再之后,驗證線上穩(wěn)定之后,才是去復(fù)盤分析這個生產(chǎn)問題的前因后果。
荒腔走板
前段時間有個讀者在我的公眾號后臺給我留言:

他說他站在我曾經(jīng)拍照的地方也拍了一張照片。
是的,我當(dāng)時就站在他拍的這個路牌下拍了一張照片,發(fā)在了文章里面。
只是我一個小小的、卑微的、成都的打工人,何德何能,通過一篇文章,讓別人對成都產(chǎn)生向往。
當(dāng)然,我也衷心的祝愿你,明年春暖花開的時候,現(xiàn)在大四實習(xí)的你,留在了成都自己喜歡的崗位,工位上插著一把花正旺盛的綻放著。
我主要是想要分享一下真正讓我澎湃的關(guān)于成都的一篇文章:
《什么是成都?》
這是星球研究所于 2018 年 3 月 2 日發(fā)布的一篇文章,那一天正是戊戌年正月十五,彼時我還是一個在外的游子,那天我沒有吃到元宵,但是這篇文章就是最好的“元宵”。
甚至不舍得一口氣讀完,仿佛在細(xì)品著一碗佳釀。之后又反復(fù)觀看了幾遍這篇文章,內(nèi)心產(chǎn)生了無數(shù)的遐想。
成都不是我的故鄉(xiāng),但是我仿佛是聽到了來自故鄉(xiāng)的歡呼。
引用評論中的一句話:
如若 1600 萬的成都人都能有幸閱讀到,那一定是至少 1600 萬次的澎湃與自豪。
加油哦,成都?xì)g迎你。
《什么是成都?》這篇文章分享給你,希望你能喜歡。
推薦?? :有哪些道理是我當(dāng)了程序員后才知道的?
推薦?? :沒想到你竟然是這樣的volatile!
推薦?? :這個Bug的排查之路,真的太有趣了。
推薦?? :臥槽,這年輕人。
推薦?? :我給Apache頂級項目貢獻了點源碼。
我是 why,一個主要寫代碼,經(jīng)常寫文章,偶爾拍視頻的程序猿。
還有,歡迎關(guān)注我呀。
轉(zhuǎn)發(fā)、點贊、在看、一鍵三連。

