http://bert82503.iteye.com/blog/2152613

前些天,线上出现“服务端长连接与客户端短连接引起Nginx的Writing、Active连接数过高问题”,这个是由于“服务端使用HTTPs长连接,而客户端使用短连接”引起。这几天,发现Nginx与Tomcat之间也存在同样的问题,原因是两边的相关配置参数不一致引起的。(这是细活!)

先说说服务为什么使用HTTPs长连接技术?有如下几个原因:

  1. 对响应时间要求较高;
  2. 服务走的是公网,客户端与服务端的TCP建立的三次握手断开的四次握手都需要40ms左右(真实数据包计算出来的),共需要80ms左右;
  3. 每个接入方使用的IP就若干个,需要建立的请求连接有限。

使用长连接技术,可以大幅减少TCP频繁握手的次数,极大提高响应时间;同时,即使使用长连接技术,也不需要消耗很多的系统资源用来缓存sockets会话信息。

以下是在自己电脑上验证三者之间的长连接请求,连接存活时间都为5min

【环境】

操作系统:Ubuntu 14.04 LTS

Nginx:1.6.2

Tomcat:7.0.51

JDK:1.7.0_51

Client:HttpClient4.3.5

【相关配置】

1. Nginx - 反向代理
nginx.conf:

http {
    ...

##

# 与Client连接的长连接配置

##

http://nginx.org/en/docs/http/ngx_http_core_module.html#keepalive_requests

# 设置通过"一个存活长连接"送达的最大请求数(默认是100,建议根据客户端在"keepalive"存活时间内的总请求数来设置)

# 当送达的请求数超过该值后,该连接就会被关闭。(通过设置为5,验证确实是这样)

keepalive_requests 8192;

http://nginx.org/en/docs/http/ngx_http_core_module.html#keepalive_timeout

# 第一个参数设置"keep-alive客户端长连接"将在"服务器端"继续打开的超时时间(默认是75秒,建议根据具体业务要求来,但必须要求所有客户端连接的"Keep-Alive"头信息与该值设置的相同(这里是5分钟),同时与上游服务器(Tomcat)的设置是一样的)

# 可选的第二个参数设置“Keep-Alive: timeout=time”响应头字段的值

    keepalive_timeout 300s 300s;

...

include /etc/nginx/web_servers.conf;

include /etc/nginx/proxy_params;

}

web_servers.conf:
upstream web_server {
    server 127.0.0.1:8080;

http://nginx.org/en/docs/http/ngx_http_upstream_module.html#keepalive

# 连接到上游服务器的最大并发空闲keepalive长连接数(默认是未设置,建议与Tomcat Connector中的maxKeepAliveRequests值一样)

# 当这个数被超过时,使用"最近最少使用算法(LUR)"来淘汰并关闭连接。

keepalive 512;
}

server {

listen 80;

server_name lihg.com www.lihg.com;

    location / {

proxy_pass http://web_server;

##

# 与上游服务器(Tomcat)建立keepalive长连接的配置,可参考上面的keepalive链接里的"For HTTP"部分

##

http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_http_version

# 设置代理的HTTP协议版本(默认是1.0版本)

# 使用keepalive连接的话,建议使用1.1版本。

        proxy_http_version 1.1;

http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_set_header

# 允许重新定义或追加字段到传递给代理服务器的请求头信息(默认是close)

        proxy_set_header Connection "";

proxy_redirect off;

}

}

[参考]

  1. nginx反向代理配置keepalive
  2. keepalive for HTTP - Module ngx_http_core_module

2. Tomcat
conf/server.xml
    <!-- 
        maxThreads:由此连接器创建的最大请求处理线程数,这决定可同时处理的最大并发请求数(默认为200)
        minSpareThreads:保持运行状态的最小线程数(默认为10)
        acceptCount:接收传入的连接请求的最大队列长度(默认队列长度为100)
        
        connectionTimeout:在接收一条连接之后,连接器将会等待请求URI行的毫秒数(默认为60000,60秒)
        maxConnections:在任何给定的时间,服务器能接收和处理的最大连接数(NIO的默认值为10000)

