我的编程空间,编程开发者的网络收藏夹
学习永远不晚

Spring cloud 限流的多种方式

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

Spring cloud 限流的多种方式

在频繁的网络请求时,服务有时候也会受到很大的压力,尤其是那种网络攻击,非法的。这样的情形有时候需要作一些限制。例如:限制对方的请求,这种限制可以有几个依据:请求IP、用户唯一标识、请求的接口地址等等。

当前限流的方式也很多:Spring cloud 中在网关本身自带限流的一些功能,基于 redis 来做的。同时,阿里也开源了一款:限流神器 Sentinel。今天我们主要围绕这两块来实战微服务的限流机制。

首先讲 Spring cloud 原生的限流功能,因为限流可以是对每个服务进行限流,也可以对于网关统一作限流处理。

一、实战基于 Spring cloud Gateway 的限流

pom.xml引入依赖:


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

其基础是基于redis,所以:


spring:
  application:
    name: gateway-service
  redis: #redis相关配置
    database: 8
    host: 10.12.15.5
    port: 6379
    password: 123456 #有密码时设置
    jedis:
      pool:
        max-active: 8
        max-idle: 8
        min-idle: 0
    timeout: 10000ms

接下来需要注入限流策略的 bean:


@Primary
  @Bean(value = "ipKeyResolver")
  KeyResolver ipKeyResolver() {
      return exchange -> Mono.just(exchange.getRequest().getRemoteAddress().getHostName());
      //return exchange -> Mono.just(exchange.getRequest().getRemoteAddress().getAddress().getHostAddress());
      //return exchange -> Mono.just(exchange.getRequest().getRemoteAddress().getAddress().getHostAddress());
  }

 
  @Bean(value = "apiKeyResolver")
  KeyResolver apiKeyResolver() {
    return exchange -> Mono.just(exchange.getRequest().getPath().value());
  }

  
  @Bean(value = "userKeyResolver")
  KeyResolver userKeyResolver() {
    return exchange -> Mono.just(exchange.getRequest().getQueryParams().getFirst("userId"));
  }

这里引入ipKeyResolver、apiKeyResolver、userKeyResolver三种策略,可以利用注解 @Primary 来决定其中一个被使用。

注入bean后,需要在配置中备用:


spring:
  application:
    name: gateway-service
  redis: #redis相关配置
    database: 8
    host: 10.12.15.5
    port: 6379
    password: 123456 #有密码时设置
    jedis:
      pool:
        max-active: 8
        max-idle: 8
        min-idle: 0
    timeout: 10000ms

后面是限流的主要配置:


