Linux中,Tomcat 怎麼承載高併發(深刻Tcp參數 backlog)

1、前言

這兩天看tomcat,查閱 tomcat 怎麼承載高併發時,看到了backlog參數。咱們知道,服務器端通常使用mq來減輕高併發下的洪峯衝擊,將暫時不能處理的請求放入隊列,後續再慢慢處理。其實操做系統已經幫咱們作了一些相似的東西了,這個東西就是backlog。服務端通常經過 accept 調用,去獲取socket。可是假設咱們的程序處理不過來(好比由於程序bug,或者設計問題,沒能及時地去調用 accept),那麼此時的網絡請求難道就直接丟掉嗎?html

固然不會!這時候,操做系統會幫咱們放入 accept 隊列,先暫存起來。等咱們的程序緩過來了,直接調用  accept 去 隊列取就好了,這就達到了相似mq的效果。java

而 backlog,和另外一個參數 /proc/sys/net/core/somaxconn 一塊兒,決定了隊列的容量,算法爲:min(/proc/sys/net/core/somaxconn, backlog) 。linux

文章比較長,若是隻須要結論,看第三章的總結便可,有時間的話,能夠仔細看看正文、第四章的驗證部分。 若是隻想知道怎麼設置這個值,直接跳到最後便可。nginx

 

下面這篇文章,基礎原理講得很不錯。可是是外國人寫的,我這裏簡(tong)單(ku)翻譯一下,我也會結合本身的理解,作一些補充。原文連接:http://veithen.io/2014/01/01/how-tcp-backlog-works-in-linux.html面試

正文以前,查了下linux中的說明。在linux下,執行 man listen,能夠看到:redis

 

int listen(int sockfd, int backlog);算法

DESCRIPTION
listen() marks the socket referred to by sockfd as a passive socket, that is, as a socket that will be used to accept incoming connection requests using accept(2).spring

The backlog argument defines the maximum length to which the queue of pending connections for sockfd may grow. If a connection request arrives when the queue is full, the client may receive an error with an indication of
ECONNREFUSED or, if the underlying protocol supports retransmission, the request may be ignored so that a later reattempt at connection succeeds.apache

 

The behavior of the backlog argument on TCP sockets changed with Linux 2.2. Now it specifies the queue length for completely established sockets waiting to be accepted, instead of the number of incomplete connection
requests. The maximum length of the queue for incomplete sockets can be set using /proc/sys/net/ipv4/tcp_max_syn_backlog. When syncookies are enabled there is no logical maximum length and this setting is ignored. See
tcp(7) for more information.tomcat

 咱們着重看上面紅色部分,「backlog 的意義從linux 2.2開始,發生了變化。如今,這個參數指定了已完成三次握手的 accept 隊列的長度,而不是半鏈接隊列的長度。半鏈接隊列的長度能夠經過 /proc/sys/net/ipv4/tcp_max_syn_backlog來設置」

 因此,下次,若是面試官問你這個參數的意思是什麼,那基本上答上面這句就沒問題了。

 但咱們仍是繼續拓展下。下面我用渣英語翻譯一下,權當鍛鍊了。

 

2、翻譯正文

一、兩種實現方式


當一個程序要進行監聽時,須要調用listen函數,此時,須要制定backlog參數。該參數,一般指定socket鏈接隊列的長度。

 

由於tcp鏈接的創建須要三次握手,所以,站在服務端的角度,一個到來的鏈接在變成established以前,須要通過一箇中間狀態SYN RECEIVED;

進入established狀態後,此時若是服務端調用accept操做,便可返回該socket。這意味着,tcp/ip協議棧要實現backlog隊列,有兩種選擇:

一、使用一個單獨的隊列,隊列的長度由 listen 調用的 backlog 參數決定。當收到一個 syn 包時,給客戶端返回 SYN/ACK,並將此連接加入到隊列。

當對應的 ACK 到達後, 鏈接狀態改變爲 ESTABLISHED,而後便可移交給應用程序處理。 這意味着,隊列能夠包含兩種狀態的鏈接: SYN RECEIVED 和 ESTABLISHED。

只有處於 ESTABLISHED 狀態的鏈接,才能返回給應用程序發起的 accept 調用。

二、使用兩個隊列,一個 SYN 隊列(或者叫作 半鏈接隊列) 和一個 accept 隊列(或者叫作 徹底鏈接隊列)。 處於 SYN RECEIVED 狀態的鏈接將被加入到 SYN 隊列,後續當

