一次線上游戲卡死的解決歷程

事故的發(fā)生詳細(xì)過(guò)程

故事是發(fā)生在幾個(gè)月前的線上真實(shí)案例让虐,我將在本文中以故事形式為大家還原這次解決游戲卡死的經(jīng)歷過(guò)程,其中有很多線上實(shí)戰(zhàn)經(jīng)驗(yàn)和技巧都值得分享借鑒的辜妓,也有作者自創(chuàng)的處理線上問(wèn)題“四部曲”--望問(wèn)聞切罗洗,還有最經(jīng)典的“甩鍋”秘訣刊棕。不管白貓黑貓,能立馬解決線上問(wèn)題的就是好貓锈嫩,線上問(wèn)題實(shí)戰(zhàn)經(jīng)驗(yàn)最重要阁苞。下來(lái)就讓我先來(lái)回顧下這次事故發(fā)生的背景吧。

公司的游戲獲得了Google Play的最佳新游推薦位展示祠挫,這代表著公司游戲可以在Google Play首頁(yè)持續(xù)一周的全球推薦那槽。如果對(duì)Google Play還不了解的小伙伴們可以看看下圖,展示了Google Play推薦位的效果:

Google Play 推薦位

就是在這樣一個(gè)重大利好消息推動(dòng)下等舔,項(xiàng)目研發(fā)組緊急加班加點(diǎn)地趕制進(jìn)度和進(jìn)行游戲壓力測(cè)試(以后有機(jī)會(huì)詳細(xì)寫篇游戲壓力測(cè)試機(jī)器人實(shí)現(xiàn)方案)骚灸,最后內(nèi)網(wǎng)測(cè)試環(huán)境(Testing Environment)和預(yù)生產(chǎn)環(huán)境(Staging Environment)一切都測(cè)試正常,隨時(shí)等待更新線上正式壞境了慌植。

像以往一樣甚牲,游戲發(fā)布了停服更新公告(由于新增加了聯(lián)盟戰(zhàn)和幾個(gè)大的活動(dòng),擔(dān)心不停服更新有問(wèn)題)蝶柿,執(zhí)行完停服丈钙、備份、更新等一系列自動(dòng)化流程后交汤,服務(wù)器狀態(tài)變?yōu)椤案峦戤叧猓酌麊慰蛇M(jìn)入”狀態(tài),然后通知QA進(jìn)行上線前的最后一次生產(chǎn)環(huán)境(Production Environment)測(cè)試芙扎。整個(gè)項(xiàng)目的同學(xué)和QA同學(xué)以白名單身份在線上生產(chǎn)環(huán)境測(cè)試了近半個(gè)小時(shí)星岗,沒(méi)有任何bug和異常,我們就信心滿滿的準(zhǔn)備開服了戒洼。

游戲?qū)ν忾_放后俏橘,我們像往常一樣邊觀察邊繼續(xù)做著新的工作,突然公司運(yùn)營(yíng)同學(xué)過(guò)來(lái)說(shuō)游戲怎么感覺(jué)好卡圈浇,我們的第一反應(yīng)是你網(wǎng)卡了吧(因?yàn)橛螒蚍?wù)器在國(guó)外寥掐,中間有一道不可逾越的qiang),我也沒(méi)太在意還是繼續(xù)做著別的事情磷蜀,后來(lái)QA同學(xué)也說(shuō)游戲好卡啊召耘,我自己也登陸游戲試了下,確實(shí)挺卡蠕搜,每一次操作都要等待好久怎茫,不過(guò)到現(xiàn)在我還是沒(méi)有意識(shí)到服務(wù)器卡了,只是讓運(yùn)維同學(xué)查看游戲服的log有沒(méi)有報(bào)錯(cuò),而日志顯示似乎一切都正常(后面會(huì)解釋為什么日志還正常地輸出)轨蛤。

慢慢地游戲內(nèi)的聊天中開始有玩家反饋這次更新后游戲太卡蜜宪,而且反饋的用戶越來(lái)越多,我這才意識(shí)到問(wèn)題的嚴(yán)重性了祥山,游戲服肯定哪里操作太慢反應(yīng)遲鈍了(之前可能因?yàn)橛螒蚬珳y(cè)到現(xiàn)在大半年還沒(méi)出現(xiàn)過(guò)事故圃验,所以有點(diǎn)掉以輕心了)。

