·【场景描述】

HTTP1.1之后,HTTP协议支持持久连接,也就是长连接,优点在于在一个TCP连接上可以传送多个HTTP请求和响应,减少了建立和关闭连接消耗和延迟

如果我们使用了nginx去作为反向代理或者负载均衡,从客户端过来的长连接请求就会被转换成短连接发送给服务器端。

为了支持长连接,我们需要在nginx服务器上做一些配置。

·【要求】

使用nginx时,想要做到长连接,我们必须做到以下两点:

  1. 从client到nginx是长连接
  2. 从nginx到server是长连接

对于客户端而言,nginx其实扮演着server的角色,反之,之于server,nginx就是一个client

·【保持和 Client 的长连接】

我们要想做到Client与Nginx之间保持长连接,需要:

  1. Client发送过来的请求携带"keep-alive"header
  2. Nginx设置支持keep-alive

【HTTP配置】

默认情况下,nginx已经开启了对client连接的 keepalive 支持。对于特殊场景,可以调整相关参数。

http {

keepalive_timeout 120s;        #客户端链接超时时间。为0的时候禁用长连接。

keepalive_requests 10000;    #在一个长连接上可以服务的最大请求数目

#当达到最大请求数目且所有已有请求结束后,连接被关闭。

#默认值为100

}

大多数情况下,keepalive_requests = 100也够用,但是对于 QPS 较高的场景,非常有必要加大这个参数,以避免出现大量连接被生成再抛弃的情况,减少TIME_WAIT。

QPS=10000 时,客户端每秒发送 10000 个请求 (通常建立有多个长连接),每个连接只能最多跑 100 次请求,意味着平均每秒钟就会有 100 个长连接因此被 nginx 关闭。

同样意味着为了保持 QPS,客户端不得不每秒中重新新建 100 个连接。

因此,如果用netstat命令看客户端机器,就会发现有大量的TIME_WAIT的socket连接 (即使此时keep alive已经在 Client 和 NGINX 之间生效)。

·【保持和Server的长连接】

想让Nginx和Server之间维持长连接,最朴素的设置如下:

http {

upstream backend {

server 192.168.0.1:8080 weight=1 max_fails=2 fail_timeout=30s;

server 192.168.0.2:8080 weight=1 max_fails=2 fail_timeout=30s;

  keepalive 300; // 这个很重要!

}

server {

listen 8080 default_server;

server_name "";

location / {

proxy_pass http://backend;

proxy_http_version 1.1;                         # 设置http版本为1.1

proxy_set_header Connection "";      # 设置Connection为长连接(默认为no)}

}

}

}

【upstream配置】

upstream中,有一个参数特别的重要,就是keepalive

这个参数和之前http里面的 keepalive_timeout 不一样

这个参数的含义是,连接池里面最大的空闲连接数量

不理解?没关系,我们来举个例子:

场景:

有一个HTTP服务,作为upstream服务器接收请求,响应时间为100毫秒。

要求性能达到10000 QPS,我们需要在nginx与upstream服务器之间建立大概1000条HTTP请求。(1000/0.1s=10000)

最优情况:

假设请求非常的均匀平稳,每一个请求都是100ms,请求结束会被马上放入连接池并置为idle(空闲)状态

我们以0.1s为单位:

1. 我们现在keepalive的值设置为10,每0.1s钟有1000个连接

2. 第0.1s的时候,我们一共有1000个请求收到并释放

3. 第0.2s的时候,我们又来了1000个请求,在0.2s结束的时候释放

请求和应答都比较均匀,0.1s释放的连接正好够用,不需要建立新连接,且连接池中没有idle状态的连接。

第一种情况:

应答非常平稳,但是请求不平稳的时候

4. 第0.3s的时候,我们只有500个请求收到,有500个请求因为网络延迟等原因没有进来

这个时候,Nginx检测到连接池中有500个idle状态的连接,就直接关闭了(500-10)个连接

5. 第0.4s的时候,我们收到了1500个请求,但是现在池里面只有(500+10)个连接,所以Nginx不得不重新建立了(1500-510)个连接。

如果在第4步的时候,没有关闭那490个连接的话,只需要重新建立500个连接。

第二种情况:

请求非常平稳,但是应答不平稳的时候

4. 第0.3s的时候,我们一共有1500个请求收到

但是池里面只有1000个连接,这个时候,Nginx又创建了500个连接,一共1500个连接

