線上 K8s Ingress 訪問(wèn)故障排查思路,看這一篇就夠了
具體現(xiàn)象
應(yīng)用遷移至我們的 PaaS 平臺(tái)后會(huì)出現(xiàn)偶發(fā)性的502問(wèn)題,錯(cuò)誤見(jiàn)圖片:
相比于程序的請(qǐng)求量,錯(cuò)誤肯定是比較少的,但是錯(cuò)誤一直在發(fā)生,會(huì)影響調(diào)用方的代碼,需要檢查下問(wèn)題原因。
為啥只看到了POST請(qǐng)求
讀者肯定會(huì)說(shuō), 你們 ELK 過(guò)濾字段里面寫(xiě)的是POST,所以肯定只有POST請(qǐng)求,其實(shí)不是這樣的,GET請(qǐng)求也會(huì)有502,只是Nginx會(huì)對(duì)GET請(qǐng)求進(jìn)行重試,產(chǎn)生類(lèi)似如下的日志:
重試機(jī)制是Nginx默認(rèn)的: proxy_next_upstreamhttp://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_next_upstream
因?yàn)镚ET方法會(huì)被認(rèn)為是冪等的, 所以當(dāng)一個(gè)upstream出現(xiàn)502的時(shí)候, nginx會(huì)再次嘗試. 對(duì)于我們的問(wèn)題, 主要想確認(rèn)為什么有502, 只看POST請(qǐng)求就足夠了, 兩者的原因應(yīng)該是一致的。
網(wǎng)絡(luò)拓?fù)浣Y(jié)構(gòu)
網(wǎng)絡(luò)請(qǐng)求流入集群時(shí), 對(duì)于我們集群的結(jié)構(gòu):
用戶請(qǐng)求=>Nginx=>Ingress =>uwsgi
不要問(wèn)為什么有了 Ingress 還有 Nginx。這是歷史原因,有些工作暫時(shí)需要由 Nginx 承擔(dān)。
統(tǒng)計(jì)排查
基于我們對(duì)于Nginx和Ingress的錯(cuò)誤請(qǐng)求統(tǒng)計(jì),發(fā)現(xiàn)兩者中的502錯(cuò)誤是想等的,說(shuō)明問(wèn)題一定是出現(xiàn)在Ingress<=>uwsgi之中。
抓包
這個(gè)并不是最先想到的方案,因?yàn)槲覀冇昧撕芏嘟y(tǒng)計(jì)方法也沒(méi)總結(jié)出來(lái)規(guī)律,最后只能寄希望于抓包了…該請(qǐng)求日志如下:
抓包結(jié)果如下:
從抓包情況來(lái)看,當(dāng)前的tcp連接被復(fù)用了,由于Ingress中使用了HTTP1.1協(xié)議,會(huì)在一次tcp連接中嘗試發(fā)送第二個(gè)HTTP請(qǐng)求,但是uwsgi沒(méi)有支持http1.1,所以在第二個(gè)請(qǐng)求根本不會(huì)被處理,直接拒絕了。所以在Ingress看來(lái),這個(gè)請(qǐng)求失敗了, 因此返回了502. 由于GET請(qǐng)求會(huì)重試, 但POST請(qǐng)求無(wú)法重試, 所以訪問(wèn)統(tǒng)計(jì)中出現(xiàn)了POST請(qǐng)求502的問(wèn)題。
Ingress配置學(xué)習(xí)
Ingress中, 默認(rèn)對(duì)upstream使用的http版本為1.1, 但是我們的uwsgi使用的是http-socket, 而非http11-socket, 我們Ingress中使用了與后端不同的協(xié)議, 出現(xiàn)了意料之外的502錯(cuò)誤。
因?yàn)镹ginx默認(rèn)是1.0, 但是切換到Ingress中默認(rèn)變成了1.1, 而我們沒(méi)有統(tǒng)一, 解決方案是強(qiáng)制指定Ingress中使用的http協(xié)議版本。
{% if keepalive_enable is sameas true %}
nginx.ingress.kubernetes.io/proxy-http-version: "1.1"
{% else %}
nginx.ingress.kubernetes.io/proxy-http-version: "1.0"
{% endif %}
如果有大佬看到了,可以簡(jiǎn)單講講Ingress會(huì)在什么時(shí)候復(fù)用http1.1的連接,以及為什么Ingress不復(fù)用每一個(gè)連接,這樣問(wèn)題會(huì)盡快的暴露,這些問(wèn)題我沒(méi)有繼續(xù)深究了。畢竟你換個(gè)語(yǔ)言比如Golang就沒(méi)有這個(gè)問(wèn)題了,這個(gè)是uwsgi專(zhuān)屬錯(cuò)誤。
總結(jié)
有關(guān)這個(gè)502問(wèn)題的排查, 我個(gè)人覺(jué)得, 最后抓包一次性解決問(wèn)題其實(shí)沒(méi)什么特別的, 抓了就能發(fā)現(xiàn)問(wèn)題, 不抓就發(fā)現(xiàn)不了。
我是希望給大家一個(gè)啟發(fā), 對(duì)于一整條鏈路, 如何來(lái)排查故障: 我們這里既使用了Nginx, 又使用了Ingress, 在排查時(shí), 需要首先檢查兩者的錯(cuò)誤數(shù)量, 如果確認(rèn)錯(cuò)誤基本一致, 那就說(shuō)明錯(cuò)誤與Nginx沒(méi)有關(guān)系, 需要檢查Ingres上的錯(cuò)誤, 對(duì)于多個(gè)中轉(zhuǎn)的請(qǐng)求, 這樣的排查能比較快的確定鏈路的錯(cuò)誤位置。