公司BOSS也過(guò)來(lái)問(wèn)怎么回事缝呕,正值Google Play推薦導(dǎo)量的時(shí)期澳窑,公司上下非常重視。當(dāng)然我知道越是面對(duì)大問(wèn)題供常,有經(jīng)驗(yàn)的人就越要冷靜摊聋,我直覺(jué)得給BOSS說(shuō):“服務(wù)器有點(diǎn)卡了,小問(wèn)題栈暇,馬上就能弄好的麻裁,別著急”。其實(shí)當(dāng)時(shí)我心里也沒(méi)底源祈,不知道問(wèn)題在哪煎源,不過(guò)根據(jù)自己以往經(jīng)驗(yàn)和實(shí)踐操作,只要按照“四步曲”流程化的執(zhí)行一遍香缺,肯定能找到點(diǎn)線索和眉目的手销。

更多的線上應(yīng)急和技術(shù)攻關(guān)可以參照我和朋友合著的《分布式服務(wù)架構(gòu):原理、設(shè)計(jì)與實(shí)戰(zhàn)》一書中的第六章“Java服務(wù)的線上應(yīng)急和技術(shù)攻關(guān)”图张,該章中介紹了海恩法則和墨菲定律锋拖,以及線上應(yīng)急目標(biāo)、原則和方法埂淮,同時(shí)提供了大量的Linux和JVM命令姑隅,也有很多平時(shí)工作中常用的自定義腳步文件和實(shí)際案例。

接下來(lái)我們一起倔撞,一步步地解決游戲卡死的問(wèn)題,文章中很多截圖只是本次文章演示說(shuō)明慕趴,不是當(dāng)時(shí)的現(xiàn)場(chǎng)截圖痪蝇,不過(guò)我會(huì)說(shuō)明清楚盡量還原線上真實(shí)過(guò)程。

事故的處理過(guò)程還原

解決線上問(wèn)題的“四部曲”

  • 望:就是觀察的意思冕房,出了問(wèn)題最重要一點(diǎn)就是觀察線上問(wèn)題發(fā)生的規(guī)律躏啰,切忌有病亂投醫(yī),一上來(lái)就先各種償試各種改的耙册。除了觀察現(xiàn)象外给僵,我們還要觀察各種日志、監(jiān)控和報(bào)警系統(tǒng),具體如何搭建“大數(shù)據(jù)日志監(jiān)控系統(tǒng)”請(qǐng)參照作者書的第四章帝际。

  • 問(wèn):就是問(wèn)清楚現(xiàn)在問(wèn)題發(fā)生的情況蔓同,這個(gè)很重要,后面會(huì)重點(diǎn)介紹具體需要問(wèn)清楚的哪些問(wèn)題蹲诀。

  • 聞:就是認(rèn)真聽取別人的意見斑粱,有時(shí)線上出了問(wèn)題,我們大多數(shù)心里還是比較抵觸別人說(shuō)這說(shuō)那的脯爪,不過(guò)在這種情況下则北,我們更應(yīng)該多聽,找到可能引起問(wèn)題的情況或有關(guān)的事情痕慢,同時(shí)也為后面的“甩鍋”技巧打開思路尚揣。

  • 切:就是動(dòng)手實(shí)踐驗(yàn)證了,通過(guò)前面的觀察掖举、詢問(wèn)問(wèn)題快骗,我們心中應(yīng)該能有些假設(shè)和猜測(cè)的線索了,這時(shí)候就需要?jiǎng)邮衷跍y(cè)試環(huán)境或預(yù)生產(chǎn)環(huán)境上進(jìn)一步驗(yàn)證我們的假設(shè)是否成立了拇泛。

下面這張圖概括的介紹了“望問(wèn)聞切”各階段需要關(guān)心和注重的事情:

四部曲

前面通過(guò)對(duì)“四部曲”的介紹滨巴,大家可能會(huì)覺(jué)得很抽象,不過(guò)它是我們解決線上問(wèn)題的指導(dǎo)方針俺叭、核心思想恭取,那我們?cè)趯?shí)際項(xiàng)目中又是如何“望問(wèn)聞切”的呢?

首先是如何發(fā)現(xiàn)問(wèn)題

發(fā)現(xiàn)問(wèn)題通常通過(guò)自動(dòng)化的監(jiān)控和報(bào)警系統(tǒng)來(lái)實(shí)現(xiàn)熄守,線上游戲服搭建了一個(gè)完善蜈垮、有效的日志中心、監(jiān)控和報(bào)警系統(tǒng)裕照,通常我們會(huì)對(duì)系統(tǒng)層面攒发、應(yīng)用層面和數(shù)據(jù)庫(kù)層面進(jìn)行監(jiān)控。

