现象
软件新版本上线后,系统经常时不时的出现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配置参考