Linux性能優化實戰學習筆記:第三十九講

1、上節回顧

上一節,我帶你學習了 tcpdump 和 Wireshark 的使用方法,並經過幾個案例,帶你用這兩個工具實際分析了網絡的收發過程。碰到網絡性能問題,不要忘記能夠用 tcpdump 和
Wireshark 這兩個大殺器,抓取實際傳輸的網絡包,排查潛在的性能問題。nginx

今天,咱們一塊兒來看另一個問題,怎麼緩解 DDoS(Distributed Denial of Service)帶來的性能降低問題。docker

2、DDoS 簡介

一、DDoS 簡介

DDoS 的前身是 DoS(Denail of Service),即拒絕服務攻擊,指利用大量的合理請求,來佔用過多的目標資源,從而使目標服務沒法響應正常請求。緩存

DDoS(Distributed Denial of Service) 則是在 DoS 的基礎上,採用了分佈式架構,利用多臺主機同時攻擊目標主機。這樣,即便目標服務部署了網絡防護設備,面對大量網絡
請求時,仍是無力應對。安全

好比,目前已知的最大流量攻擊,正是去年 Github 遭受的 DDoS 攻擊,其峯值流量已經達到了 1.35Tbps,PPS 更是超過了 1.2 億(126.9 million)。bash

二、從攻擊的原理上來看,DDoS 能夠分爲下面幾種類型。

第一種,耗盡帶寬。不管是服務器仍是路由器、交換機等網絡設備,帶寬都有固定的上限。帶寬耗盡後,就會發生網絡擁堵,從而沒法傳輸其餘正常的網絡報文。服務器

第二種,耗盡操做系統的資源。網絡服務的正常運行,都須要必定的系統資源,像是CPU、內存等物理資源,以及鏈接表等軟件資源。一旦資源耗盡,系統就不能處理其餘正常的網絡鏈接。cookie

第三種,消耗應用程序的運行資源。應用程序的運行,一般還須要跟其餘的資源或系統交互。若是應用程序一直忙於處理無效請求,也會致使正常請求的處理變慢,甚至得不到響應。網絡

好比,構造大量不一樣的域名來攻擊 DNS 服務器,就會致使 DNS 服務器不停執行迭代查詢,並更新緩存。這會極大地消耗 DNS 服務器的資源,使 DNS 的響應變慢。架構

不管是哪種類型的 DDoS,危害都是巨大的。那麼,如何能夠發現系統遭受了 DDoS 攻擊,又該如何應對這種攻擊呢?接下來,咱們就經過一個案例,一塊兒來看看這些問題。併發

3、案例準備

下面的案例仍然基於 Ubuntu 18.04,一樣適用於其餘的 Linux 系統。我使用的案例環境是這樣的:

機器配置:2 CPU,8GB 內存。
預先安裝 docker、sar 、hping三、tcpdump、curl 等工具,好比 apt-get install docker.io hping3 tcpdump curl。

這些工具你應該都比較熟悉了。其中,hping3 在 系統的軟中斷 CPU 使用率升高案例 中曾經介紹過,它能夠構造 TCP/IP 協議數據包,對系統進行安全審計、防火牆測試、DoS
攻擊測試等。

本次案例用到三臺虛擬機,我畫了一張圖來表示它們之間的關係。

你能夠看到,其中一臺虛擬機運行 Nginx ,用來模擬待分析的 Web 服務器;而另外兩臺做爲 Web 服務器的客戶端,其中一臺用做 DoS 攻擊,而另外一臺則是正常的客戶端。使用
多臺虛擬機的目的,天然仍是爲了相互隔離,避免「交叉感染」。

因爲案例只使用了一臺機器做爲攻擊源,因此這裏的攻擊,實際上仍是傳統的 DoS ,而非 DDoS。

接下來,咱們打開三個終端,分別 SSH 登陸到三臺機器上(下面的步驟,都假設終端編號與圖示 VM 編號一致),並安裝上面提到的這些工具。

同之前的案例同樣,下面的全部命令,都默認以 root 用戶運行。若是你是用普通用戶身份登錄系統,請運行 sudo su root 命令切換到 root 用戶。
接下來,咱們就進入到案例操做環節。

4、案例分析