對(duì)系統(tǒng)層面的監(jiān)控包括對(duì)系統(tǒng)的CPU利用率晋南、系統(tǒng)負(fù)載惠猿、內(nèi)存使用情況、網(wǎng)絡(luò)I/O負(fù)載负间、磁盤負(fù)載偶妖、I/O 等待、交換區(qū)的使用政溃、線程數(shù)及打開的文件句柄數(shù)等進(jìn)行監(jiān)控,一旦超出閾值, 就需要報(bào)警趾访。對(duì)應(yīng)用層面的監(jiān)控包括對(duì)服務(wù)接口的響應(yīng)時(shí)間、吞吐量董虱、調(diào)用頻次扼鞋、接口成功率及接口的波動(dòng)率等進(jìn)行監(jiān)控。

對(duì)資源層的監(jiān)控包括對(duì)數(shù)據(jù)庫(kù)、緩存和消息隊(duì)列的監(jiān)控云头。我們通常會(huì)對(duì)數(shù)據(jù)庫(kù)的負(fù)載捐友、慢 SQL、連接數(shù)等進(jìn)行監(jiān)控盘寡;對(duì)緩存的連接數(shù)楚殿、占用內(nèi)存、吞吐量竿痰、響應(yīng)時(shí)間等進(jìn)行監(jiān)控脆粥;以及對(duì)消息隊(duì)列的響應(yīng)時(shí)間、吞吐量影涉、負(fù)載变隔、積壓情況等進(jìn)行監(jiān)控。

其次是如何定位問(wèn)題

定位問(wèn)題蟹倾,首先要根據(jù)經(jīng)驗(yàn)來(lái)分析匣缘,如果應(yīng)急團(tuán)隊(duì)中有人對(duì)相應(yīng)的問(wèn)題有經(jīng)驗(yàn),并確定能夠通過(guò)某種手段進(jìn)行恢復(fù)鲜棠,則應(yīng)該第一時(shí)間恢復(fù)肌厨,同時(shí)保留現(xiàn)場(chǎng),然后定位問(wèn)題豁陆。

在應(yīng)急人員定位過(guò)程中需要與業(yè)務(wù)負(fù)責(zé)人柑爸、技術(shù)負(fù)責(zé)人、核心技術(shù)開發(fā)人員盒音、技術(shù)專家表鳍、 架構(gòu)師、運(yùn)營(yíng)和運(yùn)維人員一起祥诽,對(duì)產(chǎn)生問(wèn)題的原因進(jìn)行快速分析譬圣。在分析過(guò)程中要先考慮系統(tǒng)最近發(fā)生的變化,需要考慮如下問(wèn)題。

  • 問(wèn)題系統(tǒng)最近是否進(jìn)行了上線?

  • 依賴的基礎(chǔ)平臺(tái)和資源是否進(jìn)行了上線或者升級(jí)?

  • 依賴的系統(tǒng)最近是否進(jìn)行了上線?

  • 運(yùn)營(yíng)是否在系統(tǒng)里面做過(guò)運(yùn)營(yíng)變更?

  • 網(wǎng)絡(luò)是否有波動(dòng)?

  • 最近的業(yè)務(wù)是否上量?

  • 服務(wù)的使用方是否有促銷活動(dòng)?

然后解決問(wèn)題

解決問(wèn)題的階段有時(shí)在應(yīng)急處理中雄坪,有時(shí)在應(yīng)急處理后厘熟。在理想情況下,每個(gè)系統(tǒng)會(huì)對(duì)各種嚴(yán)重情況設(shè)計(jì)止損和降級(jí)開關(guān)维哈,因此盯漂,在發(fā)生嚴(yán)重問(wèn)題時(shí)先使用止損策略,在恢復(fù)問(wèn)題后再定位和解決問(wèn)題笨农。解決問(wèn)題要以定位問(wèn)題為基礎(chǔ),必須清晰地定位問(wèn)題產(chǎn)生的根本原因,再提出解決問(wèn)題的有效方案帖渠,切記在沒(méi)有明確原因之前谒亦,不要使用各種可能的方法來(lái)嘗試修復(fù)問(wèn)題,這樣可能還沒(méi)有解決這個(gè)問(wèn)題又引出另一個(gè)問(wèn)題。

最后消除造成的影響

