服务高可用保障:服务限流,Nginx实现服务限流

news/2024/11/17 4:36:51/

一、前言

1.1什么是限流?

限流存在于高可用服务中。
用于高可用的保护手段,主要包括:缓存,降级,限流
限流:只允许指定的事件进入系统,超过的部分将被拒绝服务,排队或者降级处理。

1.2为什么需要限流?

一:服务扛不住压力了
二:因为资源的稀缺或者处于安全防范的目的而采用的自我保护机制,保证有限的资源提供最大的服务能力,按照预期的流量提供服务 ,超过的部分将会拒绝服务,排队或者降级处理

二、按照限流算法分类

2.1.计数器(固定窗口计数器)

通用及最简单的算法,简单逻辑是维护一个固定时间的计数器,如果检测到单位时间过去则记为0,重新计数
在这里插入图片描述

存在的问题
1.没有应对突发的流量的能力:如100的qps,前100ms来了99个,后900ms只能处理一个
2.不准确,在一个窗口内后半段时间来了100个请求,以及在后一个窗口的前半段时间100个请求,等同于在一个窗口内出现了双倍的限流的流量!

2.2 漏铜算法

在这里插入图片描述

水:请求
桶:限流阈值大小
漏的水滴:固定速率,服务的处理速度
实现步骤:
1.将每个请求放入固定的大小的队列进行存储
2.以固定的速率向外流出请求,队列为空则停止流出
3.队列满了则拒绝服务

2.3令牌桶算法

在这里插入图片描述

为了保证网站在遭受流量攻击的时候,仍然能够保障正常用户的访问不受到影响,有必要对网站添加限流措施。通过简单的配置Nginx,可以帮助我们实现这一功能。
优点:令牌桶支持突发流量
因为桶中有多少令牌在等待,就允许有多少突发请求可以执行

实现步骤:
1.以恒定的速率向桶中增加令牌
2.如果令牌满了直接丢弃,如果有请求则获取令牌进行请求
3.如果桶空了,则拒绝执行

三、Nginx实现服务限流

实现服务限流的方式有很多种,下面我主要介绍的是Nginx实现,优点是不用频繁部署jar服务,减少代码编写。提高效率,短时间解决问题

Nginx支持通过以下维度,来对用户的请求进行限制:

  1. 控制访问频率
  2. 控制并发连接数
  3. 控制访问速率
  4. IP黑白名单

3.1超过访问频率就立即拒绝

对应Nginx模块:ngx_http_limit_req_module