keepAliveTimeout:在关闭这条连接之前,连接器将等待另一个HTTP请求的毫秒数(默认使用connectionTimeout属性值)
        maxKeepAliveRequests:在该连接被服务器关闭之前,可被流水线化的最大HTTP请求数(默认为100)
        
        enableLookups:启用DNS查询(默认是DNS查询被禁用)
        compression:连接器是否启用HTTP/1.1 GZIP压缩,为了节省服务器带宽
        compressionMinSize:指定输出响应数据的最小大小(默认为2048,2KB)
        compressableMimeType:可使用HTTP压缩的文件类型
        server:覆盖HTTP响应的Server头信息
     -->
    <Connector port="8080" protocol="org.apache.coyote.http11.Http11NioProtocol"
               maxThreads="512"
               minSpareThreads="10"
               acceptCount="768"
               
               connectionTimeout="1000"
               maxConnections="1280"
               keepAliveTimeout="300000"
               maxKeepAliveRequests="512"
               
               enableLookups="false"
               URIEncoding="utf-8"
               redirectPort="8443"
               compression="on" compressionMinSize="1024" compressableMimeType="text/html,text/xml,text/javascript,text/css,text/plain,application/json,application/xml"
               server="webserver" />

[参考]

The HTTP Connector - Tomcat 7 Configuration Reference

3. Client

客户端HTTP "Keep-Alive"实现代码,请打开下一行的链接。

KeepAliveHttpClientsTest -> httpclient-x

【结果验证】

使用 "sudo netstat -antp | grep 80" 监控与Nginx相关的线程状态

netstat命令输出格式

Proto    Recv-Q             Send-Q               Local Address                     Foreign Address                  State              PID/Program name

协议     接收队列长度    发送队列长度     本地socket的地址和端口号  远程socket的地址和端口号  socket状态   进程id/进程名称

套接字(socket)状态

ESTABLISHED:含有一条已建立连接(connection)的socket

SYN_SENT:正在积极尝试建立一条连接的socket

SYN_RECV:接收到来自网络的一个连接请求

FIN_WAIT1:socket已关闭,同时连接正在关闭中

FIN_WAIT2:连接已关闭,同时socket正在等待远程终端的一个关闭请求

TIME_WAIT:socket正在等待关闭仍然在网络中的处理包

CLOSE:socket未被使用

CLOSE_WAIT:远程终端已经关闭,等待本地socket关闭

LAST_ACK:远程终端已经关闭,同时本地socket也关闭了。等待确认包

LISTEN:socket正在监听传入的连接

CLOSING:两边socket都已关闭,但仍然还没有我们所需要的发送数据

UNKNOWN:未知的socket状态

=====================

单个请求的线程状态

=====================

# 第1次请求,nginx分别与上游服务器(tomcat)、client互相建立1条连接

tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN      1010/nginx

tcp        0      0 127.0.0.1:47272         127.0.0.1:8080          ESTABLISHED 1014/nginx: worker (nginx -> tomcat)

tcp        0      0 127.0.0.1:80            127.0.0.1:53240         ESTABLISHED 1014/nginx: worker (nginx -> client)

tcp6       0      0 127.0.0.1:8005          :::*                    LISTEN      10912/java

tcp6       0      0 :::8080                 :::*                    LISTEN      10912/java

tcp6       0      0 127.0.0.1:53240         127.0.0.1:80            ESTABLISHED 13845/java      (client -> nginx)

tcp6       0      0 127.0.0.1:8080          127.0.0.1:47272         ESTABLISHED 10912/java      (tomcat -> nginx)

# 休眠10秒钟后,发起第2次请求

tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN      1010/nginx

tcp        0      0 127.0.0.1:47272         127.0.0.1:8080          ESTABLISHED 1014/nginx: worker