在解決問(wèn)題時(shí)份招,某個(gè)問(wèn)題可能還沒(méi)被解決就已恢復(fù)切揭,無(wú)論在哪種情況下都需要消除問(wèn)題產(chǎn)生的影響。

  • 技術(shù)人員在應(yīng)急過(guò)程中對(duì)系統(tǒng)做的臨時(shí)性改變锁摔,后證明是無(wú)效的,則要嘗試恢復(fù)到原來(lái)的狀態(tài)廓旬。

  • 技術(shù)人員在應(yīng)急過(guò)程中對(duì)系統(tǒng)進(jìn)行的降級(jí)開關(guān)的操作,在事后需要恢復(fù)谐腰。

  • 運(yùn)營(yíng)人員在應(yīng)急過(guò)程中對(duì)系統(tǒng)做的特殊設(shè)置如某些流量路由的開關(guān)孕豹,需要恢復(fù)。

  • 對(duì)使用方或者用戶造成的問(wèn)題十气,盡量采取補(bǔ)償?shù)牟呗赃M(jìn)行修復(fù)励背,在極端情況下需要一一核實(shí)。

  • 對(duì)外由專門的客服團(tuán)隊(duì)整理話術(shù)統(tǒng)一對(duì)外宣布發(fā)生故障的原因并安撫用戶砸西,話術(shù)盡量貼近客觀事實(shí)叶眉,并從用戶的角度出發(fā)。

當(dāng)我們?cè)敿?xì)地了解了如何發(fā)現(xiàn)問(wèn)題芹枷、定位問(wèn)題衅疙、解決問(wèn)題和消除造成的影響后,接下來(lái)讓我們看下本次解決線上游戲卡死過(guò)程中是如何具體的應(yīng)用的鸳慈。

排查游戲卡死的過(guò)程

第一步饱溢,找運(yùn)維看日志

如果日志監(jiān)控系統(tǒng)中有報(bào)錯(cuò),謝天謝地蝶涩,很好定位問(wèn)題理朋,我們只需要根據(jù)日志報(bào)錯(cuò)的堆棧信息來(lái)解決。如果日志監(jiān)控系統(tǒng)中沒(méi)有任何異常信息绿聘,那么接下來(lái)就得開始最重要的保存現(xiàn)場(chǎng)了嗽上。

第二步,保存現(xiàn)場(chǎng)并恢復(fù)服務(wù)

日志系統(tǒng)中找不到任何線索的情況下熄攘,我們需要趕緊保存現(xiàn)場(chǎng)快照兽愤,并盡快恢復(fù)游戲服務(wù),以達(dá)到最大程度止損的目的挪圾。

通常JVM中保存現(xiàn)場(chǎng)快照分為兩種:

  • 保存當(dāng)前運(yùn)行線程快照浅萧。

  • 保存JVM內(nèi)存堆棧快照哲思。

其方法如下:

  1. 保存當(dāng)前運(yùn)行線程快照洼畅,可以使用jstack [pid]命令實(shí)現(xiàn),通常情況下需要保存三份不同時(shí)刻的線程快照棚赔,時(shí)間間隔在1-2分鐘帝簇。
  2. 保存JVM內(nèi)存堆椗枪快照,可以使用jmap –heap丧肴、jmap –histo残揉、 jmap -dump:format=b,file=xxx.hprof等命令實(shí)現(xiàn)。

快速恢復(fù)服務(wù)的常用方法:

1.隔離出現(xiàn)問(wèn)題的服務(wù)芋浮,使其退出線上服務(wù)抱环,便于后續(xù)的分析處理。
2.償試快速重啟服務(wù)纸巷,第一時(shí)間恢復(fù)系統(tǒng)镇草,而不是徹底解決問(wèn)題。
3.對(duì)服務(wù)降級(jí)處理何暇,只使用少量的請(qǐng)求來(lái)重現(xiàn)問(wèn)題陶夜,以便我們可以全程跟蹤觀察,因?yàn)橹翱赡軟](méi)太注意這個(gè)問(wèn)題是如何發(fā)生的裆站。

通過(guò)上面一系列的操作后条辟,保存好現(xiàn)場(chǎng)環(huán)境、快照和日志后宏胯,我們就需要通過(guò)接下來(lái)的具體分析來(lái)定位問(wèn)題了羽嫡。

第三步,分析日志定位問(wèn)題

這一步是最關(guān)鍵的肩袍,也是需要有很多實(shí)戰(zhàn)經(jīng)驗(yàn)的杭棵,接下來(lái)我將一步步還原當(dāng)時(shí)解決問(wèn)題的具體操作步聚。

診斷服務(wù)問(wèn)題氛赐,就像比醫(yī)生給病人看病一樣魂爪,需要先查看一下病人的臉色如何、摸一摸有沒(méi)有發(fā)燒艰管、或再聽聽心臟的跳動(dòng)情況等等滓侍。同樣的道理,我們需要先查看服務(wù)器的“當(dāng)前癥狀”牲芋,才能進(jìn)一步對(duì)癥下藥撩笆。

  • 首先使用top命令查看服務(wù)器負(fù)載狀況
