nginx代理node,TIME_WAIT 测试

写在前面: 阅读本文 需要了解以下知识:

       1. TIME_WAIT 是TCP连接的一种状态,对于TCP连接的双方,谁先主动断开连接,谁就要保持一段时间的TIME_WAIT状态

       2. 因为linux分配给一个用户的文件句柄是有限的(可以参考:http://blog.csdn.net/shootyou/article/details/6579139,nginx里设置了wroker_rlimit_nofile的话,会忽略ulimit -a 显示的值),而TIME_WAIT和CLOSE_WAIT两种状态如果一直被保持,那么意味着对应数目的通道就一直被占着,而且是“占着茅坑不使劲”,一旦达到句柄数上限,新的请求就无法被处理了
       注意:虽然 对nginx来说 有个参数可以突破ulimit -a 显示的数量 ,但nginx代理的上游服务器不会因nginx的设置而突破ulimit的限制。另外:如果进程启动时的ulimit是一个值,那么如果不重启这个进程,即使改了ulimit也无法对其生效。
       3. 对于nginx代理node,且同在一台机器上运行的话, time_wait 不是落在 nginx上 就是 落在node上, 要想减少整个服务器的time_wait总量,最好的个办法是重用连接,这样才能减少time_wait 的总量。

测试目标

      验证nginx 在 upstream 模块开启的 keepalive效果

测试环境

      Ubuntu16.04    nginx 1.14.2   node 8.14.0

测试代码

    1.  node  app.js

const http = require('http');
const hostname = '127.0.0.1';
const port =3000;
const server = http.createServer((req,res)=>{
        res.statusCode=200;
        res.setHeader('content-type','text/plain');
        setTimeout(function(){
                res.end('Hello World\n');
        },3000);
});
server.listen(port,hostname,()=>{
        console.log(`server running at http://${hostname}:${port}/`);
});

     node 运行在3000端口

   2. nginx.conf

events{}
http{

        upstream local {
                server 127.0.0.1:3000;
                keepalive 1; #这里为了测试方便,最大保持 1 个空闲活动连接
                #keepalive_timeout 60; #这个在nginx 1.15.3才支持
        }
        server{
                listen 1000;
                location / {
                        proxy_pass http://local;
                        proxy_set_header Connection ""; #清空这个头信息
                        proxy_http_version 1.1;#指定nginx 请求代理时使用http1.1
                }
        }
}

  这里nginx 在1000端口上 代理 3000端口的node。开启keepalive的要点:

  1) 在upstream里加入 keepalive 指令

   2)在server 里指定使用http1.1, nginx默认使用1.0。http1.1 可以重用连接,在一个连接上发送多次请求

        # 如果客户端请求nginx使用的是http1.0,头信息可能会有 connection:closed,我们需要清空这个头信息 
       proxy_set_header Connection  "";
       proxy_http_version 1.1    #指定nginx 请求node时使用http1.1

测试步骤

     1.  不开启 keepalive  (注释upstream里的 keepalive)

      通过命令循环发出4次请求,可以看到3秒一次请求

root@localhost:/www/nginx_noinlcude# for n in 1 2 3 4 ;do curl localhost:1000;date; done 
Hello World
Fri Mar  8 17:04:34 CST 2019
Hello World
Fri Mar  8 17:04:37 CST 2019
Hello World
Fri Mar  8 17:04:40 CST 2019
Hello World
Fri Mar  8 17:04:43 CST 2019

      在执行的同时,监测网络状态:

root@localhost:~# netstat -anp | grep 3000  && date
tcp        0      0 127.0.0.1:3000          0.0.0.0:*               LISTEN      1324/node       
tcp        0      0 127.0.0.1:3000          127.0.0.1:38684         ESTABLISHED 1324/node       
tcp        0      0 127.0.0.1:38684         127.0.0.1:3000          ESTABLISHED 3737/nginx: worker 
tcp        0      0 127.0.0.1:38678         127.0.0.1:3000          TIME_WAIT   -               
tcp        0      0 127.0.0.1:38672         127.0.0.1:3000          TIME_WAIT   -               
Fri Mar  8 17:06:00 CST 2019
root@localhost:~# netstat -anp | grep 3000  && date
tcp        0      0 127.0.0.1:3000          0.0.0.0:*               LISTEN      1324/node       
tcp        0      0 127.0.0.1:3000          127.0.0.1:38684         ESTABLISHED 1324/node       
tcp        0      0 127.0.0.1:38684         127.0.0.1:3000          ESTABLISHED 3737/nginx: worker 
tcp        0      0 127.0.0.1:38678         127.0.0.1:3000          TIME_WAIT   -               
tcp        0      0 127.0.0.1:38672         127.0.0.1:3000          TIME_WAIT   -               
Fri Mar  8 17:06:02 CST 2019
root@localhost:~# netstat -anp | grep 3000  && date
tcp        0      0 127.0.0.1:3000          0.0.0.0:*               LISTEN      1324/node       
tcp        0      0 127.0.0.1:38684         127.0.0.1:3000          TIME_WAIT   -               
tcp        0      0 127.0.0.1:38690         127.0.0.1:3000          ESTABLISHED 3737/nginx: worker 
tcp        0      0 127.0.0.1:38678         127.0.0.1:3000          TIME_WAIT   -               
tcp        0      0 127.0.0.1:38672         127.0.0.1:3000          TIME_WAIT   -               
tcp        0      0 127.0.0.1:3000          127.0.0.1:38690         ESTABLISHED 1324/node       
Fri Mar  8 17:06:05 CST 2019
root@localhost:~# netstat -anp | grep 3000  && date
tcp        0      0 127.0.0.1:3000          0.0.0.0:*               LISTEN      1324/node       
tcp        0      0 127.0.0.1:38684         127.0.0.1:3000          TIME_WAIT   -               
tcp        0      0 127.0.0.1:38690         127.0.0.1:3000          TIME_WAIT   -               
tcp        0      0 127.0.0.1:38678         127.0.0.1:3000          TIME_WAIT   -               
tcp        0      0 127.0.0.1:38672         127.0.0.1:3000          TIME_WAIT   -               
Fri Mar  8 17:06:08 CST 2019

   可以看到,最后有4条 time_wait ,都是由 nginx 随机端口 到 node 3000端口的连接,这说明 nginx 请求成功之后就主动断开了连接,导致time_wait状态

  2. 开启keepalive测试

  这次先在一个窗口 执行: for n in 1 2 3 4 ;do curl localhost:1000;date; done 

   同时在另一个窗口,连续执行 (curl localhost:1000 &) 

(curl localhost:1000 &)
root@localhost:/proc# (curl localhost:1000 &)
root@localhost:/proc# (curl localhost:1000 &)
root@localhost:/proc# Hello World
Hello World
Hello World

   注意:这3次执行,并没有停顿。 也就是说这3个请求是异步并发的

   再看看这次的监视结果 
 