# 限流设置,这只是设置流量限制和共享内存区域的参数,但实际上并不限制请求速率。具体的限制需要定义具体的url
limit_req_zone $binary_remote_addr zone=contentRateLimit:10m rate=10r/s;
# 指定错误码
limit_req_status 429;server {location /update_content {        proxy_pass http://192.168.211.1:18081;}location /read_content {# 使用限流配置limit_req zone=contentRateLimit;proxy_pass http://192.168.211.1:18081;}
}
  • binary_remote_addr:表示基于客户端IP做限流,使用二进制来表示IP地址;
  • zone:定义共享内存区来存储访问信息;
  • contentRateLimit:10m 表示一个大小为10M,名字为contentRateLimit的内存区域; 1M能存储8000个IP地址的访问信息(64位平台);
  • rate:用于设置最大访问速率,rate=10r/s 表示每秒最多处理10个请求。Nginx 实际上以毫秒为粒度来跟踪请求信息,因此 10r/s 实际上是限制:每100毫秒处理一个请求;
  • limit_req_zone:只定义速度限制的相关参数,一般用于http块中,使其可以在多个相关server中使用;
  • limit_req:启用定义的限速参数;
    当存储空间耗尽的时候,如果需要记录新的值,那么就会通过LRU算法移除旧的变量来腾出空间,如果这样腾出来的空间还是不足以接纳新的记录值,那么nginx就会返回状态码503。此外,为了防止内存耗尽,nginx每次创建一个新记录值的时候就会清理掉两个60秒内没被使用过的旧记录值。
    (2) 支持处理突发流量
    超过流量不会立即被拒绝,允许加入一个队列,只有队列满了之后的请求才会被拒绝。如果有时正常流量突然增大,超出的请求将被拒绝,无法处理突发流量,就可以结合 burst 参数使用来解决该问题。

3.2支持处理突发流量

超过流量不会立即被拒绝,允许加入一个队列,只有队列满了之后的请求才会被拒绝。如果有时正常流量突然增大,超出的请求将被拒绝,无法处理突发流量,就可以结合 burst 参数使用来解决该问题。

# 限流设置,这只是设置流量限制和共享内存区域的参数,但实际上并不限制请求速率。具体的限制需要定义具体的url
limit_req_zone $binary_remote_addr zone=contentRateLimit:10m rate=10r/s;server {location /update_content {        proxy_pass http://192.168.211.1:18081;}location /read_content {# 使用限流配置limit_req zone=contentRateLimit burst=4 nodelay;proxy_pass http://192.168.211.1:18081;}
}
  • burst :表示在超过设定的处理速率后能额外处理的请求数。burst=4表示有4个请求到达,Nginx
    会处理第一个请求,剩余3个请求将放入队列,然后每隔100ms从队列中获取一个请求进行处理。若请求数大于4,将拒绝处理多余的请求,直接返回503。排队中的请求虽然每100ms会处理一个,但却需要等待
    较长的处理时间。所以burst 往往结合 nodelay 一起使用,以实现削峰填谷的效果;
  • nodelay :假设我们的流量是 2,1,4,0,2
    ,正常的请求会存在峰值和谷值,代表每秒的请求数。这样当流控为2r/s,burst=4
    nodelay时,在第3秒请求数为4时(峰值),仍然允许直接处理4个请求,但是后续的请求会被拦截,保证总流量不超过2r/s,因此,当第四秒请求数为0时,就起到了削峰填谷的作用。假设流量是2,1,4,4,4
    ,峰值持续的时间比较长,那么从第二个峰值开始,就会被真的流控,被拒绝或进行排队,这样即使被处理,也会延迟稍高!

3.3控制并发连接数

Nginx内置的limit_conn_zone和limit_conn指令,提供了通过限制ip连接数来控制流量的能力。

其中只有当服务器正在处理请求并且已经读取了整个请求头时,才会计算为有效连接。
对应Nginx模块:ngx_http_limit_conn_module
(1) 控制每个IP的连接数

limit_conn_zone $binary_remote_addr zone=perip:10m;server {       location /brand {# 同一个地址只允许连接2次limit_conn perip 2;proxy_pass http://192.168.211.1:18081;}}

limit_conn_zone $binary_remote_addr zone=perip:10m :表示根据用户的IP地址来进行限制,设置共享内存大小为10M。

limit_conn perip 2 :表示同一个地址只允许连接2次。

(2) 控制与服务器的连接总数

# 根据server_name来限制,存储内存大小10M
limit_conn_zone $server_name zone=perserver:10m;server {listen 80;server_name xx.com;location / {# 限制与服务器的总连接数limit_conn perserver 100;root   html;index  index.html index.htm;}
}

limit_conn_zone $server_name zone=perserver:10m :表示根据用户访问的server_name来进行限制,设置共享内存大小为10M。

limit_conn perserver 100 :表示同一个server只允许连接100次。

3.4控制访问速率

设置http请求传输多少字节后开始限速。
对应Nginx模块:ngx_http_core_module

location /flv/ {limit_rate_after 500k;# 带宽限制,对单个连接限速limit_rate       50k;
}

limit_rate_after 500k :表示传输的前500k数据不限速,500k之后再进行限速。

limit_rate 50k :对单个连接限速为50k/s。如果一个客户端发起两个连接,就是50k * 2。

3.5黑白名单

配置固定IP为黑名单,访问时会返回403 Forbidden。
nginx 是按照自上而下的顺序进行匹配,匹配到一个就不往下继续了,如遇到 return 指令时 return 指令还是会生效。

server {listen 8080;server_name _;location / {allow 192.168.135.1;deny all;return 200 "$remote_addr 正常访问 3";}
}
# 屏蔽单个ip访问
deny IP;
# 允许单个ip访问
allow IP;
# 屏蔽所有ip访问
deny all;
# 允许所有ip访问
allow all;
# 屏蔽整个段即从123.0.0.1到123.255.255.254访问的命令
deny 123.0.0.0/8
# 屏蔽IP段即从123.45.0.1到123.45.255.254访问的命令
deny 124.45.0.0/16
# 屏蔽IP段即从123.45.6.1到123.45.6.254访问的命令
deny 123.45.6.0/24# 也可以通过配置文件来配置
include blockip.conf;

动态黑白名单:也可以采用Lua+Redis实现,将黑名单存入到Redis缓存,每次执行请求时,通过lua脚本先获取用户IP,匹配IP是否属于黑名单,如果是,则不让请求,如果不是,则放行。

 /*** provide by zym* 0 error(s), 0 warning(s)*/

http://www.ppmy.cn/news/89585.html

相关文章

STLINK V2 无法用STM32CubeProgrammer下载程序

这个问题真的挺狗的,先说结论,因为你买的STLINK V2是国产的,而且用的也是国产的芯片,不是ST的STM32F103C8T6,所以STM32CubeProgrammer识别不到芯片的串号,都是奸商为了省钱导致的。 我是去年买的一个STLINK…

“卷”还是“躺平”?职场人如何在工作中找到价值感?

今天不谈技术,只谈进步。 曾经看过一个回答说“职场人最好的姿势是仰卧起坐”。 卷累的就躺,休息好了再继续卷,卷是常态,“仰卧起坐”也好,“卷的姿势”也好,都是在反复“卷起”的过程中寻找一些舒适和平衡…

Redis BigKey问题

1.广告平台,海量数据查询固定前缀的key 不要使用keys , 使用 scan 命令 scan 0 match "user:" 10 2.Memory usage命令用过吗 memory usage key [semples count] :计算每个键值对的字节数 3.bigKey 问题,多大算bigKey,如何发现?如何处理?如…

kafka本地测试消息

一安装JDK 二zookeeper安装 Apache ZooKeeper conf下修改cfg文件名 为zoo.cfg 打开该文件编辑 配置环境变量 右击电脑--属性--高级系统设置--选择环境变量 新建系统变量 变量名:ZOOKEEPER_HOME 变量值为zookeeper的路径 然后编辑环境变量Path 新增%ZOOKEEPER…

Python网络爬虫:Scrapy和Beautiful Soup的使用和数据处理技巧

章节一:引言 在当今互联网时代,数据的价值越来越被重视,而网络爬虫作为一种强大的工具,可以帮助我们从互联网中提取有用的数据。Python作为一门广泛应用于数据科学和网络开发的编程语言,有着丰富的库和框架来支持网络…

基于Redis的Java分布式锁,接口并发处理,并发方案

Redis的分布式锁很多人都知道,比如使用Jedis的setNx、incr等方法都可以实现分布式锁的功能,但是Jedis需要自己管理连接池,就稍微麻烦一点。 今天介绍的是使用RedisTemplate切面编程自定义注解SPEL来实现分布式锁的功能,封装完成后…

低代码平台活字格,让我们一起感受低代码平台活字格的魅力

一份耕耘,一份收获,一段工作经历,让我认识了活字格。感觉活字格绝对是同类产品中的佼佼者。简单的拖拉拽,就实现一个完美的WEB页面,并且可做到前后端分离与交互。有了他,不擅长前端的我,也能大显身手了。告…

【dfs和bfs时间复杂度超时了,怎么优化呢?双向优化】【双向dfs——送礼物】【双向bfs——字串变换】

预习 笔记 复习 做题 专注 效率 记忆 欢迎观看我的博客,如有问题交流,欢迎评论区留言,一定尽快回复!(大家可以去看我的专栏,是所有文章的目录)   文章字体风格: 红色文字表示&#…