top命令

load average一共有三個(gè)平均值:1分鐘系統(tǒng)負(fù)荷、5分鐘系統(tǒng)負(fù)荷缸浦,15分鐘系統(tǒng)負(fù)荷夕冲。哪我們應(yīng)該參考哪個(gè)值?

如果只有1分鐘的系統(tǒng)負(fù)荷大于1.0裂逐,其他兩個(gè)時(shí)間段都小于1.0歹鱼,這表明只是暫時(shí)現(xiàn)象,問(wèn)題不大卜高。 如果15分鐘內(nèi)醉冤,平均系統(tǒng)負(fù)荷大于1.0秩霍,表明問(wèn)題持續(xù)存在,不是暫時(shí)現(xiàn)象蚁阳。所以,你應(yīng)該主要觀察"15分鐘系統(tǒng)負(fù)荷"鸽照,將它作為服務(wù)器正常運(yùn)行的指標(biāo)螺捐。

說(shuō)明:我們當(dāng)時(shí)服務(wù)器負(fù)載顯示并不高,所以當(dāng)時(shí)第一反應(yīng)就排除了承載壓力的問(wèn)題矮燎。

  • 接下來(lái)再使用top命令+1查看CPU的使用情況
top命令

我們主要關(guān)注紅框中指標(biāo)定血,它表示當(dāng)前cpu空閑情況,而其它各指標(biāo)具體含義如下:

0.7%us:用戶態(tài)進(jìn)程占用CPU時(shí)間百分比诞外,不包含renice值為負(fù)的任務(wù)占用的CPU的時(shí)間澜沟。

0.0%sy:內(nèi)核占用CPU時(shí)間百分比。

0.0%ni:改變過(guò)優(yōu)先級(jí)的進(jìn)程占用CPU的百分比峡谊。

99.3%id:空閑CPU時(shí)間百分比茫虽。

0.0%wa:等待I/O的CPU時(shí)間百分比。

0.0%hi:CPU硬中斷時(shí)間百分比既们。

0.0%si:CPU軟中斷時(shí)間百分比濒析。

說(shuō)明:我們線上服務(wù)器為8核16G的配置,當(dāng)時(shí)只有一個(gè)cpu顯示繁忙啥纸,id(空閑時(shí)間百分比)為50%左右号杏,其余顯示90%多。從這里看似乎沒(méi)有什么太大的問(wèn)題斯棒。

既然cpu負(fù)載和使用都沒(méi)太大問(wèn)題盾致,那是什么卡住了服務(wù)呢?直覺(jué)告訴我荣暮,可能是線程死鎖或等待了什么耗時(shí)的操作庭惜,我們接下來(lái)就來(lái)查看線程的使用情況。不過(guò)在查看線程使用情況之前渠驼,我們首先看看JVM有沒(méi)有出現(xiàn)內(nèi)存泄漏(即OOM問(wèn)題蜈块,我的書中有介紹一個(gè)實(shí)際OOM的案例),因?yàn)槿绻鸍VM大量的出現(xiàn)FGC也會(huì)造成用戶線程卡住服務(wù)變慢的情況迷扇。

  • 使用jstat –gcutil pid查看堆中各個(gè)內(nèi)存區(qū)域的變化以及GC的工作狀態(tài)
jstat命令

S0:幸存1區(qū)當(dāng)前使用比例

S1:幸存2區(qū)當(dāng)前使用比例

E:伊甸園區(qū)使用比例

O:老年代使用比例

M:元數(shù)據(jù)區(qū)使用比例

CCS:壓縮使用比例

YGC:年輕代垃圾回收次數(shù)

FGC:老年代垃圾回收次數(shù)

FGCT:老年代垃圾回收消耗時(shí)間

GCT:垃圾回收消耗總時(shí)間

說(shuō)明:當(dāng)時(shí)服務(wù)也沒(méi)有出現(xiàn)大量的FGC情況百揭,所以排除了有OOM導(dǎo)致的用戶線程卡死。

  • 接下來(lái)使用top命令+H查看線程的使用情況
top命令

PID:進(jìn)程的ID

USER:進(jìn)程所有者

PR:進(jìn)程的優(yōu)先級(jí)別蜓席,越小越優(yōu)先被執(zhí)行

NInice:值

VIRT:進(jìn)程占用的虛擬內(nèi)存

RES:進(jìn)程占用的物理內(nèi)存

SHR:進(jìn)程使用的共享內(nèi)存