tcp        0      0 127.0.0.1:80            127.0.0.1:53240         ESTABLISHED 1014/nginx: worker

tcp6       0      0 127.0.0.1:8005          :::*                    LISTEN      10912/java

tcp6       0      0 :::8080                 :::*                    LISTEN      10912/java

tcp6       0      0 127.0.0.1:53240         127.0.0.1:80            ESTABLISHED 13845/java

tcp6       0      0 127.0.0.1:8080          127.0.0.1:47272         ESTABLISHED 10912/java

超过keepalive存活时间(5min)后,nginx已断开与上游服务器(tomcat)的长连接,同时与client连接进入关闭过程

tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN      1010/nginx

tcp        0      0 127.0.0.1:80            127.0.0.1:53240         FIN_WAIT2   -                (nginx -> client)

tcp6       0      0 127.0.0.1:8005          :::*                    LISTEN      10912/java

tcp6       0      0 :::8080                 :::*                    LISTEN      10912/java

tcp6       1      0 127.0.0.1:53240         127.0.0.1:80            CLOSE_WAIT  13845/java      (client -> nginx)

tcp6       0      0 127.0.0.1:8080          127.0.0.1:47272         TIME_WAIT   -               (tomcat -> nginx)

# 休眠7分钟后,发起第3次请求。nginx与上游服务器(tomcat)、client重新建立新的长连接(不同的端口号)

tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN      1010/nginx

tcp        0      0 127.0.0.1:80            127.0.0.1:53242         ESTABLISHED 1014/nginx: worker (nginx -> client)

tcp        0      0 127.0.0.1:47274         127.0.0.1:8080          ESTABLISHED 1014/nginx: worker (nginx -> tomcat)

tcp6       0      0 127.0.0.1:8005          :::*                    LISTEN      10912/java

tcp6       0      0 :::8080                 :::*                    LISTEN      10912/java

tcp6       0      0 127.0.0.1:53242         127.0.0.1:80            ESTABLISHED 13845/java      (client -> nginx)

tcp6       0      0 127.0.0.1:8080          127.0.0.1:47274         ESTABLISHED 10912/java      (tomcat -> nginx)

# 休眠10秒钟后,发起第4次请求

tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN      1010/nginx

tcp        0      0 127.0.0.1:80            127.0.0.1:53242         ESTABLISHED 1014/nginx: worker

tcp        0      0 127.0.0.1:47274         127.0.0.1:8080          ESTABLISHED 1014/nginx: worker

tcp6       0      0 127.0.0.1:8005          :::*                    LISTEN      10912/java

tcp6       0      0 :::8080                 :::*                    LISTEN      10912/java

tcp6       0      0 127.0.0.1:53242         127.0.0.1:80            ESTABLISHED 13845/java

tcp6       0      0 127.0.0.1:8080          127.0.0.1:47274         ESTABLISHED 10912/java

# 请求刚结束后,nginx断开与client的长连接,但与上游服务器(tomcat)的长连接还打开着,直到超过keepalive存活时间(5min)后才会被关闭。若在keepalive存活时间内再次发起请求,nginx与上游服务器(tomcat)的长连接会被重用

tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN      1010/nginx

tcp        0      0 127.0.0.1:47274         127.0.0.1:8080          ESTABLISHED 1014/nginx: worker (nginx -> tomcat)

tcp6       0      0 127.0.0.1:8005          :::*                    LISTEN      10912/java

tcp6       0      0 :::8080                 :::*                    LISTEN      10912/java

tcp6       0      0 127.0.0.1:53242         127.0.0.1:80            TIME_WAIT   -               (client -> nginx)

tcp6       0      0 127.0.0.1:8080          127.0.0.1:47274         ESTABLISHED 10912/java      (tomcat -> nginx)

请求结束1分钟后,client到nginx的TIME_WAIT长连接也被释放

tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN      1010/nginx

