導航:首頁 > 操作系統 > backloglinux

backloglinux

發布時間:2023-02-14 13:39:20

linux中內核參數somaxconn

在Linux中,/proc/sys/net/core/somaxconn這個參數,linux中內核的一個不錯的參數somaxconn。

對於一個TCP連接,Server與Client需要通過三次握手來建立網路連接.當三次握手成功後,

我們可以看到埠的狀態由LISTEN轉變為ESTABLISHED,接著這條鏈路上就可以開始傳送數據了.

每一個處於監聽(Listen)狀態的埠,都有自己的監聽隊列.監聽隊列的長度,與如下兩方面有關:

- somaxconn參數.

- 使用該埠的程序中listen()函數.

1. 關於somaxconn參數:

定義了系統中每一個埠最大的監聽隊列的長度,這是個全局的參數,默認值為1024,具體信息為:

Purpose:

Specifies the maximum listen backlog.

Values:

Default: 1024 connections

Range: 0 to MAXSHORT

Type: Connect

Diagnosis:

N/A

Tuning

Increase this parameter on busy Web servers to handle peak connection rates.

看下FREEBSD的解析:

限制了接收新 TCP 連接偵聽隊列的大小。對於一個經常處理新連接的高負載 web服務環境來說,默認的128太小了(web伺服器listen函數的backlog會給我們內核參數的net.core.somaxconn先知道128,比如nginx)。大多數環境這個值建議增加到 1024 或者更多。 服務進程會自己限制偵聽隊列的大小(例如 sendmail(8) 或者 Apache),常常在它們的配置文件中有設置隊列大小的選項。大的偵聽隊列對防止拒絕服務 DoS 攻擊也會有所幫助。

socket tcp的backlog的上限是min(backlog,somaxconn),其中backlog是應用程序中傳遞給listen系統調用的參數值,somaxconn是內核規定的最大連接數。

② linux 下listen調用的backlog設為0,有何意義

listen的backlog參數指定的是已經三次握手完成,達到了established狀態但是等待accept的隊列的容量。當這個容量超過上限的時候伺服器端便不處理客戶端的三次握手了。這個隊列的容量當然不是樓主所說的並發連接數。
但是lisen的再後一道程序便是accept了。如果你想要的是在tcp並發連接數量超過上限的時候伺服器不再處理了三次握手那麼只有兩種辦法:
1.關閉listen的socket
2.自己修改tcp協議棧的實現,當然這個就比較麻煩了。

用iptables防火牆來限制tcp連接,
如下,限制用戶的tcp連接數為50

iptables -I INPUT-p tcp -m connlimit --connlimit-above 50 -j REJECT

③ 關於 Linux 網路,你必須知道這些

我們一起學習了文件系統和磁碟 I/O 的工作原理,以及相應的性能分析和優化方法。接下來,我們將進入下一個重要模塊—— Linux 的網路子系統。

由於網路處理的流程最復雜,跟我們前面講到的進程調度、中斷處理、內存管理以及 I/O 等都密不可分,所以,我把網路模塊作為最後一個資源模塊來講解。

同 CPU、內存以及 I/O 一樣,網路也是 Linux 系統最核心的功能。網路是一種把不同計算機或網路設備連接到一起的技術,它本質上是一種進程間通信方式,特別是跨系統的進程間通信,必須要通過網路才能進行。隨著高並發、分布式、雲計算、微服務等技術的普及,網路的性能也變得越來越重要。

說到網路,我想你肯定經常提起七層負載均衡、四層負載均衡,或者三層設備、二層設備等等。那麼,這里說的二層、三層、四層、七層又都是什麼意思呢?

實際上,這些層都來自國際標准化組織制定的開放式系統互聯通信參考模型(Open System Interconnection Reference Model),簡稱為 OSI 網路模型。

但是 OSI 模型還是太復雜了,也沒能提供一個可實現的方法。所以,在 Linux 中,我們實際上使用的是另一個更實用的四層模型,即 TCP/IP 網路模型。

TCP/IP 模型,把網路互聯的框架分為應用層、傳輸層、網路層、網路介面層等四層,其中,

為了幫你更形象理解 TCP/IP 與 OSI 模型的關系,我畫了一張圖,如下所示:

當然了,雖說 Linux 實際按照 TCP/IP 模型,實現了網路協議棧,但在平時的學習交流中,我們習慣上還是用 OSI 七層模型來描述。比如,說到七層和四層負載均衡,對應的分別是 OSI 模型中的應用層和傳輸層(而它們對應到 TCP/IP 模型中,實際上是四層和三層)。

OSI引入了服務、介面、協議、分層的概念,TCP/IP借鑒了OSI的這些概念建立TCP/IP模型。

OSI先有模型,後有協議,先有標准,後進行實踐;而TCP/IP則相反,先有協議和應用再提出了模型,且是參照的OSI模型。

OSI是一種理論下的模型,而TCP/IP已被廣泛使用,成為網路互聯事實上的標准。

有了 TCP/IP 模型後,在進行網路傳輸時,數據包就會按照協議棧,對上一層發來的數據進行逐層處理;然後封裝上該層的協議頭,再發送給下一層。

當然,網路包在每一層的處理邏輯,都取決於各層採用的網路協議。比如在應用層,一個提供 REST API 的應用,可以使用 HTTP 協議,把它需要傳輸的 JSON 數據封裝到 HTTP 協議中,然後向下傳遞給 TCP 層。

而封裝做的事情就很簡單了,只是在原來的負載前後,增加固定格式的元數據,原始的負載數據並不會被修改。

比如,以通過 TCP 協議通信的網路包為例,通過下面這張圖,我們可以看到,應用程序數據在每個層的封裝格式。

這些新增的頭部和尾部,增加了網路包的大小,但我們都知道,物理鏈路中並不能傳輸任意大小的數據包。網路介面配置的最大傳輸單元(MTU),就規定了最大的 IP 包大小。在我們最常用的乙太網中,MTU 默認值是 1500(這也是 Linux 的默認值)。

一旦網路包超過 MTU 的大小,就會在網路層分片,以保證分片後的 IP 包不大於 MTU 值。顯然,MTU 越大,需要的分包也就越少,自然,網路吞吐能力就越好。

理解了 TCP/IP 網路模型和網路包的封裝原理後,你很容易能想到,Linux 內核中的網路棧,其實也類似於 TCP/IP 的四層結構。如下圖所示,就是 Linux 通用 IP 網路棧的示意圖:

我們從上到下來看這個網路棧,你可以發現,

這里我簡單說一下網卡。網卡是發送和接收網路包的基本設備。在系統啟動過程中,網卡通過內核中的網卡驅動程序注冊到系統中。而在網路收發過程中,內核通過中斷跟網卡進行交互。

