上一节,我带你学习了 tcpdump 和 Wireshark 的使用方法,并经过几个案例,带你用这两个工具实际分析了网络的收发过程。碰到网络性能问题,不要忘记能够用 tcpdump 和
Wireshark 这两个大杀器,抓取实际传输的网络包,排查潜在的性能问题。nginx
今天,咱们一块儿来看另一个问题,怎么缓解 DDoS(Distributed Denial of Service)带来的性能降低问题。docker
DDoS 的前身是 DoS(Denail of Service),即拒绝服务攻击,指利用大量的合理请求,来占用过多的目标资源,从而使目标服务没法响应正常请求。缓存
DDoS(Distributed Denial of Service) 则是在 DoS 的基础上,采用了分布式架构,利用多台主机同时攻击目标主机。这样,即便目标服务部署了网络防护设备,面对大量网络
请求时,仍是无力应对。安全
好比,目前已知的最大流量攻击,正是去年 Github 遭受的 DDoS 攻击,其峰值流量已经达到了 1.35Tbps,PPS 更是超过了 1.2 亿(126.9 million)。bash
第一种,耗尽带宽。不管是服务器仍是路由器、交换机等网络设备,带宽都有固定的上限。带宽耗尽后,就会发生网络拥堵,从而没法传输其余正常的网络报文。服务器
第二种,耗尽操做系统的资源。网络服务的正常运行,都须要必定的系统资源,像是CPU、内存等物理资源,以及链接表等软件资源。一旦资源耗尽,系统就不能处理其余正常的网络链接。cookie
第三种,消耗应用程序的运行资源。应用程序的运行,一般还须要跟其余的资源或系统交互。若是应用程序一直忙于处理无效请求,也会致使正常请求的处理变慢,甚至得不到响应。网络
好比,构造大量不一样的域名来攻击 DNS 服务器,就会致使 DNS 服务器不停执行迭代查询,并更新缓存。这会极大地消耗 DNS 服务器的资源,使 DNS 的响应变慢。架构
不管是哪种类型的 DDoS,危害都是巨大的。那么,如何能够发现系统遭受了 DDoS 攻击,又该如何应对这种攻击呢?接下来,咱们就经过一个案例,一块儿来看看这些问题。并发
下面的案例仍然基于 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 用户。
接下来,咱们就进入到案例操做环节。
首先,在终端一中,执行下面的命令运行案例,也就是启动一个最基本的 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
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
到这里,今天的案例就结束了。不过,你确定还有疑问。你应该注意到了,今天的主题是“缓解”,而不是“解决” 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 等等
今天,咱们学习了分布式拒绝服务(DDoS)时的缓解方法。DDoS 利用大量的伪造请求,使目标服务耗费大量资源,来处理这些无效请求,进而没法正常响应正常的用户请求。
因为 DDoS 的分布式、大流量、难追踪等特色,目前尚未方法能够彻底防护 DDoS 带来的问题,只能设法缓解这个影响。
好比,你能够购买专业的流量清洗设备和网络防火墙,在网络入口处阻断恶意流量,只保留正常流量进入数据中心的服务器中。
在 Linux 服务器中,你能够经过内核调优、DPDK、XDP 等多种方法,来增大服务器的抗攻击能力,下降 DDoS 对正常服务的影响。而在应用程序中,你能够利用各级缓存、WAF、CDN 等方式,缓解 DDoS 对应用程序的影响。