zoukankan      html  css  js  c++  java
  • Spring Cloud Gateway限流实战

    欢迎访问我的GitHub

    https://github.com/zq2599/blog_demos

    内容:所有原创文章分类汇总及配套源码,涉及Java、Docker、Kubernetes、DevOPS等;

    本篇概览

    • 本文是《Spring Cloud Gateway实战》系列的第八篇,经过前面的学习,咱们对过滤器已了解得差不多,今天来补全过滤器的最后一个版块:限流(RequestRateLimiter )

    • 默认的限流器是基于redis实现的,限流算法是大家熟悉的令牌桶(Token Bucket Algorithm),关于令牌捅的原理就不在此展开了,聪明的您看一眼下图应该就懂了:装令牌的桶容量有限,例如最多20个,令牌进入桶的速度恒定(注意,这里是和漏桶算法的区别),例如每秒10个,底部每个请求能拿到令牌才会被处理:

    在这里插入图片描述

    RequestRateLimiter基本套路

    • 使用RequestRateLimiter过滤器的步骤非常简单:
    1. 准备可用的redis
    2. maven或者gradle中添加依赖org.springframework.boot:spring-boot-starter-data-redis-reactive
    3. 确定按照什么维度限流,例如按照请求中的username参数限流,这是通过编写KeyResolver接口的实现来完成的
    4. 配置application.yml文件,添加过滤器
    • 以上就是使用RequestRateLimiter过滤器的套路了,简单么?接下来,咱们先编码再验证

    源码下载

    名称 链接 备注
    项目主页 https://github.com/zq2599/blog_demos 该项目在GitHub上的主页
    git仓库地址(https) https://github.com/zq2599/blog_demos.git 该项目源码的仓库地址,https协议
    git仓库地址(ssh) git@github.com:zq2599/blog_demos.git 该项目源码的仓库地址,ssh协议
    • 这个git项目中有多个文件夹,本篇的源码在spring-cloud-tutorials文件夹下,如下图红框所示:

    在这里插入图片描述

    • spring-cloud-tutorials文件夹下有多个子工程,本篇的代码是gateway-requestratelimiter,如下图红框所示:

    在这里插入图片描述

    准备工作

    • 为了更好的演示Gateway的效果,在服务提供者provider-hello的代码(Hello.java)中新增一个web接口,可以接受一个入参:
        @GetMapping("/userinfo")
        public String userInfo(@RequestParam("username") String username) {
            return Constants.HELLO_PREFIX + " " + username + ", " + dateStr();
        }
    
    • 后面的测试咱们就用上述接口;

    编码

    • 在父工程spring-cloud-tutorials之下新增子工程gateway-requestratelimiter,其pom.xml内容如下,重点是org.springframework.boot:spring-boot-starter-data-redis-reactive
    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <parent>
            <artifactId>spring-cloud-tutorials</artifactId>
            <groupId>com.bolingcavalry</groupId>
            <version>1.0-SNAPSHOT</version>
        </parent>
        <modelVersion>4.0.0</modelVersion>
    
        <artifactId>gateway-requestratelimiter</artifactId>
    
        <dependencies>
            <dependency>
                <groupId>com.bolingcavalry</groupId>
                <artifactId>common</artifactId>
                <version>${project.version}</version>
            </dependency>
    
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-gateway</artifactId>
            </dependency>
    
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-data-redis-reactive</artifactId>
            </dependency>
        </dependencies>
    </project>
    
    • 配置文件application.yml,请注意RequestRateLimiter的几个参数,已经用中文添加了详细的注释:
    server:
      #服务端口
      port: 8081
    spring:
      application:
        name: circuitbreaker-gateway
      # redis配置
      redis:
        host: 192.168.50.43
        port: 6379
    
      cloud:
        gateway:
          routes:
            - id: path_route
              uri: http://127.0.0.1:8082
              predicates:
                - Path=/hello/**
              filters:
                - name: RequestRateLimiter
                  args:
                  	# 令牌入桶的速度为每秒100个,相当于QPS
                    redis-rate-limiter.replenishRate: 100
                    # 桶内能装200个令牌,相当于峰值,要注意的是:第一秒从桶内能去200个,但是第二秒只能取到100个了,因为入桶速度是每秒100个
                    redis-rate-limiter.burstCapacity: 200
                    # 每个请求需要的令牌数
                    redis-rate-limiter.requestedTokens: 1
    
    • 指定限流维度的代码CustomizeConfig.java,这里是根据请求参数username的值来限流的,假设真实请求中一半请求的username的等于Tom,另一半的username的等于Jerry,按照application.yml的配置,Tom的请求QPS为10,Jerry的QPS也是10:
    package com.bolingcavalry.gateway.config;
    
    import org.springframework.cloud.gateway.filter.ratelimit.KeyResolver;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import reactor.core.publisher.Mono;
    import java.util.Objects;
    
    @Configuration
    public class CustomizeConfig {
        @Bean
        KeyResolver userKeyResolver() {
            return exchange -> Mono.just(exchange.getRequest().getQueryParams().getFirst("username"));
        }
    }
    
    • 毫无营养的启动类RequestRateLimiterApplication.java:
    package com.bolingcavalry.gateway;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    
    @SpringBootApplication
    public class RequestRateLimiterApplication {
        public static void main(String[] args) {
            SpringApplication.run(RequestRateLimiterApplication.class,args);
        }
    }
    
    • 代码写完了,接下来开始验证;

    验证(桶容量等于入桶速度)

    • 首先验证的是桶容量等于入桶速度时的效果,请修改gateway-requestratelimiter应用的application.yml中文件,使得redis-rate-limiter.replenishRate和redis-rate-limiter.burstCapacity的值都等于100,也就是说桶的大小等于100,每秒放入的令牌数也是100

    • 确保redis已经启动,并且与application.yml中的配置保持一直

    • 启动nacos(provider-hello依赖)

    • 启动服务提供者provider-hello

    • 启动gateway-requestratelimiter

    • 为了模拟web请求,我这里使用了Apache Benchmark,windows版本的下载地址:
      https://www.apachelounge.com/download/VS16/binaries/httpd-2.4.48-win64-VS16.zip

    • 上述文件下载解压后即可使用,在控制台进入Apache24\bin后执行以下命令,意思是向指定地址发送10000个请求,并发数为2:

    ab -n 10000  -c 2 http://localhost:8081/hello/userinfo?username=Tom
    
    • 控制台输出如下,可见不到八秒的时间,只成功了800个,证明限流符合预期:

    在这里插入图片描述

    验证(桶容量大于入桶速度)

    • 接下来试试桶容量大于入桶速度时的限流效果,这对于我们控制峰值响应有很重要的参考价值

    • 请修改gateway-requestratelimiter应用的application.yml中文件,redis-rate-limiter.replenishRate维持100不变,但是redis-rate-limiter.burstCapacity改成200,也就是说每秒放入的令牌数还是100,但桶的容量翻倍了

    • 重启应用gateway-requestratelimiter

    • 再次执行以下命令,意思是向指定地址发送10000个请求,并发数为2:

    ab -n 10000  -c 2 http://localhost:8081/hello/userinfo?username=Tom
    
    • 测试结果如下图,可见符合预期,可以将桶内令牌全部用掉,以支撑峰值超过QPS的场景:

    在这里插入图片描述

    验证(根据username的维度限流)

    • 接下来验证限流的维度,究竟是不是按照请求参数username的值来限流的

    • 咱们打开两个命令行,同时发送请求(动作要快),第一个的username等于Tom,第二个等于Jerry,理论上推测,如果都是8秒内完成,那么每个命令都有900个请求能成功

    • 测试结果如下图,可见符合预期,每个username用的是自己的令牌:

    在这里插入图片描述

    • 至此,Spring Cloud Gateway限流实战已经完成,如此简单易用的限流方案,希望能给您的学习和使用带来参考

    你不孤单,欣宸原创一路相伴

    1. Java系列
    2. Spring系列
    3. Docker系列
    4. kubernetes系列
    5. 数据库+中间件系列
    6. DevOps系列

    欢迎关注公众号:程序员欣宸

    微信搜索「程序员欣宸」,我是欣宸,期待与您一同畅游Java世界...
    https://github.com/zq2599/blog_demos

  • 相关阅读:
    为当前用户创建cron服务
    PHP程序员的简单运维
    mysql事件学习
    ubantu16.04服务器错误提示没有安装php_fileinfo扩展
    XAMPP配置vhosts多站点/绝对正确
    yii2框架获取刚插入数据库的id (原创)
    ajax详解
    Git密钥生成步骤SSH Key
    jquery禁用select和取消禁用
    a标签实现不跳转点击
  • 原文地址:https://www.cnblogs.com/bolingcavalry/p/15591501.html
Copyright © 2011-2022 走看看