本文詳解高併發場景下backlog的配置和作用

2021-10-07 12:24:00 字數 4121 閱讀 7657

環境介紹: php 7.3.5 +nginx/1.16.0 +linux vm_0_15_centos 3.10.0-514.26.2.el7.x86_64

backlog定義:

已連線但未進行accept處理的socket佇列大小,並非syn的socket佇列。如果這個佇列滿了,將會傳送乙個econnrefused錯誤資訊給到客戶端,即 linux 標頭檔案 /usr/include/asm-generic/errno.h中定義的「connection refused」

在linux 2.2以前:

在底層維護乙個由backlog指定大小的佇列。服務端收到syn後,返回乙個syn/ack,並把連線放入佇列中,此時這個連線的狀態是syn_received。當客戶端返回ack後,此連線的狀態變為established。佇列中只有established狀態的連線能夠交由應用處理。第一種實現方式可以簡單概括為:乙個佇列,兩種狀態。

linux 2.2以後:

在底層維護乙個syn_received佇列和乙個established佇列,當syn_received佇列中的連線返回ack後,將被移動到established佇列中。backlog指的是established佇列的大小。syn_received佇列的大小由/proc/sys/net/ipv4/tcp_max_syn_backlog系統引數指定,established佇列由backlog和/proc/sys/net/core/somaxconn中較小的指定。

當前最流行的dos(拒絕服務)與ddos(分布式拒絕服務)的方式之一,這是一種利用tcp協議缺陷,導致伺服器保持大量的syn_recv狀態的「半鏈結」,並且會重試預設的5次回應第二個握手包,塞滿tcp等待連線佇列,耗盡資源(cpu滿負載或記憶體不足),讓正常的業務請求連線不進來。

tcp 3次握手

可分為4步

1 客戶端發起connect(),傳送syn j

2 伺服器從半鏈結佇列(syn queue)中建立條目,響應syn k, ack j+1

3 客戶端connect()成功返回,響應ack k+1,伺服器將socket從半鏈結佇列(syn queue)移入全連線佇列(accept queue),accept()成功返回

如何觀察socket overflow 和 socket droped。

如果應用處理全連線佇列(accept queue)過慢則會導致socket overflow

影響半連線佇列(syn queue)溢位而導致socket dropped

[root@vm_0_15_centos ~]# netstat -s | grep -i listen    

62678 times the listen queue of a socket overflowed

65640 syns to listen sockets dropped

如果syn socket overflow和socket droped急劇增加的話則說明,tcp的三次握手是存在很大的問題的。

驗證檢視全連線佇列(accept queue)溢位之後,os處理設定:

0:表示如果三次握手第三步的時候全連線佇列滿了那麼server扔掉client發過來的ack(在server端則會認為連線沒有建立起來),server過一段時間再次傳送syn+ack給client(也就是重新走握手的第二步),如果client超時等待比較短,client就很容易異常了。

1:表示如果三次握手第三步的時候全連線佇列滿了,server端就會傳送乙個reset包給client端,表示廢棄這個握手過程和這個鏈結。(在server端也會認為連線沒有建立起來)

cat /proc/sys/net/ipv4/tcp_abort_on_overflow

設定tcp_abort_on_overflow為1

echo 1 > /proc/sys/net/ipv4/tcp_abort_on_overflow

檢視server端的web服務是否存在許多的connection reset peer錯誤。

在使用listen函式時,核心會根據傳入引數的backlog跟系統配置引數/proc/sys/net/core/somaxconn中,二者取最小值,作為「established狀態之後,完成tcp連線,等待服務程式accept」的佇列大小。在kernel 2.4.25之前,是寫死在**常量somaxconn,預設值是128。在kernel 2.4.25之後,在配置檔案/proc/sys/net/core/somaxconn (即 /etc/sysctl.conf 之類 )中可以修改。

[root@vm_0_15_centos ~]# cat /proc/sys/net/core/somaxconn

32768