spring
  cloud:
    gateway:
      routes: #路由配置:参数为一个List
      - id: cas-server #唯一标识
        uri: lb://cas-server-service #转发的地址,写服务名称
        order: -1
        predicates:
        - Path=/cas-server/** #判断匹配条件,即地址带有/ribbon/**的请求,会转发至lb:cas-server-service
        filters:
        - StripPrefix=1 #去掉Path前缀,参数为1代表去掉/ribbon

        - name: RequestRateLimiter #基于redis的Gateway的自身限流
          args:
            redis-rate-limiter.replenishRate: 1  # 允许用户每秒处理多少个请求
            redis-rate-limiter.burstCapacity: 3  # 令牌桶的容量,允许在一秒钟内完成的最大请求数
            key-resolver: "#{@ipKeyResolver}" #SPEL表达式取的对应的bean

      - id: admin-web
        uri: lb://admin-web-service
        order: -1
        predicates:
        - Path=/admin-web/**
        filters:
        - StripPrefix=1

        - name: RequestRateLimiter
          args:
            redis-rate-limiter.replenishRate: 1  # 允许用户每秒处理多少个请求
            redis-rate-limiter.burstCapacity: 3  # 令牌桶的容量,允许在一秒钟内完成的最大请求数
            key-resolver: "#{@ipKeyResolver}" #SPEL表达式取的对应的bean

这里是在原有的路由基础上加入 RequestRateLimiter限流过滤器,包括三个参数:


- name: RequestRateLimiter #基于redis的Gateway的自身限流
          args:
            redis-rate-limiter.replenishRate: 3  #允许用户每秒处理多少个请求
            redis-rate-limiter.burstCapacity: 5  #令牌桶的容量,允许在一秒钟内完成的最大请求数
            key-resolver: "#{@ipKeyResolver}" #SPEL表达式取的对应的bean
  • 其中 replenishRate,其含义表示允许每秒处理请求数;
  • burstCapacity 表示允许在一秒内处理的最大请求数;
  • key-resolver 这里采用请求 IP 限流,利用SPEL 表达式取对应的 bean

写一个小脚本来压测一下:


for i in $(seq 1 30000); do echo $(expr $i \\* 3 + 1);curl -i -H "Accept: application/json" -H "Authorization:bearer b064d95b-af3f-4053-a980-377c63ab3413" -X GET http://10.10.15.5:5556/order-service/api/order/getUserInfo;done

for i in $(seq 1 30000); do echo $(expr $i \\* 3 + 1);curl -i -H "Accept: application/json" -H "Authorization:bearer b064d95b-af3f-4053-a980-377c63ab3413" -X GET http://10.10.15.5:5556/admin-web/api/user/getCurrentUser;done

上面两个脚本分别对2个服务进行压测,打印结果:

{"message":{"status":200,"code":0,"message":"success"},"data":"{\"message\":{\"status\":200,\"code\":0,\"message\":\"get user success\"},\"data\":{\"id\":23,\"isAdmin\":1,\"userId\":\"fbb18810-e980-428c-932f-848f3b9e7c84\",\"userType\":\"super_admin\",\"username\":\"admin\",\"realName\":\"super_admin\",\"password\":\"$2a$10$89AqlYKlnsTpNmWcCMvgluRFQ/6MLK1k/nkBpz.Lw6Exh.WMQFH6W\",\"phone\":null,\"email\":null,\"createBy\":\"admin\",\"createTime\":1573119753172,\"updateBy\":\"admin\",\"updateTime\":1573119753172,\"loginTime\":null,\"expireTime\":null,\"remarks\":\"super_admin\",\"delFlag\":0,\"loginType\":null}}"}ex

在用测试工具Jmeter在同一秒内多次请求后:


HTTP/1.1 429 Too Many Requests
X-RateLimit-Remaining: 0
X-RateLimit-Burst-Capacity: 3
X-RateLimit-Replenish-Rate: 1
content-length: 0

expr: syntax error

HTTP/1.1 429 Too Many Requests
X-RateLimit-Remaining: 0
X-RateLimit-Burst-Capacity: 3
X-RateLimit-Replenish-Rate: 1
content-length: 0

expr: syntax error

从上面可以看到,执行后,会出现调用失败的情况,状态变为429 (Too Many Requests) 。

二、基于阿里开源限流神器:Sentinel

首先引入依赖:


<!--基于 阿里的sentinel作限流 -->
    <dependency>
          <groupId>com.alibaba.cloud</groupId>
          <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
    </dependency>

在配置文件 application.yaml 文件中配置,需要新增2个配置:


spring:
  application:
    name: admin-web
  cloud:
    kubernetes:
      discovery:
        all-namespaces: true
    sentinel:
      eager: true #取消Sentinel控制台的懒加载
      transport:
        dashboard: 10.12.15.2:8080 #sentinel的Dashboard地址
        port: 8719 #是sentinel应用端和控制台通信端口
        heartbeat-interval-ms: 500 #心跳时间
      scg:
        fallback: #scg.fallback为sentinel限流后的响应配置
          mode: response
          response-status: 455
          response-body: 已被限流

其中,这里面配置了一个服务:spring.cloud.sentinel.transport.dashboard,配置的是 sentinel 的 Dashboard 地址。同时 spring.cloud.sentinel.transport.port 这个端口配置会在应用对应的机器上启动一个Http Server,该 Server 会与 Sentinel 控制台做交互。

Sentinel 默认为所有的 HTTP 服务提供限流埋点,上面配置完成后自动完成所有埋点,只需要控制配置限流规则即可。
这里我们讲下通过注解来给指定接口函数加上限流埋点,写一个RestController,在接口函数上加上注解


@SentinelResource:
@GetMapping(value = "/getToken")
@SentinelResource("getToken")
public Response<Object> getToken(Authentication authentication){
    //Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
    authentication.getCredentials();
    OAuth2AuthenticationDetails details = (OAuth2AuthenticationDetails)authentication.getDetails();
    String token = details.getTokenValue();
    return Response.ok(200, 0, "get token success", token);
}

以上代码部分完成了,接下来先安装SentinelDashBoard,Sentinel DashBoard下载地址:github.com/alibaba/Sentinel/releases。

下载完成后,命令启动:


java -jar sentinel-dashboard-1.6.2.jar

默认启动端口为8080,访问 IP:8080,就可以显示 Sentinel 的登录界面,用户名与密码均为sentinel。登录 Dashboard 成功后,多次访问接口"/getToken",可以在 Dashboard 看到相应数据,这里不展示了。接下来可以设置接口的限流功能,在 “+流控” 按钮点击打开设置界面,设置阈值类型为 qps,单机阈值为5。

浏览器重复请求 http://10.10.15.5:5556/admin-web/api/user/getToken 如果超过阀值就会出现如下界面信息:
Blocked by Sentinel (flow limiting)

此时,就看到Sentinel 限流起作用了,可以加上 spring.cloud.sentinel.scg.fallback 为sentinel 限流后的响应配置,亦可自定义限流异常信息:


@GetMapping(value = "/getToken")
@SentinelResource(value = "getToken", blockHandler = "handleSentinelException", blockHandlerClass = {MySentinelException.class}))
public Response<Object> getToken(Authentication authentication){
    //Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
    authentication.getCredentials();
    OAuth2AuthenticationDetails details = (OAuth2AuthenticationDetails)authentication.getDetails();
    String token = details.getTokenValue();
    return Response.ok(200, 0, "get token success", token);
}

public class MySentinelException {
    public static Response<Object> handleSentinelException(BlockException e) {
        Map<String,Object> map=new HashMap<>();
        logger.info("Oops: " + ex.getClass().getCanonicalName());
        return Response.ok(200, -8, "通过注解 @SentinelResource 配置限流埋点并自定义限流后的处理逻辑", null);
    }
}

这里讲下注解 @SentinelResource 包含以下属性:

  • value:资源名称,必需项;
  • entryType:入口类型,可选项(默认为 EntryType.OUT);
  • blockHandler:blockHandlerClass中对应的异常处理方法名,参数类型和返回值必须和原方法一致;
  • blockHandlerClass:自定义限流逻辑处理类

Sentinel 限流逻辑处理完毕了,但每次服务重启后,之前配置的限流规则就会被清空。因为是内存形式的规则对象。所以下面就讲下用 Sentinel 的一个特性 ReadableDataSource 获取文件、数据库或者配置中心设置限流规则,目前支持 Apollo、Nacos、ZK 配置来管理。

首先回忆一下,一条限流规则主要由下面几个因素组成:

  • resource:资源名,即限流规则的作用对象,即为注解 @SentinelResource 的value;
  • count:限流阈值;grade:限流阈值类型(QPS 或并发线程数);
  • limitApp:流控针对的调用来源,若为 default 则不区分调用来源;
  • strategy:基于调用关系的限流策略;
  • controlBehavior:流量控制效果(直接拒绝、排队等待、匀速器模式)

理解了意思,接下来通过文件来配置:


#通过文件读取限流规则
spring.cloud.sentinel.datasource.ds1.file.file=classpath:flowrule.json
spring.cloud.sentinel.datasource.ds1.file.data-type=json
spring.cloud.sentinel.datasource.ds1.file.rule-type=flow

在resources新建一个文件,比如 flowrule.json 添加限流规则:


[
  {
    "resource": "getToken",
    "count": 1,
    "controlBehavior": 0,
    "grade": 1,
    "limitApp": "default",
    "strategy": 0
  },
  {
    "resource": "resource",
    "count": 1,
    "controlBehavior": 0,
    "grade": 1,
    "limitApp": "default",
    "strategy": 0
  }
]

重新启动项目,出现如下日志说明成功:


DataSource ds1-sentinel-file-datasource start to loadConfig
DataSource ds1-sentinel-file-datasource load 2 FlowRule

如果采用 Nacos 作为配置获取限流规则,可在文件中加如下配置:


spring:
  application:
    name: order-service
  cloud:
    nacos:
      config:
        server-addr: 10.10.15.5:8848
      discovery:
        server-addr: 10.10.15.5:8848
    sentinel:
      eager: true
      transport:
        dashboard: 10.10.15.5:8080
      datasource:
        ds1:
          nacos:
            server-addr: 10.10.15.5:8848
            dataId: ${spring.application.name}-flow-rules
            data-type: json
            rule-type: flow

到此这篇关于Spring cloud 限流的多种方式的文章就介绍到这了,更多相关Spring cloud 限流内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

Spring cloud 限流的多种方式

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

Spring cloud中限流的方式有哪些

这篇文章主要介绍了Spring cloud中限流的方式有哪些,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。在频繁的网络请求时,服务有时候也会受到很大的压力,尤其是那种网络攻击
2023-06-15

Java实现5种限流算法及7种限流方式

本文主要介绍了Java实现5种限流算法及7种限流方式,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
2022-11-13

Spring Cloud Alibaba之Sentinel实现熔断限流功能的方法

这篇文章主要介绍Spring Cloud Alibaba之Sentinel实现熔断限流功能的方法,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!sentinel简介这个在阿里云有企业级的商用版本 应用高可用服务 AHA
2023-06-14

Spring Cloud Gateway中的令牌桶限流算法实例分析

这篇“Spring Cloud Gateway中的令牌桶限流算法实例分析”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“Spr
2023-06-29

springboot-mybatis/JPA流式查询的多种实现方式

这篇文章主要介绍了springboot-mybatis/JPA流式查询,本文给大家分享三种方式,每种方式结合示例代码给大家讲解的非常详细,需要的朋友可以参考下
2022-12-19

Spring Boot配置多数据源的四种方式

1、导读 在日常开发中我们都是以单个数据库进行开发,在小型项目中是完全能够满足需求的。 但是,当我们牵扯到像淘宝、京东这样的大型项目的时候,单个数据库就难以承受用户的CRUD操作。 那么此时,我们就需要使用多个数据源进行读写分离的操作,这种
2023-08-20

Redis实现IP限流的2种方式举例详解

目录通过reids实现通过Lua+Redis实现注意事项总结 通过reids实现限流的流程图在配置文件配置限流参数blackIP:# ip 连续请求的次数continue-counts: ${counts:3}# ip 判断的时间间隔
Redis实现IP限流的2种方式举例详解
2024-08-13

Spring Cloud Data Flow:数据流式处理,大数据的利剑

Spring Cloud Data Flow是一款轻量级的流式数据处理框架,为用户提供了开发、部署和监控数据流管道的强大功能。它融合了Apache Kafka、RabbitMQ等消息代理,并支持多种数据处理技术,如Apache Spark、Flink等,帮助企业轻松应对大数据处理的挑战。
Spring Cloud Data Flow:数据流式处理,大数据的利剑
2024-03-07

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录