三层限流:为高并发系统保驾护航

文章目录

  • 前言
  • 一、第一层限流: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 个请求等待处理。 通过调整 rateburstnodelay 等配置参数,我们能够根据不同的业务需求灵活定制限流策略。比如,假设我们的业务主要面向个人用户,并且大部分时间请求量相对稳定,但在某些特定的高峰期会出现请求量的突然增加。在这种情况下,我们可能会选择设定一个适中的 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、引入依赖

<<
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

知北游z

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值