[root@vm_0_15_centos ~]# cat /usr/local/php/etc/php-fpm.conf |grep backlog

listen.backlog = 1024

[root@vm_0_15_centos ~]# ss -ln |grep -e 'php|netid'

netid  state      recv-q send-q local address:port               peer address:port              

u_str  listen     0      1024   /dev/shm/php-cgi.sock 79785144              * 0

可見: 核心會根據傳入引數的backlog跟系統配置引數/proc/sys/net/core/somaxconn中,二者取最小值

我這裡php-fpm 配置的 listen = /dev/shm/php-cgi.sock ,如果你配置的 tcp監聽9000,應該用如下命令驗證

[root@vm_0_15_centos ~]# ss -lt

state      recv-q send-q local address:port             peer address:port                

listen     0      1024   0.0.0.0:9000               *:*

backlog大小設定為多少合適?

1、backlog太大了,導致php-fpm處理不過來,nginx那邊等待超時,斷開連線,報504 gateway timeout錯。同時php-fpm處理完準備write 資料給nginx時,發現tcp連線斷開了,報「broken pipe」。

2、php-fpm的backlog太小的話,nginx之類的client請求,根本進入不了php-fpm的accept queue,報「502 bad gateway」錯。所以,這還得去根據php-fpm的qps來決定backlog的大小。計算方式最好為qps=backlog。建議設定在1024以上,最好是2的冪值(因為核心會調整成2的n次冪)

syn queue長度由tcp_max_syn_backlog指定,accept queue則由net.core.somaxconn決定,listen(fd, backlog)的backlog上限由somaxconn決定.

php-fpm下backlog配置

php-fpm.conf進行配置

listen.backlog = 1024  預設值是 511 ,是在2023年7月22日修改的, set fpm_backlog_default to 511

其中理由是「backlog值為65535太大了。會導致前面的nginx(或者其他客戶端)超時」,假設fpm的qps為5000,那麼65535個請求全部處理完需要13s的樣子。但nginx(或其他客戶端)已經等待超時,關閉了這個連線。當fpm處理完之後,再往這個socket id 寫資料時,卻發現連線已關閉,得到的是「error: broken pipe」,在nginx、redis、apache裡,預設的backlog值都是511。故這裡也建議改為511。

nginx下backlog配置

/etc/nginx/nginx.conf進行配置

listen       80 backlog=8192; # 預設為511

linux下backlog配置

/etc/sysctl.conf 進行配置

net.core.somaxconn = 1048576 # 預設為128

net.core.netdev_max_backlog = 1048576 # 預設為1000

net.ipv4.tcp_max_syn_backlog = 1048576 # 預設為1024

高併發 秒殺業務場景詳解

一 秒殺場景的特點 秒殺的商品具有 低 庫存有限 定時開始的特點,因此秒殺場景最大的特點就是高併發。數以千萬的使用者的流量集中在某個時間點上 即秒殺開始時 給後端伺服器造成很大壓力,如果不能進行有效削峰 限流,所有請求一次性打到某一台伺服器或資料庫上,必然造成服務的不可用,給使用者造成不良體驗。二 ...

高併發場景下的限流策略

目錄快取 降級 限流 漏桶演算法 令牌桶演算法 漏桶演算法與令牌桶演算法的區別 有效提公升熱點資料的訪問效率,在高併發 大流量的場景降低服務端壓力。當訪問量快速增長 服務可能會出現一些問題 響應超時 或者會存在非核心服務影響到核心流程的效能時,仍然需要保證服務的可用性,即便是有損服務。所以意味著我們...

高併發場景下的請求合併

一.在專案中,我們經常用到如下方式進行介面呼叫 有多少請求訪問,就會呼叫多少次第三方介面或資料庫,這樣的情況在高併發場景下很容易出現執行緒被打滿,返回結果慢。為了優化這個介面,後台可以將相同的請求進行合併,然後呼叫批量的查詢介面。請求合併 下面上 已查詢資料庫舉例 1.建立請求類 data buil...