文章目录
- 前言
- 一、第一层限流:Nginx 层面的 IP 限流
- 二、第二层限流:Gateway 对用户层级的限流
- 三、第三层限流:微服务限流
-
- 分布式限流和单机限流的优缺点:
- 1、RateLimiter的使用
- 2、Hystrix的使用
- 3、Redis+lua脚本
- 4、使用Sentinel
- 四、关于为何同时使用 Nginx 和 Spring Cloud Gateway
- 总结
前言
在高并发网络环境中,确保系统的可用性、稳定性以及防范恶意流量攻击至关重要。为此,在我们的项目中构建了三层限流设计。
第一层是 Nginx 层面的 IP 限流,借助 Nginx 的 http_limit_req_module 模块,依据用户 IP 设限,这是抵御恶意 IP 的 DDoS 攻击、阻挡大量非法请求深入系统的首道防线。
第二层为 gateway 针对用户层级的限流,通过用户的唯一标识如 user_id,控制每个用户在单位时间内的请求数量,确保公平,避免单一用户过度占用资源而影响他人体验。
第三层则是微服务限流,每个微服务运用如 Google 的 Guava RateLimiter 等技术限流,防止服务过载影响系统稳定,且各服务根据自身能力和业务需求独立设定限流阈值。
三层限流的结构图如下:

一、第一层限流:Nginx 层面的 IP 限流
Nginx 的 http_limit_req_module 模块是我们构建的第一道坚固防线。 其工作原理基于定义一个明确的“速率”值,用于对单位时间内的请求数量进行严格的限制。比如说,您可以设定每分钟只处理 100 个请求。当某个客户端的请求速率超过预先设定的限制时,Nginx 就会地将这些请求放入一个专门的队列中,等待后续的处理。然而,如果队列中的请求数量过多,或者等待处理的时间超出了可接受的范围,那么这些请求将会被果断丢弃。
在配置方面,首先需要在 Nginx 的 http 块中使用 limit_req_zone 指令来定义限制速率的区域。例如,如果我们决定根据客户端的 IP 进行限制,限流20MB,每秒允许处理1000个请求,配置如下:
http http {
limit_req_zone $binary_remote_addr zone=perip:20m rate=1000r/s;
...
}
这里,$binary_remote_addr 代表客户端的 IP 地址,zone=totalLimit:20m 定义了一个名为 totalLimit 的存储区域,其大小为 20M,用于存储每个 IP 的状态信息,而 rate=10r/s 则清晰地设定了每秒 1000 个请求的限制速率。
接下来,在需要应用这个限制的 server 块或 location 块中,使用 limit_req 指令来设定这个限制。例如:
json server {
location / {
limit_req zone=totalLimit burst=1000 nodelay;
...
}
}
在上述配置中,zone=totalLimit 明确表示应用之前定义的 totalLimit 区域,而 burst=1000 则意味着允许在短时间内超过定义的速率,最多累积 1000 个请求等待处理。 通过调整 rate 、burst 和 nodelay 等配置参数,我们能够根据不同的业务需求灵活定制限流策略。比如,假设我们的业务主要面向个人用户,并且大部分时间请求量相对稳定,但在某些特定的高峰期会出现请求量的突然增加。在这种情况下,我们可能会选择设定一个适中的 rate ,并同时允许一定数量的 burst ,以在保障系统稳定性的同时,最大程度地优化用户体验。
二、第二层限流:Gateway 对用户层级的限流
为了进一步增强系统的限流效果和精细化管理,我们在 API 网关层面也实施了限流策略。 首先,在 Spring Cloud Gateway 中,通过在配置文件中明确地定义限流规则,我们能够基于 user_id 这一关键标识,精准地控制每个用户在单位时间内所能发送的请求数量。以下是一个针对 user_id 进行限流的配置示例:
spring:
cloud:
gateway:
routes:
- id: user_route
uri: http://mybackend.com
predicates:
- Path=/api/**
filters:
- name: RequestRateLimiter
args:
redis-rate-limiter.replenishRate: 10
redis-rate-limiter.burstCapacity: 20
key-resolver: "#{@userIdResolver}"
在这个配置中,redis-rate-limiter.replenishRate 定义了每秒可以处理的请求数量,而 redis-rate-limiter.burstCapacity 则设定了可以接受的突发请求数量。同时,key-resolver 用于明确如何从请求中准确获取 user_id 。
为了实现从请求中提取 user_id ,我们需要实现一个 KeyResolver 接口。以下是一个使用 Java 语言实现的示例代码,展示了如何从请求的查询参数中获取 user_id :
1、引入依赖
<<

最低0.47元/天 解锁文章
8515

被折叠的 条评论
为什么被折叠?



