前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >spring cloud gateway网关使用JMeter进行限流测试与熔断

spring cloud gateway网关使用JMeter进行限流测试与熔断

作者头像
用户10196776
发布2023-10-17 15:23:02
5110
发布2023-10-17 15:23:02
举报
文章被收录于专栏:SpringBoot+MyBatis前端

一·. spring cloud gateway网关限流

    1. 限流简介

限流就是限制流量,因为服务器能处理的请求数有限,如果请求量特别大,我们需要做限流(要么就让请求等待,要么就把请求给扔了), 限流可以保障我们的 API 服务对所有用户的可用性,也可以防止网络攻击。在高并发的应用中,限流是一个绕不开的话题。

注1:为什么要限流?如下图所示:

    2. 常见的限流手段

一般开发高并发系统常见的限流有:

1)限制总并发数(比如数据库连接池、线程池)、限制瞬时并发数(如 nginx 的 limit_conn 模块,用来限制瞬时并发连接数)、         2)限制时间窗口内的平均速率(如 Guava 的 RateLimiter、nginx 的 limit_req 模块,限制每秒的平均速率);         3)其他还有如限制远程接口调用速率、限制 MQ 的消费速率。         4)另外还可以根据网络连接数、网络流量、CPU 或内存负载等来限流。         本文讨论在gateway集成的实现

    3. 限流算法

        1.漏桶算法(Leaky Bucket)    

        是网络世界中流量整形(Traffic Shaping)或速率限制(Rate Limiting)时经常使用的一种算法,它的主要目的是控制数据注入到网络的速率,平滑网络上的突发流量。漏桶算法提供了一种机制,通过它,突发流量可以被整形以便为网络提供一个稳定的流量。

        2.令牌桶算法(Token Bucket)

令牌桶算法是网络流量整形(Traffic Shaping)和速率限制(Rate Limiting)中最常使用的一种算法。典型情况下,令牌桶算法用来控制发送到网络上的数据的数目,并允许突发数据的发送。

           随着时间流逝,系统会按恒定 1/QPS 时间间隔(如果 QPS=100,则间隔是 10ms)往桶里加入 Token(想象和漏洞漏水相反,有个水龙头在不断的加水),            如果桶已经满了就不再加了。新请求来临时,会各自拿走一个 Token,如果没有 Token 可拿了就阻塞或者拒绝服务。

           令牌桶的另外一个好处是可以方便的改变速度:一旦需要提高速率,则按需提高放入桶中的令牌的速率 (1秒生成20令牌  令牌桶容量100)

    4. gateway网关限流快速实现

Spring Cloud Gateway官方提供了RequestRateLimiterGatewayFilterFactory类,使用redis和lua脚本来实现令牌桶的方式。         我们也可以基于Google Guava中的RateLimiter、Bucket4j、RateLimitJ来实现。但是,本文将采用官方提供的方式来实现。

Gateway通过内置的RequestRateLimiter过滤器实现限流,使用令牌桶算法,借助Redis保存中间数据。用户可通过自定义KeyResolver设置限流维度

例如: 1.对请求的目标URL进行限流         2.对来源IP进行限流         3.特定用户进行限流         本案例实现对IP进行限流

1. 导入redis依赖
代码语言:javascript
复制
 <!--redis依赖-->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-data-redis-reactive</artifactId>
            </dependency>
        2. 修改application.yml文件添加redis相关配置

#此处为单机版配置,实际开发中,应该是一个redis集群配置。

代码语言:javascript
复制
 spring:
        redis:
         host: 192.168.217.132
         port: 6379
         password: 123456
       database: 0

注1:如果redis连接失败,限流功能将不能开启。因为没有redis作为容器来保存令牌,限流功能自然就失效了。切记~~~切记~~~切记~~~             注2:可以将redis的配置信息保存到nacos中,通过添加nacos配置中心客户端的方式进行读取

  3. 创建限流Bean   

代码语言:javascript
复制
package com.zking.gatewayserver.config;

import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.filter.ratelimit.KeyResolver;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import reactor.core.publisher.Mono;

/**
 * 请求限流配置
 */
@Configuration
public class RequestRateLimiterConfig {

    /**
     * 按IP来限流
     */
    @Bean
    public KeyResolver ipAddrKeyResolver() {//JDK8的新特性——Lambda表达式
        return exchange -> Mono.just(exchange.getRequest().getRemoteAddress().getAddress().getHostAddress());
    }

    ///**
    // * 按用户限流
    // */
    //@Bean
    //KeyResolver userKeyResolver() {
    //    return exchange -> Mono.just(exchange.getRequest().getQueryParams().getFirst("user"));
    //}