tcp        0      0 127.0.0.1:47274         127.0.0.1:8080          ESTABLISHED 1014/nginx: worker

tcp6       0      0 127.0.0.1:8005          :::*                    LISTEN      10912/java

tcp6       0      0 :::8080                 :::*                    LISTEN      10912/java

tcp6       0      0 127.0.0.1:8080          127.0.0.1:47274         ESTABLISHED 10912/java

# 请求结束5分钟后,nginx断开与上游服务器(tomcat)的长连接

tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN      1010/nginx

tcp6       0      0 127.0.0.1:8005          :::*                    LISTEN      10912/java

tcp6       0      0 :::8080                 :::*                    LISTEN      10912/java

tcp6       0      0 127.0.0.1:8080          127.0.0.1:47274         TIME_WAIT   -               (tomcat -> nginx)

========================

3个并发请求的线程状态

========================

# 第1次请求,nginx分别与上游服务器(tomcat)、client互相建立3条连接

tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN      1010/nginx

tcp        0      0 127.0.0.1:80            127.0.0.1:53245         ESTABLISHED 1014/nginx: worker

tcp        0      0 127.0.0.1:47279         127.0.0.1:8080          ESTABLISHED 1014/nginx: worker

tcp        0      0 127.0.0.1:80            127.0.0.1:53247         ESTABLISHED 1014/nginx: worker

tcp        0      0 127.0.0.1:47281         127.0.0.1:8080          ESTABLISHED 1014/nginx: worker

tcp        0      0 127.0.0.1:80            127.0.0.1:53246         ESTABLISHED 1014/nginx: worker

tcp        0      0 127.0.0.1:47280         127.0.0.1:8080          ESTABLISHED 1014/nginx: worker

tcp6       0      0 127.0.0.1:8005          :::*                    LISTEN      10912/java

tcp6       0      0 :::8080                 :::*                    LISTEN      10912/java

tcp6       0      0 127.0.0.1:53247         127.0.0.1:80            ESTABLISHED 13976/java

tcp6       0      0 127.0.0.1:53245         127.0.0.1:80            ESTABLISHED 13976/java

tcp6       0      0 127.0.0.1:8080          127.0.0.1:47281         ESTABLISHED 10912/java

tcp6       0      0 127.0.0.1:8080          127.0.0.1:47280         ESTABLISHED 10912/java

tcp6       0      0 127.0.0.1:53246         127.0.0.1:80            ESTABLISHED 13976/java

tcp6       0      0 127.0.0.1:8080          127.0.0.1:47279         ESTABLISHED 10912/java

tcp6       0      0 127.0.0.1:8080          127.0.0.1:47274         TIME_WAIT   -

[参考]

netstat(8) - Print network connections, routing tables, interface statistics - Linux manual page

至此,长连接验证完毕!

玩的开心!^_^