5. 第0.3s的时候,第0.3s的连接全部被释放,我们收到了500个请求

Nginx检测到池里面有1000个idle状态的连接,所以不得不释放了(1000-10)个连接

造成连接数量反复震荡的一个推手,就是这个keepalive 这个最大空闲连接数

上面的两种情况说的都是 keepalive 设置的不合理导致Nginx有多次释放与创建连接的过程,造成资源浪费。

keepalive 这个参数设置一定要小心,尤其是对于 QPS 要求比较高或者网络环境不稳定的场景,一般根据 QPS 值平均响应时间能大致推算出需要的长连接数量。

然后将keepalive设置为长连接数量的10%到30%。

【location配置】

http {

server {

location / {

proxy_pass http://backend;

proxy_http_version 1.1;                         # 设置http版本为1.1

proxy_set_header Connection "";      # 设置Connection为长连接(默认为no)

}

}

}

HTTP 协议中对长连接的支持是从 1.1 版本之后才有的,因此最好通过 proxy_http_version 指令设置为 1.1。

HTTP1.0不支持keepalive特性,当没有使用HTTP1.1的时候,后端服务会返回101错误,然后断开连接

而 "Connection" header 可以选择被清理,这样即便是 Client 和 Nginx 之间是短连接,Nginx 和 upstream 之间也是可以开启长连接的。

【另外一种高级方式】

http {

map $http_upgrade $connection_upgrade {

default upgrade;

'' close;

}

upstream backend {

server 192.168.0.1:8080 weight=1 max_fails=2 fail_timeout=30s;

server 192.168.0.2:8080 weight=1 max_fails=2 fail_timeout=30s;

keepalive 300;

}

server {

listen 8080 default_server;

server_name "";

location / {

proxy_pass http://backend;

proxy_connect_timeout 15;       #与upstream server的连接超时时间(没有单位,最大不可以超过75s)

proxy_read_timeout 60s;           #nginx会等待多长时间来获得请求的响应

proxy_send_timeout 12s;           #发送请求给upstream服务器的超时时间

proxy_http_version 1.1;

proxy_set_header Upgrade $http_upgrade;

proxy_set_header Connection $connection_upgrade;

}

}

}

http里面的map的作用是:

让转发到代理服务器的 "Connection" 头字段的值,取决于客户端请求头的 "Upgrade" 字段值。

如果 $http_upgrade没有匹配,那 "Connection" 头字段的值会是upgrade

如果 $http_upgrade为空字符串的话,那 "Connection" 头字段的值会是 close

【补充】

NGINX支持WebSocket。

对于NGINX将升级请求从客户端发送到后台服务器,必须明确设置Upgrade和Connection标题。

这也算是上面情况所非常常用的场景。

HTTP的Upgrade协议头机制用于将连接从HTTP连接升级到WebSocket连接,Upgrade机制使用了Upgrade协议头和Connection协议头。

为了让Nginx可以将来自客户端的Upgrade请求发送到后端服务器Upgrade和Connection的头信息必须被显式的设置

【注意】

在nginx的配置文件中,如果当前模块中没有proxy_set_header的设置,则会从上级别继承配置

继承顺序为:http, server, location

如果在下一层使用proxy_set_header修改了header的值,则所有的header值都可能会发生变化,之前继承的所有配置将会被丢弃

所以,尽量在同一个地方进行proxy_set_header,否则可能会有别的问题。

·【参考】

Nginx中文官方文档: http://www.nginx.cn/doc/

测试参考文档: https://www.lijiaocn.com/问题/2019/05/08/nginx-ingress-keep-alive-not-work.html

keep-alive参考文档: https://wglee.org/2018/12/02/nginx-keepalive/

