正值週末,娃兒6:30又如鬧鈴般準時來叫醒了咱們。年前離開美菜,又回到了杭州。本來是想有更多時間陪伴娃兒,然而新的工做節奏與工做地點,讓咱們天天都是早上見面;這不,爲了週末能夠多玩一下子,早早就過來喚醒咱們。由於前幾天咱們就約好了週末一塊兒放風箏。有些事兒,我覺得只是隨口一說,小孩子確真真的記着。html
吃過早飯,拉着媳婦兒,領着娃,帶上風箏就出門了。其實我是忐忑的,由於我也歷來沒有把風箏放起來過。來到草坪上,娃就拉着風箏如脫繮之馬跑了起來。小孩子的幸福就這麼簡單,無關乎風箏能飛多高。java
迎着暖暖朝陽,吹着徐徐春風,一會兒感受2周加班的疲憊都消散了。然而,一陣兒急促的「釘釘」聲打破了可貴的寧靜:Warning, ***applicaiton, cpu 高於51%,持續2分鐘。此服務涉及大部分單車投放操做,目前是新老並用,咱們是新服務,tps不高,但業務很是重要。因而拉着還未盡興的娃兒,回去處理問題了。固然個人心裏是緊張而喜悅的,每次的故障就是一次學習的機會。git
既然是cpu告警,首先查看cpu最近的使用狀況,一看獲得兩條信息:1,下圖中剪頭所指的地方就是促發告警的閥值,2,cpu一直在40-50%上下徘徊 。程序員
我想你們看到這個圖也明白了:告警是正常的,目前cpu的狀況很容易就會促發告警。反思一分鐘:成天埋頭支撐業務,連繫統的如此重要指標都沒有關注到。而後迅速回憶最近上線的功能,想到2月底,上線過電子鎖的需求,可是系統已經沒法查看2月分的cpu日誌,接下來咱們須要去找出問題。github
平時不多有處理生產環境cpu太高問題,真正碰到這樣的場景仍是蒙圈的。看看網上好些帖子都是說: heap 內存不足,分配內存失敗,會致使cpu偏高。首先使用jstat -gcutil 查看內存使用狀況,以下圖,可見 新生代的區域 survivor0, survivor1, eden 以及老生代都正常,FGC 也正常。 json
jstat -gcutil 參數說明以下服務器
遇到問題,猜是須要經驗的,瞎忙是沒用的,既然沒經驗那就一步一步來驗證吧;app
1, ps -ef | grep java 找到進程id 27931jvm
2, top -H -p 9527 找到佔cpu的線程svg
3, 使用jstack 分別找也上面的線程的具體內容,好比第一個線程 28045。
a, 轉化線程id爲16進制 printf '%x\n' 28045,輸出 6d8d, 由於jstack 中線程id 是16進制的。
b,jstack 27931 | grep 6d8d ,找到此線程
c, 再用一樣的方法,發現其餘幾個線程也是 kafka 消費者引發的。
4,知道問題在於消費kafka了,原來上次作電子鎖需求時,爲了拿到開鎖結果,監聽了一個kafka topic,這是一個特別核心的topic(後來聽其餘同事說,這是公司消息量最多的上個topic了),
隨手查了下一個小時的數據26億/h,也就是 70w/s, 如此巨大的tps, 而此服務只有兩個結點,cpu維持在50%左右就不奇怪了。
到這裏,我還想再深究下,到底時哪幾行代碼佔了cpu, 那應該如何找到這些代碼呢。說來真是特別巧,上週5聽了測試同窗的性能測試分享,後來還找時間瞭解了其中的火焰圖(flame graph)和arthas , 對就是「火焰圖」- 今天的主角兒。關於火焰圖有幾個基本的知識就能夠簡單分析了:
1,y-axis 表示調用父子關係,下面函數是上面的parent;
2 x-axis 表示抽樣合併的結果,越寬表示調用頻率越高,即執行的時間長;
3 顏色,左右,沒有特別的意義。
一開始看到火焰圖,也是特別蒙圈的,下面有幾個文章特別不錯,英文文檔讀起來不算太複雜,中文的彷佛就是翻譯英文文檔。
英文文檔:
http://www.brendangregg.com/flamegraphs.html , https://queue.acm.org/detail.cfm?id=2927301
中文說明:
http://www.ruanyifeng.com/blog/2017/09/flame-graph.html
火焰圖demo:
https://queue.acm.org/downloads/2016/Gregg7.svg
1,clone javaFlameGraph,git 地址以下:https://github.com/saquibkhan/javaFlameGraph,
有一個地方要特別注意下:javaFlameGraph 核心是調用 FlameGraph中的實現,如圖中剪頭所指的項目,要確保FlameGraph也下載了。
2,拉出一個節點摘掉流量,上傳clone的文件。
3,到上傳文件的所在目錄執行 ./flame-gen.sh 27931 ,等待30s, control +c 就開始生成報告了。
4,報告爲當前目錄下的 flame.html , 找開就是生成的火焰圖了。以下圖。
這個圖是可交互的,能夠點擊每一個長方形獲取更多詳情的信息,如圖,可看到有不少都是消耗都是 fastjson的 perseobject,由於咱們每收到一個消息,會使用fastjson解析,過濾出指定的消息。
說明下其中幾個除kafka相關線程外的線程,參考文章地址:https://blog.csdn.net/clamaa/article/details/70045983
DestroyJavaVM:
執行main()的線程在main執行完後調用JNI中的 jni_DestroyJavaVM() 方法喚起DestroyJavaVM 線程。JVM在服務器啓動以後,就會喚起DestroyJavaVM線程,處於等待狀態,等待其它線程(java線程和native線程)退出時通知它卸載JVM。線程退出時,都會判斷本身當前是不是整個JVM中最後一個非daemon線程,若是是,則通知DestroyJavaVM 線程卸載JVM。
Surrogate Locker Thread:
這個線程主要用於配合CMS垃圾回收器使用,它是一個守護線程,其主要負責處理GC過程當中,Java層的Reference(指軟引用、弱引用等等)與jvm 內部層面的對象狀態同步。
由於工做的緣由,不多有機會處理高tps場景下的問題,終於理性的分析了一次生產環境cpu的問題,相信之後的再有這樣的狀況會從容一些。由於經驗不足,文章中也有不少不足的地方,歡迎指出;若是以爲有用,也歡迎點贊鼓勵。
成爲一名優秀的程序員!