S:進(jìn)程的狀態(tài)器一。S表示休眠,R表示正在運(yùn)行厨内,Z表示僵死狀態(tài)祈秕,N表示該進(jìn)程優(yōu)先值為負(fù)數(shù)

%CPU:進(jìn)程占用CPU的使用率

%MEM:進(jìn)程使用的物理內(nèi)存和總內(nèi)存的百分比

TIME+:該進(jìn)程啟動(dòng)后占用的總的CPU時(shí)間渺贤,即占用CPU使用時(shí)間的累加值。

COMMAND:進(jìn)程啟動(dòng)命令名稱

說(shuō)明:通過(guò)查看線程%CPU指標(biāo)请毛,明顯能看到某個(gè)java線程執(zhí)行非常占用CPU志鞍,因此斷定該線程當(dāng)時(shí)出現(xiàn)了問(wèn)題。那么我們接下來(lái)如何找到這個(gè)線程當(dāng)時(shí)在干嘛呢方仿?請(qǐng)看以下三步聚固棚。(圖片只是示意圖,不是當(dāng)時(shí)線上截圖)

  • 使用jstack pid打印進(jìn)程中線程堆棧信息仙蚜,我們可以使用如下三步找出最繁忙的線程信息此洲。

查看進(jìn)程中各線程占用cpu狀態(tài), 選出最繁忙的線程id委粉,使用命令top -Hp pid

jstack命令

把線程id轉(zhuǎn)成16進(jìn)制呜师,使用命令printf “%x\n”{線程id}

jstack命令

打印當(dāng)前線程運(yùn)行的堆棧信息,查找線程id為0x766B的線程堆棧信息

jstack命令

說(shuō)明:線上通過(guò)打印繁忙線程贾节,查看線程的執(zhí)行堆棧汁汗,并沒(méi)有找到被卡住的業(yè)務(wù)代碼,每次都是執(zhí)行成功的氮双。當(dāng)時(shí)就非常納悶削彬,為什么一直只是這一個(gè)線程在不停地消耗著CPU余爆,突然一個(gè)編程的小技巧幫我找到了問(wèn)題的罪魁禍?zhǔn)住€程中任務(wù)分配不均導(dǎo)致的服務(wù)響應(yīng)變慢稼虎。

小技巧:為不同的業(yè)務(wù)線程自定義名稱咽笼,比如打印日志的線程為log_xxx,接收消息請(qǐng)求的線程為msg_xxx暖释,游戲業(yè)務(wù)線程為game_xxx等袭厂。java中具體如何為線程命令如下圖所示:


線程命令
  • 罪魁禍?zhǔn)住植际轿ㄒ籌D生成器
罪魁禍?zhǔn)?/div>

通過(guò)上面紅框中的代碼我們可以看到,線程任務(wù)的分配規(guī)則是通過(guò)用戶的uuid模上線程池的長(zhǎng)度球匕,這樣實(shí)現(xiàn)的目的是想讓同一個(gè)用戶的所有請(qǐng)求操作都分配到同一個(gè)線程中去完成(線程親和性)纹磺,這樣的實(shí)現(xiàn)是為了從用戶角度保證線程的安全性,不會(huì)出現(xiàn)多線程下數(shù)據(jù)的不一致性亮曹。

而問(wèn)題就出現(xiàn)在這個(gè)uuid取模上了橄杨,我們使用的是Twitter的分布式自增ID算法snowflake,而它生成的所有id剛好與我設(shè)置的線程池大小64取模后為0(具體原因不明)照卦,導(dǎo)致所有用戶的所有請(qǐng)求全部分配到了一個(gè)線程中排隊(duì)執(zhí)行了式矫。這也是為什么在查看線程堆棧信息時(shí)感覺(jué)都在正常執(zhí)行,而打印的所有線程中只看到編號(hào)為0的線程在執(zhí)行役耕,其它都空閑等待采转。

說(shuō)明:此功能實(shí)現(xiàn)是在上線前兩天,運(yùn)營(yíng)同學(xué)告訴說(shuō)瞬痘,有玩家反饋前一刻領(lǐng)取到的鉆石在下一刻莫名消失了故慈,我的第一反應(yīng)肯定是多線程造成的板熊,所以就臨時(shí)采取了這種線程親和方式統(tǒng)一解決了線程安全的問(wèn)題。現(xiàn)在找到了問(wèn)題產(chǎn)生的原因察绷,接下來(lái)看是如何解決的干签。

  • 使用MurmurHash散列下解決ID生成不均勻的問(wèn)題
jiejue

第四步,Hotfix后繼續(xù)觀察情況