root@localhost:~# netstat -anp | grep 3000  && date
tcp        0      0 127.0.0.1:3000          0.0.0.0:*               LISTEN      1324/node       
tcp        0      0 127.0.0.1:38744         127.0.0.1:3000          TIME_WAIT   -               
tcp        0      0 127.0.0.1:38738         127.0.0.1:3000          ESTABLISHED 3873/nginx: worker 
tcp        0      0 127.0.0.1:38754         127.0.0.1:3000          TIME_WAIT   -               
tcp        0      0 127.0.0.1:3000          127.0.0.1:38760         ESTABLISHED 1324/node       
tcp        0      0 127.0.0.1:3000          127.0.0.1:38738         ESTABLISHED 1324/node       
tcp        0      0 127.0.0.1:38760         127.0.0.1:3000          ESTABLISHED 3873/nginx: worker 
Fri Mar  8 17:14:34 CST 2019
root@localhost:~# netstat -anp | grep 3000  && date
tcp        0      0 127.0.0.1:3000          0.0.0.0:*               LISTEN      1324/node       
tcp        0      0 127.0.0.1:38744         127.0.0.1:3000          TIME_WAIT   -               
tcp        0      0 127.0.0.1:38738         127.0.0.1:3000          ESTABLISHED 3873/nginx: worker 
tcp        0      0 127.0.0.1:38754         127.0.0.1:3000          TIME_WAIT   -               
tcp        0      0 127.0.0.1:3000          127.0.0.1:38738         ESTABLISHED 1324/node       
tcp        0      0 127.0.0.1:38760         127.0.0.1:3000          TIME_WAIT   -               
Fri Mar  8 17:14:37 CST 2019
root@localhost:~# netstat -anp | grep 3000  && date
tcp        0      0 127.0.0.1:3000          0.0.0.0:*               LISTEN      1324/node       
tcp        0      0 127.0.0.1:38744         127.0.0.1:3000          TIME_WAIT   -               
tcp        0      0 127.0.0.1:38738         127.0.0.1:3000          ESTABLISHED 3873/nginx: worker 
tcp        0      0 127.0.0.1:38754         127.0.0.1:3000          TIME_WAIT   -               
tcp        0      0 127.0.0.1:3000          127.0.0.1:38738         ESTABLISHED 1324/node       
tcp        0      0 127.0.0.1:38760         127.0.0.1:3000          TIME_WAIT   -               
Fri Mar  8 17:14:40 CST 2019
root@localhost:~# netstat -anp | grep 3000  && date
tcp        0      0 127.0.0.1:3000          0.0.0.0:*               LISTEN      1324/node       
tcp        0      0 127.0.0.1:38744         127.0.0.1:3000          TIME_WAIT   -               
tcp        0      0 127.0.0.1:38738         127.0.0.1:3000          ESTABLISHED 3873/nginx: worker 
tcp        0      0 127.0.0.1:38754         127.0.0.1:3000          TIME_WAIT   -               
tcp        0      0 127.0.0.1:3000          127.0.0.1:38738         ESTABLISHED 1324/node       
tcp        0      0 127.0.0.1:38760         127.0.0.1:3000          TIME_WAIT   -               
Fri Mar  8 17:14:43 CST 2019
root@localhost:~# netstat -anp | grep 3000  && date
tcp        0      0 127.0.0.1:3000          0.0.0.0:*               LISTEN      1324/node       
tcp        0      0 127.0.0.1:38744         127.0.0.1:3000          TIME_WAIT   -               
tcp        0      0 127.0.0.1:38754         127.0.0.1:3000          TIME_WAIT   -               
tcp        0      0 127.0.0.1:3000          127.0.0.1:38738         TIME_WAIT   -               
tcp        0      0 127.0.0.1:38760         127.0.0.1:3000          TIME_WAIT   -               
Fri Mar  8 17:14:46 CST 2019

  分析监测结果 :
  1) 由于3个窗口切换,操作不是很及时,所以第一次监测结果时已经有了time_wait
  2) 最后有4 个time_wait, 其中3个是 随机端口到 node 3000端口的(这是异步请求对应的连接)      
  3) 另一个是反过来的 3000---38738(这是循环请求使用的连接),可以看到这两个端口之间的连接在中间过程一直是 ESTABLISHED 状态。
    tcp        0      0 127.0.0.1:38738         127.0.0.1:3000          ESTABLISHED 3873/nginx: worker     
    tcp        0      0 127.0.0.1:3000          127.0.0.1:38738         ESTABLISHED 1324/node

 3. 开启keepalive 但发起请求的间隔时间长

   循环请求,每次睡眠5s:
   

root@localhost:/www/nginx_noinlcude# for n in 1 2 3 4 ;do curl localhost:1000;date;sleep 5s; done
Hello World
Fri Mar  8 17:33:48 CST 2019
Hello World
Fri Mar  8 17:33:56 CST 2019
Hello World
Fri Mar  8 17:34:04 CST 2019
Hello World
Fri Mar  8 17:34:12 CST 2019

    监测结果:

root@localhost:~# netstat -anp | grep 3000  && date
tcp        0      0 127.0.0.1:3000          0.0.0.0:*               LISTEN      1324/node       
tcp        0      0 127.0.0.1:38774         127.0.0.1:3000          ESTABLISHED 3873/nginx: worker 
tcp        0      0 127.0.0.1:3000          127.0.0.1:38774         ESTABLISHED 1324/node       
Fri Mar  8 17:33:50 CST 2019
root@localhost:~# netstat -anp | grep 3000  && date
tcp        0      0 127.0.0.1:3000          0.0.0.0:*               LISTEN      1324/node       
tcp        0      0 127.0.0.1:38780         127.0.0.1:3000          ESTABLISHED 3873/nginx: worker 
tcp        0      0 127.0.0.1:3000          127.0.0.1:38780         ESTABLISHED 1324/node       
tcp        0      0 127.0.0.1:3000          127.0.0.1:38774         TIME_WAIT   -               
Fri Mar  8 17:33:54 CST 2019
root@localhost:~# netstat -anp | grep 3000  && date
tcp        0      0 127.0.0.1:3000          0.0.0.0:*               LISTEN      1324/node       
tcp        0      0 127.0.0.1:3000          127.0.0.1:38780         TIME_WAIT   -               
tcp        0      0 127.0.0.1:3000          127.0.0.1:38774         TIME_WAIT   -               
tcp        0      0 127.0.0.1:38786         127.0.0.1:3000          ESTABLISHED 3873/nginx: worker 
tcp        0      0 127.0.0.1:3000          127.0.0.1:38786         ESTABLISHED 1324/node       
Fri Mar  8 17:34:07 CST 2019
root@localhost:~# netstat -anp | grep 3000  && date
tcp        0      0 127.0.0.1:3000          0.0.0.0:*               LISTEN      1324/node       
tcp        0      0 127.0.0.1:3000          127.0.0.1:38780         TIME_WAIT   -               
tcp        0      0 127.0.0.1:3000          127.0.0.1:38792         ESTABLISHED 1324/node       
tcp        0      0 127.0.0.1:3000          127.0.0.1:38774         TIME_WAIT   -               
tcp        0      0 127.0.0.1:38792         127.0.0.1:3000          ESTABLISHED 3873/nginx: worker 
tcp        0      0 127.0.0.1:3000          127.0.0.1:38786         TIME_WAIT   -               
Fri Mar  8 17:34:13 CST 2019
root@localhost:~# netstat -anp | grep 3000  && date
tcp        0      0 127.0.0.1:3000          0.0.0.0:*               LISTEN      1324/node       
tcp        0      0 127.0.0.1:3000          127.0.0.1:38780         TIME_WAIT   -               
tcp        0      0 127.0.0.1:3000          127.0.0.1:38792         TIME_WAIT   -               
tcp        0      0 127.0.0.1:3000          127.0.0.1:38774         TIME_WAIT   -               
tcp        0      0 127.0.0.1:3000          127.0.0.1:38786         TIME_WAIT   -               
Fri Mar  8 17:34:25 CST 2019

   结果分析:
     1) 由于每次睡眠了5s, 所以虽然设置了 keepalive,但node已经等不及了,就主动关闭了连接(是node主动关闭)   
     2) 由于无空闲连接可以使用,每次请求新开辟了一个连接,最终全由node主动关闭,造成4个time_wait

 结论

  1. keepalive 不设置的话nginx不会重用连接

  2. keepalive 的值 表示 nginx 缓存的最大空闲连接,但这个连接的保持时间是有限的。
      至于这个时间是多长,在我这里发现就是5s。
      另外:nginx1.15.3之后可以在upstream里设置keepalive_timeout,但这里显示的是node主动关闭,是否能生效还需要测试
  3. keepalive 缓存的连接只有在空闲的时候才能被新的请求重用,如果请求过多,空闲连接不足,nginx仍然会发起新的连接,从而在nginx端保留很多time_wait。 所以keepalive的值需要根据实际情况调整。
  4. 理论上说 keepalive 的值应该这么算:

      假设平均请求量为 1000/s
      后端程序平均响应时长为:1s
      nginx woker进程数 : 16
      那么 keepalive的值 = 1000/16 ==62.5   大概64就好。

     这只是理论值,具体情况还需要根据可以根据服务器运行情况调整。

 

你可能感兴趣的:(nginx代理node,TIME_WAIT 测试)