Linux中,Tomcat 怎么承載高並發(深入Tcp參數 backlog)


一、前言

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

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

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

文章比較長,如果只需要結論,看第三章的總結即可,有時間的話,可以仔細看看正文、第四章的驗證部分。 如果只想知道怎么設置這個值,直接跳到最后即可。

 

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

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

 

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).

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.

 

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.

 我們着重看上面紅色部分,“backlog 的意義從linux 2.2開始,發生了變化。現在,這個參數指定了已完成三次握手的 accept 隊列的長度,而不是半連接隊列的長度。半連接隊列的長度可以通過 /proc/sys/net/ipv4/tcp_max_syn_backlog來設置”

 所以,下次,如果面試官問你這個參數的意思是什么,那基本上答上面這句就沒問題了。

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

 

二、翻譯正文

1、兩種實現方式


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

 

因為tcp連接的建立需要三次握手,因此,站在服務端的角度,一個到來的連接在變成established之前,需要經過一個中間狀態SYN RECEIVED;

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

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

當對應的 ACK 到達后, 連接狀態改變為 ESTABLISHED,然后即可移交給應用程序處理。 這意味着,隊列可以包含兩種狀態的連接: SYN RECEIVED 和 ESTABLISHED。

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

2、使用兩個隊列,一個 SYN 隊列(或者叫做 半連接隊列) 和一個 accept 隊列(或者叫做 完全連接隊列)。 處於 SYN RECEIVED 狀態的連接將被加入到 SYN 隊列,后續當

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

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

 

2、BSD 的選擇

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

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

 

3、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 隊列取。

 

 

4、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 包。(上圖標紅那行)

 

5、問題延伸

上面的網絡抓包,也展示出另一個有趣的方面。 從客戶端的角度來說, 收到 服務端發來的 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 調用就返回了, 然后 服務器將連接從隊列中移除。

 

4、Stevens老爺子的建議

Stevens老爺子的建議是,增加backlog的值。 假設一個程序,打算對backlog 進行調優,不僅要考慮它怎么處理新建立的連接,也要考慮網絡狀況,比如客戶端到服務器的往返時間。

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

程序只需要負責調優 backlog,保證它能夠盡快地調用 accept,避免堆滿 accept 隊列;

系統管理員可以基於 網絡狀況,對 /proc/sys/net/ipv4/tcp_max_syn_backlog 進行調優。

 

三、譯文的測試驗證

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

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

1、服務端程序

首先,服務端程序為:

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();
        }
    }

}

 

2、客戶端程序

 
         
/**
* 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();
}

}
 

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

 

3、客戶端請求發送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。執行兩次后:

 

4、再次發送連接請求

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 ,而在服務器端,查不到對應的連接信息。這也就驗證了譯文中 “問題延伸” 一節的猜想。

客戶端:

 

服務器:

  5、測試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 。

 

 5、服務端正常accept時的連接情況

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

 

 

 

 

四、簡單總結

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隊列的大小:

 

 

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

1、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。

如果要修改,可以直接:

https://www.cnblogs.com/Hleaves/p/11284316.html

 

2、nginx

server{
        listen      8080  default_server backlog=1024;
}

 

3、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基礎架構快報

 


免責聲明!

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



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