在測(cè)試環(huán)境或預(yù)生產(chǎn)環(huán)境修改測(cè)試后克婶,如果問(wèn)題不能再?gòu)?fù)現(xiàn)了筒严,可以根據(jù)公司的Hotfix流程進(jìn)行線上bug更新,并繼續(xù)觀察情萤。如果一切都正常后,需要消除之前可能造成的影響摹恨。

一鍵查看最繁忙線程堆棧腳本

此命令通過(guò)結(jié)合Linux操作系統(tǒng)的ps命令和JVM自帶的jstack命令筋岛,來(lái)查找Java進(jìn)程內(nèi)CPU利用率最高的線程,一般適用于服務(wù)器負(fù)載較高的場(chǎng)景晒哄,并需要快速定位負(fù)載高的成因睁宰。
此腳本最初來(lái)自于互聯(lián)網(wǎng),后來(lái)為了讓其在不同的類UNIX環(huán)境下運(yùn)行寝凌,所以我做了一些修改柒傻,該命令在我每一次定位負(fù)載問(wèn)題時(shí)都起到了重要作用。
命令格式:

./show-busiest-java-threads -p 進(jìn)程號(hào) -c 顯示條數(shù)
./show-busiest-java-threads -h

使用示例:

./show-busiest-java-threads -p 30054 -c 3

示例輸出:

findtop

腳本源碼見《分布式服務(wù)架構(gòu):原理较木、設(shè)計(jì)與實(shí)戰(zhàn)》書中241頁(yè)红符,更多服務(wù)化治理腳本請(qǐng)參照書中的第六章“Java服務(wù)的線上應(yīng)急和技術(shù)攻關(guān)”。

對(duì)本次線上事故的總結(jié)

在技術(shù)方面伐债,線上問(wèn)題大致分為以下三類预侯。

CPU繁忙型

  • 線程中出現(xiàn)死循環(huán)、線程阻塞峰锁,JVM中頻繁的垃圾回收萎馅,或者線程上下文切換導(dǎo)致。

  • 常用命令top虹蒋、jstack [pid]和Btrace等工具排查解決糜芳。

內(nèi)存溢出型

  • 堆外內(nèi)存: JNI的調(diào)用或NIO中的DirectByteBuffer等使用不當(dāng)造成的。

  • 堆內(nèi)內(nèi)存:程序中創(chuàng)建的大對(duì)象魄衅、全局集合峭竣、緩存、 ClassLoader加載的類或大量的線程消耗等容易引起徐绑。

  • 常用的命令有jmap –heap邪驮、jmap –histo、jmap -dump:format=b,file=xxx.hprof等查看JVM內(nèi)存情況的傲茄。

IO讀寫型

  • 文件IO:可以使用命令vmstat毅访、lsof –c -p pid等沮榜。

  • 網(wǎng)絡(luò)IO: 可以使用命令netstat –anp、tcpdump -i eth0 ‘dst host 239.33.24.212’ -w raw.pcap和wireshark工具等喻粹。

以上只是簡(jiǎn)單的介紹了下相關(guān)問(wèn)題分類和常用命令工具蟆融,由于篇幅有限更多內(nèi)容請(qǐng)參照《分布式服務(wù)架構(gòu):原理、設(shè)計(jì)與實(shí)戰(zhàn)》書中“線上應(yīng)急和技術(shù)攻關(guān)”一章守呜,詳細(xì)介紹了各種情況下技術(shù)命令的使用型酥。

在制度方面的應(yīng)急處理和響應(yīng)保障

制定事故的種類和級(jí)別

  • S級(jí)事故,核心業(yè)務(wù)重要功能不可用且大面積影響用戶查乒,響應(yīng)時(shí)間:立即弥喉。

  • A級(jí)事故,核心業(yè)務(wù)重要功能不可用玛迄,但影響用戶有限由境;周邊業(yè)務(wù)功能不可用且大面積影響用戶體驗(yàn),響應(yīng)時(shí)間:小于15分鐘蓖议。

  • B級(jí)事故虏杰,周邊業(yè)務(wù)功能不可用,輕微影響用戶體驗(yàn)勒虾,響應(yīng)時(shí)間:小于4小時(shí)纺阔。

說(shuō)明:每個(gè)公司定義的事故種類和級(jí)別都不一樣,具體情況具體分析修然,只要公司有了統(tǒng)一化的標(biāo)準(zhǔn)笛钝,當(dāng)我們遇到線上問(wèn)題時(shí)才不會(huì)顯的雜亂無(wú)章,知道事情的輕重緩急低零,以及如何處理和什么時(shí)候處理婆翔。