    ///**
    // * 按URL限流,即以每秒内请求数按URL分组统计,超出限流的url请求都将返回429状态
    // *
    // * @return
    // */
    //@Bean
    //@Primary
    //KeyResolver apiKeyResolver() {
    //    return exchange -> Mono.just(exchange.getRequest().getPath().toString());
    //}
}

注1:限流bean的名字,必须和步骤4引用时的名字一样

    4. 在路由配置中添加限流配置

代码语言:javascript
复制
  #filter名称必须是 RequestRateLimiter
            - name: RequestRateLimiter
              args:
                #用于限流的键的解析器的 Bean 对象的名字,使用 SpEL表达式根据#{@beanName}获取Bean对象
                key-resolver: '#{@ipAddrKeyResolver}'
                #令牌桶填充速率,允许用户每秒处理多少个请求
                redis-rate-limiter.replenishRate: 10
                #令牌桶总容量,允许在一秒钟内完成的最大请求数
                redis-rate-limiter.burstCapacity: 20

  5. 使用JMeter进行限流测试             测试结果,没有抢到令牌的请求就返回429,这边的限流相当于平均request:10/s 6. 在前端页面,比如:vue处理429错误,显示“服务忙请稍后再试”             Response code:429             Response message:Too Many Requests

二. 熔断

  网关是所有请求的入口,如果部分后端服务延时严重,则可能导致大量请求堆积在网关上,拖垮网关进而瘫痪整个系统。   这就需要对响应慢的服务做超时快速失败处理,即熔断     在组件的选型上有两种:Hystrix与Sentinel,本章介绍的是Spring Cloud Gateway基于Hystrix实现的熔断

    1. 修改gateway-server子模块的pom,增加pom相关依赖

代码语言:javascript
复制
  <!--Gateway基于Hystrix实现的熔断-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
        </dependency>

    2. 修改application.yml配置,在路由中添加熔断配置

Hystrix支持两个参数:         name:即HystrixCommand的名字         fallbackUri:fallback对应的uri,这里的uri仅支持forward:schemed
代码语言:javascript
复制
   filters:
            - name: Hystrix
              args:
                name: fallback
                fallbackUri: forward:/fallback

     3. 创建FallBackControlle

代码语言:javascript
复制
  @RestController
         public class FallBackController {

             @GetMapping("/fallback")
             public String fallback() {
                 return "Error:fallback";
             }
         } 

     4. 测试

         启动各个微服务,并访问,成功后再关闭生产者    至此:熔断的简单配置实现就完成了,如需自定义熔断策略需要学习了解HystrixGatewayFilter的相关内容

三. Spring Cloud 服务第一次请求超时的优化

  Spring Cloud项目启动后,首次使用 FeignClient 请求往往会消耗大量时间,并有一定概率因此导致请求超时(java.net.SocketTimeoutException: Read timed out),因而有可能会触发熔断     这是由于在调用其他微服务接口前,会去请求该微服务的相关信息(地址、端口等),并做一些初始化操作,由于默认的懒加载特性,导致了在第一次调用时,出现超时的情况  解决方法主要有两种: 1. 第一种办法是设置超时时间,具体设置成多少,因项目而异,配置如下         #hystrix调用方法的超时时间,默认是1000毫秒 hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=5000

        理论上这是一个治标的办法,这样处理能够解决超时的问题,但无法解决首次花费时间长的问题。同时因为需要将熔断器的超时时间设置得更长,等价于在一定程度上限制了熔断器的适用范围。所以可用这个方法,但不推荐这个方法

    2. 推荐的方式:配置ribbon立即加载,链路分析,服务之间的调用顺序为:gateway->消费者->生产者         接下来分两部分解决这个问题,一是服务之间调用Ribbon的饥饿加载,对应上面的测试为消费者调用生产者;二是网关的饥饿加载。         第一步: 找到消费者的application.yml文件,添加如下配置:         #此处需要注意的是,光配置立即加载是不生效的,还要配置客户端列表

代码语言:javascript
复制
    ribbon:
          eager-load:
            enabled: true                                                                  #开始饥饿模式
            clients: user-service, material-product, outer-data        #生产者的服务名,多个之间逗号分隔 

  重启消费者后,你会发现虽然没有发送调用请求,但日志中已经显示Feign的客户端创建成功了       第二步:网关的饥饿模式

代码语言:javascript
复制
   ribbon:
          eager-load:
            enabled: true
            clients: user-service-api

四. 个人体会

  外部请求用限流、内部请求用熔断

五.补充

