再谈nginx中的keepalive

阿凡达2018-08-21 09:21

前言

在性能测试过程中,经常会发现nginx端端口不够用的情况,出现如下错误:

connect() to 10.165.124.134:8181 failed (99: Cannot assign requested address) while connecting to upstream

问题原因:nginx和tomcat之间的连接为短连接,且无连接复用,会导致每次请求结束后,连接会断开,且需要两个2MSL的时间来回收TIME_WAIT状态的链接。当TPS过高的时候,就会使得nginx端端口资源不够用,出现上面的错误。

解决方法

  • upstream.conf中,对应的upstream配置 keepalive 100;
  • 虚拟站点site-enabled中location,增加:

      proxy_http_version 1.1;
      proxy_set_header Connection "";
    

在性能测试环境中,端口不够用的问题解决了,然后我们推荐线上配置。

但是这样真的可以了么?!

背景知识

keepalive参数的含义

Syntax: keepalive connections;
Default:    —
Context:    upstream
This directive appeared in version 1.1.4.
Activates the cache for connections to upstream servers.

The connections parameter sets the maximum number of idle keepalive connections to upstream servers that are preserved in the cache of each worker process. 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. The connections parameter should be set to a number small enough to let upstream servers process new incoming connections as well.

说明:
    1. keepalive的值表示最大的空闲链接数,并不是到上游服务的最大连接数
    2. keepalive的值不需要配置的特别大,只需要足够就可以
    3. keepalive的值如果配置的太小的话,会导致空闲链接超过最大值,不停的被回收,也是会有端口号的浪费的
    4. keepalive指定的数值是针对每个worker的,并且是针对所有后端的

分析keepalive的参数含义,我们发现:

  1. keepalive值不能配置过大:通过线上配置调试发现,如果配置过大会占用过多的连接,导致tomcat服务的currentThreadsBusy值过高而产生告警
  2. keepalive值不能配置过小:配置过小会导致nginx端检测到过多的空闲连接,依然会主动断开连接,不停的被回收,导致端口浪费。

那究竟是否应该配置,如何配置呢?

测试中的新发现

针对这个问题,对nginx配置是否配置keepalive以及如何配置,进行了系列测试:

测试目的

  • 确定是否开启keepalive
  • 确定upstream中keepalive配置多少可以被接受:
    • 保证TIME_WAIT的端口号不会过多,导致端口不够用的风险
    • 保证开启keepalive后,上游tomcat服务的currentThreadsBusy值不会过高,影响告警

测试结论

  1. 不开启keepalive,暂不存在端口号会被占用完毕的风险
    1. 测试结果显示,对于每一个upstream,可用端口号都是5.7w(65535-8192)(改写了认知,一直以为总的可用端口号是这么多
    2. 后端配置的upstream数量较多,端口被占用完成的风险暂不存在
  2. 开启keepalive的风险:
    1. 为了不影响后端tomcat对currentThreadsBusy值的监控,nginx中keepalive的值建议配置为10,但是keepalive配置过小,同样存在端口被占用的风险
    2. 且测试结果显示,同样的TPS值,开启keepalive后,nginx出现端口不够用的错误,不开启时,反而没有,后面的数据会解释下出现这个问题的原因。

其他测试发现

  • 不开启keepalive
    • 端口号的使用
      • 混合场景测试过程中:tomcat和nginx端都有大量的time_wait
      • 返回类型为applicat/json格式的单接口测试中,只有tomcat端有大量的time_wait,且出现了tomcat端端口不够用的情况
      • 返回类型为text/html格式的单接口测试中,tomcat和nginx端都有大量的time_wait
    • 抓包分析:
      • applicat/json格式的返回,tomcat会返回Fin-Ack包,tomcat主动关闭链接,tomcat端有大量的time_wait,对应application接口
      • text/html格式的返回,tomcat不会带Fin-Ack包,但是有些是nginx主动关闭链接,有些是tomcat,对应user/message接口
      • 混合接口中两种格式都有
      • 原因不明
  • 开启keepalive
    • currentThreadsBusy
      • 响应时间的长短影响tomcat currentThreadsBusy的值
      • keepalive大小影响tomcat currentThreadsBusy的值
    • 端口号的使用
      • keepalive的表示最大的空闲链接数量,如果设置过小的话,同样会导致nginx端不断的主动关闭链接
      • 测试结果显示:如果keepalive设置过小,开启keepalive反而会提前出现端口不够用的情况

测试数据

对比点一:不同返回类型端口号的使用

场景 TPS MRT nginx time_wait nginx time_wait max mobile time_wait mobile time_wait max 备注
混合场景 1840.49 52.95 23262 32618 33693 50146
混合场景,设置http协议为1.1 1588.26 52.63 133083 172038 11 23 三台mobile,nginx端出现端口不够用的情况
返回类型为json格式请求 896.15 86.83 11 23 54090 57339 返回类型json格式,tomcat端出现端口不够用的情况
返回类型为text/html格式请求 603.7 161.69 34800 48766 13633 23076 返回类型text/html格式

备注:均为100个并发

对比点二:currentThreadsBusy的影响因素

keepalive值 TPS MRT RT90值 currentThreadsBusy currentThreadsBusyMax
10 126.94 31.08 43 5 10
50 113.55 35.07 43 10 12
10 134.73 110.21 160 15 16
50 123.48 120.36 168 19 28

数据分析

  1. keepalive值配置的越高,currentThreadBusy值越高
  2. 同样的TPS值,响应越长,currentThreadBusy值越高

对比点三:开启、不开启keepalive端口号的使用

场景 TPS MRT nginx time_wait nginx time_wait max mobile time_wait mobile time_wait max 备注
不开启keepalive 1840.49 52.95 23262 32618 33693 50146
开启keepalive 1830.88 52.72 41917 57336 11 23 端口不够用


网易云新用户大礼包:https://www.163yun.com/gift

本文来自网易实践者社区,经作者侯本文授权发布。