我的小项目是django+uwsgi+nginx这样的结构,nginx的配置如下:
upstream myapp.test.com{
server 10.*.*.*:8080;
keepalive 768;
}
server {
listen 443 ssl;
server_name myapp.test.com;
access_log /data/log/nginx/access.log main;
error_log /data/log/nginx/error.log;
server_tokens off;
ssl on;
ssl_certificate ca256.crt;
ssl_certificate_key ca256.key;
ssl_session_timeout 30m;
ssl_protocols TLSv1.2 TLSv1.1 TLSv1;
ssl_ciphers ******;
ssl_prefer_server_ciphers on;
location ~* .*\.svn.* {
return 404;
}
location / {
include uwsgi_params;
proxy_redirect off;
proxy_store off;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $http_host;
proxy_pass http://myapp.test.com;
proxy_connect_timeout 300;
proxy_read_timeout 600;
proxy_send_timeout 300;
}
location ~.*\.(html|htm|gif|jpg|bmp|png|ico|txt|js|css)$ {
proxy_pass http://myapp.test.com;
}
location /static/ {
alias /data/MyServer;
}
}
另外还配置了
# 当一个连接送达的请求数超过该值后,该连接就会被关闭
keepalive_requests 8192;
keepalive_timeout 65;
在执行过程中,nginx异常日志中会出现一些问题:
- recv() failed (104: Connection reset by peer) while reading response header from upstream
查阅资料的时候,看到不少答案说是因为客户端发送的请求头比较大,uwsgi默认接受的buffer不足以接受,需要增加buffer-size的值。我是在并发10000请求的情况下发生的这个问题,且虽然Nginx的错误日志中有异常记录,访问日志中的状态码全是200。
追寻该问题的时候,发现这个问题涉及到了nginx的长连接。
我配置了upstream的keepalive
为768,官方解释:
- The connections parameter sets the maximum number of idle keepalive connections to upstream servers connections(设置到upstream服务器的空闲keepalive连接的最大数量)
- When this number is exceeded, the least recently used connections are closed. (当这个数量被突破时,最近使用最少的连接将被关闭)
- It should be particularly noted that the keepalive directive does not limit the total number of connections to upstream servers that an nginx worker process can open.(特别提醒:keepalive指令不会限制一个nginx worker进程到upstream服务器连接的总数量)
意思就是,当请求到达时,会使用长连接池中的长连接向后端转发请求,如果长连接池没有空闲的连接可用,那么会创建一个新的长连接去处理该请求,后端执行一段时间后,一些长连接空闲了下来,如果空闲的长连接数量多于keepalive的设置,那么会将最近最少使用的长连接关闭。nginx错误日志中出现recv() failed (104: Connection reset by peer)”和”upstream prematurely closed connection”这两个错误记录,但是访问日志中却没有出现错误的状态码,是因为nginx关闭了最近最少使用的长连接导致的。当我将配置中的以下行去除之后,该问题就消失了。
keepalive 768;
........
proxy_http_version 1.1;
proxy_set_header Connection "";
http1.1协议是默认使用长连接的,去除”proxy_http_version”和”proxy_set_header”后将使用http1.0协议;去除”keepalive 768;”的将不再使用长连接。
长连接是比较有效率的,能够节省tcp三次握手的开销。不使用长连接虽然有效减少了nginx的错误日志,但是这并不是一个好的解决方案。