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. Java [Leetcode 273]Delete Node in a Linked List

    题目描述: Write a function to delete a node (except the tail) in a singly linked list, given only access ...

  2. Java [leetcode 31]Next Permutation

    题目描述: Implement next permutation, which rearranges numbers into the lexicographically next greater p ...

  3. Android 多种方式正确的加载图像,有效避免oom

    图像加载的方式: Android开发中消耗内存较多一般都是在图像上面,本文就主要介绍怎样正确的展现图像减少对内存的开销,有效的避免oom现象.首先我们知道我的获取图像的来源一般有三种源头:1.从网络加 ...

  4. 前端的小Demo——涉及keyCode

    以下是我的代码: <!doctype html> <html> <head> <meta charset="utf-8"> < ...

  5. MessagePack介绍

    在项目中,服务端的人需要我研究messagepcak 进行数据的传输,对messagePack的了解就是传输的数据格式都是二进制,可以节省用户的流量,就因为这点 数据格式小,服务端决定采用msgpac ...

  6. JMX学习笔记(二)-Notification

    Notification通知,也可理解为消息,有通知,必然有发送通知的广播,JMX这里采用了一种订阅的方式,类似于观察者模式,注册一个观察者到广播里,当有通知时,广播通过调用观察者,逐一通知. 这里写 ...

  7. POJ3279 Fliptile 枚举+简单搜索

    题意:一个矩阵,每个点1或0,然后每次翻一个点,它周围上下左右(包括自己)1->0,0->1,问最少翻几次可以矩阵全是0,忽略题目说的字典序 分析:枚举第一行所有的情况,然后下面几行也随之 ...

  8. lightoj 1017

    思路:动态规划,设dp[i][j]表示在前j个dusts中用了i刷子刷掉dusts的个数:状态转移方程就是: dp[i][j] = max(dp[i][j-1], dp[i-1][j-len[j]] ...

  9. Excel2010: Excel使用小技巧(不断更新)

    目录 1. 如何设置定时保存2. 调出“开发工具”功能区3. 在Excel单元格中输入对号和错号4. 设置单元格自动换行5. 向Excel中导入.txt文件6. 如何批量删除超链接7. 如何冻结窗格8 ...

  10. vector(相对线程安全) arryList(线程不安全)

    1.什么是线程安全? 如果说某个集合是线程安全的,那么我们就不用考虑并发访问这个集合?(需要定义自己百度,但是很难懂) 2.深入jvm中的线程安全的级别. a不变模式(String等基本类型) b.绝 ...