附录一:JDK8的新特性——Lambda表达式

在JDK8之前,Java是不支持函数式编程的,所谓的函数编程,即可理解是将一个函数(也称为“行为”)作为一个参数进行传递。 通常我们提及得更多的是面向对象编程,面向对象编程是对数据的抽象(各种各样的POJO类),而函数式编程则是对行为的抽象(将行为作为一个参数进行传递)。 在JavaScript中这是很常见的一个语法特性,但在Java中将一个函数作为参数传递这却行不通,好在JDK8的出现打破了Java的这一限制。简单示例如下:

代码语言:javascript
复制
 new Thread(new Runnable() {
         @Override
         public void run() {
             System.out.println("Hello World!");
         }
     });

     使用Lambda表达式则只需要使用一句话就可代替上面使用匿名类的方式。  new Thread(() -> System.out.println("Hello World!"));

附录二:如何使用JMeter进行并发测试

1. 安装     将下载得到的压缩包解压即可,这里我解压到自己电脑的路径为D:\tools\apache-jmeter-5.2.1 2. 运行 点击bin目录下的jmeter.bat即可启动Jmeter。 3. 一个简单的压测实例     现有一个http请求接口localhost:5000/usr3/hello,要使用Jmeter对其进行压测,测试步骤如下:     1.新建一个线程组     2.设置线程组参数

1.Number of Threads 10 线程数量 10 个线程        2.Ramp-Up Period      0   所有线程在多少秒内启动,设置为0表示同时启动        3.Loop Count              1   线程重复资料        这里配置为:10个线程,同时启动,循环一次

 3.新增http请求默认值 在上一步创建的线程组上,新增http请求默认值,所有的请求都会使用设置的默认值,这设置协议为http,IP为localhost,端口为8080     4.添加要压测的http请求         协议、IP、端口不需要设置,会使用步骤c中设置的默认值,只需设置请求路径Path即可,这里填入/usr3/hello     5.新增监听器,用于查看压测结果。这里添加三种:聚合报告、图形结果、用表格查看结果,区别在于结果展现形式不同     6.点击运行按钮开始压测,并查看结果

附录三:@Primary注解

此注解用在类上面。它表示在需要自动注入一个单值依赖的地方,却有多个候选依赖,那么这个注解会指定一个类作为preference(偏好)选择。 可以简单理解为,我们把@Primary注解标记在任意一个类上面,在使用@Autowired注入的时候,如果不特殊指明(如何特殊指明请看@Qualifier的讲解), 那么默认就注入被@Primary标记的类。但是只可以指定一个类作为偏好类,否则依然会产生冲突。

附录四:SpringCloud服务消费者第一次调用出现超时问题的解决方案

在第一次访问服务消费者的时候(消费者去调用服务提供者服务)会出现如下异常: com.netflix.hystrix.exception.HystrixRuntimeException: TestService#hello(String) timed-out and no fallback available 解决方案是在application.properties增加如下配置信息: #hystrix调用方法的超时时间,默认是1000毫秒 hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=5000  更绝的一个方案是直接禁用hystrix: feign.hystrix.enabled=false

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2023-10-11,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一·. spring cloud gateway网关限流
    •     1. 限流简介
      •     2. 常见的限流手段
        •     3. 限流算法
          •         1.漏桶算法(Leaky Bucket)    
          •         2.令牌桶算法(Token Bucket)
        •     4. gateway网关限流快速实现
          • 1. 导入redis依赖
          •         2. 修改application.yml文件添加redis相关配置
      • 二. 熔断
        •     1. 修改gateway-server子模块的pom,增加pom相关依赖
          •     2. 修改application.yml配置,在路由中添加熔断配置
            • Hystrix支持两个参数:         name:即HystrixCommand的名字         fallbackUri:fallback对应的uri,这里的uri仅支持forward:schemed
          •      3. 创建FallBackControlle
            •      4. 测试
            • 三. Spring Cloud 服务第一次请求超时的优化
            • 四. 个人体会
            • 五.补充
              • 附录一:JDK8的新特性——Lambda表达式
                • 附录二:如何使用JMeter进行并发测试
                  • 附录三:@Primary注解
                    • 附录四:SpringCloud服务消费者第一次调用出现超时问题的解决方案
                    相关产品与服务
                    腾讯云服务器利旧
                    云服务器(Cloud Virtual Machine,CVM)提供安全可靠的弹性计算服务。 您可以实时扩展或缩减计算资源,适应变化的业务需求,并只需按实际使用的资源计费。使用 CVM 可以极大降低您的软硬件采购成本,简化 IT 运维工作。
                    领券
                    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档