再結合前面提到的 Linux 網路棧,可以看出,網路包的處理非常復雜。所以,網卡硬中斷只處理最核心的網卡數據讀取或發送,而協議棧中的大部分邏輯,都會放到軟中斷中處理。

我們先來看網路包的接收流程。

當一個網路幀到達網卡後,網卡會通過 DMA 方式,把這個網路包放到收包隊列中;然後通過硬中斷,告訴中斷處理程序已經收到了網路包。

接著,網卡中斷處理程序會為網路幀分配內核數據結構(sk_buff),並將其拷貝到 sk_buff 緩沖區中;然後再通過軟中斷,通知內核收到了新的網路幀。

接下來,內核協議棧從緩沖區中取出網路幀,並通過網路協議棧,從下到上逐層處理這個網路幀。比如,

最後,應用程序就可以使用 Socket 介面,讀取到新接收到的數據了。

為了更清晰表示這個流程,我畫了一張圖,這張圖的左半部分表示接收流程,而圖中的粉色箭頭則表示網路包的處理路徑。

了解網路包的接收流程後,就很容易理解網路包的發送流程。網路包的發送流程就是上圖的右半部分,很容易發現,網路包的發送方向,正好跟接收方向相反。

首先,應用程序調用 Socket API(比如 sendmsg)發送網路包。

由於這是一個系統調用,所以會陷入到內核態的套接字層中。套接字層會把數據包放到 Socket 發送緩沖區中。

接下來,網路協議棧從 Socket 發送緩沖區中,取出數據包;再按照 TCP/IP 棧,從上到下逐層處理。比如,傳輸層和網路層,分別為其增加 TCP 頭和 IP 頭,執行路由查找確認下一跳的 IP,並按照 MTU 大小進行分片。

分片後的網路包,再送到網路介面層,進行物理地址定址,以找到下一跳的 MAC 地址。然後添加幀頭和幀尾,放到發包隊列中。這一切完成後,會有軟中斷通知驅動程序:發包隊列中有新的網路幀需要發送。

最後,驅動程序通過 DMA ,從發包隊列中讀出網路幀,並通過物理網卡把它發送出去。

多台伺服器通過網卡、交換機、路由器等網路設備連接到一起,構成了相互連接的網路。由於網路設備的異構性和網路協議的復雜性,國際標准化組織定義了一個七層的 OSI 網路模型,但是這個模型過於復雜,實際工作中的事實標准,是更為實用的 TCP/IP 模型。

TCP/IP 模型,把網路互聯的框架,分為應用層、傳輸層、網路層、網路介面層等四層,這也是 Linux 網路棧最核心的構成部分。

我結合網路上查閱的資料和文章中的內容,總結了下網卡收發報文的過程,不知道是否正確:

當發送數據包時,與上述相反。鏈路層將數據包封裝完畢後,放入網卡的DMA緩沖區,並調用系統硬中斷,通知網卡從緩沖區讀取並發送數據。

了解 Linux 網路的基本原理和收發流程後,你肯定迫不及待想知道,如何去觀察網路的性能情況。具體而言,哪些指標可以用來衡量 Linux 的網路性能呢?

實際上,我們通常用帶寬、吞吐量、延時、PPS(Packet Per Second)等指標衡量網路的性能。

除了這些指標,網路的可用性(網路能否正常通信)、並發連接數(TCP 連接數量)、丟包率(丟包百分比)、重傳率(重新傳輸的網路包比例)等也是常用的性能指標。

分析網路問題的第一步,通常是查看網路介面的配置和狀態。你可以使用 ifconfig 或者 ip 命令,來查看網路的配置。我個人更推薦使用 ip 工具,因為它提供了更豐富的功能和更易用的介面。

以網路介面 eth0 為例,你可以運行下面的兩個命令,查看它的配置和狀態:

你可以看到,ifconfig 和 ip 命令輸出的指標基本相同,只是顯示格式略微不同。比如,它們都包括了網路介面的狀態標志、MTU 大小、IP、子網、MAC 地址以及網路包收發的統計信息。

第一,網路介面的狀態標志。ifconfig 輸出中的 RUNNING ,或 ip 輸出中的 LOWER_UP ,都表示物理網路是連通的,即網卡已經連接到了交換機或者路由器中。如果你看不到它們,通常表示網線被拔掉了。

第二,MTU 的大小。MTU 默認大小是 1500,根據網路架構的不同(比如是否使用了 VXLAN 等疊加網路),你可能需要調大或者調小 MTU 的數值。

第三,網路介面的 IP 地址、子網以及 MAC 地址。這些都是保障網路功能正常工作所必需的,你需要確保配置正確。

第四,網路收發的位元組數、包數、錯誤數以及丟包情況,特別是 TX 和 RX 部分的 errors、dropped、overruns、carrier 以及 collisions 等指標不為 0 時,通常表示出現了網路 I/O 問題。其中:

ifconfig 和 ip 只顯示了網路介面收發數據包的統計信息,但在實際的性能問題中,網路協議棧中的統計信息,我們也必須關注。你可以用 netstat 或者 ss ,來查看套接字、網路棧、網路介面以及路由表的信息。

我個人更推薦,使用 ss 來查詢網路的連接信息,因為它比 netstat 提供了更好的性能(速度更快)。

比如,你可以執行下面的命令,查詢套接字信息:

netstat 和 ss 的輸出也是類似的,都展示了套接字的狀態、接收隊列、發送隊列、本地地址、遠端地址、進程 PID 和進程名稱等。

其中,接收隊列(Recv-Q)和發送隊列(Send-Q)需要你特別關注,它們通常應該是 0。當你發現它們不是 0 時,說明有網路包的堆積發生。當然還要注意,在不同套接字狀態下,它們的含義不同。

當套接字處於連接狀態(Established)時,

當套接字處於監聽狀態(Listening)時,

所謂全連接,是指伺服器收到了客戶端的 ACK,完成了 TCP 三次握手,然後就會把這個連接挪到全連接隊列中。這些全連接中的套接字,還需要被 accept() 系統調用取走,伺服器才可以開始真正處理客戶端的請求。

與全連接隊列相對應的,還有一個半連接隊列。所謂半連接是指還沒有完成 TCP 三次握手的連接,連接只進行了一半。伺服器收到了客戶端的 SYN 包後,就會把這個連接放到半連接隊列中,然後再向客戶端發送 SYN+ACK 包。

類似的,使用 netstat 或 ss ,也可以查看協議棧的信息:

這些協議棧的統計信息都很直觀。ss 只顯示已經連接、關閉、孤兒套接字等簡要統計,而 netstat 則提供的是更詳細的網路協議棧信息。

比如,上面 netstat 的輸出示例,就展示了 TCP 協議的主動連接、被動連接、失敗重試、發送和接收的分段數量等各種信息。

接下來,我們再來看看,如何查看系統當前的網路吞吐量和 PPS。在這里,我推薦使用我們的老朋友 sar,在前面的 CPU、內存和 I/O 模塊中,我們已經多次用到它。

給 sar 增加 -n 參數就可以查看網路的統計信息,比如網路介面(DEV)、網路介面錯誤(EDEV)、TCP、UDP、ICMP 等等。執行下面的命令,你就可以得到網路介面統計信息:

這兒輸出的指標比較多,我來簡單解釋下它們的含義。

其中,Bandwidth 可以用 ethtool 來查詢,它的單位通常是 Gb/s 或者 Mb/s,不過注意這里小寫字母 b ,表示比特而不是位元組。我們通常提到的千兆網卡、萬兆網卡等,單位也都是比特。如下你可以看到,我的 eth0 網卡就是一個千兆網卡:

其中,Bandwidth 可以用 ethtool 來查詢,它的單位通常是 Gb/s 或者 Mb/s,不過注意這里小寫字母 b ,表示比特而不是位元組。我們通常提到的千兆網卡、萬兆網卡等,單位也都是比特。如下你可以看到,我的 eth0 網卡就是一個千兆網卡:

我們通常使用帶寬、吞吐量、延時等指標,來衡量網路的性能;相應的,你可以用 ifconfig、netstat、ss、sar、ping 等工具,來查看這些網路的性能指標。

小狗同學問到: 老師,您好 ss —lntp 這個 當session處於listening中 rec-q 確定是 syn的backlog嗎?
A: Recv-Q為全連接隊列當前使用了多少。 中文資料里這個問題講得最明白的文章: https://mp.weixin.qq.com/s/yH3PzGEFopbpA-jw4MythQ

看了源碼發現,這個地方講的有問題.關於ss輸出中listen狀態套接字的Recv-Q表示全連接隊列當前使用了多少,也就是全連接隊列的當前長度,而Send-Q表示全連接隊列的最大長度

④ linux 內核參數優化

一、Sysctl命令用來配置與顯示在/proc/sys目錄中的內核參數.如果想使參數長期保存,可以通過編輯/etc/sysctl.conf文件來實現。

命令格式:
sysctl [-n] [-e] -w variable=value
sysctl [-n] [-e] -p (default /etc/sysctl.conf)
sysctl [-n] [-e] –a

常用參數的意義:
-w 臨時改變某個指定參數的值,如
# sysctl -w net.ipv4.ip_forward=1
-a 顯示所有的系統參數
-p從指定的文件載入系統參數,默認從/etc/sysctl.conf 文件中載入,如:

以上兩種方法都可能立即開啟路由功能,但如果系統重啟,或執行了
# service network restart
命令,所設置的值即會丟失,如果想永久保留配置,可以修改/etc/sysctl.conf文件,將 net.ipv4.ip_forward=0改為net.ipv4.ip_forward=1

二、linux內核參數調整:linux 內核參數調整有兩種方式

方法一:修改/proc下內核參數文件內容,不能使用編輯器來修改內核參數文件,理由是由於內核隨時可能更改這些文件中的任意一個,另外,這些內核參數文件都是虛擬文件,實際中不存在,因此不能使用編輯器進行編輯,而是使用echo命令,然後從命令行將輸出重定向至 /proc 下所選定的文件中。如:將 timeout_timewait 參數設置為30秒:

參數修改後立即生效,但是重啟系統後,該參數又恢復成默認值。因此,想永久更改內核參數,需要修改/etc/sysctl.conf文件

方法二.修改/etc/sysctl.conf文件。檢查sysctl.conf文件,如果已經包含需要修改的參數,則修改該參數的值,如果沒有需要修改的參數,在sysctl.conf文件中添加參數。如:
net.ipv4.tcp_fin_timeout=30
保存退出後,可以重啟機器使參數生效,如果想使參數馬上生效,也可以執行如下命令:

三、sysctl.conf 文件中參數設置及說明
proc/sys/net/core/wmem_max
最大socket寫buffer,可參考的優化值:873200

/proc/sys/net/core/rmem_max
最大socket讀buffer,可參考的優化值:873200
/proc/sys/net/ipv4/tcp_wmem
TCP寫buffer,可參考的優化值: 8192 436600 873200

/proc/sys/net/ipv4/tcp_rmem
TCP讀buffer,可參考的優化值: 32768 436600 873200

/proc/sys/net/ipv4/tcp_mem
同樣有3個值,意思是:
net.ipv4.tcp_mem[0]:低於此值,TCP沒有內存壓力.
net.ipv4.tcp_mem[1]:在此值下,進入內存壓力階段.
net.ipv4.tcp_mem[2]:高於此值,TCP拒絕分配socket.
上述內存單位是頁,而不是位元組.可參考的優化值是:786432 1048576 1572864

/proc/sys/net/core/netdev_max_backlog
進入包的最大設備隊列.默認是300,對重負載伺服器而言,該值太低,可調整到1000

/proc/sys/net/core/somaxconn
listen()的默認參數,掛起請求的最大數量.默認是128.對繁忙的伺服器,增加該值有助於網路性能.可調整到256.

/proc/sys/net/core/optmem_max
socket buffer的最大初始化值,默認10K

/proc/sys/net/ipv4/tcp_max_syn_backlog
進入SYN包的最大請求隊列.默認1024.對重負載伺服器,可調整到2048

/proc/sys/net/ipv4/tcp_retries2
TCP失敗重傳次數,默認值15,意味著重傳15次才徹底放棄.可減少到5,盡早釋放內核資源.

/proc/sys/net/ipv4/tcp_keepalive_time
/proc/sys/net/ipv4/tcp_keepalive_intvl
/proc/sys/net/ipv4/tcp_keepalive_probes
這3個參數與TCP KeepAlive有關.默認值是:
tcp_keepalive_time = 7200 seconds (2 hours)
tcp_keepalive_probes = 9
tcp_keepalive_intvl = 75 seconds
意思是如果某個TCP連接在idle 2個小時後,內核才發起probe.如果probe 9次(每次75秒)不成功,內核才徹底放棄,認為該連接已失效.對伺服器而言,顯然上述值太大. 可調整到:
/proc/sys/net/ipv4/tcp_keepalive_time 1800
/proc/sys/net/ipv4/tcp_keepalive_intvl 30
/proc/sys/net/ipv4/tcp_keepalive_probes 3

/proc/sys/net/ipv4/ip_local_port_range
指定埠范圍的一個配置,默認是32768 61000,已夠大.
net.ipv4.tcp_syncookies = 1
表示開啟SYN Cookies。當出現SYN等待隊列溢出時,啟用cookies來處理,可防範少量SYN攻擊,默認為0,表示關閉;

net.ipv4.tcp_tw_reuse = 1
表示開啟重用。允許將TIME-WAIT sockets重新用於新的TCP連接,默認為0,表示關閉;

net.ipv4.tcp_tw_recycle = 1
表示開啟TCP連接中TIME-WAIT sockets的快速回收,默認為0,表示關閉。

net.ipv4.tcp_fin_timeout = 30
表示如果套接字由本端要求關閉,這個參數決定了它保持在FIN-WAIT-2狀態的時間。

net.ipv4.tcp_keepalive_time = 1200
表示當keepalive起用的時候,TCP發送keepalive消息的頻度。預設是2小時,改為20分鍾。

net.ipv4.ip_local_port_range = 1024 65000
表示用於向外連接的埠范圍。預設情況下很小:32768到61000,改為1024到65000。

net.ipv4.tcp_max_syn_backlog = 8192
表示SYN隊列的長度,默認為1024,加大隊列長度為8192,可以容納更多等待連接的網路連接數。

net.ipv4.tcp_max_tw_buckets = 5000
表示系統同時保持TIME_WAIT套接字的最大數量,如果超過這個數字,TIME_WAIT套接字將立刻被清除並列印警告信息。默認為 180000,改為 5000。對於Apache、Nginx等伺服器,上幾行的參數可以很好地減少TIME_WAIT套接字數量,但是對於Squid,效果卻不大。此項參數可以控制TIME_WAIT套接字的最大數量,避免Squid伺服器被大量的TIME_WAIT套接字拖死。

Linux上的NAT與iptables
談起Linux上的NAT,大多數人會跟你提到iptables。原因是因為iptables是目前在linux上實現NAT的一個非常好的介面。它通過和內核級直接操作網路包,效率和穩定性都非常高。這里簡單列舉一些NAT相關的iptables實例命令,可能對於大多數實現有多幫助。
這里說明一下,為了節省篇幅,這里把准備工作的命令略去了,僅僅列出核心步驟命令,所以如果你單單執行這些沒有實現功能的話,很可能由於准備工作沒有做好。如果你對整個命令細節感興趣的話,可以直接訪問我的《如何讓你的Linux網關更強大》系列文章,其中對於各個腳本有詳細的說明和描述。

EXTERNAL="eth0"
INTERNAL="eth1"

echo 1 > /proc/sys/net/ipv4/ip_forward
iptables -t nat -A POSTROUTING -o $EXTERNAL -j MASQUERADE

LOCAL_EX_IP=11.22.33.44 #設定網關的外網卡ip,對於多ip情況,參考《如何讓你的Linux網關更強大》系列文章
LOCAL_IN_IP=192.168.1.1 #設定網關的內網卡ip
INTERNAL="eth1" #設定內網卡

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

modprobe ip_conntrack_ftp
modprobe ip_nat_ftp

iptables -t nat -A PREROUTING -d $LOCAL_EX_IP -p tcp --dport 80 -j DNAT --to 192.168.1.10

iptables -t nat -A POSTROUTING -d 192.168.1.10 -p tcp --dport 80 -j SNAT --to $LOCAL_IN_IP

iptables -A FORWARD -o $INTERNAL -d 192.168.1.10 -p tcp --dport 80 -j ACCEPT

iptables -t nat -A OUTPUT -d $LOCAL_EX_IP -p tcp --dport 80 -j DNAT --to 192.168.1.10
獲取系統中的NAT信息和診斷錯誤
了解/proc目錄的意義
在Linux系統中,/proc是一個特殊的目錄,proc文件系統是一個偽文件系統,它只存在內存當中,而不佔用外存空間。它包含當前系統的一些參數(variables)和狀態(status)情況。它以文件系統的方式為訪問系統內核數據的操作提供介面
通過/proc可以了解到系統當前的一些重要信息,包括磁碟使用情況,內存使用狀況,硬體信息,網路使用情況等等,很多系統監控工具(如HotSaNIC)都通過/proc目錄獲取系統數據。
另一方面通過直接操作/proc中的參數可以實現系統內核參數的調節,比如是否允許ip轉發,syn-cookie是否打開,tcp超時時間等。
獲得參數的方式:
第一種:cat /proc/xxx/xxx,如 cat /proc/sys/net/ipv4/conf/all/rp_filter
第二種:sysctl xxx.xxx.xxx,如 sysctl net.ipv4.conf.all.rp_filter
改變參數的方式:
第一種:echo value > /proc/xxx/xxx,如 echo 1 > /proc/sys/net/ipv4/conf/all/rp_filter
第二種:sysctl [-w] variable=value,如 sysctl [-w] net.ipv4.conf.all.rp_filter=1
以上設定系統參數的方式只對當前系統有效,重起系統就沒了,想要保存下來,需要寫入/etc/sysctl.conf文件中
通過執行 man 5 proc可以獲得一些關於proc目錄的介紹
查看系統中的NAT情況
和NAT相關的系統變數
/proc/slabinfo:內核緩存使用情況統計信息(Kernel slab allocator statistics)
/proc/sys/net/ipv4/ip_conntrack_max:系統支持的最大ipv4連接數,默認65536(事實上這也是理論最大值)
/proc/sys/net/ipv4/netfilter/ip_conntrack_tcp_timeout_established 已建立的tcp連接的超時時間,默認432000,也就是5天
和NAT相關的狀態值
/proc/net/ip_conntrack:當前的前被跟蹤的連接狀況,nat翻譯表就在這里體現(對於一個網關為主要功能的Linux主機,裡面大部分信息是NAT翻譯表)
/proc/sys/net/ipv4/ip_local_port_range:本地開放埠范圍,這個范圍同樣會間接限制NAT表規模

cat /proc/sys/net/ipv4/ip_conntrack_max

cat /proc/sys/net/ipv4/netfilter/ip_conntrack_tcp_timeout_established

cat /proc/net/ip_conntrack

cat /proc/sys/net/ipv4/ip_local_port_range

wc -l /proc/net/ip_conntrack

grep ip_conntrack /proc/slabinfo | grep -v expect | awk '{print 2;}'

grep ip_conntrack /proc/slabinfo | grep -v expect | awk '{print 3;}'

cat /proc/net/ip_conntrack | cut -d ' ' -f 10 | cut -d '=' -f 2 | sort | uniq -c | sort -nr | head -n 10

cat /proc/net/ip_conntrack | perl -pe s/^(.*?)src/src/g | cut -d ' ' -f1 | cut -d '=' -f2 | sort | uniq -c | sort -nr | head -n 10

⑤ linux日誌 audit

我們知道在Linux系統中有大量的日誌文件可以用於查看應用程序的各種信息,但是對於用戶的操作行為(如某用戶修改刪除了某文件)卻無法通過這些日誌文件來查看,如果我們想實現監管企業員工的操作行為就需要開啟審計功能,也就是audit。

1、首先執行以下命令開啟auditd服務

| 1 | service auditd start |

2、接著查看看auditd的服務狀態,有兩種方法可以實現,使用auditctl命令時主要看enabled是否為1,1為開啟,0為關閉

[root@ns-master-c01 ~]``# service auditd status` |

`auditd (pid 20594) is running...
[root@ns-master-c01 ~]``# auditctl -s

| 5 | AUDIT_STATUS: enabled=1 flag=1 pid=20594 rate_limit=0 backlog_limit=320 lost=0 backlog=0 |

3、開啟了autid服務後,所有的審計日誌會記錄在/var/log/audit/audit.log文件中,該文件記錄格式是每行以type開頭,其中紅框處是事件發生的時間(代表從1970年1月1日到現在過了多久,可以用date命令轉換格式),冒號後面的數字是事件ID,同一個事件ID是一樣的。

4、audit可以自定義對指定的文件或命令進行審計(如監視rm命令被執行、/etc/passwd文件內容被改變),只要配置好對應規則即可,配置規則可以通過命令行(臨時生效)或者編輯配置文件(永久生效)兩種方式來實現。

命令行語法(臨時生效****)****:

| 1 | auditctl -w /bin/``rm -p x -k removefile ``#-w指定所要監控的文件或命令 |

| 2 | #-p指定監控屬性,如x執行、w修改 |

| 3 | #-k是設置一個關鍵詞用於查詢 |

編輯配置文件(****永久生效)****:

auditd的配置文件為/etc/audit/audit下的auditd.conf 和audit.rules,auditd.conf 主要是定義了auditd服務日誌和性能等相關配置,audit.rules才是定義規則的文件,下面是一個例子,其實就是把auditctl的命令直接拿過來即可,auditctl里支持的選項都可以在這個文件里指定

修改完後重啟服務

| 1 | service auditd restart |

5、如果直接使用tailf等查看工具進行日誌分析會比較麻煩,好在audit已經提供了一個更好的事件查看工具—— ausea****rch, 使用auserach -h查看下該命令的用法:

這里列出幾個常用的選項:

-a number #只顯示事件ID為指定數字的日誌信息,如只顯示926事件:ausearch -a 926

-c commond #只顯示和指定命令有關的事件,如只顯示rm命令產生的事件:auserach -c rm

-i #顯示出的信息更清晰,如事件時間、相關用戶名都會直接顯示出來,而不再是數字形式

-k #顯示出和之前auditctl -k所定義的關鍵詞相匹配的事件信息

通過下圖可以看到每個事件被虛線分開,用戶名和執行的操作也都能清晰的看到了:

6、使用auditctl還可以查看和清空規則

查看源碼

<embed width="16" height="16" id="highlighter_638828_clipboard" type="application/x-shockwave-flash" title="復制到剪貼板" allowscriptaccess="always" wmode="transparent" flashvars="highlighterId=highlighter_638828" menu="false" src="http://www.linuxe.cn/content/plugins/et_highlighter51/scripts/clipboard.swf" style="margin: 0px; padding: 0px; outline: 0px; zoom: 1; max-width: 96%;">

摘自 http://www.linuxe.cn/post-255.html

| 1 | auditctl -l 查看定義的規則 |

| 2 | auditctl -D 清空定義的規則 |

⑥ listen 函數中參數 backlog

我們該如何理解 listen 函數中的參數 backlog?如果 backlog 表示的是未完成連接隊列的大小,那麼已完成連接的隊列的大小有限制嗎?如果都是已經建立連接的狀態,那麼並發取決於已完成連接的隊列的大小嗎?

backlog 的值含義從來就沒有被嚴格定義過。原先 Linux 實現中,backlog 參數定義了該套接字對應的未完成連接隊列的最大長度 (pending connections)。如果一個連接到達時,該隊列已滿,客戶端將會接收一個 ECONNREFUSED 的錯誤信息,如果支持重傳,該請求可能會被忽略,之後會進行一次重傳。

從 Linux 2.2 開始,backlog 的參數內核有了新的語義,它現在定義的是已完成連接隊列的最大長度,表示的是已建立的連接(established connection),正在等待被接收(accept 調用返回),而不是原先的未完成隊列的最大長度。現在,未完成隊列的最大長度值可以通過 /proc/sys/net/ipv4/tcp_max_syn_backlog 完成修改,默認值為 128。

至於已完成連接隊列,如果聲明的 backlog 參數比 /proc/sys/net/core/somaxconn 的參數要大,那麼就會使用我們聲明的那個值。實際上,這個默認的值為 128。注意在 Linux 2.4.25 之前,這個值是不可以修改的一個固定值,大小也是 128。

設計良好的程序,在 128 固定值的情況下也是可以支持成千上萬的並發連接的,這取決於 I/O 分發的效率,以及多線程程序的設計。在後面的性能篇里,我們的目標就是設計這樣的程序。

https://time.geekbang.org/column/article/135735

⑦ 暢談linux下TCP(上)

tcp 協議 是互聯網中最常用的協議 , 開發人員基本上天天和它打交道,對它進行深入了解。 可以幫助我們排查定位bug和進行程序優化。下面我將就TCP幾個點做深入的探討

客戶端:收到 ack 後 分配連接資源。 發送數據
伺服器 : 收到 syn 後立即 分配連接資源

客戶端:收到ACK, 立即分配資源
伺服器:收到ACK, 立即分配資源

既然三次握手也不是100%可靠, 那四次,五次,六次。。。呢? 其實都一樣,不管多少次都有丟包問題。

client 只發送一個 SYN, server 分配一個tcb, 放入syn隊列中。 這時候連接叫 半連接 狀態;如果server 收不到 client 的ACK, 會不停重試 發送 ACK-SYN 給client 。重試間隔 為 2 的 N 次方 疊加(2^0 , 2^1, 2^2 ....);直至超時才釋放syn隊列中的這個 TCB;
在半連接狀態下, 一方面會佔用隊列配額資源,另一方面佔用內存資源。我們應該讓半連接狀態存在時間盡可能的小

當client 向一個未打開的埠發起連接請求時,會收到一個RST回復包

當listen 的 backlog 和 somaxconn 都設置了得時候, 取兩者min值

Recv-Q 是accept 隊列當前個數, Send-Q 設置最大值

這種SYN洪水攻擊是一種常見攻擊方式,就是利用半連接隊列特性,占滿syn 隊列的 資源,導致 client無法連接上。
解決方案:

為什麼不像握手那樣合並成三次揮手? 因為和剛開始連接情況,連接是大家都從0開始, 關閉時有歷史包袱的。server(被動關閉方) 收到 client(主動關閉方) 的關閉請求FIN包。 這時候可能還有未發送完的數據,不能丟棄。 所以需要分開。事實可能是這樣

當然,在沒有待發數據,並且允許 Delay ACK 情況下, FIN-ACK合並還是非常常見的事情,這是三次揮手是可以的。

同上

CLOSE_WAIT 是被動關閉方才有的狀態

被動關閉方 [收到 FIN 包 發送 ACK 應答] 到 [發送FIN, 收到ACK ] 期間的狀態為 CLOSE_WAIT, 這個狀態仍然能發送數據。 我們叫做 半關閉 , 下面用個例子來分析:

這個是我實際生產環境碰到的一個問題,長連接會話場景,server端收到client的rpc call 請求1,處理發現請求包有問題,就強制關閉結束這次會話, 但是 因為client 發送 第二次請求之前,並沒有去調用recv,所以並不知道 這個連接被server關閉, 繼續發送 請求2 , 此時是半連接,能夠成功發送到對端機器,但是recv結果後,遇到連接已經關閉錯誤。

如果 client 和 server 恰好同時發起關閉連接。這種情況下,兩邊都是主動連接,都會進入 TIME_WAIT狀態

1、 被動關閉方在LAST_ACK狀態(已經發送FIN),等待主動關閉方的ACK應答,但是 ACK丟掉, 主動方並不知道,以為成功關閉。因為沒有TIME_WAIT等待時間,可以立即創建新的連接, 新的連接發送SYN到前面那個未關閉的被動方,被動方認為是收到錯誤指令,會發送RST。導致創建連接失敗。

2、 主動關閉方斷開連接,如果沒有TIME_WAIT等待時間,可以馬上建立一個新的連接,但是前一個已經斷開連接的,延遲到達的數據包。 被新建的連接接收,如果剛好seq 和 ack欄位 都正確, seq在滑動窗口范圍內(只能說機率非常小,但是還是有可能會發生),會被當成正確數據包接收,導致數據串包。 如果不在window范圍內,則沒有影響( 發送一個確認報文(ack 欄位為期望ack的序列號,seq為當前發送序列號),狀態變保持原樣)

TIME_WAIT 問題比較比較常見,特別是CGI機器,並發量高,大量連接後段服務的tcp短連接。因此也衍生出了多種手段解決。雖然每種方法解決不是那麼完美,但是帶來的好處一般多於壞處。還是在日常工作中會使用。
1、改短TIME_WAIT 等待時間

這個是第一個想到的解決辦法,既然等待時間太長,就改成時間短,快速回收埠。但是實際情況往往不樂觀,對於並發的機器,你改多短才能保證回收速度呢,有時候幾秒鍾就幾萬個連接。太短的話,就會有前面兩種問題小概率發生。

2、禁止Socket lingering

這種情況下關閉連接,會直接拋棄緩沖區中待發送的數據,會發送一個RST給對端,相當於直接拋棄TIME_WAIT, 進入CLOSE狀態。同樣因為取消了 TIME_WAIT 狀態,會有前面兩種問題小概率發生。

3、tcp_tw_reuse
net.ipv4.tcp_tw_reuse選項是 從 TIME_WAIT 狀態的隊列中,選取條件:1、remote 的 ip 和埠相同, 2、選取一個時間戳小於當前時間戳; 用來解決埠不足的尷尬。

現在埠可以復用了,看看如何面對前面TIME_WAIT 那兩種問題。 我們仔細回顧用一下前面兩種問題。 都是在新建連接中收到老連接的包導致的問題 , 那麼如果我能在新連接中識別出此包為非法包,是不是就可以丟掉這些無用包,解決問題呢。

需要實現這些功能,需要擴展一下tcp 包頭。 增加 時間戳欄位。 發送者 在每次發送的時候。 在tcp包頭裡面帶上發送時候的時間戳。 當接收者接收的時候,在ACK應答中除了TCP包頭中帶自己此時發送的時間戳,並且把收到的時間戳附加在後面。也就是說ACK包中有兩個時間戳欄位。結構如下:

那我們接下來一個個分析tcp_tw_reuse是如何解決TIME_WAIT的兩個問題的

4、tcp_tw_recycle

tcp_tw_recycle 也是藉助 timestamp機制。顧名思義, tcp_tw_reuse 是復用 埠,並不會減少 TIME-WAIT 數量。你去查詢機器上TIME-WAIT 數量,還是 幾千幾萬個,這點對有強迫症的同學感覺很不舒服。tcp_tw_recycle 是 提前 回收 TIME-WAIT資源。會減少 機器上 TIME-WAIT 數量。

tcp_tw_recycle 工作原理是。

⑧ 如何在linux下開啟napi

天重點對linux網路數據包的處理做下分析,但是並不關繫到上層協議,僅僅到鏈路層。
之前轉載過一篇文章,對NAPI做了比較詳盡的分析,本文結合Linux內核源代碼,對當前網路數據包的處理進行梳理。根據NAPI的處理特性,對設備提出一定的要求
1、設備需要有足夠的緩沖區,保存多個數據分組
2、可以禁用當前設備中斷,然而不影響其他的操作。
當前大部分的設備都支持NAPI,但是為了對之前的保持兼容,內核還是對之前中斷方式提供了兼容。我們先看下NAPI具體的處理方式。我們都知道中斷分為中斷上半部和下半部,上半部完成的任務很是簡單,僅僅負責把數據保存下來;而下半部負責具體的處理。為了處理下半部,每個CPU有維護一個softnet_data結構。我們不對此結構做詳細介紹,僅僅描述和NAPI相關的部分。結構中有一個poll_list欄位,連接所有的輪詢設備。還 維護了兩個隊列input_pkt_queue和process_queue。這兩個用戶傳統不支持NAPI方式的處理。前者由中斷上半部的處理函數吧數據包入隊,在具體的處理時,使用後者做中轉,相當於前者負責接收,後者負責處理。最後是一個napi_struct的backlog,代表一個虛擬設備供輪詢使用。在支持NAPI的設備下,每個設備具備一個緩沖隊列,存放到來數據。每個設備對應一個napi_struct結構,該結構代表該設備存放在poll_list中被輪詢。而設備還需要提供一個poll函數,在設備被輪詢到後,會調用poll函數對數據進行處理。基本邏輯就是這樣,下面看下具體流程。
中斷上半部:
非NAPI:
非NAPI對應的上半部函數為netif_rx,位於Dev.,c中

int netif_rx(struct sk_buff *skb)
{
int ret;
/* if netpoll wants it, pretend we never saw it */
/*如果是net_poll想要的,則不作處理*/
if (netpoll_rx(skb))
return NET_RX_DROP;
/*檢查時間戳*/
net_timestamp_check(netdev_tstamp_prequeue, skb);
trace_netif_rx(skb);
#ifdef CONFIG_RPS
if (static_key_false(&rps_needed)) {
struct rps_dev_flow voidflow, *rflow = &voidflow;
int cpu;
/*禁用搶占*/
preempt_disable();
rcu_read_lock();

cpu = get_rps_cpu(skb->dev, skb, &rflow);
if (cpu < 0)
cpu = smp_processor_id();
/*把數據入隊*/
ret = enqueue_to_backlog(skb, cpu, &rflow->last_qtail);
rcu_read_unlock();
preempt_enable();
} else
#endif
{
unsigned int qtail;
ret = enqueue_to_backlog(skb, get_cpu(), &qtail);
put_cpu();
}
return ret;
}

中間RPS暫時不關心,這里直接調用enqueue_to_backlog放入CPU的全局隊列input_pkt_queue

static int enqueue_to_backlog(struct sk_buff *skb, int cpu,
unsigned int *qtail)
{
struct softnet_data *sd;
unsigned long flags;
/*獲取cpu相關的softnet_data變數*/
sd = &per_cpu(softnet_data, cpu);
/*關中斷*/
local_irq_save(flags);
rps_lock(sd);
/*如果input_pkt_queue的長度小於最大限制,則符合條件*/
if (skb_queue_len(&sd->input_pkt_queue) <= netdev_max_backlog) {
/*如果input_pkt_queue不為空,說明虛擬設備已經得到調度,此時僅僅把數據加入
input_pkt_queue隊列即可
*/
if (skb_queue_len(&sd->input_pkt_queue)) {
enqueue:
__skb_queue_tail(&sd->input_pkt_queue, skb);
input_queue_tail_incr_save(sd, qtail);
rps_unlock(sd);
local_irq_restore(flags);
return NET_RX_SUCCESS;
}
/* Schele NAPI for backlog device
* We can use non atomic operation since we own the queue lock
*/
/*否則需要調度backlog 即虛擬設備,然後再入隊。napi_struct結構中的state欄位如果標記了NAPI_STATE_SCHED,則表明該設備已經在調度,不需要再次調度*/
if (!__test_and_set_bit(NAPI_STATE_SCHED, &sd->backlog.state)) {
if (!rps_ipi_queued(sd))
____napi_schele(sd, &sd->backlog);
}
goto enqueue;
}
/*到這里緩沖區已經不足了,必須丟棄*/
sd->dropped++;
rps_unlock(sd);
local_irq_restore(flags);
atomic_long_inc(&skb->dev->rx_dropped);
kfree_skb(skb);
return NET_RX_DROP;
}

該函數邏輯也比較簡單,主要注意的是設備必須先添加調度然後才能接受數據,添加調度調用了____napi_schele函數,該函數把設備對應的napi_struct結構插入到softnet_data的poll_list鏈表尾部,然後喚醒軟中斷,這樣在下次軟中斷得到處理時,中斷下半部就會得到處理。不妨看下源碼
static inline void ____napi_schele(struct softnet_data *sd,
struct napi_struct *napi)
{
list_add_tail(&napi->poll_list, &sd->poll_list);
__raise_softirq_irqoff(NET_RX_SOFTIRQ);
}

NAPI方式
NAPI的方式相對於非NAPI要簡單許多,看下e100網卡的中斷處理函數e100_intr,核心部分
if (likely(napi_schele_prep(&nic->napi))) {
e100_disable_irq(nic);//屏蔽當前中斷
__napi_schele(&nic->napi);//把設備加入到輪訓隊列
}

if條件檢查當前設備是否 可被調度,主要檢查兩個方面:1、是否已經在調度 2、是否禁止了napi pending.如果符合條件,就關閉當前設備的中斷,調用__napi_schele函數把設備假如到輪訓列表,從而開啟輪詢模式。
分析:結合上面兩種方式,還是可以發現兩種方式的異同。其中softnet_data作為主導結構,在NAPI的處理方式下,主要維護輪詢鏈表。NAPI設備均對應一個napi_struct結構,添加到鏈表中;非NAPI沒有對應的napi_struct結構,為了使用NAPI的處理流程,使用了softnet_data結構中的back_log作為一個虛擬設備添加到輪詢鏈表。同時由於非NAPI設備沒有各自的接收隊列,所以利用了softnet_data結構的input_pkt_queue作為全局的接收隊列。這樣就處理而言,可以和NAPI的設備進行兼容。但是還有一個重要區別,在NAPI的方式下,首次數據包的接收使用中斷的方式,而後續的數據包就會使用輪詢處理了;而非NAPI每次都是通過中斷通知。
下半部:
下半部的處理函數,之前提到,網路數據包的接發對應兩個不同的軟中斷,接收軟中斷NET_RX_SOFTIRQ的處理函數對應net_rx_action

static void net_rx_action(struct softirq_action *h)
{
struct softnet_data *sd = &__get_cpu_var(softnet_data);
unsigned long time_limit = jiffies + 2;
int budget = netdev_budget;
void *have;
local_irq_disable();
/*遍歷輪詢表*/
while (!list_empty(&sd->poll_list)) {
struct napi_struct *n;
int work, weight;
/* If softirq window is exhuasted then punt.
* Allow this to run for 2 jiffies since which will allow
* an average latency of 1.5/HZ.
*/
/*如果開支用完了或者時間用完了*/
if (unlikely(budget <= 0 || time_after_eq(jiffies, time_limit)))
goto softnet_break;
local_irq_enable();
/* Even though interrupts have been re-enabled, this
* access is safe because interrupts can only add new
* entries to the tail of this list, and only ->poll()
* calls can remove this head entry from the list.
*/
/*獲取鏈表中首個設備*/
n = list_first_entry(&sd->poll_list, struct napi_struct, poll_list);
have = netpoll_poll_lock(n);
weight = n->weight;
/* This NAPI_STATE_SCHED test is for avoiding a race
* with netpoll's poll_napi(). Only the entity which
* obtains the lock and sees NAPI_STATE_SCHED set will
* actually make the ->poll() call. Therefore we avoid
* accidentally calling ->poll() when NAPI is not scheled.
*/
work = 0;
/*如果被設備已經被調度,則調用其處理函數poll函數*/
if (test_bit(NAPI_STATE_SCHED, &n->state)) {
work = n->poll(n, weight);//後面weight指定了一個額度
trace_napi_poll(n);
}
WARN_ON_ONCE(work > weight);
/*總額度遞減*/
budget -= work;
local_irq_disable();
/* Drivers must not modify the NAPI state if they
* consume the entire weight. In such cases this code
* still "owns" the NAPI instance and therefore can
* move the instance around on the list at-will.
*/
/*如果work=weight的話。任務就完成了,把設備從輪詢鏈表刪除*/
if (unlikely(work == weight)) {
if (unlikely(napi_disable_pending(n))) {
local_irq_enable();
napi_complete(n);
local_irq_disable();
} else {
if (n->gro_list) {
/* flush too old packets
* If HZ < 1000, flush all packets.
*/
local_irq_enable();
napi_gro_flush(n, HZ >= 1000);
local_irq_disable();
}
/*每次處理完就把設備移動到列表尾部*/
list_move_tail(&n->poll_list, &sd->poll_list);
}
}
netpoll_poll_unlock(have);
}
out:
net_rps_action_and_irq_enable(sd);
#ifdef CONFIG_NET_DMA
/*
* There may not be any more sk_buffs coming right now, so push
* any pending DMA copies to hardware
*/
dma_issue_pending_all();
#endif
return;
softnet_break:
sd->time_squeeze++;
__raise_softirq_irqoff(NET_RX_SOFTIRQ);
goto out;
}

這里有處理方式比較直觀,直接遍歷poll_list鏈表,處理之前設置了兩個限制:budget和time_limit。前者限制本次處理數據包的總量,後者限制本次處理總時間。只有二者均有剩餘的情況下,才會繼續處理。處理期間同樣是開中斷的,每次總是從鏈表表頭取設備進行處理,如果設備被調度,其實就是檢查NAPI_STATE_SCHED位,則調用 napi_struct的poll函數,處理結束如果沒有處理完,則把設備移動到鏈表尾部,否則從鏈表刪除。NAPI設備對應的poll函數會同樣會調用__netif_receive_skb函數上傳協議棧,這里就不做分析了,感興趣可以參考e100的poll函數e100_poll。

而非NAPI對應poll函數為process_backlog。

static int process_backlog(struct napi_struct *napi, int quota)
{
int work = 0;
struct softnet_data *sd = container_of(napi, struct softnet_data, backlog);
#ifdef CONFIG_RPS
/* Check if we have pending ipi, its better to send them now,
* not waiting net_rx_action() end.
*/
if (sd->rps_ipi_list) {
local_irq_disable();
net_rps_action_and_irq_enable(sd);
}
#endif
napi->weight = weight_p;
local_irq_disable();
while (work < quota) {
struct sk_buff *skb;
unsigned int qlen;
/*涉及到兩個隊列process_queue和input_pkt_queue,數據包到來時首先填充input_pkt_queue,
而在處理時從process_queue中取,根據這個邏輯,首次處理process_queue必定為空,檢查input_pkt_queue
如果input_pkt_queue不為空,則把其中的數據包遷移到process_queue中,然後繼續處理,減少鎖沖突。
*/
while ((skb = __skb_dequeue(&sd->process_queue))) {
local_irq_enable();
/*進入協議棧*/
__netif_receive_skb(skb);
local_irq_disable();
input_queue_head_incr(sd);
if (++work >= quota) {
local_irq_enable();
return work;
}
}
rps_lock(sd);
qlen = skb_queue_len(&sd->input_pkt_queue);
if (qlen)
skb_queue_splice_tail_init(&sd->input_pkt_queue,
&sd->process_queue);
if (qlen < quota - work) {
/*
* Inline a custom version of __napi_complete().
* only current cpu owns and manipulates this napi,
* and NAPI_STATE_SCHED is the only possible flag set on backlog.
* we can use a plain write instead of clear_bit(),
* and we dont need an smp_mb() memory barrier.
*/
list_del(&napi->poll_list);
napi->state = 0;
quota = work + qlen;
}
rps_unlock(sd);
}
local_irq_enable();
return work;
}

函數還是比較簡單的,需要注意的每次處理都攜帶一個配額,即本次只能處理quota個數據包,如果超額了,即使沒處理完也要返回,這是為了保證處理器的公平使用。處理在一個while循環中完成,循環條件正是work < quota,首先會從process_queue中取出skb,調用__netif_receive_skb上傳給協議棧,然後增加work。當work即將大於quota時,即++work >= quota時,就要返回。當work還有剩餘額度,但是process_queue中數據處理完了,就需要檢查input_pkt_queue,因為在具體處理期間是開中斷的,那麼期間就有可能有新的數據包到來,如果input_pkt_queue不為空,則調用skb_queue_splice_tail_init函數把數據包遷移到process_queue。如果剩餘額度足夠處理完這些數據包,那麼就把虛擬設備移除輪詢隊列。這里有些疑惑就是最後為何要增加額度,剩下的額度已經足夠處理這些數據了呀?根據此流程不難發現,其實執行的是在兩個隊列之間移動數據包,然後再做處理。

⑨ redis.conf詳解之tcp-backlog

在 linux 系統中控制tcp三次握手 已完成連接隊列 的長度。
在高並發系統中,你需要設置一個較高的 tcp-backlog 來避免客戶端連接速度慢的問題(三次握手的速度)。

1. 已完成連接隊列 的長度也與操作系統中 somaxconn 有關,取二者最小 min(tcp-backlog,somaxconn)

2. 已完成連接隊列 又與 半連接隊列 長度有關

3.簡要介紹下 半連接 與 已完成連接
半連接 :服務端收到客戶端 syn 後,將連接放入半連接隊列。如果半連接隊列已滿會丟棄,客戶端報錯 connection time out 。
已完成連接 :服務端收到客戶端的 ack 後,從半連接隊列中拿出連接放入已完成連接隊列。如果已完成連接隊列已經滿則無法放入,客戶端報錯 read timeout 或者 connection reset by peer

TCP queue 的一些問題
深入探索 Linux listen() 函數 backlog 的含義

閱讀全文

與backloglinux相關的資料

熱點內容
centos開機命令行模式 瀏覽:695
遍歷所有listpython 瀏覽:660
力控加密文件夾 瀏覽:515
如何更改移動伺服器密碼 瀏覽:686
蘋果8p手機加密 瀏覽:749
ipad建文件夾怎麼弄 瀏覽:833
iphone13對wap3加密 瀏覽:555
pdf文件打開失敗 瀏覽:913
dubbo怎麼調用不同伺服器介面 瀏覽:40
全能解壓王app歷史版本 瀏覽:75
優先隊列與拓撲排序演算法 瀏覽:281
pdf轉換formacbook 瀏覽:871
pdf文件內容怎麼編輯 瀏覽:48
134壓縮機排氣溫度多少 瀏覽:256
unity等待編譯後 瀏覽:806
黑鯊手機鎖屏視頻在哪個文件夾 瀏覽:781
wow地圖解壓後怎麼壓縮 瀏覽:823
有pdf卻打不開 瀏覽:461
七星彩軟體app怎麼下載 瀏覽:219
32單片機的重映射哪裡改 瀏覽:818