目錄
一、半連接隊列和全連接隊列的概念
二、全連接隊列溢出
三、半連接隊列溢出
一、半連接隊列和全連接隊列的概念
1. 半連接隊列:服務端收到客戶端發送的 SYN 包時,內核會將該連接加入半連接 SYN 隊列,并向客戶端返回響應
2. 全連接隊列:服務端收到客戶端發送的 ACK + SYN 包時,會從半連接隊列中移除該連接,創建一個新的完全連接,加入全連接 accept 隊列,等待進程調用 accept 函數取出全連接
二、全連接隊列溢出
1. 查看全連接隊列情況:ss 命令
- Recv-Q:當前全連接隊列的大小
- Send-Q:允許的全連接隊列最大大小
2. 全連接隊列溢出:大量請求打到服務器,如果請求數量超過 TCP 全連接隊列的大小,就會丟棄后面的連接(默認策略,可以修改策略為向客戶端發送 RST 復位報文,告訴客戶端連接建立失敗),導致服務器請求數量上不去
3. 查看全連接隊列是否溢出:netstat -s 可以查看丟掉的 TCP 連接,如果丟棄數量在變大說明某段時間內發生了全連接隊列溢出(是個累計值,不是大于 0 就代表當前全連接隊列溢出了,持續變大有上升趨勢才能說明溢出,半連接隊列查看溢出情況也是如此)
4. 調大全連接隊列的大小:修改 Linux 內核參數 somaxconn 和 backlog(全連接隊列大小是兩者的最小值)
5. 丟棄策略
- tcp_abort_on_overflow = 0:丟棄連接,客戶端會重發帶有 ACK 的請求,收不到服務端的 ACK 就會重發,如果服務端只是暫時繁忙,忙完就會收到大量客戶端重發的帶有 ACK 的請求,還可以繼續處理(全連接隊列有空位時),繼續建立完全連接
- tcp_abort_on_overflow = 1:給客戶端響應 RST 復位報文,報告連接建立失敗,只有肯定全連接隊列會長時間溢出時才將策略設置為 1,盡快通知客戶端,否則就 設置為 0,可以增大連接建立的成功率
三、半連接隊列溢出
1. 查看半連接隊列情況:沒有命令可以直接查看,但是可以通過查看服務端處于 SYN_RECV 狀態的 TCP 連接,就是 TCP 的半連接數量
2. 半連接隊列溢出:客戶端發送大量 SYN 請求,但是一直不回復 ACK,服務端就會出現大量處于 SYN_RECV 的 TCP 導致半連接隊列溢出,無法處理后續的正常的請求,也就是 SYN 洪泛、SYN 攻擊、DDos 攻擊
3. 調大半連接隊列的大小 TODO
4. 如何防止洪泛攻擊?
- 增大半連接隊列:同時增大全連接隊列,因為半連接隊列的大小會受到全連接的隊列大小的影響(半連接隊列的大小具體要看源碼)
- 開啟 tcp_syncookies 功能,在發生溢出時不會丟棄連接,而是根據 syncookies 判斷連接是否建立成功
- 減少 SYN+ACK 重傳次數:收到 SYN 攻擊時,就會有大量處于 SYN_RECV 狀態的 TCP 連接,處于這個狀態的 TCP 連接會重傳 SYN+ACK 報文,當重傳次數達到上限就會斷開連接,減少重傳次數,加快斷開連接的速度