現象
軟件新版本上線后,系統經常時不時的出現500 Internal Server Error和502問題。
探查
下面是軟件的大體架構
SLB<---->traefik<--->uwsgi<---->web server
請求從瀏覽器客戶端發起,先到負載均衡,然后負載均衡轉發到traefik,traefik再轉發到具體的服務器某個端口;服務器端口后面是實際的web服務,當然,先通過uwsgi層再進入web server。
當出現500 Internal Server Error時,去查看具體的請求,發現三個蛛絲馬跡:
1.客戶端同時發送了多個相同請求;
2.在web server的日志中看不到對應的請求報文;
3.traefik日志中出現:time="2017-03-20T03:43:17Z" level=warning msg="Error forwarding to http://xx.xx.xx.xx:8888, err: http: server closed idle connection”
錯誤;
4.所有request headers和response headers中都帶有Connection: keep-alive
;
分析
1.請求在traefik和uwsgi之間中斷了;
2.跟http的長連接有關系;
解決
對于相同請求,第一個請求過來,帶了Connection:keep-alive
頭,traefik認為跟uwsgi建立了長連接通道,但由于uwsgi沒有支持長連接,在返回后就將連接關閉。當相同的第二個請求過來時,traefik還是使用之前的通道,而此時uwsgi已經關閉了連接,所以報錯:http: server closed idle connection
。
再來看系統中uwsgi.ini:
[uwsgi]
......
http-socket = 0.0.0.0:5000
http-keepalive = 1
add-header=Connection: Keep-Alive
......
雖然看上去設置了http-keepalive,但是由于http-socket不支持keep-alive,所以無用。
正確的配置方式如下:
[uwsgi]
......
http = 0.0.0.0:5000
http-keepalive = 1
add-header=Connection: Keep-Alive
......
作者 @yaoel
2017 年 05月 11日
參考
1.Traefik sporadically failing when proxying requests
2.uWSGI Options
3.HTTP權威指南 4.5.6 Keep--Alive和啞代理
4.http-socket does not support Keep-Alive
5.uwsgi.ini配置參考