Nginx與Tomcat、Client之間請求的長連接配置不一致問題解決[轉]


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:HttpClient 4.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

 

至此,長連接驗證完畢!

 

 

玩的開心!^_^


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM