SpringCloud&Gateway网关限流

本文涉及的产品
传统型负载均衡 CLB,每月750个小时 15LCU
云数据库 Tair(兼容Redis),内存型 2GB
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
简介: SpringCloud&Gateway网关限流

网关除了请求路由、身份验证,还有一个非常重要的作用:请求限流。当系统面对高并发请求时,为了减少对业务处理服务的压力,需要在网关中对请求限流,按照一定的速率放行请求。


常见的限流算法包括:


  • 计数器算法
  • 漏桶算法
  • 令牌桶算法

算法介绍: https://blog.csdn.net/u012441595/article/details/102483501


令牌桶算法原理


SpringGateway中采用的是令牌桶算法,令牌桶算法原理:


  • 准备一个令牌桶,有固定容量,一般为服务并发上限
  • 按照固定速率,生成令牌并存入令牌桶,如果桶中令牌数达到上限,就丢弃令牌。
  • 每次请求调用需要先获取令牌,只有拿到令牌,才继续执行,否则选择选择等待或者直接拒绝。


Gateway中限流实现


SpringCloudGateway是采用令牌桶算法,其令牌相关信息记录在redis中,因此我们需要安装redis,并引入Redis相关依赖。


1) 引入redis有关依赖:

<!--redis-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis-reactive</artifactId>
</dependency>

注意:这里不是普通的redis依赖,而是响应式的Redis依赖,因为SpringGateway是基于WebFlux的响应式


2) 配置过滤条件key:

Gateway会在Redis中记录令牌相关信息,我们可以自己定义令牌桶的规则,例如:

  • 给不同的请求URI路径设置不同令牌桶
  • 给不同的登录用户设置不同令牌桶
  • 给不同的请求IP地址设置不同令牌桶

Redis中的一个Key和Value对就是一个令牌桶。因此Key的生成规则就是桶的定义规则。SpringCloudGateway中key的生成规则定义在KeyResolver接口中:

public interface KeyResolver {

  Mono<String> resolve(ServerWebExchange exchange);

}

这个接口中的方法返回值就是给令牌桶生成的key。API说明:

  • Mono:是一个单元素容器,用来存放令牌桶的key
  • ServerWebExchange:上下文对象,可以理解为ServletContext,可以从中获取request、response、cookie等信息

比如上面的三种令牌桶规则,生成key的方式如下:

  • 给不同的请求URI路径设置不同令牌桶,示例代码:
return Mono.just(exchange.getRequest().getURI().getPath());// 获取请求URI

给不同的登录用户设置不同令牌桶

return exchange.getPrincipal().map(Principal::getName);// 获取用户

给不同的请求IP地址设置不同令牌桶

return Mono.just(exchange.getRequest().getRemoteAddress().getHostName());// 获取请求者IP

这里我们选择最后一种,使用IP地址的令牌桶key。

我们定义一个类,配置一个 KeyResolve r的 Bean 实例:

import org.springframework.cloud.gateway.filter.ratelimit.KeyResolver;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
@Component
public class PathKeyResolver implements KeyResolver {
    @Override
    public Mono<String> resolve(ServerWebExchange exchange) {
        return Mono.just(exchange.getRequest().getURI().getPath());// 获取请求URI
    }
}


3) 配置桶参数:

另外,令牌桶的参数需要通过yaml文件来配置,参数有2个

  • replenishRate:每秒钟生成令牌的速率,基本上就是每秒钟允许的最大请求数量
  • burstCapacity:令牌桶的容量,就是令牌桶中存放的最大的令牌的数量

完整配置如下:

server:
  port: 10010 # 网关端口
spring:
  application:
    name: gateway # 服务名称
  redis:
    host: localhost
  cloud:
    nacos:
      server-addr: localhost:8848 # nacos地址
    gateway:
      routes: # 网关路由配置
        - id: user-server # 路由id,自定义,只要唯一即可
          # uri: http://127.0.0.1:8081 # 路由的目标地址 http就是固定地址
          uri: lb://user-server# 路由的目标地址 lb就是负载均衡,后面跟服务名称
          predicates: # 路由断言,也就是判断请求是否符合路由规则的条件
            - Path=/user/**
        - id: order-service # 路由id,自定义,只要唯一即可
          uri: lb://orderservice # 路由的目标地址 lb就是负载均衡,后面跟服务名称
          predicates: # 路由断言,也就是判断请求是否符合路由规则的条件
            - Path=/order/**
      default-filters:
        - AddRequestHeader=name,xiaoming
        - name: RequestRateLimiter #请求数限流 名字不能随便写
          args:
            key-resolver: "#{@ipKeyResolver}" # 指定一个key生成器
            redis-rate-limiter.replenishRate: 2 # 生成令牌的速率
            redis-rate-limiter.burstCapacity: 4 # 桶的容量
      globalcors: # 全局的跨域处理
        ........

这里配置了一个过滤器:RequestRateLimiter,并设置了三个参数:


key-resolver:"#{@ipKeyResolver}"是SpEL表达式,写法是#{@bean的名称},ipKeyResolver就是我们定义的Bean名称

redis-rate-limiter.replenishRate:每秒钟生成令牌的速率

redis-rate-limiter.burstCapacity:令牌桶的容量

这样的限流配置可以达成的效果:

  • 每一个IP地址,每秒钟最多发起2次请求
  • 每秒钟超过2次请求,则返回429的异常状态码


4) 测试


429:代表请求次数过多,触发限流了。

相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore &nbsp; &nbsp; ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库&nbsp;ECS 实例和一台目标数据库&nbsp;RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&amp;RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
相关文章
|
11天前
|
负载均衡 Java 应用服务中间件
Gateway服务网关
Gateway服务网关
24 1
Gateway服务网关
|
1月前
|
XML Java 数据格式
如何使用 Spring Cloud 实现网关
如何使用 Spring Cloud 实现网关
31 3
|
2月前
|
负载均衡 Java Nacos
SpringCloud基础2——Nacos配置、Feign、Gateway
nacos配置管理、Feign远程调用、Gateway服务网关
SpringCloud基础2——Nacos配置、Feign、Gateway
|
2月前
|
Java 开发者 Spring
Spring Cloud Gateway 中,过滤器的分类有哪些?
Spring Cloud Gateway 中,过滤器的分类有哪些?
48 3
|
2月前
|
负载均衡 Java 网络架构
实现微服务网关:Zuul与Spring Cloud Gateway的比较分析
实现微服务网关:Zuul与Spring Cloud Gateway的比较分析
102 5
|
1月前
|
负载均衡 Java API
【Spring Cloud生态】Spring Cloud Gateway基本配置
【Spring Cloud生态】Spring Cloud Gateway基本配置
37 0
|
2月前
|
安全 Java 开发者
强大!Spring Cloud Gateway新特性及高级开发技巧
在微服务架构日益盛行的今天,网关作为微服务架构中的关键组件,承担着路由、安全、监控、限流等多重职责。Spring Cloud Gateway作为新一代的微服务网关,凭借其基于Spring Framework 5、Project Reactor和Spring Boot 2.0的强大技术栈,正逐步成为业界的主流选择。本文将深入探讨Spring Cloud Gateway的新特性及高级开发技巧,助力开发者更好地掌握这一强大的网关工具。
217 6
|
4月前
|
监控 负载均衡 Java
深入理解Spring Cloud中的服务网关
深入理解Spring Cloud中的服务网关
|
1月前
|
安全 5G 网络性能优化
|
2月前
|
监控 负载均衡 安全
微服务(五)-服务网关zuul(一)
微服务(五)-服务网关zuul(一)