分类目录归档:架构

nginx反向代理对后端某个节点优雅下线的问题

上次雪球的SRE同学过来交流的时候,一同聊到过关于后端节点优雅下线的一种情况:nginx将请求给了一个后端节点,这个请求在后端耗时较长,在请求还没处理完的时候后端恰好要做发布,发布时先将该节点对nginx的健康检测标记为不可用,这样nginx就将该节点从后端集群里摘掉了,若在这之后这个请求才处理完毕,是否还会正常的经过nginx返回给客户端,还是当nginx通过健康检测发现该后端节点已经不可用时,其建立的连接也已经不可用了呢?

当时问他们说也不太确定,后来忙忘了去验证一下,今晚写个小程序在tomcat端sleep 20秒才返回,然后通过nginx配置健康检测为1秒X2,测试结果表明,即使nginx发现后端节点已经不可用,只要该请求连接还保持,并不会被nginx端主动中止,20秒之后客户端仍会得到处理结果。

这样对于用nginx做负载,在后端发布时,对健康检测标记不可用之后只要再留出一定的时间让之前的请求都已响应完毕即可。

nginx与tomcat之间的keep-alive配置

今天碰到的一个情况,tomcat与前端nginx之间的存在大量的TIME_WAIT状态的连接,第一反应是这里可能没有配置keep-alive。问ops,回复说启用了;要来nginx的配置看了一下,发现upstream里设置了keepalive参数:

upstream  tomcat {
    server x.x.x.x:8080;
    ...
    keepalive 16;
}

不确定这个参数是不是http的keep-alive,在nginx的网站上找了一下

Syntax: keepalive connections;
Default:    —
Context:    upstream

The connections parameter sets the maximum number of idle keepalive connections to upstream servers that are preserved in the cache of each worker process.

它并不是与后端节点开启http-alive方式的意思,nginx作为反向代理后端并不局限http协议,这里的keepalive设置相当于每个worker连接池的最大空闲keepalive连接数,跟http里的keep-alive不是一回事。

在官方文档里明确要对后端节点使用http keep-alive 可以指定http版本为1.1:

location /http/ {
    proxy_pass http://http_backend;
    proxy_http_version 1.1;
    proxy_set_header Connection "";
    ...
}

或者仍使用http 1.0协议,但显式的设置http header里Connection参数为Keep-Alive,这是因为keep-alive是http1.1的默认特性,在1.0里最初并未实现是后来从1.1里backport到1.0的,需要显式设定这个参数才启用:

location /http/ {
    proxy_pass http://http_backend;
    proxy_http_version 1.0;
    proxy_set_header Connection "Keep-Alive";
    ...
}

为了确认有效性,可以对tomcat的logger增加一句

org.apache.coyote.http11.level = FINE

这样可以在tomcat日志里看到每个请求的http header信息:

FINE: Received [GET / HTTP/1.0
Connection: Keep-Alive
Host: localhost:8080
User-Agent: curl/7.37.1
Accept: */*

确实在header里增加了。建议还是配置为http 1.1协议,支持chunked等特性。

ps, keepalive 这个词可能是指连接池或者tcp层面的参数,要看上下文。在http里是keep-alive,注意中间有个连字符。