首先,在終端一中,執行下面的命令運行案例,也就是啓動一個最基本的 Nginx 應用:

# 運行 Nginx 服務並對外開放 80 端口
# --network=host 表示使用主機網絡(這是爲了方便後面排查問題)
$ docker run -itd --name=nginx --network=host nginx

而後,在終端二和終端三中,使用 curl 訪問 Nginx 監聽的端口,確認 Nginx 正常啓動。假設 192.168.0.30 是 Nginx 所在虛擬機的 IP 地址,那麼運行 curl 命令後,你應該會看
到下面這個輸出界面:

# -w 表示只輸出 HTTP 狀態碼及總時間,-o 表示將響應重定向到 /dev/null
$ curl -s -w 'Http code: %{http_code}\nTotal time:%{time_total}s\n' -o /dev/null http://192.168.0.30/
...
Http code: 200
Total time:0.002s

從這裏能夠看到,正常狀況下,咱們訪問 Nginx 只須要 2ms(0.002s)。

接着,在終端二中,運行 hping3 命令,來模擬 DoS 攻擊:

# -S 參數表示設置 TCP 協議的 SYN(同步序列號),-p 表示目的端口爲 80
# -i u10 表示每隔 10 微秒發送一個網絡幀
$ hping3 -S -p 80 -i u10 192.168.0.30

如今,再回到終端一,你就會發現,如今無論執行什麼命令,都慢了不少。不過,在實踐時要注意:

若是你的現象不那麼明顯,那麼請嘗試把參數裏面的 u10 調小(好比調成 u1),或者加上–flood 選項;
若是你的終端一徹底沒有響應了,那麼請適當調大 u10(好比調成 u30),不然後面就不能經過 SSH 操做 VM1

而後,到終端三中,執行下面的命令,模擬正常客戶端的鏈接:

# --connect-timeout 表示鏈接超時時間
$ curl -w 'Http code: %{http_code}\nTotal time:%{time_total}s\n' -o /dev/null --connect-timeout 10 http://192.168.0.30
...
Http code: 000
Total time:10.001s
curl: (28) Connection timed out after 10000 milliseconds

你能夠發現,在終端三中,正常客戶端的鏈接超時了,並無收到 Nginx 服務的響應。這是發生了什麼問題呢?咱們再回到終端一中,檢查網絡情況。你應該還記得咱們屢次用
過的 sar,它既能夠觀察 PPS(每秒收發的報文數),還能夠觀察 BPS(每秒收發的字節數)。

咱們能夠回到終端一中,執行下面的命令:

sar -n DEV 1
08:55:49        IFACE   rxpck/s   txpck/s    rxkB/s    txkB/s   rxcmp/s   txcmp/s  rxmcst/s   %ifutil
08:55:50      docker0      0.00      0.00      0.00      0.00      0.00      0.00      0.00      0.00
08:55:50         eth0  22274.00    629.00   1174.64     37.78      0.00      0.00      0.00      0.02
08:55:50           lo      0.00      0.00      0.00      0.00      0.00      0.00      0.00      0.00

關於 sar 輸出中的各列含義,我在前面的 Linux 網絡基礎中已經介紹過,你能夠點擊 這裏查看,或者執行 man sar 查詢手冊。

從此次 sar 的輸出中,你能夠看到,網絡接收的 PPS 已經達到了 20000 多,可是 BPS 卻只有 1174 kB,這樣每一個包的大小就只有 54B(1174*1024/22274=54)。

這明顯就是個小包了,不過具體是個什麼樣的包呢?那咱們就用 tcpdump 抓包看看吧。在終端一中,執行下面的 tcpdump 命令:

# -i eth0 只抓取 eth0 網卡,-n 不解析協議名和主機名
# tcp port 80 表示只抓取 tcp 協議而且端口號爲 80 的網絡幀
$ tcpdump -i eth0 -n tcp port 80
09:15:48.287047 IP 192.168.0.2.27095 > 192.168.0.30: Flags [S], seq 1288268370, win 512, length 0
09:15:48.287050 IP 192.168.0.2.27131 > 192.168.0.30: Flags [S], seq 2084255254, win 512, length 0
09:15:48.287052 IP 192.168.0.2.27116 > 192.168.0.30: Flags [S], seq 677393791, win 512, length 0
09:15:48.287055 IP 192.168.0.2.27141 > 192.168.0.30: Flags [S], seq 1276451587, win 512, length 0
09:15:48.287068 IP 192.168.0.2.27154 > 192.168.0.30: Flags [S], seq 1851495339, win 512, length 0
...

