背景:上周消息中心 上線了一個(gè)新功能(群發(fā)消息)恋日,監(jiān)控系統(tǒng)發(fā)現(xiàn)調(diào)用我的系統(tǒng)里接口總是出現(xiàn)莫名其妙的502狀態(tài)碼拟逮,告警了
502概念:502 Bad Gateway是指錯(cuò)誤網(wǎng)關(guān)檀头,無(wú)效網(wǎng)關(guān);在互聯(lián)網(wǎng)中表示一種網(wǎng)絡(luò)錯(cuò)誤憔古。表現(xiàn)在WEB瀏覽器中給出的頁(yè)面反饋。它通常并不意味著上游服務(wù)器已關(guān)閉(無(wú)響應(yīng)網(wǎng)關(guān)/代理) 淋袖,而是上游服務(wù)器和網(wǎng)關(guān)/代理使用不一致的協(xié)議交換數(shù)據(jù)投放。鑒于互聯(lián)網(wǎng)協(xié)議是相當(dāng)清楚的,它往往意味著一個(gè)或兩個(gè)機(jī)器已不正確或不完全編程适贸。
一 原因分析
1.1 可能是服務(wù)器出現(xiàn)了大規(guī)模報(bào)錯(cuò)導(dǎo)致網(wǎng)關(guān)認(rèn)為服務(wù)不可用,直接拒絕
本次上線的功能是群發(fā)消息功能涝桅,目前疫情結(jié)束拜姿,通常會(huì)有許多人有群發(fā)消息通知顧客已恢復(fù)正常運(yùn)營(yíng)的需求,因此目前這個(gè)功能使用非常多冯遂,而且這個(gè)消息通知規(guī)模比較大蕊肥,每次通常會(huì)向幾萬(wàn)或者幾十萬(wàn)人發(fā)送消息,在現(xiàn)有資源情況下蛤肌,通常會(huì)帶動(dòng)服務(wù)器有一定的資源波動(dòng)壁却,因此第一時(shí)間懷疑是服務(wù)器資源不夠用了,系統(tǒng)產(chǎn)生大規(guī)模超時(shí)等報(bào)錯(cuò)讓網(wǎng)關(guān)層產(chǎn)生了假性服務(wù)器不可用的判斷,致使網(wǎng)關(guān)直接拒絕第三方調(diào)用的情況裸准。
我看了下展东,確實(shí)是每次出現(xiàn)502基本都是出現(xiàn)在群發(fā)任務(wù)調(diào)度比較多的情況,但是我在我們?nèi)罩鞠到y(tǒng)并沒有發(fā)現(xiàn)成規(guī)模的其他報(bào)錯(cuò)炒俱,另外服務(wù)器資源有波動(dòng)但是也沒那么大的波動(dòng)盐肃,因?yàn)槲覀冞@一般申請(qǐng)服務(wù)器資源比較容易爪膊,都是做了一定的富余的。
這邊咨詢了下運(yùn)維側(cè)最近是否有什么變動(dòng)或者解決方案砸王,運(yùn)維側(cè)覺得是服務(wù)器資源問(wèn)題推盛,先直接給我們加了一倍的機(jī)器
但是觀察后發(fā)現(xiàn)502少了但是問(wèn)題還是沒解決
1.2 網(wǎng)關(guān)兩邊鏈接保活時(shí)間不一致
我新功能上線的那一天的同時(shí)把我們的服務(wù)切到了K8s下谦铃,運(yùn)維側(cè)對(duì)那邊服務(wù)架構(gòu)做了比較大的調(diào)整耘成,對(duì)于代理這塊,以前使用的是nginx驹闰,現(xiàn)在改用了traefik瘪菌,我們知道在用了代理的情況下,其實(shí)客戶端和服務(wù)器并不是直接交互建立連接的疮方,而是客戶端請(qǐng)求交給代理控嗜,代理再進(jìn)行轉(zhuǎn)發(fā), 兩邊都是對(duì)代理層建立連接骡显。
先解釋下什么是keepalive疆栏?
這是http 1.1協(xié)議的缺省配置,在http 1.0的時(shí)候惫谤,如果你的網(wǎng)頁(yè)上有10個(gè)圖片壁顶,那么瀏覽器和服務(wù)器之間要同時(shí)建立10個(gè)連接,把這10個(gè)圖片發(fā)過(guò)去然后再關(guān)閉這10個(gè)連接溜歪,顯然對(duì)于服務(wù)器來(lái)說(shuō)若专,建立10個(gè)連接再關(guān)閉10個(gè)連接,消耗是比較大的蝴猪。所以在http 1.1協(xié)議里增加了keepalive的功能调衰,在發(fā)10張圖片的時(shí)候只需要建立一個(gè)連接就夠了,只要還有內(nèi)容要傳輸自阱,這個(gè)通道會(huì)始終保持開放狀態(tài)嚎莉,不會(huì)在傳輸完畢之后立刻關(guān)閉,這就是keepalive迸嫱悖活的意思趋箩。
但是keepalive不能把這個(gè)連接永遠(yuǎn)保持,如果沒有內(nèi)容了還繼續(xù)保持加派,無(wú)疑也是一種浪費(fèi)叫确,所以這里就產(chǎn)生了超時(shí)的概念,keepalive_timeout的意思是說(shuō)如果這個(gè)連接當(dāng)中沒有內(nèi)容傳輸了并且超過(guò)了這個(gè)時(shí)間芍锦,那么就把這個(gè)連接斷掉竹勉,keepalive_requests的意思是說(shuō)我們這個(gè)連接最多允許傳輸多少個(gè)內(nèi)容,超過(guò)這個(gè)內(nèi)容那么也把它斷掉醉旦。
那么這個(gè)keepalive_timout和我們的502錯(cuò)誤之間有什么關(guān)系呢饶米?
如我前面所說(shuō):因?yàn)樗芯W(wǎng)站的架構(gòu)都不是瀏覽器直接連接后端的應(yīng)用服務(wù)器桨啃,而一定是中間有nginx、traefik服務(wù)器做反向代理的檬输,瀏覽器和nginx服務(wù)器之間建立keepalive連接照瘾,nginx再和后端的應(yīng)用服務(wù)器建立keepalive連接,所以這是兩種不同的keepalive連接丧慈。
我們把瀏覽器和nginx之間的keepalive連接叫做ka1析命,把nginx和應(yīng)用服務(wù)器之間的keepalive連接叫做ka2。
如果ka1的超時(shí)設(shè)置為100秒逃默,也就是說(shuō)如果100秒之內(nèi)沒有新內(nèi)容要傳輸鹃愤,就把nginx和瀏覽器之間的連接斷掉。而同時(shí)完域,我們把ka2設(shè)置為50秒软吐,也就是說(shuō)如果nginx和應(yīng)用服務(wù)器之間沒有新內(nèi)容要傳輸,那么就把應(yīng)用服務(wù)器和nginx之間的連接斷掉吟税。那么這時(shí)候就會(huì)產(chǎn)生一個(gè)現(xiàn)象:前50秒沒有傳輸內(nèi)容凹耙,在第51秒的時(shí)候,瀏覽器向nginx發(fā)了一個(gè)請(qǐng)求肠仪,這時(shí)候ka1還沒有斷掉肖抱,因?yàn)闆]有到100秒的時(shí)間,所以這是沒有問(wèn)題的异旧,但是當(dāng)nginx試圖向應(yīng)用服務(wù)器發(fā)請(qǐng)求的時(shí)候就出問(wèn)題了意述,ka2斷了!因?yàn)閗a2的超時(shí)設(shè)置是50秒吮蛹,這時(shí)候已經(jīng)超了荤崇,所以就斷了,這時(shí)候nginx無(wú)法再?gòu)膽?yīng)用服務(wù)器獲得正確響應(yīng)潮针,只好返回瀏覽器502錯(cuò)誤天试!
但是我們根本就沒有設(shè)置過(guò)這些參數(shù)啊,怎么會(huì)有這種問(wèn)題呢然低?
這沒關(guān)系,既然沒有設(shè)置過(guò)务唐,那系統(tǒng)肯定用的是缺省參數(shù)雳攘,我們來(lái)看一下ka1的缺省設(shè)置是多少,也就是nginx(ingress)和瀏覽器之間的缺省的keepalive_timeout值:
upstream-keepalive-timeout
Sets a timeout during which an idle keepalive connection to an upstream server will stay open. default: 60
ka1的缺省設(shè)置是60秒枫笛。
我們?cè)倏匆幌耴a2的缺省設(shè)置是多少秒吨灭,Tomcat官方文檔上說(shuō):
The number of milliseconds this Connector will wait for another HTTP request before closing the connection.
The default value is to use the value that has been set for the connectionTimeout attribute. Use a value of -1 to indicate no (i.e. infinite) timeout.
缺省值等同于connectionTimeout
的值,那connectionTimeout等于多少呢刑巧?
The number of milliseconds this Connector will wait, after accepting a connection, for the request URI line to be presented.
Use a value of -1 to indicate no (i.e. infinite) timeout. The default value is 60000 (i.e. 60 seconds)
but note that the standard server.xml that ships with Tomcat sets this to 20000 (i.e. 20 seconds).
Unless disableUploadTimeout is set to false, this timeout will also be used when reading the request body (if any).
connectionTimeout的缺省值是60秒喧兄,但是无畔,他們提供的標(biāo)準(zhǔn)的server.xml里把這個(gè)值設(shè)為了20秒!
那么現(xiàn)在問(wèn)題就很清楚了吠冤,我們的ka1是60秒浑彰,而ka2是20秒,從21秒到60秒之間的任何時(shí)間有請(qǐng)求進(jìn)來(lái)都會(huì)發(fā)生502錯(cuò)誤拯辙。
找到了問(wèn)題的根源郭变,解決起來(lái)就好辦了,我們只需要確保ka1的超時(shí)設(shè)置小于ka2的設(shè)置就夠了涯保∷弑簦或者修改ka1,或者修改ka2夕春,都是可以的未荒。
對(duì)于traefik也是一樣的,我們?cè)谇械絫raefik后及志,由于客戶端到traefik設(shè)置的keepalive為180s片排,而我們traefik到我們服務(wù)器設(shè)置的為60s,因此如果在客戶端到traefik的連接斷了后困肩,traefik到服務(wù)器連接還沒斷的時(shí)間區(qū)間內(nèi)請(qǐng)求服務(wù)划纽,那么極有可能出現(xiàn)502
二 解決
運(yùn)維側(cè)調(diào)整了客戶端到traefik的keepalive時(shí)間,調(diào)整為小于等于我們服務(wù)器到traefik的keepalive皆可锌畸,我們這里是調(diào)整的等于勇劣。
后面觀察了幾天,發(fā)現(xiàn)調(diào)整后服務(wù)器完全正常了潭枣,再也沒出現(xiàn)過(guò)502比默;
三 總結(jié)
其實(shí)這次問(wèn)題還是比較明顯的
- 1.出現(xiàn)時(shí)機(jī)是新功能發(fā)布上線后
- 2.502的同時(shí)往往伴隨著鏈接數(shù)的下降(先是系統(tǒng)充分預(yù)熱,鏈接數(shù)全部激活了,后期又逐漸下降)
這次的盲點(diǎn)
盲點(diǎn)主要是不清楚運(yùn)維側(cè)代理把nginx換成了traefik盆犁,不然問(wèn)題會(huì)更加明顯命咐,定位的更快些;