對(duì)待事故的態(tài)度

  • 保存現(xiàn)場(chǎng)并減少損失,第一時(shí)間恢復(fù)服務(wù)掏婶,減少線上損失啃奴,保存好現(xiàn)在所有信息用于問(wèn)題分析定位。

  • 積極主動(dòng)的解決問(wèn)題雄妥,線上問(wèn)題第一時(shí)間解決最蕾,也是展現(xiàn)個(gè)人能力的最佳時(shí)機(jī)。

  • 主動(dòng)承擔(dān)部分責(zé)任老厌,承擔(dān)自己能承擔(dān)的責(zé)任瘟则,畢竟事故涉及KPI考核等問(wèn)題,有時(shí)也需要混淆問(wèn)題原因枝秤,拒絕老實(shí)人背鍋醋拧。

  • 不要輕信經(jīng)驗(yàn),線上無(wú)小事,而大多引起線上事故的問(wèn)題一般都是小問(wèn)題丹壕,所以一定不要輕信經(jīng)驗(yàn)庆械,每一項(xiàng)改動(dòng)都必須經(jīng)過(guò)測(cè)試。

說(shuō)明:當(dāng)線上出現(xiàn)問(wèn)題后菌赖,大多數(shù)人第一反應(yīng)可能是“這不關(guān)我事缭乘,我寫的東西沒(méi)問(wèn)題”,面對(duì)線上問(wèn)題不要怕承擔(dān)責(zé)任琉用,反而正是我們表現(xiàn)個(gè)人能力的最好時(shí)機(jī)堕绩。平時(shí)大家可能做了非常多的工作,勤勤懇懇的努力奉獻(xiàn)著邑时,最后BOSS連你的名字可能都沒(méi)記住奴紧,尷尬!晶丘!但是一旦線上遇到問(wèn)題绰寞,可能直接就造成很大的經(jīng)濟(jì)損失,全項(xiàng)目組甚至全公司都在關(guān)注的時(shí)候铣口,你勇于站出來(lái)完美的解決了該問(wèn)題,收獲的成就會(huì)是相當(dāng)大的觉壶。當(dāng)然在這個(gè)過(guò)程中脑题,我們最重要的是快速解決問(wèn)題,最大程序的減少造成的損失铜靶。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末叔遂,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子争剿,更是在濱河造成了極大的恐慌已艰,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,695評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件蚕苇,死亡現(xiàn)場(chǎng)離奇詭異哩掺,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)涩笤,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,569評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門嚼吞,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人蹬碧,你說(shuō)我怎么就攤上這事舱禽。” “怎么了恩沽?”我有些...
    開封第一講書人閱讀 168,130評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵誊稚,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng)里伯,這世上最難降的妖魔是什么城瞎? 我笑而不...
    開封第一講書人閱讀 59,648評(píng)論 1 297
  • 正文 為了忘掉前任,我火速辦了婚禮俏脊,結(jié)果婚禮上全谤,老公的妹妹穿的比我還像新娘。我一直安慰自己爷贫,他們只是感情好认然,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,655評(píng)論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著漫萄,像睡著了一般卷员。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上腾务,一...
    開封第一講書人閱讀 52,268評(píng)論 1 309
  • 那天毕骡,我揣著相機(jī)與錄音,去河邊找鬼岩瘦。 笑死未巫,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的启昧。 我是一名探鬼主播叙凡,決...
    沈念sama閱讀 40,835評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼密末!你這毒婦竟也來(lái)了握爷?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,740評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤严里,失蹤者是張志新(化名)和其女友劉穎新啼,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體刹碾,經(jīng)...
    沈念sama閱讀 46,286評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡燥撞,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,375評(píng)論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了教硫。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片叨吮。...
    茶點(diǎn)故事閱讀 40,505評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖瞬矩,靈堂內(nèi)的尸體忽然破棺而出茶鉴,到底是詐尸還是另有隱情,我是刑警寧澤景用,帶...
    沈念sama閱讀 36,185評(píng)論 5 350
  • 正文 年R本政府宣布涵叮,位于F島的核電站惭蹂,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏割粮。R本人自食惡果不足惜盾碗,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,873評(píng)論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望舀瓢。 院中可真熱鬧廷雅,春花似錦、人聲如沸京髓。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,357評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)堰怨。三九已至芥玉,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間备图,已是汗流浹背灿巧。 一陣腳步聲響...
    開封第一講書人閱讀 33,466評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留揽涮,地道東北人抠藕。 一個(gè)月前我還...
    沈念sama閱讀 48,921評(píng)論 3 376
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像蒋困,于是被迫代替她去往敵國(guó)和親幢痘。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,515評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容