這個輸出中,Flags [S] 表示這是一個 SYN 包。大量的 SYN 包代表,這是一個 SYNFlood 攻擊。若是你用上一節講過的 Wireshark 來觀察,則能夠更直觀地看到 SYNFlood 的過程:

 

 

實際上,SYN Flood 正是互聯網中最經典的 DDoS 攻擊方式。從上面這個圖,你也能夠看到它的原理:

即客戶端構造大量的 SYN 包,請求創建 TCP 鏈接;
而服務器收到包後,會向源 IP 發送 SYN+ACK 報文,並等待三次握手的最後一次 ACK報文,直到超時。

這種等待狀態的 TCP 鏈接,一般也稱爲半開鏈接。因爲鏈接表的大小有限,大量的半開鏈接就會致使鏈接表迅速佔滿,從而沒法創建新的 TCP 鏈接。
參考下面這張 TCP 狀態圖,你能看到,此時,服務器端的 TCP 鏈接,會處於SYN_RECEIVED 狀態:

這其實提示了咱們,查看 TCP 半開鏈接的方法,關鍵在於 SYN_RECEIVED 狀態的鏈接。咱們可使用 netstat ,來查看全部鏈接的狀態,不過要注意,SYN_REVEIVED 的狀態,
一般被縮寫爲 SYN_RECV。

咱們繼續在終端一中,執行下面的 netstat 命令:

# -n 表示不解析名字,-p 表示顯示鏈接所屬進程
$ netstat -n -p | grep SYN_REC
tcp        0      0 192.168.0.30:80          192.168.0.2:12503      SYN_RECV    -
tcp        0      0 192.168.0.30:80          192.168.0.2:13502      SYN_RECV    -
tcp        0      0 192.168.0.30:80          192.168.0.2:15256      SYN_RECV    -
tcp        0      0 192.168.0.30:80          192.168.0.2:18117      SYN_RECV    -
...

從結果中,你能夠發現大量 SYN_RECV 狀態的鏈接,而且源 IP 地址爲 192.168.0.2。

進一步,咱們還能夠經過 wc 工具,來統計全部 SYN_RECV 狀態的鏈接數:

netstat -n -p | grep SYN_REC | wc -l
193

找出源 IP 後,要解決 SYN 攻擊的問題,只要丟掉相關的包就能夠。這時,iptables 能夠幫你完成這個任務。你能夠在終端一中,執行下面的 iptables 命令:

iptables -I INPUT -s 192.168.0.2 -p tcp -j REJECT

而後回到終端三中,再次執行 curl 命令,查看正經常使用戶訪問 Nginx 的狀況:

curl -w 'Http code: %{http_code}\nTotal time:%{time_total}s\n' -o /dev/null --connect-timeout 10 http://192.168.0.30
Http code: 200
Total time:1.572171s

如今,你能夠發現,正經常使用戶也能夠訪問 Nginx 了,只是響應比較慢,從原來的 2ms 變成了如今的 1.5s。

不過,通常來講,SYN Flood 攻擊中的源 IP 並非固定的。好比,你能夠在 hping3 命令中,加入 --rand-source 選項,來隨機化源 IP。不過,這時,剛纔的方法就不適用了。
幸虧,咱們還有不少其餘方法,實現相似的目標。好比,你能夠用如下兩種方法,來限制syn 包的速率:

# 限制 syn 併發數爲每秒 1 次
$ iptables -A INPUT -p tcp --syn -m limit --limit 1/s -j ACCEPT

# 限制單個 IP 在 60 秒新創建的鏈接數爲 10
$ iptables -I INPUT -p tcp --dport 80 --syn -m recent --name SYN_FLOOD --update --seconds 60 --hitcount 10 -j REJECT

到這裏,咱們已經初步限制了 SYN Flood 攻擊。不過這還不夠,由於咱們的案例還只是單個的攻擊源。

