一、nginx使用场景
大型应用架构中,一般会使用nginx反向代理,分为三层:
1.调用层,浏览器或APP;
2.中间层,反向代理nginx;
3.服务层,server一般是apche、tomcat
请求调用过程:
1.浏览器/app发起请求
2.DNS解析网址为ip地址
3.通过外网ip访问nginx
4.nginx发送请求给内网ip的server
上面架构,要想支持全链路的长连接,需要做到两点:
1.从client到nginx的连接是长连接;
2.从nginx到server的连接是长连接;
二、长连接设置
1.client到nginx的长连接:
由于目前浏览器默认使用HTTP/1.1,请求header中默认设置Connection:keep-alive,所以只需在nginx配置中做如下配置:
http {
keepalive_timeount 120s 120s;
keepalive_requests 10000;
}
#语法
keepalive_timeout timeout [header_timeout]
第一个参数(timeout):设置keep_alive客户端(浏览器)连接在服务端(nginx端)保持开启的超时值(默认75s);值为0会禁用keep_alive客户端连接;
第二个参数(header_timeout):可选,在响应的header中设置值"Keep-Alive:timeout=time";通常可以不用设置;
keepalive_requests这个配置项用于设置一个keep-alive连接上可以服务的请求最大数量,当达到配置的最大请求数时,连接会被关闭,默认值为100.具体过程时指一个keep-alive连接建立之后,nginx会为这个连接设置一个计数器,记录这个长连接上已经接收并处理的客户端请求的数量,一旦达到设置的最大值时,nginx会强行关闭这个长连接,此时如果客户端有新请求,就需要重新建立新的长连接。
注:在QPS较高的场景下,服务端需要将keepalive_requests设置大一些,默认数值就不够了,否则服务端可能会出现大量的TIME_WAIT状态的TCP连接数异常!另外nginx(version 1.15.3)在Upstream内增加了keepalive_requests配置项,默认值也是100,也是需要手动设置,而且这两个数量可以不一致,一般服务端要设置的大些,因为多数情况是一个nginx代理对应多个服务端。
2.nginx和server的长连接
默认情况下,nginx访问后端都是用的短连接(HTTP/1.0)一个请求来了,nginx会新开一个端口和后端建立连接,后端执行完毕后主动关闭该tcp连接。为了让nginx和后端server(nginx称之为upstream)之间保持长连接,典型设置如下:
http {
upstream http_backend {
server 192.168.2.154:8080;
server 192.168.2.109:8080;
keepalive 32; # 长连接缓存池大小为32
keepalive_timeout 120s; # 长连接失效时间
keepalive_requests 2000; # 每条长连接最大复用请求数为2000
}
server {
location /http/ {
proxy_pass http://http_backend;
proxy_http_version 1.1; # 启用HTTP/1.1版本与被代理服务器建立连接
proxy_set_header Connection "Keep-Alive"; # 设置发送被代理服务器请求头属性字段Connection
}
}
nginx 与被代理服务器间建立的长连接是通过启用 HTTP/1.1 版本协议实现的。由于 HTTP 代理模块默认会将发往被代理服务器的请求头属性字段 Connection 的值设置为 Close,因此需要通过配置指令设置请求头属性字段 Connection 的内容为"Keep-Alive"或者空值。
另外upstream中的keepalive_timeout和keepalive_requests参数与上面的含义一样,不做过多解析,需要重点关注keepalive参数,他的含义是指设置到upstream服务器的空闲keepalive连接的最大数,当这个数量被突破时,最近最少使用的连接将被关闭,另外这个参数不会限制一个nginx worker进程到upstream服务器连接的总数量,有点像线程池中的核心线程数。
注:keepalive参数设置一定要合理,尤其对于QPS比较高的场景,推荐做一下估算,根据QPS和平均响应时间大概计算出需要长连接的数量,尽量避免系统运行时产生连接数量的反复震荡,比如keepalive设置为10,前一秒系统qps较低,只需50个长连接,用完立马关闭其中50-10=40个连接,而后一秒系统qps突增,需要150个连接,空缺了150-10=140个连接,此时nginx不得不新建140个新连接来满足要求。
三、问题总结
综上所述,nginx反向代理的情况下,tcp长连接设置完成。在实际系统应用长连接的场景中,可能会出现大量TIME_WAIT的情况,这里简单做个总结:
1.导致nginx端出现大量TIME_WAIT的情况有两种:
a.keepalive_requests设置比较小,高并发下超过此值后nginx会强制关闭和客户端的长连接;(主动关闭连接后导致nginx出现TIME_WAIT)
b.keepalive设置比较小(空闲数太小),导致高并发下nginx会频繁出现连接数震荡,不停的关闭、开启和后端server的长连接;
2.导致后端server端出现大量TIME_WAIT的情况:
nginx没有打开和后端的长连接,即:没有设置proxy_http_version 1.1和proxy_set_header Connection "Keep-Alive",从而导致后端server每次请求后就关闭连接,高并发下就会出现server端的大量TIME_WAIT.