狀態變爲 ESTABLISHED 狀態時(好比三次握手中的最後一次 ACK 到達時),被移到 accept 隊列。 就像 accept函數的名字所表示的那樣, 實現 accept 調用時,只須要簡單地從

accept 隊列中獲取鏈接便可。 在這種實現方式下, backlog 參數決定了 accept 隊列的長度。

 

二、BSD 的選擇

歷史上, BSD 系統的 TCP 實現,使用第一種方式。 這種方式下,當 隊列達到 backlog 指定的最大值時, 系統將再也不給客戶端發來的 SYN 返回 SYN/ACK 。 一般, TCP 實現會簡單地丟棄 SYN 包(甚至不會返回 RST 包),所以客戶端會觸發重試。 這個在  W. Richard Stevens 老爺子的 TCP/IP 卷三種的14.5節有講。值得注意的是, Stevens 老爺子解釋了, BSD 實際上確實用了兩個單獨的隊列, 可是它們表現的和一個單獨的,具備backlog參數指定的長度的隊列沒什麼差異。好比,BSD 邏輯上表現得和下面的表述一致:

隊列的大小是半鏈接隊列的長度 和 全鏈接隊列的長度之和。(意思是 sum = 半鏈接隊列長度 + 全鏈接隊列長度)

 

三、Linux 的選擇

在linux 上,事情不太同樣,在 listen 調用的 man page 上(就是我們前言那一段):

The behavior of the backlog argument on TCP sockets changed with Linux 2.2. Now it specifies the queue length forcompletely established sockets waiting to be accepted,

instead of the number of incomplete connection requests. The maximum length of the queue for incomplete sockets can be set using /proc/sys/net/ipv4/tcp_max_syn_backlog.

 

這意味着, Linux非要對着幹,選了第二種方案: 一個 SYN 隊列, 大小由 系統級別的參數指定 ; 一個 accept 隊列, 大小由應用程序指定。

下面圖的意思是,服務端收到 SYN 後,會把該socket 放入 syns queue ,當該 socket 的 ack到來時, 服務端將其從 syns queue取出來,移到 accept queue 中。應用程序調用 accept 時,其實就是去 accept 隊列取。

 

 

四、linux實現中, accept 隊列滿了怎麼辦

 

有個問題是, 若是 accept 隊列滿了, 一個鏈接又須要從 SYN 隊列移到 accept 隊列時(好比收到了三次握手中的第三個包,客戶端發來的 ack),linux 下的該種實現會如何表現呢? 

這種場景下的代碼處理在 net/ipv4/tcp_minisocks.c 中的 tcp_check_req 函數:

 child = inet_csk(sk)->icsk_af_ops->syn_recv_sock(sk, skb, req, NULL);
        if (child == NULL)
                goto listen_overflow;

 

對於 ipv4, 代碼中第一行會最終調用net/ipv4/tcp_ipv4.c 中的 tcp_v4_syn_recv_sock:

ctcp_v4_syn_recv_sock的方法實現:

if (sk_acceptq_is_full(sk))
                goto exit_overflow;

 

這裏,咱們看到有對accept 隊列的檢測。 exit_overflow 後的代碼,會進行一些清理工做, 更新 /proc/net/netstat中的 ListenOverflows 和 ListenDrops 統計信息 。 這會觸發 tcp_check_req 中 listen_overflow的執行:

## 看起來像咱們的監聽者模式。。。
listen_overflow:
if (!sysctl_tcp_abort_on_overflow) { inet_rsk(req)->acked = 1; return NULL; }

 

這個什麼意思呢? 意思是,除非  /proc/sys/net/ipv4/tcp_abort_on_overflow 設爲 1 ,(這種狀況下,會發送 RST 包),不然就什麼都不作。

(emmmm 。。。。。。有點偷懶?)

 

總結一下, 若是 linux 下的tcp實現,在 accept 隊列滿的狀況下,收到了 三次握手中的最後一次 ack 包, 它就直接無視這個包。 一開始,看起來有點奇怪,可是記得, SYN RECEIVED 狀態下的 socket 有一個定時器。

該定時器的機制: 若是 ack 包沒收到(或者被無視,就像咱們上面描述的這個狀況), tcp 協議棧 會重發 SYN/ACK 包。(重發次數由 /proc/sys/net/ipv4/tcp_synack_retries  指定)

 

譯者這裏補充下:

答案: 若 /proc/sys/net/ipv4/tcp_abort_on_overflow = 0,服務端直接忽略該ack,由於服務端一直處於 SYN RECEIVED,觸發了定時器,該定時器會重傳 SYN/ACK 給客戶端,(不超過 /proc/sys/net/ipv4/tcp_synack_retries 指定的次數 );
若是 /proc/sys/net/ipv4/tcp_abort_on_overflow = 1, 則服務端會直接返回 RST,而不會重傳 SYN/ACK。

 

經過下面的網絡跟蹤包(一個客戶端試圖鏈接到一個服務端的,隊列已達到最大 backlog 值的監聽 socket),咱們看看會是神馬狀況:

0.000  127.0.0.1 -> 127.0.0.1  TCP 74 53302 > 9999 [SYN] Seq=0 Len=0
  0.000  127.0.0.1 -> 127.0.0.1  TCP 74 9999 > 53302 [SYN, ACK] Seq=0 Ack=1 Len=0
  0.000  127.0.0.1 -> 127.0.0.1  TCP 66 53302 > 9999 [ACK] Seq=1 Ack=1 Len=0
  0.000  127.0.0.1 -> 127.0.0.1  TCP 71 53302 > 9999 [PSH, ACK] Seq=1 Ack=1 Len=5
  0.207  127.0.0.1 -> 127.0.0.1  TCP 71 [TCP Retransmission] 53302 > 9999 [PSH, ACK] Seq=1 Ack=1 Len=5
  0.623  127.0.0.1 -> 127.0.0.1  TCP 71 [TCP Retransmission] 53302 > 9999 [PSH, ACK] Seq=1 Ack=1 Len=5
  1.199  127.0.0.1 -> 127.0.0.1  TCP 74 9999 > 53302 [SYN, ACK] Seq=0 Ack=1 Len=0
  1.199  127.0.0.1 -> 127.0.0.1  TCP 66 [TCP Dup ACK 6#1] 53302 > 9999 [ACK] Seq=6 Ack=1 Len=0
  1.455  127.0.0.1 -> 127.0.0.1  TCP 71 [TCP Retransmission] 53302 > 9999 [PSH, ACK] Seq=1 Ack=1 Len=5
  3.123  127.0.0.1 -> 127.0.0.1  TCP 71 [TCP Retransmission] 53302 > 9999 [PSH, ACK] Seq=1 Ack=1 Len=5
  3.399  127.0.0.1 -> 127.0.0.1  TCP 74 9999 > 53302 [SYN, ACK] Seq=0 Ack=1 Len=0
  3.399  127.0.0.1 -> 127.0.0.1  TCP 66 [TCP Dup ACK 10#1] 53302 > 9999 [ACK] Seq=6 Ack=1 Len=0
  6.459  127.0.0.1 -> 127.0.0.1  TCP 71 [TCP Retransmission] 53302 > 9999 [PSH, ACK] Seq=1 Ack=1 Len=5
  7.599  127.0.0.1 -> 127.0.0.1  TCP 74 9999 > 53302 [SYN, ACK] Seq=0 Ack=1 Len=0
  7.599  127.0.0.1 -> 127.0.0.1  TCP 66 [TCP Dup ACK 13#1] 53302 > 9999 [ACK] Seq=6 Ack=1 Len=0
 13.131  127.0.0.1 -> 127.0.0.1  TCP 71 [TCP Retransmission] 53302 > 9999 [PSH, ACK] Seq=1 Ack=1 Len=5
 15.599  127.0.0.1 -> 127.0.0.1  TCP 74 9999 > 53302 [SYN, ACK] Seq=0 Ack=1 Len=0
 15.599  127.0.0.1 -> 127.0.0.1  TCP 66 [TCP Dup ACK 16#1] 53302 > 9999 [ACK] Seq=6 Ack=1 Len=0
 26.491  127.0.0.1 -> 127.0.0.1  TCP 71 [TCP Retransmission] 53302 > 9999 [PSH, ACK] Seq=1 Ack=1 Len=5
 31.599  127.0.0.1 -> 127.0.0.1  TCP 74 9999 > 53302 [SYN, ACK] Seq=0 Ack=1 Len=0
 31.599  127.0.0.1 -> 127.0.0.1  TCP 66 [TCP Dup ACK 19#1] 53302 > 9999 [ACK] Seq=6 Ack=1 Len=0
 53.179  127.0.0.1 -> 127.0.0.1  TCP 71 [TCP Retransmission] 53302 > 9999 [PSH, ACK] Seq=1 Ack=1 Len=5
106.491  127.0.0.1 -> 127.0.0.1  TCP 71 [TCP Retransmission] 53302 > 9999 [PSH, ACK] Seq=1 Ack=1 Len=5
106.491  127.0.0.1 -> 127.0.0.1  TCP 54 9999 > 53302 [RST] Seq=1 Len=0

 

因爲 客戶端的 tcp 協議棧收到了多個 SYN/ACK 包, 所以,它假設 ACK 包丟失了,因而進行重發。(能夠看上面的 帶有 TCP dup ACK 的行)。

若是服務端監聽socket 的 backlog 值下降了 (好比,從 accept 隊列消費了一個鏈接,所以隊列變成未滿),並且, SYN/ACK 重試次數沒有達到最大值的狀況下,那麼, tcp 協議棧就能夠最終處理 客戶端發來的 ack 包, 將鏈接狀態從 SYN RECEIVED 改成

ESTABLISHED, 並將其加入到 accept 隊列中。 不然, 客戶端最終將會拿到一個 RST 包。(上圖標紅那行)

 

五、問題延伸

上面的網絡抓包,也展現出另外一個有趣的方面。 從客戶端的角度來講, 收到 服務端發來的 SYN/ACK 後,一直就處於 ESTABLISHED 狀態。 若是它發生數據 (不等待服務端發來的數據,畢竟是全雙工), 那麼數據一樣將會重傳。 TCP 慢開始算法,會限制發出的包的數量。 (這裏意思是, 慢開始算法下,一開始不會傳不少包,可能只傳一個,收到服務端的響應後,下一次傳2個,再一次傳4個,這樣指數級增加,直到達到一個值後,進入線性增加階段,由於服務端一直沒響應,就不會增大發送的包的個數,避免浪費網絡流量)

 

另外一方面, 若是客戶端一直等待服務端發送數據,可是服務端的 backlog 一直沒有下降(一直沒能 accept 該客戶端), 那麼最終結果是, 客戶端該鏈接爲 ESTABLISHED 狀態,在服務端,該鏈接狀態爲 CLOSED。

 

還有一個咱們沒討論的問題。 listen 的 man page 上說,每一個 SYN 包將會添加到 SYN 隊列(除非隊列滿了)。 這個不徹底準確。理由是,在 net/ipv4/tcp_ipv4.c 中的 tcp_v4_conn_request 函數中 (該函數負責 SYN 包的處理):

        /* Accept backlog is full. If we have already queued enough

         * of warm entries in syn queue, drop request. It is better than

         * clogging syn queue with openreqs with exponentially increasing

         * timeout.

         */

        if (sk_acceptq_is_full(sk) && inet_csk_reqsk_queue_young(sk) > 1) {

                NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENOVERFLOWS);

                goto drop;

        }

這個意味着,若是 accept 隊列滿了, 那麼內核會隱式限制 SYN 包接收的速度。 若是收到了太多的 SYN 包, 部分會被丟棄。 在這種狀況下, 由客戶端決定 進行重發,而後咱們最終表現就和在 BSD 下的實現同樣。

總結下,爲何linux的設計,會比傳統的BSD下的實現更爲優越。 Stevens老爺子作了以下的觀點(這個翻譯太崩潰了。。。深奧。。。智商不行了。。。):

隊列長度將會達到backlog 限定值,若是全鏈接隊列滿了的話(好比,服務器太忙,以致於進程沒法足夠快地調用 accept 進行處理,好方便從 accept 隊列中騰出位置);或者,在半鏈接隊列滿了時,隊列長度也會達到 backlog。 後者就是http服務器面臨的問題,當客戶端和服務端之間的往返時間較長時,(相對於什麼較長?相對於 新鏈接的到達速率),由於一個新的 syn 包 會佔據隊列,長達客戶端到服務端之間一次往返的時間。

當一個鏈接放入全鏈接隊列時,它幾乎老是空的, 由於當一個鏈接放入這個隊列時, accept 調用就返回了, 而後 服務器將鏈接從隊列中移除。

 

四、Stevens老爺子的建議

Stevens老爺子的建議是,增長backlog的值。 假設一個程序,打算對backlog 進行調優,不只要考慮它怎麼處理新創建的鏈接,也要考慮網絡情況,好比客戶端到服務器的往返時間。

Linux的實現有效地分離了這兩個問題:

程序只須要負責調優 backlog,保證它可以儘快地調用 accept,避免堆滿 accept 隊列;

系統管理員能夠基於 網絡情況,對 /proc/sys/net/ipv4/tcp_max_syn_backlog 進行調優。

 

3、譯文的測試驗證

文章不太好理解,我查了些資料,參考https://www.cnblogs.com/xrq730/p/6910719.html後,我打算本地也進行一次驗證。

主要是經過ss命令、以及wireshark抓包,觀察這其中的細節。

一、服務端程序

首先,服務端程序爲:

import java.net.ServerSocket;

public class ServerSocketClass {

    public static void main(String[] args) throws Exception {
        ServerSocket server = new ServerSocket(8888, 5);

        while (true) {
            // server.accept();
        }
    }

}

 

二、客戶端程序

 
 
/**
* desc:
*
* @author : caokunliang
* creat_date: 2019/6/11 0011
* creat_time: 10:16
**/
import java.io.OutputStream;
import java.net.Socket;
import java.util.concurrent.locks.LockSupport;


public class ClientSocketClass {

private static Socket[] clients = new Socket[30];

public static void main(String[] args) throws Exception {
for (int i = 0; i < 1; i++) {
Socket socket = null;
socket = new Socket("192.168.19.13", 8888);
System.out.println("Client:" + socket + ", isConnected:" + socket.isConnected());
OutputStream outputStream = socket.getOutputStream();
outputStream.write('a');
}

// 阻止程序退出,由於退出的話,程序會直接發送一個 RST 給服務器,不能觀察 服務器的 ACK/SYN 重傳
LockSupport.park();
}

}
 

值得注意的是,這裏,咱們每次只發一次請求。

 

三、客戶端請求發送5次,填滿 accept 隊列

觀察下面的圖,其中ss命令, 若是該條socket記錄爲監聽端口,則Recv-Q 表示 accept 隊列中元素的個數, Send-Q 表示 accept 隊列中隊列的容量。

Recv-Q

Established: The count of bytes not copied by the user program connected to this socket.

Listening: Since Kernel 2.6.18 this column contains the current syn backlog. 
Send-Q

Established: The count of bytes not acknowledged by the remote host.

Listening: Since Kernel 2.6.18 this column contains the maximum size of the syn backlog.

 

啓動服務端程序,初始時,

 

每次咱們執行客戶端,這裏便會加1。執行兩次後:

 

四、再次發送鏈接請求

5次後,Recv-Q隊列將會變滿。若是此時再發送的話,按照參考博客中的說法,是會報錯。但我這邊沒報錯,看 wireshark 抓包:首先看服務端發給客戶端的包,咱們發現, 服務器確實會一直髮送 SYN/ACK 給客戶端,一共發了5次(即: /proc/sys/net/ipv4/tcp_synack_retries)。每次時間間隔加一倍。(參考退火算法)

 

 

能夠看到,服務端一直給客戶端發送 SYN/ACK,因此,客戶端假設本身發出去的 ACK (三次握手的最後一次) 丟失了。因而會一直重發:

 

完整的交互以下:

 

 咱們發現,這裏, 最後服務端會發送一個 RST ,但若是咱們把客戶端程序改改:

//            OutputStream outputStream = socket.getOutputStream();
//            outputStream.write('a');

再次請求,進行抓包的話,會發現不會發送 RST 了:

 

 值得注意的是,在這種狀況下,在客戶端查看鏈接狀態是 ESTABLISHED ,而在服務器端,查不到對應的鏈接信息。這也就驗證了譯文中 「問題延伸」 一節的猜測。

客戶端:

 

服務器:

  五、測試tcp_abort_on_overflow 參數

上面步驟都是在tcp_abort_on_overflow 爲 false的狀況下測試的, 此次咱們打開後,再用下面程序測試。

sysctl -w net.ipv4.tcp_abort_on_overflow = 1
import java.net.Socket;
import java.util.concurrent.locks.LockSupport;


public class ClientSocketClass {

    private static Socket[] clients = new Socket[30];

    public static void main(String[] args) throws Exception {
        for (int i = 0; i < 15; i++) {
            Socket socket = null;
            socket = new Socket("192.168.19.13", 8888);
            System.out.println("Client:" + socket + ", isConnected:" + socket.isConnected());
        }

        // 阻止程序退出,由於退出的話,程序會直接發送一個 RST 給服務器,不能觀察 服務器的 ACK/SYN 重傳
        LockSupport.park();
    }

}

 

咱們發起了15次鏈接,可是咱們的 accept 隊列爲5,按理說只能成功 5 +1 = 6個鏈接,剩下的9個鏈接都會無效。tcp_abort_on_overflow 的做用是,在 accept 隊列滿時,返回 rst。下面測試:

 

上圖能夠看出,成功創建的只有6個,剩下的都被服務器返回了 RST 。

 

 五、服務端正常accept時的鏈接狀況

修改程序:將ServerSocketClass.java中的註釋行打開,容許服務器調用accept;客戶端循環次數改成20,看看服務器上的狀況:

 

 

 

 

4、簡單總結

backlog:該參數,每一個程序能夠在listen時本身設置,和另一個參數( /proc/sys/net/core/somaxconn)一塊兒,影響 全鏈接隊列的容量。 具體算法是:min (backlog, /proc/sys/net/core/somaxconn ),最終能夠創建的鏈接爲 該值 + 1。

/proc/sys/net/ipv4/tcp_max_syn_backlog : 半鏈接隊列的容量。(os層面,只能設一個,由全部程序共享)

/proc/sys/net/ipv4/tcp_synack_retries :分兩種狀況:

  1. tcp_abort_on_overflow = 0,服務端 accept 隊列滿了,客戶端發來 ack , 服務端直接忽略該ack。所以服務端一直處於 SYN RECEIVED,觸發了該狀態下的定時器,該定時器會重傳 SYN/ACK 給客戶端,(不超過 /proc/sys/net/ipv4/tcp_synack_retries 指定的次數 ), 超事後,服務端再也不重傳,後續也不會再有任何動做;若是客戶端此時傳輸數據的話,服務端會返回 RST;
  2. tcp_abort_on_overflow = 1,服務端 accept 隊列滿了,客戶端發來 ack , 服務端直接返回 RST 。

 ps: 查看、修改這些參數的簡單方法:

#查看全部系統變量並查找
[root@localhost ~]# sysctl -a |grep somaxconn
net.core.somaxconn = 128

# 設置系統變量
[root@localhost ~]# sysctl -w net.core.somaxconn=129
net.core.somaxconn = 129

 

如何查看一個程序,最終生效的accept隊列的大小:

 

 

5、 Tomcat 、nginx、redis中如何設置 backlog

一、tomcat

在tomcat 中, backlog 參數定義在org.apache.tomcat.util.net.AbstractEndpoint#backlog中,默認值爲100。

    /**
     * Allows the server developer to specify the backlog that
     * should be used for server sockets. By default, this value
     * is 100.
     */
    private int backlog = 100;
    public void setBacklog(int backlog) { if (backlog > 0) this.backlog = backlog; }

 

可是在實際處理中, 會由 Digester 框架,去解析 server.xml,解析到 connector 時, 首先新建 org.apache.catalina.connector.Connector,

而後開始設置屬性值:

 

當設置 acceptCount 時, 會調用 org.apache.catalina.connector.Connector#setProperty:

 

咱們能夠看看 replacements的定義:

     protected static HashMap<String,String> replacements =
         new HashMap<String,String>();
     static {
 replacements.put("acceptCount", "backlog");          replacements.put("connectionLinger", "soLinger");
         replacements.put("connectionTimeout", "soTimeout");
         replacements.put("rootFile", "rootfile");
     }

 

因此,其實 connector 中 acceptCount 最終是 backlog 的值。

 

update於2020/03/12:

若是是spring boot內置的tomcat,我這邊是

    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-tomcat</artifactId>
      <version>2.1.7.RELEASE</version>
      <scope>compile</scope>
    </dependency>

我發現,設置backlog的地方,在源碼的以下位置:

org.apache.tomcat.util.net.AbstractEndpoint#acceptCount

 

 

默認值仍是100。

若是要修改,能夠直接:

http://www.javashuo.com/article/p-gicmkitc-mw.html

 

二、nginx

server{
        listen      8080  default_server backlog=1024;
}

 

三、redis

修改redis.conf

# TCP listen() backlog.
#
# In high requests-per-second environments you need an high backlog in order
# to avoid slow clients connections issues. Note that the Linux kernel
# will silently truncate it to the value of /proc/sys/net/core/somaxconn so
# make sure to raise both the value of somaxconn and tcp_max_syn_backlog
# in order to get the desired effect.
tcp-backlog 511

 

參考文檔:

http://jm.taobao.org/2017/05/25/525-1/

360基礎架構快報

相關文章
相關標籤/搜索