若是是多臺機器同時發送 SYN Flood,這種方法可能就直接無效了。由於你極可能沒法SSH 登陸(SSH 也是基於 TCP 的)到機器上去,更別提執行上述全部的排查命令。
因此,這還須要你事先對系統作一些 TCP 優化。

好比,SYN Flood 會致使 SYN_RECV 狀態的鏈接急劇增大。在上面的 netstat 命令中,你也能夠看到 190 多個處於半開狀態的鏈接。

不過,半開狀態的鏈接數是有限制的,執行下面的命令,你就能夠看到,默認的半鏈接容量只有 256:

sysctl net.ipv4.tcp_max_syn_backlog
net.ipv4.tcp_max_syn_backlog = 256

換句話說, SYN 包數再稍微增大一些,就不能 SSH 登陸機器了。 因此,你還應該增大半鏈接的容量,好比,你能夠用下面的命令,將其增大爲 1024:

sysctl -w net.ipv4.tcp_max_syn_backlog=1024
net.ipv4.tcp_max_syn_backlog = 1024

另外,鏈接每一個 SYN_RECV 時,若是失敗的話,內核還會自動重試,而且默認的重試次數是 5 次。你能夠執行下面的命令,將其減少爲 1 次:

sysctl -w net.ipv4.tcp_synack_retries=1
net.ipv4.tcp_synack_retries = 1

除此以外,TCP SYN Cookies 也是一種專門防護 SYN Flood 攻擊的方法。SYN Cookies基於鏈接信息(包括源地址、源端口、目的地址、目的端口等)以及一個加密種子(如系
統啓動時間),計算出一個哈希值(SHA1),這個哈希值稱爲 cookie。

而後,這個 cookie 就被用做序列號,來應答 SYN+ACK 包,並釋放鏈接狀態。當客戶端發送完三次握手的最後一次 ACK 後,服務器就會再次計算這個哈希值,確認是上次返回的
SYN+ACK 的返回包,纔會進入 TCP 的鏈接狀態。

於是,開啓 SYN Cookies 後,就不須要維護半開鏈接狀態了,進而也就沒有了半鏈接數的限制。

注意,開啓 TCP syncookies 後,內核選項net.ipv4.tcp_max_syn_backlog 也就無效了。

你能夠經過下面的命令,開啓 TCP SYN Cookies:

注意,上述 sysctl 命令修改的配置都是臨時的,重啓後這些配置就會丟失。因此,爲了保證配置持久化,你還應該把這些配置,寫入 /etc/sysctl.conf 文件中。好比:

cat /etc/sysctl.conf
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_synack_retries = 1
net.ipv4.tcp_max_syn_backlog = 1024

不過要記得,寫入 /etc/sysctl.conf 的配置,須要執行 sysctl -p 命令後,纔會動態生效。固然案例結束後,別忘了執行 docker rm -f nginx 命令,清理案例開始時啓動的 Nginx應用。

實際測試代碼以下:

192.168.118.85:
[root@luoahong ~]# sar -n DEV 1
Linux 5.1.0-1.el7.elrepo.x86_64 (luoahong) 	09/17/2019 	_x86_64_	(2 CPU)

06:31:44 PM     IFACE   rxpck/s   txpck/s    rxkB/s    txkB/s   rxcmp/s   txcmp/s  rxmcst/s   %ifutil
06:31:45 PM      eth0   1369.00    685.00     80.21     40.26      0.00      0.00      0.00      0.07
06:31:45 PM   docker0      0.00      0.00      0.00      0.00      0.00      0.00      0.00      0.00
06:31:45 PM br-ad2616372f01      0.00      0.00      0.00      0.00      0.00      0.00      0.00      0.00
06:31:45 PM        lo      0.00      0.00      0.00      0.00      0.00      0.00      0.00      0.00
......
06:31:48 PM        lo      0.00      0.00      0.00      0.00      0.00      0.00      0.00      0.00
^C

