站点工具


服务器技术:nginx:nginx反向代理时保持长连接

差别

这里会显示出您选择的修订版和当前版本之间的差别。

到此差别页面的链接

服务器技术:nginx:nginx反向代理时保持长连接 [2020/05/14 17:40]
admin 创建
服务器技术:nginx:nginx反向代理时保持长连接 [2020/05/14 17:54] (当前版本)
admin
行 1: 行 1:
 +<​p><​span style="​color:​ #7f6000; font-family:​ 方正隶变简体;​ font-size: 20pt;"><​strong>​【场景描述】</​strong>​ </​span></​p><​p style="​margin-left:​ 27pt;"><​span style="​font-family:​ 方正隶变简体;​ font-size: 16pt;">​HTTP1.1之后,HTTP协议支持<​span style="​color:​ #​002060;"><​strong>​持久连接</​strong></​span>​,也就是<​span style="​color:​ #​002060;"><​strong>​长连接</​strong></​span>​,优点在于在<​span style="​color:​ #​002060;"><​strong>​一个TCP连接上可以传送多个HTTP请求和响应</​strong></​span>​,减少了<​span style="​color:​ #​002060;"><​strong>​建立和关闭连接</​strong></​span>​的<​span style="​color:​ #​002060;"><​strong>​消耗和延迟</​strong></​span>​。 </​span></​p><​p style="​margin-left:​ 27pt;"><​span style="​font-family:​ 方正隶变简体;​ font-size: 16pt;">​如果我们使用了nginx去作为<​span style="​color:​ #​002060;"><​strong>​反向代理或者负载均衡</​strong></​span>​,从客户端过来的长连接请求就会被<​span style="​color:​ #​002060;"><​strong>​转换成短连接</​strong></​span>​发送给服务器端。 </​span></​p><​p style="​margin-left:​ 27pt;"><​span style="​font-family:​ 方正隶变简体;​ font-size: 16pt;">​为了<​span style="​color:​ #​002060;"><​strong>​支持长连接</​strong></​span>​,我们需要在nginx服务器上做一些配置。 </​span></​p><​p>&​nbsp;​ &​nbsp;</​p><​p><​span style="​color:​ #7f6000; font-family:​ 方正隶变简体;​ font-size: 20pt;"><​strong>​·【要求】</​strong>​ </​span></​p><​p style="​margin-left:​ 27pt;"><​span style="​font-family:​ 方正隶变简体;​ font-size: 16pt;">​使用nginx时,想要做到长连接,我们必须做到以下两点: </​span></​p><​ol style="​margin-left:​ 81pt;" class="​ list-paddingleft-2"><​li><​p><​span style="​color:​ #00b050; font-family:​ 方正隶变简体;​ font-size: 16pt;"><​strong>​从client到nginx是长连接 </​strong></​span></​p></​li><​li><​p><​span style="​color:​ #00b050; font-family:​ 方正隶变简体;​ font-size: 16pt;"><​strong>​从nginx到server是长连接 </​strong></​span></​p></​li></​ol><​p>&​nbsp;​ &​nbsp;</​p><​p style="​margin-left:​ 27pt;"><​span style="​font-family:​ 方正隶变简体;​ font-size: 16pt;">​对于客户端而言,<​strong>​nginx其实扮演着server的角色</​strong>​,反之,之于server,<​strong>​nginx就是一个client</​strong>​。 </​span></​p><​p style="​margin-left:​ 27pt;">&​nbsp;​ &​nbsp;</​p><​p><​span style="​color:​ #7f6000; font-family:​ 方正隶变简体;​ font-size: 20pt;"><​strong>​·【保持和 Client 的长连接】</​strong>​ </​span></​p><​p style="​margin-left:​ 27pt;"><​span style="​font-family:​ 方正隶变简体;​ font-size: 16pt;">​我们要想做到Client与Nginx之间保持长连接,需要: </​span></​p><​ol style="​margin-left:​ 81pt;" class="​ list-paddingleft-2"><​li><​p><​span style="​font-size:​ 16pt;"><​span style="​font-family:​ 方正隶变简体;">​Client发送过来的请求携带<​span style="​color:​ #​c00000;"><​strong>&​quot;​keep</​strong></​span></​span><​strong>​-<​span style="​color:​ #c00000; font-family:​ 方正隶变简体;">​alive&​quot;​header</​span></​strong><​span style="​font-family:​ 方正隶变简体;">​。 </​span></​span></​p></​li><​li><​p><​span style="​font-family:​ 方正隶变简体;​ font-size: 16pt;">​Nginx设置<​span style="​color:​ #​c00000;"><​strong>​支持keep-alive</​strong></​span>​ </​span></​p></​li></​ol><​p>&​nbsp;​ &​nbsp;</​p><​p style="​margin-left:​ 27pt;"><​span style="​color:​ #bf9000; font-family:​ 方正隶变简体;​ font-size: 18pt;">​【HTTP配置】 </​span></​p><​p style="​margin-left:​ 54pt;"><​span style="​font-family:​ 方正隶变简体;​ font-size: 16pt;"><​span style="​color:​ #​002060;"><​strong>​默认情况</​strong></​span>​下,nginx<​span style="​color:​ #​002060;"><​strong>​已经开启</​strong></​span>​了对client连接的 keepalive 支持。对于特殊场景,可以调整相关参数。 </​span></​p><​table width="​917"><​colgroup><​col style="​width:​ 471px;"/></​colgroup><​tbody valign="​top"><​tr class="​firstRow"><​td style="​border:​ solid #a3a3a3 1.0pt; padding: 5px;"><​p><​span style="​font-family:​ 方正隶变简体;​ font-size: 16pt;">​http { </​span></​p><​p style="​margin-left:​ 27pt;"><​span style="​font-family:​ 方正隶变简体;​ font-size: 16pt;"><​span style="​color:​ #​c00000;"><​strong>​keepalive_timeout</​strong></​span>​ 120s;&​nbsp;​ &nbsp; &nbsp; &nbsp; #<span style="​color:​ #​00b050;"><​strong>​客户端链接超时时间</​strong></​span>​。为0的时候禁用长连接。 </​span></​p><​p style="​margin-left:​ 27pt;"><​span style="​font-family:​ 方正隶变简体;​ font-size: 16pt;"><​span style="​color:​ #​c00000;"><​strong>​keepalive_requests</​strong></​span>​ 10000;&​nbsp;​ &nbsp; #<span style="​color:​ #​00b050;"><​strong>​在一个长连接上可以服务的最大请求数目</​strong></​span>​。 </​span></​p><​p style="​margin-left:​ 27pt;"><​span style="​font-family:​ 方正隶变简体;​ font-size: 16pt;">&​nbsp;​ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; #​当达到最大请求数目且所有已有请求结束后,连接被关闭。 </​span></​p><​p style="​margin-left:​ 27pt;"><​span style="​font-family:​ 方正隶变简体;​ font-size: 16pt;">&​nbsp;​ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; #​默认值为100 </​span></​p><​p><​span style="​font-family:​ 方正隶变简体;​ font-size: 16pt;">​}</​span></​p></​td></​tr></​tbody></​table><​p style="​margin-left:​ 54pt;">&​nbsp;​ &​nbsp;</​p><​p style="​margin-left:​ 54pt;"><​span style="​font-size:​ 16pt;"><​span style="​font-family:​ 方正隶变简体;">​大多数情况下,keepalive_requests = 100也够用,但是对于<​span style="​color:​ #​002060;"><​strong>​ QPS 较高</​strong></​span>​的场景,非常有必要<​span style="​color:​ #​002060;"><​strong>​加大</​strong></​span>​这个参数,以避免出现大量连接被生成再抛弃的情况,减少TIME_WAIT。<​br/></​span><​span style="​font-family:​ Calibri;">&​nbsp;</​span></​span></​p><​p style="​margin-left:​ 54pt;"><​span style="​font-family:​ 方正隶变简体;​ font-size: 16pt;">​QPS=10000 时,客户端每秒发送 10000 个请求 (通常建立有多个长连接),每个连接只能最多跑 100 次请求,意味着平均每秒钟就会有 100 个长连接因此被 nginx 关闭。</​span></​p><​p style="​margin-left:​ 54pt;"><​span style="​font-family:​ 方正隶变简体;​ font-size: 16pt;">​同样意味着为了保持 QPS,客户端不得不每秒中重新新建 100 个连接。</​span></​p><​p style="​margin-left:​ 54pt;">&​nbsp;​ 
 +&​nbsp;</​p><​p style="​margin-left:​ 54pt;"><​span style="​font-family:​ 方正隶变简体;​ font-size: 16pt;">​因此,如果用<​span style="​color:​ #​002060;"><​strong>​netstat</​strong></​span>​命令看客户端机器,就会发现有<​span style="​color:​ #​002060;"><​strong>​大量的TIME_WAIT的socket连接</​strong></​span>​ (即使此时keep alive已经在 Client 和 NGINX 之间生效)。</​span></​p><​p style="​margin-left:​ 54pt;">&​nbsp;​ 
 +&​nbsp;</​p><​p><​span style="​color:​ #7f6000; font-family:​ 方正隶变简体;​ font-size: 20pt;"><​strong>​·【保持和Server的长连接】</​strong></​span></​p><​p style="​margin-left:​ 27pt;"><​span style="​font-family:​ 方正隶变简体;​ font-size: 16pt;">​想让Nginx和Server之间维持长连接,最朴素的设置如下:</​span></​p><​table width="​988"><​colgroup><​col style="​width:​ 543px;"/></​colgroup><​tbody valign="​top"><​tr class="​firstRow"><​td style="​border:​ solid #a3a3a3 1.0pt; padding: 5px;"><​p><​span style="​font-family:​ 方正隶变简体;​ font-size: 16pt;">​http {</​span></​p><​p style="​margin-left:​ 27pt;"><​span style="​font-family:​ 方正隶变简体;​ font-size: 16pt;">​upstream backend {</​span></​p><​p style="​margin-left:​ 57px;"><​span style="​font-family:​ 方正隶变简体;​ font-size: 16pt;">&​nbsp;​ server &nbsp; 192.168.0.1:8080 &​nbsp;​weight=1 max_fails=2 fail_timeout=30s;</​span></​p><​p style="​margin-left:​ 57px;"><​span style="​font-family:​ 方正隶变简体;​ font-size: 16pt;">&​nbsp;​ server &nbsp; 192.168.0.2:8080 &​nbsp;​weight=1 max_fails=2 fail_timeout=30s;</​span></​p><​p style="​margin-left:​ 57px;"><​span style="​color:​ #c00000; font-family:​ 方正隶变简体;​ font-size: 16pt;"><​strong>&​nbsp;​ keepalive 300; &nbsp; &nbsp; &​nbsp;//​ 这个很重要!</​strong></​span></​p><​p style="​margin-left:​ 27pt;"><​span style="​font-family:​ 方正隶变简体;​ font-size: 16pt;">​}</​span>&​nbsp;​ &​nbsp;</​p><​p style="​margin-left:​ 27pt;"><​span style="​font-family:​ 方正隶变简体;​ font-size: 16pt;">​server {</​span></​p><​p style="​margin-left:​ 54pt;"><​span style="​font-family:​ 方正隶变简体;​ font-size: 16pt;">​listen 8080 default_server;</​span></​p><​p style="​margin-left:​ 54pt;"><​span style="​font-family:​ 方正隶变简体;​ font-size: 16pt;">​server_name &​quot;&​quot;;</​span></​p><​p style="​margin-left:​ 54pt;">&​nbsp;​ 
 +&​nbsp;</​p><​p style="​margin-left:​ 54pt;"><​span style="​font-family:​ 方正隶变简体;​ font-size: 16pt;">​location / {</​span></​p><​p style="​margin-left:​ 81pt;"><​span style="​font-family:​ 方正隶变简体;​ font-size: 16pt;">​proxy_pass <a href="​http://​backend">​http://​backend</​a>;</​span></​p><​p style="​margin-left:​ 81pt;"><​span style="​font-family:​ 方正隶变简体;​ font-size: 16pt;"><​span style="​color:​ #​c00000;"><​strong>​proxy_http_version 1.1;</​strong></​span>&​nbsp;​ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;# <span style="​color:​ #​00b050;"><​strong>​设置http版本为1.1</​strong></​span></​span></​p><​p style="​margin-left:​ 81pt;"><​span style="​font-family:​ 方正隶变简体;​ font-size: 16pt;"><​span style="​color:​ #​c00000;"><​strong>​proxy_set_header Connection &​quot;&​quot;;</​strong></​span>&​nbsp;​ &nbsp; &nbsp; #&​nbsp;<​span style="​color:​ #​00b050;"><​strong>​设置Connection为长连接</​strong></​span>​(默认为<​strong>​no</​strong>​)}</​span></​p><​p style="​margin-left:​ 54pt;"><​span style="​font-family:​ 方正隶变简体;​ font-size: 16pt;">​}</​span></​p><​p style="​margin-left:​ 27pt;"><​span style="​font-family:​ 方正隶变简体;​ font-size: 16pt;">​}</​span></​p><​p><​span style="​font-family:​ 方正隶变简体;​ font-size: 16pt;">​}</​span></​p></​td></​tr></​tbody></​table><​p style="​margin-left:​ 27pt;">&​nbsp;​ 
 +&​nbsp;</​p><​p style="​margin-left:​ 27pt;"><​span style="​color:​ #bf9000; font-family:​ 方正隶变简体;​ font-size: 18pt;">​【upstream配置】</​span></​p><​p style="​margin-left:​ 54pt;"><​span style="​font-family:​ 方正隶变简体;​ font-size: 16pt;">​upstream中,有一个参数特别的重要,就是<​span style="​color:​ #​c00000;"><​strong>​keepalive</​strong></​span>​。</​span></​p><​p style="​margin-left:​ 54pt;"><​span style="​font-family:​ 方正隶变简体;​ font-size: 16pt;">​这个参数和<​span style="​color:​ #​002060;"><​strong>​之前http里面的 &​nbsp;​keepalive_timeout &​nbsp;​不一样</​strong></​span>​。</​span></​p><​p style="​margin-left:​ 54pt;"><​span style="​font-family:​ 方正隶变简体;​ font-size: 16pt;">​这个参数的含义是,<​span style="​color:​ #​00b050;"><​strong>​连接池里面最大的空闲连接数量</​strong></​span>​。</​span></​p><​p style="​margin-left:​ 54pt;">&​nbsp;​ 
 +&​nbsp;</​p><​p style="​margin-left:​ 54pt;"><​span style="​font-family:​ 方正隶变简体;​ font-size: 16pt;">​不理解?没关系,我们来举个例子:</​span></​p><​p style="​margin-left:​ 54pt;"><​span style="​font-family:​ 方正隶变简体;​ font-size: 16pt;">​场景:</​span></​p><​p style="​margin-left:​ 81pt;"><​span style="​font-family:​ 方正隶变简体;​ font-size: 16pt;">​有一个HTTP服务,作为upstream服务器接收请求,响应时间为100毫秒。</​span></​p><​p style="​margin-left:​ 81pt;"><​span style="​font-family:​ 方正隶变简体;​ font-size: 16pt;">​要求性能达到10000 QPS,我们需要在nginx与upstream服务器之间建立大概1000条HTTP请求。(1000/​0.1s=10000)</​span></​p><​p style="​margin-left:​ 54pt;">&​nbsp;​ 
 +&​nbsp;</​p><​p style="​margin-left:​ 54pt;"><​span style="​font-family:​ 方正隶变简体;​ font-size: 16pt;">​最优情况:</​span></​p><​p style="​margin-left:​ 81pt;"><​span style="​font-family:​ 方正隶变简体;​ font-size: 16pt;">​假设<​span style="​color:​ #​002060;"><​strong>​请求非常的均匀平稳</​strong></​span>​,每一个请求都是100ms,请求结束会被马上放入连接池并置为<​span style="​color:​ #​002060;"><​strong>​idle(空闲)状态</​strong></​span>​。</​span></​p><​p style="​margin-left:​ 81pt;"><​span style="​font-family:​ 方正隶变简体;​ font-size: 16pt;">​我们以0.1s为单位:</​span></​p><​p style="​margin-left:​ 81pt;"><​span style="​font-family:​ 方正隶变简体;​ font-size: 16pt;">​1. &​nbsp;​我们现在keepalive的值设置为10,每0.1s钟有1000个连接</​span></​p><​p style="​margin-left:​ 81pt;"><​span style="​font-family:​ 方正隶变简体;​ font-size: 16pt;">​2. 第0.1s的时候,我们一共有1000个请求收到并释放</​span></​p><​p style="​margin-left:​ 81pt;"><​span style="​font-family:​ 方正隶变简体;​ font-size: 16pt;">​3. 第0.2s的时候,我们又来了1000个请求,在0.2s结束的时候释放</​span></​p><​p style="​margin-left:​ 81pt;">&​nbsp;​ 
 +&​nbsp;</​p><​p style="​margin-left:​ 81pt;"><​span style="​font-family:​ 方正隶变简体;​ font-size: 16pt;"><​span style="​color:​ #​002060;"><​strong>​请求和应答都比较均匀</​strong></​span>​,0.1s释放的连接正好够用,不需要建立新连接,且连接池中没有idle状态的连接。</​span></​p><​p style="​margin-left:​ 81pt;">&​nbsp;​ 
 +&​nbsp;</​p><​p style="​margin-left:​ 54pt;"><​span style="​font-family:​ 方正隶变简体;​ font-size: 16pt;">​第一种情况:</​span></​p><​p style="​margin-left:​ 81pt;"><​span style="​font-family:​ 方正隶变简体;​ font-size: 16pt;"><​span style="​color:​ #​002060;"><​strong>​应答非常平稳,但是请求不平稳</​strong></​span>​的时候</​span></​p><​p style="​margin-left:​ 81pt;"><​span style="​font-family:​ 方正隶变简体;​ font-size: 16pt;">​4. 第0.3s的时候,我们只有500个请求收到,有500个请求因为网络延迟等原因没有进来</​span></​p><​p style="​margin-left:​ 81pt;"><​span style="​font-family:​ 方正隶变简体;​ font-size: 16pt;">​ &nbsp; &​nbsp;​这个时候,Nginx检测到连接池中有500个idle状态的连接,就直接关闭了(500-10)个连接</​span></​p><​p style="​margin-left:​ 81pt;"><​span style="​font-family:​ 方正隶变简体;​ font-size: 16pt;">​5. 第0.4s的时候,我们收到了1500个请求,但是现在池里面只有(500+10)个连接,所以Nginx不得不重新建立了(1500-510)个连接。</​span></​p><​p style="​margin-left:​ 81pt;"><​span style="​font-family:​ 方正隶变简体;​ font-size: 16pt;">​ &nbsp; &nbsp; 如果在第4步的时候,没有关闭那490个连接的话,只需要重新建立500个连接。</​span></​p><​p style="​margin-left:​ 81pt;">&​nbsp;​ 
 +&​nbsp;</​p><​p style="​margin-left:​ 54pt;"><​span style="​font-family:​ 方正隶变简体;​ font-size: 16pt;">​第二种情况:</​span></​p><​p style="​margin-left:​ 81pt;"><​span style="​font-family:​ 方正隶变简体;​ font-size: 16pt;"><​span style="​color:​ #​002060;"><​strong>​请求非常平稳,但是应答不平稳</​strong></​span>​的时候</​span></​p><​p style="​margin-left:​ 81pt;"><​span style="​font-family:​ 方正隶变简体;​ font-size: 16pt;">​4. 第0.3s的时候,我们一共有1500个请求收到</​span></​p><​p style="​margin-left:​ 81pt;"><​span style="​font-family:​ 方正隶变简体;​ font-size: 16pt;">​ &nbsp; &​nbsp;​但是池里面只有1000个连接,这个时候,Nginx又创建了500个连接,一共1500个连接</​span></​p><​p style="​margin-left:​ 81pt;"><​span style="​font-family:​ 方正隶变简体;​ font-size: 16pt;">​5. 第0.3s的时候,第0.3s的连接全部被释放,我们收到了500个请求</​span></​p><​p style="​margin-left:​ 81pt;"><​span style="​font-family:​ 方正隶变简体;​ font-size: 16pt;">​ &nbsp; &nbsp; Nginx检测到池里面有1000个idle状态的连接,所以不得不释放了(1000-10)个连接</​span></​p><​p style="​margin-left:​ 54pt;">&​nbsp;​ 
 +&​nbsp;</​p><​p style="​margin-left:​ 54pt;"><​span style="​font-family:​ 方正隶变简体;​ font-size: 16pt;">​造成<​span style="​color:​ #​002060;"><​strong>​连接数量反复震荡</​strong></​span>​的一个推手,就是这个<​span style="​color:​ #​002060;"><​strong>​keepalive</​strong></​span>​ 这个<​span style="​color:​ #​002060;"><​strong>​最大空闲连接数</​strong></​span>​。</​span></​p><​p style="​margin-left:​ 54pt;"><​span style="​font-family:​ 方正隶变简体;​ font-size: 16pt;">​上面的两种情况说的都是 &​nbsp;​keepalive &​nbsp;​设置的不合理导致Nginx有多次释放与创建连接的过程,造成资源浪费。</​span></​p><​p style="​margin-left:​ 54pt;">&​nbsp;​ 
 +&​nbsp;</​p><​p style="​margin-left:​ 54pt;"><​span style="​font-family:​ 方正隶变简体;​ font-size: 16pt;">​keepalive 这个参数设置一定要小心,尤其是对于 <span style="​color:​ #​002060;"><​strong>​QPS 要求比较高</​strong></​span>​或者<​span style="​color:​ #​002060;"><​strong>​网络环境不稳定</​strong></​span>​的场景,一般根据 <span style="​color:​ #​002060;"><​strong>​QPS 值</​strong></​span>​和 <span style="​color:​ #​002060;"><​strong>​平均响应时间</​strong></​span>​能大致推算出需要的长连接数量。</​span></​p><​p style="​margin-left:​ 54pt;"><​span style="​font-family:​ 方正隶变简体;​ font-size: 16pt;">​然后将keepalive设置为长连接数量的10%到30%。</​span></​p><​p style="​margin-left:​ 54pt;">&​nbsp;​ 
 +&​nbsp;</​p><​p style="​margin-left:​ 27pt;"><​span style="​color:​ #bf9000; font-family:​ 方正隶变简体;​ font-size: 18pt;">​【location配置】</​span></​p><​table width="​910"><​colgroup><​col style="​width:​ 507px;"/></​colgroup><​tbody valign="​top"><​tr class="​firstRow"><​td style="​border:​ solid #a3a3a3 1.0pt; padding: 5px;"><​p><​span style="​font-family:​ 方正隶变简体;​ font-size: 16pt;">​http {</​span></​p><​p style="​margin-left:​ 27pt;"><​span style="​font-family:​ 方正隶变简体;​ font-size: 16pt;">​server {</​span></​p><​p style="​margin-left:​ 54pt;"><​span style="​font-family:​ 方正隶变简体;​ font-size: 16pt;">​location / &​nbsp;​{</​span></​p><​p style="​margin-left:​ 81pt;"><​span style="​font-family:​ 方正隶变简体;​ font-size: 16pt;">​proxy_pass <a href="​http://​backend">​http://​backend</​a>;</​span></​p><​p style="​margin-left:​ 81pt;"><​span style="​font-family:​ 方正隶变简体;​ font-size: 16pt;"><​span style="​color:​ #​c00000;"><​strong>​proxy_http_version 1.1</​strong></​span>;&​nbsp;​ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;# <span style="​color:​ #​00b050;"><​strong>​设置http版本为1.1</​strong></​span></​span></​p><​p style="​margin-left:​ 81pt;"><​span style="​font-family:​ 方正隶变简体;​ font-size: 16pt;"><​span style="​color:​ #​c00000;"><​strong>​proxy_set_header Connection</​strong></​span>​ &​quot;&​quot;;&​nbsp;​ &nbsp; &nbsp; #&​nbsp;<​span style="​color:​ #​00b050;"><​strong>​设置Connection为长连接</​strong></​span>​(默认为no)</​span></​p><​p style="​margin-left:​ 54pt;"><​span style="​font-family:​ 方正隶变简体;​ font-size: 16pt;">​}</​span></​p><​p style="​margin-left:​ 27pt;"><​span style="​font-family:​ 方正隶变简体;​ font-size: 16pt;">​}</​span></​p><​p><​span style="​font-family:​ 方正隶变简体;​ font-size: 16pt;">​}</​span></​p></​td></​tr></​tbody></​table><​p style="​margin-left:​ 54pt;"><​span style="​font-family:​ 方正隶变简体;​ font-size: 16pt;">​HTTP 协议中<​span style="​color:​ #​002060;"><​strong>​对长连接的支持是从 1.1 版本之后才有</​strong></​span>​的,因此最好通过 proxy_http_version 指令设置为 1.1。</​span></​p><​p style="​margin-left:​ 54pt;"><​span style="​font-family:​ 方正隶变简体;​ font-size: 16pt;"><​span style="​color:​ #​002060;"><​strong>​HTTP1.0不支持keepalive特性</​strong></​span>​,当<​strong>​没有使用HTTP1.1</​strong>​的时候,后端服务会<​span style="​color:​ #​002060;"><​strong>​返回101错误</​strong></​span>​,然后<​span style="​color:​ #​002060;"><​strong>​断开连接</​strong></​span>​。</​span></​p><​p style="​margin-left:​ 54pt;">&​nbsp;​ 
 +&​nbsp;</​p><​p style="​margin-left:​ 54pt;"><​span style="​font-family:​ 方正隶变简体;​ font-size: 16pt;">​而 &​quot;​Connection&​quot;​ header 可以<​span style="​color:​ #​002060;"><​strong>​选择被清理</​strong></​span>​,这样即便是 Client 和 Nginx 之间是短连接,Nginx 和 upstream 之间也是可以开启长连接的。</​span></​p><​p style="​margin-left:​ 54pt;">&​nbsp;​ 
 +&​nbsp;</​p><​p style="​margin-left:​ 27pt;"><​span style="​color:​ #bf9000; font-family:​ 方正隶变简体;​ font-size: 18pt;">​【另外一种高级方式】</​span></​p><​table style=""><​colgroup><​col style="​width:​ 507px;"/></​colgroup><​tbody valign="​top"><​tr class="​firstRow"><​td style="​border:​ solid #a3a3a3 1.0pt; padding: 5px;" width="​1014"><​p><​span style="​font-family:​ 方正隶变简体;​ font-size: 16pt;">​http { &nbsp; &​nbsp;</​span></​p><​p style="​margin-left:​ 27pt;"><​span style="​color:​ #c00000; font-family:​ 方正隶变简体;​ font-size: 16pt;"><​strong>​map $http_upgrade $connection_upgrade {</​strong></​span></​p><​p style="​margin-left:​ 54pt;"><​span style="​color:​ #c00000; font-family:​ 方正隶变简体;​ font-size: 16pt;"><​strong>​default upgrade;</​strong></​span></​p><​p style="​margin-left:​ 54pt;"><​span style="​color:​ #c00000; font-family:​ 方正隶变简体;​ font-size: 16pt;"><​strong>&#​39;&#​39;​ close;</​strong></​span></​p><​p style="​margin-left:​ 27pt;"><​span style="​color:​ #c00000; font-family:​ 方正隶变简体;​ font-size: 16pt;"><​strong>​}</​strong></​span>&​nbsp;​ &​nbsp;</​p><​p style="​margin-left:​ 27pt;"><​span style="​font-family:​ 方正隶变简体;​ font-size: 16pt;">​upstream backend {</​span></​p><​p style="​margin-left:​ 54pt;"><​span style="​font-family:​ 方正隶变简体;​ font-size: 16pt;">​server &nbsp; 192.168.0.1:8080 &​nbsp;​weight=1 max_fails=2 fail_timeout=30s;</​span></​p><​p style="​margin-left:​ 54pt;"><​span style="​font-family:​ 方正隶变简体;​ font-size: 16pt;">​server &nbsp; 192.168.0.2:8080 &​nbsp;​weight=1 max_fails=2 fail_timeout=30s;</​span></​p><​p style="​margin-left:​ 54pt;"><​span style="​font-family:​ 方正隶变简体;​ font-size: 16pt;">​keepalive 300;</​span></​p><​p style="​margin-left:​ 27pt;"><​span style="​font-family:​ 方正隶变简体;​ font-size: 16pt;">​}</​span>&​nbsp;​ &​nbsp;</​p><​p style="​margin-left:​ 27pt;"><​span style="​font-family:​ 方正隶变简体;​ font-size: 16pt;">​server {</​span></​p><​p style="​margin-left:​ 54pt;"><​span style="​font-family:​ 方正隶变简体;​ font-size: 16pt;">​listen 8080 default_server;</​span></​p><​p style="​margin-left:​ 54pt;"><​span style="​font-family:​ 方正隶变简体;​ font-size: 16pt;">​server_name &​quot;&​quot;;</​span></​p><​p style="​margin-left:​ 54pt;"><​span style="​font-family:​ 方正隶变简体;​ font-size: 16pt;">​location / {</​span></​p><​p style="​margin-left:​ 81pt;"><​span style="​font-family:​ 方正隶变简体;​ font-size: 16pt;">​proxy_pass <a href="​http://​backend">​http://​backend</​a>;</​span></​p><​p style="​margin-left:​ 81pt;">&​nbsp;​ 
 +&​nbsp;</​p><​p style="​margin-left:​ 81pt;"><​span style="​font-family:​ 方正隶变简体;​ font-size: 16pt;"><​span style="​color:​ #​c00000;"><​strong>​proxy_connect_timeout 15;</​strong></​span>&​nbsp;​ &nbsp; &nbsp; &​nbsp;#<​span style="​color:​ #​00b050;">​与upstream server的连接超时时间</​span>​(没有单位,最大不可以超过75s)</​span></​p><​p style="​margin-left:​ 81pt;"><​span style="​font-family:​ 方正隶变简体;​ font-size: 16pt;"><​span style="​color:​ #​c00000;"><​strong>​proxy_read_timeout 60s;</​strong></​span>&​nbsp;​ &nbsp; &nbsp; &nbsp; &nbsp; &​nbsp;#<​span style="​color:​ #​00b050;">​nginx会等待多长时间来获得请求的响应</​span></​span></​p><​p style="​margin-left:​ 81pt;"><​span style="​font-family:​ 方正隶变简体;​ font-size: 16pt;"><​span style="​color:​ #​c00000;"><​strong>​proxy_send_timeout 12s;</​strong></​span>&​nbsp;​ &nbsp; &nbsp; &nbsp; &nbsp; &​nbsp;#<​span style="​color:​ #​00b050;">​发送请求给upstream服务器的超时时间</​span></​span>&​nbsp;​ &​nbsp;</​p><​p style="​margin-left:​ 81pt;"><​span style="​font-family:​ 方正隶变简体;​ font-size: 16pt;">​proxy_http_version &nbsp; 1.1; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  
 +</​span></​p><​p style="​margin-left:​ 81pt;"><​span style="​color:​ #c00000; font-family:​ 方正隶变简体;​ font-size: 16pt;"><​strong>​proxy_set_header &nbsp; &​nbsp;​Upgrade &nbsp; &​nbsp;​$http_upgrade;</​strong></​span></​p><​p style="​margin-left:​ 81pt;"><​span style="​color:​ #c00000; font-family:​ 方正隶变简体;​ font-size: 16pt;"><​strong>​proxy_set_header &nbsp; &​nbsp;​Connection &nbsp; &nbsp; $connection_upgrade;</​strong></​span></​p><​p style="​margin-left:​ 54pt;"><​span style="​font-family:​ 方正隶变简体;​ font-size: 16pt;">​ }</​span></​p><​p style="​margin-left:​ 27pt;"><​span style="​font-family:​ 方正隶变简体;​ font-size: 16pt;">​}</​span></​p><​p><​span style="​font-family:​ 方正隶变简体;​ font-size: 16pt;">​}</​span></​p></​td></​tr></​tbody></​table><​p style="​margin-left:​ 54pt;">&​nbsp;​ 
 +&​nbsp;</​p><​p style="​margin-left:​ 54pt;"><​span style="​font-family:​ 方正隶变简体;​ font-size: 16pt;">​http里面的map的作用是:</​span></​p><​p style="​margin-left:​ 81pt;"><​span style="​font-family:​ 方正隶变简体;​ font-size: 16pt;">​让转发到代理服务器的<​strong><​span style="​color:​ #​00b050;">​ &​quot;​Connection&​quot;</​span>​ 头字段</​strong>​的值,<​span style="​color:​ #​c00000;"><​strong>​取决于</​strong></​span>​客户端请求头的 <span style="​color:​ #​00b050;"><​strong>&​quot;​Upgrade&​quot;</​strong></​span>​ 字段值。</​span></​p><​p style="​margin-left:​ 81pt;"><​span style="​font-family:​ 方正隶变简体;​ font-size: 16pt;">​如果<​span style="​color:​ #​002060;"><​strong>​ $http_upgrade没有匹配</​strong></​span>​,那 &​quot;<​span style="​color:​ #​002060;"><​strong>​Connection</​strong></​span>&​quot;​ 头字段的值会是<​span style="​color:​ #​002060;"><​strong>​upgrade</​strong></​span>​。</​span></​p><​p style="​margin-left:​ 81pt;"><​span style="​font-family:​ 方正隶变简体;​ font-size: 16pt;">​如果<​span style="​color:​ #​002060;"><​strong>​ $http_upgrade为空字符串</​strong></​span>​的话,那 &​quot;<​span style="​color:​ #​002060;"><​strong>​Connection</​strong></​span>&​quot;​ 头字段的值会是 <span style="​color:​ #​002060;"><​strong>​close</​strong></​span>​。</​span></​p><​p style="​margin-left:​ 81pt;">&​nbsp;​ 
 +&​nbsp;</​p><​p style="​margin-left:​ 27pt;"><​span style="​color:​ #bf9000; font-family:​ 方正隶变简体;​ font-size: 18pt;">​【补充】</​span></​p><​p style="​margin-left:​ 54pt;"><​span style="​font-family:​ 方正隶变简体;​ font-size: 16pt;"><​strong>​NGINX支持WebSocket。</​strong></​span></​p><​p style="​margin-left:​ 54pt;"><​span style="​font-family:​ 方正隶变简体;​ font-size: 16pt;">​对于NGINX将<​span style="​color:​ #​c00000;"><​strong>​升级请求</​strong></​span>​从客户端发送到后台服务器,必须<​span style="​color:​ #​c00000;"><​strong>​明确设置</​strong></​span>​Upgrade和Connection标题。</​span></​p><​p style="​margin-left:​ 54pt;"><​span style="​font-family:​ 方正隶变简体;​ font-size: 16pt;">​这也算是<​span style="​color:​ #​002060;"><​strong>​上面情况所非常常用</​strong></​span>​的场景。</​span></​p><​p style="​margin-left:​ 54pt;"><​span style="​font-family:​ 方正隶变简体;​ font-size: 16pt;">​HTTP的Upgrade协议头机制用于将<​span style="​color:​ #​c00000;"><​strong>​连接从HTTP连接升级到WebSocket连接</​strong></​span>​,Upgrade机制使用了Upgrade协议头和Connection协议头。</​span></​p><​p style="​margin-left:​ 54pt;"><​span style="​font-family:​ 方正隶变简体;"><​span style="​font-size:​ 16pt;">​为了让Nginx可以将<​span style="​color:​ #​002060;"><​strong>​来自客户端的Upgrade请求发送到后端服务器</​strong></​span>​,<​span style="​color:​ #​c00000;"><​strong>​Upgrade和Connection的头信息必须被</​strong></​span></​span><​span style="​font-size:​ 20pt;"><​strong>​显式</​strong></​span><​span style="​font-size:​ 16pt;"><​span style="​color:​ #​c00000;"><​strong>​的设置</​strong></​span>​。</​span></​span></​p><​p style="​margin-left:​ 27pt;">&​nbsp;​ 
 +&​nbsp;</​p><​p style="​margin-left:​ 27pt;"><​span style="​color:​ #bf9000; font-family:​ 方正隶变简体;​ font-size: 18pt;">​【注意】</​span></​p><​p style="​margin-left:​ 54pt;"><​span style="​font-family:​ 方正隶变简体;​ font-size: 16pt;">​在nginx的配置文件中,如果<​span style="​color:​ #​c00000;"><​strong>​当前模块中没有proxy_set_header的设置</​strong></​span>​,则会从<​span style="​color:​ #​c00000;"><​strong>​上级别继承配置</​strong></​span>​。</​span></​p><​p style="​margin-left:​ 54pt;"><​span style="​font-size:​ 16pt;"><​span style="​font-family:​ 方正隶变简体;">​继承顺序为:</​span><​span style="​color:​ #c00000; font-family:​ Consolas;"><​strong>​http,​ server, location</​strong></​span><​span style="​font-family:​ 方正隶变简体;">​。</​span></​span></​p><​p style="​margin-left:​ 54pt;">&​nbsp;​ 
 +&​nbsp;</​p><​p style="​margin-left:​ 54pt;"><​span style="​font-family:​ 方正隶变简体;"><​span style="​font-size:​ 16pt;">​如果在下一层<​span style="​color:​ #​002060;"><​strong>​使用proxy_set_header修改了header</​strong></​span>​的值,则</​span><​span style="​color:​ #c00000; font-size: 18pt;"><​strong>​所有的header值都可能会发生变化</​strong></​span><​span style="​font-size:​ 16pt;">​,之前</​span><​span style="​color:​ #c00000; font-size: 18pt;"><​strong>​继承的所有配置将会被丢弃</​strong></​span><​span style="​font-size:​ 16pt;">​。</​span></​span></​p><​p style="​margin-left:​ 54pt;"><​span style="​font-family:​ 方正隶变简体;​ font-size: 16pt;">​所以,<​span style="​color:​ #​002060;"><​strong>​尽量在同一个地方进行proxy_set_header</​strong></​span>​,否则可能会有别的问题。</​span></​p><​p style="​margin-left:​ 54pt;">&​nbsp;​ 
 +&​nbsp;</​p><​p><​span style="​color:​ #7f6000; font-family:​ 方正隶变简体;​ font-size: 20pt;"><​strong>​·【参考】</​strong></​span></​p><​p style="​margin-left:​ 27pt;"><​span style="​font-family:​ 方正隶变简体;​ font-size: 16pt;">​Nginx中文官方文档: <a href="​http://​www.nginx.cn/​doc/">​http://​www.nginx.cn/​doc/</​a></​span></​p><​p style="​margin-left:​ 27pt;"><​span style="​font-family:​ 方正隶变简体;​ font-size: 16pt;">​测试参考文档: <a href="​https://​www.lijiaocn.com/​问题/​2019/​05/​08/​nginx-ingress-keep-alive-not-work.html">​https://​www.lijiaocn.com/​问题/​2019/​05/​08/​nginx-ingress-keep-alive-not-work.html</​a></​span></​p><​p style="​margin-left:​ 27pt;"><​span style="​font-family:​ 方正隶变简体;​ font-size: 16pt;">​keep-alive参考文档: <a href="​https://​wglee.org/​2018/​12/​02/​nginx-keepalive/">​https://​wglee.org/​2018/​12/​02/​nginx-keepalive/</​a></​span></​p><​p><​br/></​p>​
服务器技术/nginx/nginx反向代理时保持长连接.txt · 最后更改: 2020/05/14 17:54 由 admin