Nginx与Tomcat、Client之间请求的长连接配置不一致问题解决[转]的更多相关文章

  1. Nginx 核心配置-长连接配置

    Nginx 核心配置-长连接配置 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.长连接配置参数说明 keepalive_timeout number; 设定保持连接超时时长,0 ...

  2. 配置nginx,Tomcat日志记录请求耗时

    由于公司的业务比较特殊,对速度比较在意,客户最近反应我们的平台时间比较久,处理一个请求十秒左右才返回,领导要求找出原因,我想让nginx日志记录请求处理用了多长时间,后端处理用了多长时间,总共用了多长 ...

  3. WebSocket 长连接 及超时问题解决

    <?phpset_time_limit(0); class SocketService { private $address = 'localhost'; private $port = 80; ...

  4. nginx和tomcat访问图片和静态页面的配置方法

    生产环境下,有时候需要访问图片,正常需要应用ftp.nginx等配套使用,但是有时候为了简化,可以用以下的两种简单的访问,说实话,就是为了偷懒,但是效果是能有的,这就行了,所以今天做这个简化版的方便大 ...

  5. nginx长连接设置

    http { keepalive_timeout 20; --长连接timeout keepalive_requests 8192; --每个连接最大请求数} events { worker_conn ...

  6. nginx配置长连接

    http { keepalive_timeout 20; --长连接timeout keepalive_requests 8192; --每个连接最大请求数 } events { worker_con ...

  7. Nginx服务器之Nginx与tomcat结合访问jsp

    本文使用linux centos系统 本文概述: JSP是一种动态网页技术标准.使用的方式是在HTML文件中插入程序段和JSP标记,而形成JSP文件.使用JSP开发WEB应用可以跨平台开发.但jsp需 ...

  8. Nginx upstream 长连接

    原文: http://bollaxu.iteye.com/blog/900424 Nginx upstream目前只有短连接,通过HTTP/1.0向后端发起连接,并把请求的"Connecti ...

  9. HTTP实现长连接(TTP1.1和HTTP1.0相比较而言,最大的区别就是增加了持久连接支持Connection: keep-alive)

    HTTP实现长连接 HTTP是无状态的 也就是说,浏览器和服务器每进行一次HTTP操作,就建立一次连接,但任务结束就中断连接.如果客户端浏览器访问的某个HTML或其他类型的Web页中包含有其他的Web ...

随机推荐

  1. The Impact of Garbage Collection on Application Performance

    As we’ve seen, the performance of the garbage collector is not determined by the number of dead obje ...

  2. oralce索引和分区索引的使用

    oracle分区表和分区索引的本质就是将数据分段存储,包括表和索引(索引从本质上来讲也是表),表分区会将表分成多个段分别存储.由此数据查询过程改变为先根据查询条件定位分区表,然后从该表中查询数据,从而 ...

  3. LeetCode Product of Array Except Self (除自身外序列之积)

    题意:给一个序列nums,要求返回一个序列ans,两序列元素个数相同,ans第i个元素就是除了nums[i]之外所有的数相乘之积. 思路:时间O(n),额外空间O(0). 第一次扫一遍,处理nums[ ...

  4. LeetCode Binary Tree Level Order Traversal (按层收集元素)

    题意:按层,将元素收集在一个二维数组中. 思路:广搜应该是普遍的方法了.还能避免栈溢出,多好用.搭配deque,因为要经常删除. /** * Definition for a binary tree ...

  5. 用VisualSVN做项目版本控制

    一.SVN服务端 1.VisualSVN Server下载: http://download.csdn.net/detail/jiminull/4448874 或 http://www.visuals ...

  6. Diamond

    Diamond主要提供持久配置的发布和订阅服务,最大特点是结构简单,稳定可靠.Diamond的主要使用场景是用来进行动态数据库切换与扩容,进行一些业务系统运行时开关配置的推送.Diamond产品专注于 ...

  7. 《深入Java虚拟机学习笔记》- 第10章 栈和局部变量操作

    Java栈和局部变量操作 Java虚拟机是基于栈的机器,几乎所有Java虚拟机的指令都与操作数栈相关.栈操作包括把常量压入操作数栈.执行通用的栈操作.在操作数栈和局部变量之间往返传输值. 1常量入栈操 ...

  8. LeetCode题解——Reverse Integer

    题目: 数字翻转,即输入123,返回321:输入-123,返回-321. 代码: class Solution { public: int reverse(int x) { , sign = ; ) ...

  9. 问题与对策:CSS的margin塌陷(collapse)

    1: <!DOCTYPEHTML PUBLIC"-//W3C//DTD HTML 4.0 Transitional//EN"> 2: <html> 3: & ...

  10. C语言基础--结构体对齐,位域,联合体

    结构体对齐 1--结构体对齐的原因与意义 许多计算机系统对基本数据类型的可允许地址做出了一些限制,要求某种类型的对象的地址必须是某个值K(通常是2,4,8)的倍数,而这个k则被称为该数据类型的对齐模数 ...