Average:        IFACE   rxpck/s   txpck/s    rxkB/s    txkB/s   rxcmp/s   txcmp/s  rxmcst/s   %ifutil
Average:         eth0   1453.25    727.00     85.15     43.06      0.00      0.00      0.00      0.07
Average:      docker0      0.00      0.00      0.00      0.00      0.00      0.00      0.00      0.00
Average:    br-ad2616372f01      0.00      0.00      0.00      0.00      0.00      0.00      0.00      0.00
Average:           lo      0.00      0.00      0.00      0.00      0.00      0.00      0.00      0.00

192.168.118.85:
[root@luoahong ~]# netstat -n -p | grep SYN_REC
tcp        0      0 192.168.118.85:80       192.168.118.77:29723    SYN_RECV    -                   
tcp        0      0 192.168.118.85:80       192.168.118.77:29722    SYN_RECV    -                   
[root@luoahong ~]# netstat -n -p | grep SYN_REC
[root@luoahong ~]# netstat -n -p | grep SYN_REC
[root@luoahong ~]# netstat -n -p | grep SYN_REC | wc -l
1

192.168.118.109:
[root@69 ~]# curl -s -w 'Http code: %{http_code}\nTotal time:%{time_total}s\n' -o /dev/null http://192.168.118.85/
Http code: 200
Total time:0.024s

[root@69 ~]# curl -w 'Http code: %{http_code}\nTotal time:%{time_total}s\n' -o /dev/null --connect-timeout 10 http://192.168.118.85
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
102   612  102   612    0     0  46167      0 --:--:-- --:--:-- --:--:-- 68000
Http code: 200
Total time:0.013s

192.168.118.85:
[root@luoahong ~]# tcpdump -i eth0 -n tcp port 80
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes
18:36:45.485762 IP 192.168.118.77.33258 > 192.168.118.85.http: Flags [S], seq 654860237, win 512, length 0
18:36:45.485819 IP 192.168.118.85.http > 192.168.118.77.33258: Flags [S.], seq 3270815133, ack 654860238, win 64240, options [mss 1460], length 0
18:36:45.488677 IP 192.168.118.77.33258 > 192.168.118.85.http: Flags [R], seq 654860238, win 0, length 0
18:36:45.489600 IP 192.168.118.77.33259 > 192.168.118.85.http: Flags [S], seq 1979340837, win 512, length 0
18:36:45.489649 IP 192.168.118.85.http > 192.168.118.77.33259: Flags [S.], seq 903753158, ack 1979340838, win 64240, options [mss 1460], length 0
18:36:45.490384 IP 192.168.118.77.33259 > 192.168.118.85.http: Flags [R], seq 1979340838, win 0, length 0
18:36:45.490892 IP 192.168.118.77.33260 > 192.168.118.85.http: Flags [S], seq 1525245122, win 512, length 0
18:36:45.490920 IP 192.168.118.85.http > 192.168.118.77.33260: Flags [S.], seq 1880256039, ack 1525245123, win 64240, options [mss 1460], length 0
18:36:45.491789 IP 192.168.118.77.33260 > 192.168.118.85.http: Flags [R], seq 1525245123, win 0, length 0
18:36:45.491864 IP 192.168.118.77.33261 > 192.168.118.85.http: Flags [S], seq 1545646639, win 512, length 0
18:36:45.491890 IP 192.168.118.85.http > 192.168.118.77.33261: Flags [S.], seq 3645078853, ack 1545646640, win 64240, options [mss 1460], length 0
18:36:45.492769 IP 192.168.118.77.33261 > 192.168.118.85.http: Flags [R], seq 1545646640, win 0, length 0
18:36:45.493446 IP 192.168.118.77.33262 > 192.168.118.85.http: Flags [S], seq 1991815131, win 512, length 0
18:36:45.493478 IP 192.168.118.85.http > 192.168.118.77.33262: Flags [S.], seq 1541006520, ack 1991815132, win 64240, options [mss 1460], length 0
......
18:36:45.503180 IP 192.168.118.85.http > 192.168.118.77.33267: Flags [S.], seq 2597604106, ack 1299736667, win 64240, options [mss 1460], length 0
18:36:45.505689 IP 192.168.118.77.33268 > 192.168.118.85.http: Flags [S], seq 565857447, win 512, length 0
18:36:45.505865 IP 192.168.118.85.http > 192.168.118.77.33268: Flags [S.], seq 2577025015, ack 565857448, win 64240, options [mss 1460], length 0
18:36:45.507444 IP 192.168.118.77.33269 > 192.168.118.85.http: Flags [S], seq 2082323681, win 512, length 0
18:36:45.507518 IP 192.168.118.85.http > 192.168.118.77.33269: Flags [S.], seq 3200834539, ack 2082323682, win 64240, options [mss 1460], length 0
18:36:45.507618 IP 192.168.118.77.33268 > 192.168.118.85.http: Flags [R], seq 565857448, win 0, length 0

