實(shí)戰(zhàn)!一次kafka卡頓事故排查過(guò)程!
作者 |?等你歸去來(lái)
讀者福利:
分享一套SpringBoot開(kāi)發(fā)博客系統(tǒng)源碼,含完整開(kāi)發(fā)文檔和視頻!速保存!
精選一套 SpringBoot + Vue 開(kāi)發(fā)的開(kāi)源系統(tǒng)(前端+后端+小程序)
由于一次功能上線后,導(dǎo)致某數(shù)據(jù)量急劇下滑,給我們緊張的呢!排查過(guò)程也是個(gè)學(xué)習(xí)過(guò)程!拋開(kāi)結(jié)果,方法論可供參考~
1. 確認(rèn)問(wèn)題的真實(shí)性?
被數(shù)據(jù)部門(mén)告知,某數(shù)據(jù)量下滑嚴(yán)重,當(dāng)時(shí)即知道問(wèn)題的嚴(yán)重性。且該問(wèn)題是在我的功能上線后產(chǎn)生,第一反應(yīng)就是,我代碼哪里寫(xiě)錯(cuò)了?
但是,還得按流程來(lái),通過(guò)各種維度數(shù)據(jù)對(duì)比請(qǐng)求量,實(shí)際落地量。確認(rèn)問(wèn)題!
其實(shí)該過(guò)程中,我們并沒(méi)有確認(rèn)自己的數(shù)據(jù)量下滑。但是這也脫不了數(shù)據(jù)下滑的干系。只能進(jìn)行下一步!
2. 檢查代碼,找有經(jīng)驗(yàn)的同學(xué),對(duì)比原有功能差異點(diǎn)?
這個(gè)步驟其實(shí),是有點(diǎn)盲目的感覺(jué)。因?yàn)榈谝徊降呐挪椴](méi)有找到足夠的證明說(shuō)明問(wèn)題出在我們,但是問(wèn)題在于期間只有我們上過(guò)線,所以只能自我反省了。
不過(guò)幸好,這過(guò)程還真有用,果真發(fā)現(xiàn)了自己埋的一個(gè)坑,此坑確實(shí)會(huì)導(dǎo)致該數(shù)據(jù)量的下滑。趕緊修掉唄!
然后松了一口氣,以為搞好了。其實(shí)不然,數(shù)據(jù)量依然上不去。這就尷尬了!
我已經(jīng)開(kāi)始懷疑人生,難道代碼沒(méi)發(fā)上去?難道線上和本地某個(gè)地方不一樣?測(cè)試環(huán)境反復(fù)測(cè)試正確無(wú)誤。我真想直接把測(cè)試環(huán)境代碼弄到線上去,哎,算了吧,很多東西是不會(huì)以人的意志為轉(zhuǎn)移的,咱們還是理性點(diǎn)!別謀出路吧!
3. 直接坐到dba旁邊去吧,讓我們隨時(shí)關(guān)注數(shù)據(jù)量?
自我排查已經(jīng)救不了自己了,那就上dba那里。麻煩幫我統(tǒng)計(jì)下上線后,數(shù)據(jù)量的變化,結(jié)果是沒(méi)多大差別。心想有可能是時(shí)間太短,看不出變化,等會(huì)兒再統(tǒng)計(jì)吧。依然沒(méi)有變化!我的神吶,定了鍋還在。
大的數(shù)據(jù)量不行,那我用自己的賬號(hào)來(lái)測(cè)試吧,操作完成后,觀察數(shù)據(jù),發(fā)現(xiàn)有時(shí)有有時(shí)無(wú)!額,說(shuō)不出啥了。
4. 本地調(diào)試吧?
原本以為,是線上問(wèn)題,緊急處理下就好了。然而事實(shí)卻超出了我的預(yù)料,將驗(yàn)證直接交給線上,是對(duì)用戶(hù)的不負(fù)責(zé),是對(duì)數(shù)據(jù)的不負(fù)責(zé)。咱們還是從本地做起吧。
本地調(diào)試要走vpn,有點(diǎn)煩,但不管怎么樣,還是跑起來(lái)了。沒(méi)問(wèn)題啊!這尷尬了。
然后,引出下一個(gè)議題!
5. 線上環(huán)境配置與測(cè)試環(huán)境不一樣?
然后我們努力找出其中的不同點(diǎn),哪怕是多了一個(gè)文件,某個(gè)文件的更改時(shí)間點(diǎn)不一致,我們都想去試一下!當(dāng)然了,為了穩(wěn)妥起見(jiàn),我們還是不能直接在線上驗(yàn)證的,除非有足夠的證據(jù)說(shuō)明線上的配置是有問(wèn)題的。當(dāng)然我們最終并沒(méi)有找到這樣的證據(jù),只是將線上的所有東西都搬到測(cè)試環(huán)境來(lái)驗(yàn)證,結(jié)果是暢通無(wú)阻!
還有一個(gè)證明此路不通的理由,之前的配置跑得好好的東西,難道會(huì)自己壞掉?不可能吧。此路不通!
6. 實(shí)在不行了,只能改代碼線上調(diào)試?
調(diào)試第一步,各自打日志!把之前請(qǐng)求打印不全的地方,加上完整日志,再發(fā)一版吧!有了日志,就有證據(jù),但是真的是急中生錯(cuò)啊,日志居然打得不對(duì),將參數(shù)打印為了內(nèi)存地址也真是夠了。
日志改好后,測(cè)試唄,繼續(xù)用自己的賬號(hào)。還是一樣,有時(shí)能能進(jìn)有時(shí)不能(監(jiān)控手段為dba起一個(gè)臨時(shí)的kafka消費(fèi)者,然后將數(shù)據(jù)拉出來(lái)看)!那咋整呢?
難道是有的機(jī)器壞了?分配到壞的機(jī)器上去的請(qǐng)求就失敗,分配到正確機(jī)器的上去的請(qǐng)求就正確。然后吭哧吭哧搞了半天的數(shù)據(jù)驗(yàn)證,曾經(jīng)以為這是方向,結(jié)果又被打回。
7. 不行咱們就抓包吧?
tcpdump,一個(gè)網(wǎng)絡(luò)流抓包神器,lsof助攻一下。
抓包只是為了確認(rèn)一個(gè)問(wèn)題,客戶(hù)機(jī)器有發(fā)送請(qǐng)求到服務(wù)端機(jī)器,網(wǎng)絡(luò)流正常運(yùn)轉(zhuǎn)!然后證明,客戶(hù)端機(jī)器有大量長(zhǎng)連接到服務(wù)器,數(shù)據(jù)流發(fā)送接收正常(syn)。這至少說(shuō)明了一點(diǎn),客戶(hù)端是沒(méi)有問(wèn)題的!那么就還剩一個(gè)問(wèn)題,那就是服務(wù)端出問(wèn)題了!我們堅(jiān)信,當(dāng)然要有證據(jù)嘛。
同理,我們?cè)诜?wù)端機(jī)器上進(jìn)行反向抓包,然后抓到了來(lái)自客戶(hù)端的包,很流暢嘛!額。。。
8. 不行,沒(méi)有思路了,重啟機(jī)器吧?
不,我說(shuō)的是重啟服務(wù)。最近不是有改動(dòng)嘛,按理誰(shuí)改動(dòng)重啟誰(shuí)。然而這是沒(méi)有用的,因?yàn)橹暗膸状伟l(fā)布早已重啟了n次。那咋整呢。只剩重啟服務(wù)端,kafka服務(wù)了唄,死馬當(dāng)活馬醫(yī)吧!
重啟后,驗(yàn)證唄。結(jié)果貌似還是發(fā)現(xiàn)有成功,有失敗!
9. 改異步請(qǐng)求為同步請(qǐng)求?
又沒(méi)思路了,我不甘心吶,為啥測(cè)試環(huán)境好好的,到線上就不行了呢?再想想差別在哪里?
得出的結(jié)論是,線上并發(fā)大,測(cè)試環(huán)境量無(wú)。然后發(fā)現(xiàn)這一塊代碼是由異步線程做的,會(huì)不會(huì)是這里有問(wèn)題?
不管了,改成同步請(qǐng)求試試吧。再來(lái)一版!
別說(shuō),改為同步后,雖然用戶(hù)請(qǐng)求基本都慢死了,但是發(fā)現(xiàn)kafka請(qǐng)求確實(shí)存在了。難道真的是因?yàn)檫@個(gè),那我們也不能這么改啊,用戶(hù)體驗(yàn)是第一位的,為了這事改異步為同步,咱得吃不了兜著走啊。改回來(lái)繼續(xù)其他的吧!
10. 再回測(cè)試環(huán)境,壓測(cè)并發(fā)?
改還原為異步后,又回到當(dāng)初有成功有失敗境地了。
既然懷疑線上高并發(fā)導(dǎo)致,那為什么不在測(cè)試環(huán)境高并發(fā)壓測(cè)一下呢?用shell腳本快速寫(xiě)了一個(gè)循環(huán)請(qǐng)求腳本,大量請(qǐng)求到kafka后,并無(wú)一絲異常,到此并發(fā)問(wèn)題取消。(for,nohup
a.sh > /dev/null 2&>1 &)n 次即模擬n個(gè)并發(fā)請(qǐng)求
11. 再來(lái)細(xì)細(xì)檢查代碼吧?
都不知道查了幾遍了,但是還是要查啊,不然咋整呢,幾個(gè)人一起看代碼唄!
然而這并沒(méi)有什么卵用。
12. 拋開(kāi)用戶(hù)行為,直接以命令行形式操作請(qǐng)求?
雖然用戶(hù)行為是最真實(shí)的驗(yàn)證,但是也是比較麻煩的驗(yàn)證。
我們就拋開(kāi)各種中間環(huán)節(jié),直接向kafka服務(wù)器發(fā)起請(qǐng)求!
分兩種方式,1 用現(xiàn)在的代碼去請(qǐng)求,2
用kafka自帶的請(qǐng)求方式請(qǐng)求。結(jié)果得到兩個(gè)不同的結(jié)果,用代碼的方式請(qǐng)求的數(shù)據(jù),沒(méi)有成功,用kafka自己的請(qǐng)求方式,則毫秒級(jí)響應(yīng)。哎,這是讓我又懷疑代碼?
13. 已走投無(wú)路,讓我們?cè)倏匆谎蹟?shù)據(jù)吧?
真的是沒(méi)有思路了,只能再來(lái)看看數(shù)據(jù),當(dāng)打發(fā)時(shí)間了。
意外就在你想不到的時(shí)候發(fā)生了。數(shù)據(jù)已經(jīng)恢復(fù)正常了!我擦!
倒推時(shí)間,倒推事件,是由于kafka重啟,導(dǎo)致數(shù)據(jù)回升的。
好吧,問(wèn)題已經(jīng)定位,kafka卡頓導(dǎo)致。咱們已經(jīng)熬不住了,發(fā)個(gè)結(jié)論郵件,就先回去洗洗睡吧!
14. 為什么kafka會(huì)卡頓?
這才是問(wèn)題的根本!只是我們當(dāng)時(shí)已經(jīng)沒(méi)有力氣再往下搞了!
結(jié)論是由于topic請(qǐng)求量過(guò)大,而partition過(guò)小,導(dǎo)致吞吐量下降。將partition改大之后,終于真正恢復(fù)正常!
額,好像做了很多無(wú)用功,沒(méi)辦法 !
歡迎長(zhǎng)按下方二維碼關(guān)注我的小號(hào):Java開(kāi)發(fā)寶典,每天會(huì)分享一篇技術(shù)干貨,質(zhì)量非常高,您的支持,是我創(chuàng)作的持續(xù)動(dòng)力!
點(diǎn)贊是最大的支持?![]()