TIME_WAIT 优化的更多相关文章

  1. TIME_WAIT 优化注意事项

    不同时开启tcp_timestamps和tcp_tw_recycle的场景描述 FULL NAT下 FULL NAT  在client请求VIP 时,不仅替换了package 的dst ip,还替换了 ...

  2. [web] 系统运维--单机

    处理过程 浏览器发送请求经过网络到达web服务器 web服务器处理请求并响应数据 响应数据从web服务器发送到用户端 用户浏览器接收数据,本地计算渲染 指标 响应时间 吞吐量 响应时间 响应时间 = ...

  3. 减少TIME_WAIT时间的优化配置

    减少TIME_WAIT时间的优化配置 建立TCP需要三次握手才能建立,而断开连接则需要四次握手.整个过程如下图所示: net.ipv4.tcp_max_syn_backlog=8192 增加TCP S ...

  4. linux 服务器优化 --TIME_WAIT 问题

    linux 服务器优化 --TIME_WAIT 问题: 问题现象: 1.外部机器不能正常连接SSH 2.内向外不能够正常的ping通过,域名也不能正常解析. 通过一些命令,查看服务器TIME_WAIT ...

  5. 解决WEB(apache)服务器time_wait过高的性能优化过程

    目录 1.网站的硬件环境 2.修改Httpd.conf 3.修改sysctl.conf文件 一.网站环境LAMP硬件环境 [root@www conf]# dmidecode -s processor ...

  6. nginx time_wait 较多优化

    1. 查看命令   netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}'   结果 ESTABLISHED 22 F ...

  7. ubuntu系统TCP连接参数优化-TIME_WAIT过多解决办法

    状态:描述CLOSED:无连接是活动的或正在进行LISTEN:服务器在等待进入呼叫SYN_RECV:一个连接请求已经到达,等待确认SYN_SENT:应用已经开始,打开一个连接ESTABLISHED:正 ...

  8. MySQL优化聊两句

    原文地址:http://www.cnblogs.com/verrion/p/mysql_optimised.html MySQL优化聊两句 MySQL不多介绍,今天聊两句该如何优化以及从哪些方面入手, ...

  9. nginx--->高并发优化

    在日常的运维工作中,经常会用到nginx服务,也时常会碰到nginx因高并发导致的性能瓶颈问题. nginx配置文件和内核参数的优化,如有不妥,敬请指出 一.nginx的配置优化 1)nginx进程数 ...

随机推荐

  1. 【C# Task】 ValueTask/Task<TResult>

    概要 1.如果异步方法的使用者使用 Task.WhenAll 或 Task.WhenAny,则在异步方法中使用 ValueTask<T> 作为返回类型可能会产生高昂的成本.这是因为您需要使 ...

  2. 十分钟掌握CSS基本内容

         (一) 定位      绝对定位和相对定位.其实用一句话说就是"子绝父相",理解这句话很多效果通过定位做出来的话都没问题了.一般平时用的都的情况都是子div设置为绝对定位 ...

  3. Ubuntu 18.04 安装配置LAMP

    --作者:飞翔的小胖猪 --创建时间:2021年5月29日 --修改时间:2021年5月29日 一.准备 1.1 环境 操作系统:Ubuntu 18.04 网页引擎:Apache php版本:7.4 ...

  4. DirectX11 With Windows SDK--36 延迟渲染基础

    前言 随着图形硬件变得越来越通用和可编程化,采用实时3D图形渲染的应用程序已经开始探索传统渲染管线的替代方案,以避免其缺点.其中一项最流行的技术就是所谓的延迟渲染.这项技术主要是为了支持大量的动态灯光 ...

  5. Qt:QNetworkRequest

    0.说明 QNetworkRequest类代表被QNetworkAccessManager发送的请求. QNetworkReuqest是网络访问API的一部分,在其内部保留了在网络上发送一个reque ...

  6. 华山论剑之 PostgreSQL sequence (一)

    前言 本文是 sequence 系列继三大数据库 sequence 之华山论剑 (Oracle PostgreSQL MySQL sequence 十年经验总结) 之后的第二篇,主要分享一下 Post ...

  7. linux添加串口权限

    通过添加到用户组的方式实现1.由于tty属于"dialout"组别,比如你的用户名是blue, 先命令查看下用户隶属的组别 groups blue 2.如果没有隶属"di ...

  8. Spring系列20:注解详解和Spring注解增强(基础内功)

    有部分小伙伴反馈说前面基于注解的Spring中大量使用注解,由于对Java的注解不熟悉,有点难受.建议总结一篇的Java注解的基础知识,那么,它来了! 本文内容 什么是注解? 如何定义注解 如何使用注 ...

  9. VIM中简化删除,光标移动和查找操作

    # 一.命令行模式下简化删除 1. 向后删除单个字符:[x] 2. 向前删除单个字符:[X] 3. 删除从光标开始到单词结尾:[dw] 删除从光标后的2个单词:[d2w] 4. 删除整个单词:[daw ...

  10. think php 框架下拉分页

    //以对象的形式获取数据库$data变量的信息,将lastPage()传输至页面 $lastpage = $data->lastPage(); $this->assign('lastpag ...