[root@luoahong ~]# iptables -I INPUT -s 192.168.118.77 -p tcp -j REJECT
192.168.118.77:
root@luoahong:~# hping3 -S -p 80 -i u1 192.168.118.85
HPING 192.168.118.85 (ens33 192.168.118.85): S set, 40 headers + 0 data bytes
ICMP Port Unreachable from ip=192.168.118.85 name=UNKNOWN   
ICMP Port Unreachable from ip=192.168.118.85 name=UNKNOWN   
ICMP Port Unreachable from ip=192.168.118.85 name=UNKNOWN   
ICMP Port Unreachable from ip=192.168.118.85 name=UNKNOWN   
ICMP Port Unreachable from ip=192.168.118.85 name=UNKNOWN   
ICMP Port Unreachable from ip=192.168.118.85 name=UNKNOWN   

192.168.118.109:
[root@69 ~]# curl -w 'Http code: %{http_code}\nTotal time:%{time_total}s\n' -o /dev/null --connect-timeout 10 http://192.168.118.85
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
102   612  102   612    0     0   185k      0 --:--:-- --:--:-- --:--:--  597k
Http code: 200
Total time:0.003s

[root@69 ~]# curl -w 'Http code: %{http_code}\nTotal time:%{time_total}s\n' -o /dev/null --connect-timeout 10 http://192.168.118.85
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
102   612  102   612    0     0  78562      0 --:--:-- --:--:-- --:--:--  149k
Http code: 200
Total time:0.008s

把攻擊的值調整到u1被攻擊的機器依然很快

root@luoahong:~# hping3 -S -p 80 -i u1 192.168.118.85
HPING 192.168.118.85 (ens33 192.168.118.85): S set, 40 headers + 0 data bytes
len=46 ip=192.168.118.85 ttl=64 DF id=0 sport=80 flags=SA seq=0 win=64240 rtt=0.0 ms
len=46 ip=192.168.118.85 ttl=64 DF id=0 sport=80 flags=SA seq=0 win=64240 rtt=0.0 ms
len=46 ip=192.168.118.85 ttl=64 DF id=0 sport=80 flags=SA seq=0 win=64240 rtt=0.0 ms
len=46 ip=192.168.118.85 ttl=64 DF id=0 sport=80 flags=SA seq=0 win=64240 rtt=0.0 ms
len=46 ip=192.168.118.85 ttl=64 DF id=0 sport=80 flags=SA seq=0 win=64240 rtt=0.0 ms
len=46 ip=192.168.118.85 ttl=64 DF id=0 sport=80 flags=SA seq=0 win=64240 rtt=0.0 ms
len=46 ip=192.168.118.85 ttl=64 DF id=0 sport=80 flags=SA seq=0 win=64240 rtt=0.0 ms
len=46 ip=192.168.118.85 ttl=64 DF id=0 sport=80 flags=SA seq=0 win=64240 rtt=0.0 ms
len=46 ip=192.168.118.85 ttl=64 DF id=0 sport=80 flags=SA seq=0 win=64240 rtt=0.0 ms
len=46 ip=192.168.118.85 ttl=64 DF id=0 sport=80 flags=SA seq=0 win=64240 rtt=0.0 ms
len=46 ip=192.168.118.85 ttl=64 DF id=0 sport=80 flags=SA seq=0 win=64240 rtt=0.0 ms
len=46 ip=192.168.118.85 ttl=64 DF id=0 sport=80 flags=SA seq=0 win=64240 rtt=0.0 ms
len=46 ip=192.168.118.85 ttl=64 DF id=0 sport=80 flags=SA seq=0 win=64240 rtt=0.0 ms
len=46 ip=192.168.118.85 ttl=64 DF id=0 sport=80 flags=SA seq=0 win=64240 rtt=0.0 ms
len=46 ip=192.168.118.85 ttl=64 DF id=0 sport=80 flags=SA seq=0 win=64240 rtt=0.0 ms
len=46 ip=192.168.118.85 ttl=64 DF id=0 sport=80 flags=SA seq=0 win=64240 rtt=0.0 ms
len=46 ip=192.168.118.85 ttl=64 DF id=0 sport=80 flags=SA seq=0 win=64240 rtt=0.0 ms
len=46 ip=192.168.118.85 ttl=64 DF id=0 sport=80 flags=SA seq=0 win=64240 rtt=0.0 ms
len=46 ip=192.168.118.85 ttl=64 DF id=0 sport=80 flags=SA seq=0 win=64240 rtt=0.0 ms

