nginx在CDN加速或使用SLB代理后,获取真实IP,做并发访问限制的方法(限流)

本文主要是介绍nginx在CDN加速或使用SLB代理后,获取真实IP,做并发访问限制的方法(限流),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

本文80%转载于张戈博客,后续加入了自己的理解和想法
原文地址:https://zhangge.net/4879.html

站点在运行时,为了防止DDoS 攻击、或内部接口调用造成的数据迸发,nginx提供了limit限流模块:

HttpLimitZoneModule 限制同时并发访问的数量
HttpLimitReqModule 限制访问数据,每秒内最多几个请求

一、普通配置:

什么叫普通配置?

普通配置就是针对【用户浏览器】→【网站服务器】这种常规模式的 nginx 配置。那么,如果我要对单 IP 做访问限制,绝大多数教程都是这样写的:

## 用户的 IP 地址 $binary_remote_addr 作为 Key,每个 IP 地址最多有 50 个并发连接
## 你想开 几千个连接 刷死我? 超过 50 个连接,直接返回 503 错误给你,根本不处理你的请求了
limit_conn_zone $binary_remote_addr zone=TotalConnLimitZone:10m ;
limit_conn  TotalConnLimitZone  50;
limit_conn_log_level notice;## 用户的 IP 地址 $binary_remote_addr 作为 Key,每个 IP 地址每秒处理 10 个请求
## 你想用程序每秒几百次的刷我,没戏,再快了就不处理了,直接返回 503 错误给你
limit_req_zone $binary_remote_addr zone=ConnLimitZone:10m  rate=10r/s;
limit_req_log_level notice;## 具体服务器配置
server {listen   80;location ~ \.php$ {## 最多 5 个排队, 由于每秒处理 10 个请求 + 5个排队,你一秒最多发送 15 个请求过来,再多就直接返回 503 错误给你了limit_req zone=ConnLimitZone burst=5 nodelay;fastcgi_pass   127.0.0.1:9000;fastcgi_index  index.php;include fastcgi_params;}   }

这样一个最简单的服务器安全限制访问就完成了,这个基本上你 Google 一搜索能搜索到 90% 的网站都是这个例子,而且还强调用“$binary_remote_addr”可以节省内存之类的云云。

二、CDN 或 SLB 代理之后

为了增加安全、性能,许多站点都用到了CDN加速,或者其他的二级代理,例如阿里的SLB负载均衡等等。

于是,网站的访问模式就变为:
用户浏览器 → CDN 节点 / SLB 节点→ 网站源服务器

甚至是更复杂的模式:
用户浏览器 → CDN/SLB 节点(CDN 入口、CC\DDoS 攻击流量清洗等) → 阿里云盾 → 源服务器

可以看到,我们的网站中间经历了好几层的透明加速和安全过滤, 这种情况下,我们就不能用上面的“普通配置”。因为普通配置中基于【源 IP 的限制】的结果就是,我们把【CDN /SLB节点】或者【阿里云盾】给限制了,因为这里“源 IP”地址不再是真实用户的 IP,而是中间 CDN /SLB节点的 IP 地址。

我们需要限制的是最前面的真实用户,而不是中间为我们做加速的加速服务器。

其实,当一个 CDN /SLB或者透明代理服务器把用户的请求转到后面服务器的时候,这个 CDN /SLB服务器会在 Http 的头中加入一个记录

X-Forwarded-For : 用户 IP, 代理服务器 IP

如果中间经历了不止一个代理服务器,这个记录会是这样

X-Forwarded-For : 用户 IP, 代理服务器 1-IP, 代理服务器 2-IP, 代理服务器 3-IP, ….

可以看到经过好多层代理之后, 用户的真实 IP 在第一个位置, 后面会跟一串中间代理服务器的 IP 地址,从这里取到用户真实的 IP 地址,针对这个 IP 地址做限制就可以了。

那么针对 CDN /SLB模式下的访问限制配置就应该这样写:

http{## 这里取得原始用户的IP地址,没走CDN/SLB的,给到$remote_addrmap $http_x_forwarded_for  $clientRealIp {default $remote_addr;~^(?P<firstAddr>[0-9\.]+),?.*$	$firstAddr;}#设置IP白名单,对内部的IP不设限map $clientRealIp $limit{default $clientRealIp;xx.xx.xx.xx "";}#以真实IP为单位,限制请求数,并返回429状态;limit_req_status 429;limit_req_zone $limit zone=ConnLimitZone:20m rate=5r/s;limit_req_log_level notice;#以真实IP为单位,限制该IP的并发连接数,并返回429状态;limit_conn_status 429;limit_conn_zone $limit zone=TotalConnLimitZone:20m ;limit_conn  TotalConnLimitZone 100;limit_conn_log_level notice;#以访问域名为单位,限制总并发链接数;limit_conn_zone $server_name zone=SumConnLimitZone:20m;
}## 具体Server:如下在监听php/go/java部分新增限制规则即可,或直接放在域名下面,限制全部访问
server {listen   80;location ~ \.php$ {#限制总并发连接数limit_conn SumConnLimitZone 10000;#最多5个排队, 由于每秒处理 10 个请求 + 5个排队,你一秒最多发送 15 个请求过来,再多就直接返回 429 错误给你了limit_req  zone=ConnLimitZone  burst=5  nodelay;fastcgi_pass   127.0.0.1:9000;fastcgi_index  index.php;include fastcgi_params;}   
}

三、如何验证

根据以上配置,我们知道nginx,每秒最多允许通过10+5个请求,在压测时,就会有两种情况:

  1. 在白名单内(到白名单的服务器测试),压测该站点,应该全部通过
  2. 不在白名单内,最多只允许通过10 +5 个请求,余下部分应该返回429

前提:压测总次数超过 10 +5,否则看不出效果。

centos一般都自带有 siege压测工具,还比较好用:
yum -y install siege

使用方法:
siege -c 3 -r 10 -b https://xxxx.xx.com/api/xxxx
-c 3 表示3个用户
-r 10 表示访问10次
以上表示:3个用户,每个用户访问10次请求,共计30次

经测试,每增加一台nginx,相同的配置应该是 x 2,例如:nginx1 的配置是 10+5,nginx2的配置也是10+5,域名部署在这两台nginx上,请求数最大允许为:20+10

以上测试,如果不能通过,应该是配置问题,那么我们用echo模块来调试下:

四、echo 模块
作者原文提到了 nginx 的一个 echo 模块,特意玩了下感觉挺有意思的,下面贴一下简单集成步骤。

①、给 nginx 集成 echo 模块:

cd /usr/local/src
#下载echo模块并解压:
wget https://github.com/openresty/echo-nginx-module/archive/v0.61.tar.gz
tar zxvf v0.61.tar.gz#下载nginx并解压
wget http://nginx.org/download/nginx-1.12.2.tar.gz
tar -xzvf nginx-1.12.2.tar.gz
cd nginx-1.12.2/#查看在用nginx的编译参数(如果是全新安装则省略)
/usr/local/nginx/sbin/nginx -V
nginx version: nginx/1.12.2
built by gcc 4.4.7 20120313 (Red Hat 4.4.7-4) (GCC) #以下这行即为旧的编译参数:
configure arguments: --user=www --group=www --prefix=/usr/local/nginx --with-http_gzip_static_module
#在旧的编译参数基础上新增【--add-module=/echo模块的解压路径】参数,开始编译
./configure --prefix=/usr/local/nginx/nginx  --add-module=/usr/local/src/echo-nginx-module-0.61#make编译
make -j2#平滑升级nginx (如果是全新安装请执行:make install)
mv /usr/local/nginx/sbin/nginx /usr/local/nginx/sbin/nginx.old
cp -f objs/nginx /usr/local/nginx/sbin/
make upgrade

以上升级、编译和添加第三方模块不熟悉的朋友,可以参考我另外一篇博客:
https://mp.csdn.net/mdeditor/81136273

②、echo 用法举例:
其实就和 shell 的 echo 差不多,能否输出自定义信息。

比如,在 nginx 里面配置如下:

location /hello {echo "hello, world!";
}

访问 http://xxx.com/hello 就会在浏览器里面输出 hello, world! 了(如果域名开了 CDN 可能会报 404)。

又比如,测试本文提到的真实用户的 IP,只要在本文第二步配置基础上,加上如下规则并 reload 即可:

server {listen   80;server_name  yourdomain.com;## 以下是新增规则:## 当用户访问 /ip 的时候,我们输出 $clientRealIp 和 $limit变量,看看这个变量## 值是不是真的 用户源IP 地址location /ip{echo $clientRealIp;echo $limit;}
}

认真看的朋友,会问 clientRealIp 和 limit 有什么区别:
clientRealIp 如果走 SLB/CDN,获取的就是真实IP,反之,获取的就是remote_addr

limit 是在clientRealIp的基础上,排除了“IP白名单”,也就是说,当你的源IP,是白名单时,你的limit,应该为“空”,这样就不受限流了

所以,我们可以以此来判断,IP白名单是否有效:
curl http://xxx.xxx.cn/ip
这里写图片描述

本文介绍到这就差不多结束了,也是在神作的基础上精简整理并测试的,如果看完还有些许疑问,请前往查看神作原文,也许还是大神写的比较好理解(是否是原创我就不深究了,感觉也是转来转去,都没留链接,悲哀的互联网)!

转载:https://zhangge.net/4879.html

这篇关于nginx在CDN加速或使用SLB代理后,获取真实IP,做并发访问限制的方法(限流)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/250924

相关文章

前端bug调试的方法技巧及常见错误

《前端bug调试的方法技巧及常见错误》:本文主要介绍编程中常见的报错和Bug,以及调试的重要性,调试的基本流程是通过缩小范围来定位问题,并给出了推测法、删除代码法、console调试和debugg... 目录调试基本流程调试方法排查bug的两大技巧如何看控制台报错前端常见错误取值调用报错资源引入错误解析错误

Springboot控制反转与Bean对象的方法

《Springboot控制反转与Bean对象的方法》文章介绍了SpringBoot中的控制反转(IoC)概念,描述了IoC容器如何管理Bean的生命周期和依赖关系,它详细讲解了Bean的注册过程,包括... 目录1 控制反转1.1 什么是控制反转1.2 SpringBoot中的控制反转2 Ioc容器对Bea

如何使用Docker部署FTP和Nginx并通过HTTP访问FTP里的文件

《如何使用Docker部署FTP和Nginx并通过HTTP访问FTP里的文件》本文介绍了如何使用Docker部署FTP服务器和Nginx,并通过HTTP访问FTP中的文件,通过将FTP数据目录挂载到N... 目录docker部署FTP和Nginx并通过HTTP访问FTP里的文件1. 部署 FTP 服务器 (

MySQL 日期时间格式化函数 DATE_FORMAT() 的使用示例详解

《MySQL日期时间格式化函数DATE_FORMAT()的使用示例详解》`DATE_FORMAT()`是MySQL中用于格式化日期时间的函数,本文详细介绍了其语法、格式化字符串的含义以及常见日期... 目录一、DATE_FORMAT()语法二、格式化字符串详解三、常见日期时间格式组合四、业务场景五、总结一、

Python中配置文件的全面解析与使用

《Python中配置文件的全面解析与使用》在Python开发中,配置文件扮演着举足轻重的角色,它们允许开发者在不修改代码的情况下调整应用程序的行为,下面我们就来看看常见Python配置文件格式的使用吧... 目录一、INI配置文件二、YAML配置文件三、jsON配置文件四、TOML配置文件五、XML配置文件

Go使用pprof进行CPU,内存和阻塞情况分析

《Go使用pprof进行CPU,内存和阻塞情况分析》Go语言提供了强大的pprof工具,用于分析CPU、内存、Goroutine阻塞等性能问题,帮助开发者优化程序,提高运行效率,下面我们就来深入了解下... 目录1. pprof 介绍2. 快速上手:启用 pprof3. CPU Profiling:分析 C

C++实现回文串判断的两种高效方法

《C++实现回文串判断的两种高效方法》文章介绍了两种判断回文串的方法:解法一通过创建新字符串来处理,解法二在原字符串上直接筛选判断,两种方法都使用了双指针法,文中通过代码示例讲解的非常详细,需要的朋友... 目录一、问题描述示例二、解法一:将字母数字连接到新的 string思路代码实现代码解释复杂度分析三、

Ubuntu 22.04 服务器安装部署(nginx+postgresql)

《Ubuntu22.04服务器安装部署(nginx+postgresql)》Ubuntu22.04LTS是迄今为止最好的Ubuntu版本之一,很多linux的应用服务器都是选择的这个版本... 目录是什么让 Ubuntu 22.04 LTS 变得安全?更新了安全包linux 内核改进一、部署环境二、安装系统

MySQL InnoDB引擎ibdata文件损坏/删除后使用frm和ibd文件恢复数据

《MySQLInnoDB引擎ibdata文件损坏/删除后使用frm和ibd文件恢复数据》mysql的ibdata文件被误删、被恶意修改,没有从库和备份数据的情况下的数据恢复,不能保证数据库所有表数据... 参考:mysql Innodb表空间卸载、迁移、装载的使用方法注意!此方法只适用于innodb_fi

Keepalived+Nginx双机配置小结

《Keepalived+Nginx双机配置小结》本文主要介绍了Keepalived+Nginx双机配置小结,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面... 目录1.1 软硬件要求1.2 部署前服务器配置调优1.3 Nginx+Keepalived部署1.3