4、DDoS 到底該怎麼防護

到這裏,今天的案例就結束了。不過,你確定還有疑問。你應該注意到了,今天的主題是「緩解」,而不是「解決」 DDoS 問題。

爲何不是解決 DDoS ,而只是緩解呢?並且今天案例中的方法,也只是讓 Nginx 服務訪問再也不超時,但訪問延遲仍是比一開始時的 2ms 大得多。

實際上,當 DDoS 報文到達服務器後,Linux 提供的機制只能緩解,而沒法完全解決。即便像是 SYN Flood 這樣的小包攻擊,其巨大的 PPS ,也會致使 Linux 內核消耗大量資
源,進而致使其餘網絡報文的處理緩慢。

雖然你能夠調整內核參數,緩解 DDoS 帶來的性能問題,卻也會像案例這樣,沒法完全解決它。

在以前的 C10K、C100K 文章 中,我也提到過,Linux 內核中冗長的協議棧,在 PPS 很大時,就是一個巨大的負擔。對 DDoS 攻擊來講,也是同樣的道理。

因此,當時提到的 C10M 的方法,用到這裏一樣適合。好比,你能夠基於 XDP 或者DPDK,構建 DDoS 方案,在內核網絡協議棧前,或者跳過內核協議棧,來識別並丟棄
DDoS 報文,避免 DDoS 對系統其餘資源的消耗。

不過,對於流量型的 DDoS 來講,當服務器的帶寬被耗盡後,在服務器內部處理就無能爲力了。這時,只能在服務器外部的網絡設備中,設法識別並阻斷流量(固然前提是網絡設
備要能扛住流量攻擊)。好比,購置專業的入侵檢測和防護設備,配置流量清洗設備阻斷惡意流量等。

既然 DDoS 這麼難防護,這是否是說明, Linux 服務器內部壓根兒就不關注這一點,而是所有交給專業的網絡設備來處理呢?

固然不是,由於 DDoS 並不必定是由於大流量或者大 PPS,有時候,慢速的請求也會帶來巨大的性能降低(這種狀況稱爲慢速 DDoS)。

好比,不少針對應用程序的攻擊,都會假裝成正經常使用戶來請求資源。這種狀況下,請求流量可能自己並不大,但響應流量卻可能很大,而且應用程序內部也極可能要耗費大量資源處理。

這時,就須要應用程序考慮識別,並儘早拒絕掉這些惡意流量,好比合理利用緩存、增長WAF(Web Application Firewall)、使用 CDN 等等

5、小結

今天,咱們學習了分佈式拒絕服務(DDoS)時的緩解方法。DDoS 利用大量的僞造請求,使目標服務耗費大量資源,來處理這些無效請求,進而沒法正常響應正常的用戶請求。

因爲 DDoS 的分佈式、大流量、難追蹤等特色,目前尚未方法能夠徹底防護 DDoS 帶來的問題,只能設法緩解這個影響。

好比,你能夠購買專業的流量清洗設備和網絡防火牆,在網絡入口處阻斷惡意流量,只保留正常流量進入數據中心的服務器中。

在 Linux 服務器中,你能夠經過內核調優、DPDK、XDP 等多種方法,來增大服務器的抗攻擊能力,下降 DDoS 對正常服務的影響。而在應用程序中,你能夠利用各級緩存、WAF、CDN 等方式,緩解 DDoS 對應用程序的影響。

相關文章
相關標籤/搜索