IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> 分布式限流之 - Spring Cloud Gateway层限流实现 -> 正文阅读

[Java知识库]分布式限流之 - Spring Cloud Gateway层限流实现

写在前面的话

  • 高兵发的三驾马车:缓存、降级、限流,这里仅仅说限流
  • 常用的限流算法有:计数器算法、固定窗口算法、滑动窗口算法、漏桶算法、令牌桶算法;每种算法的特点和优缺点这里不展开,比较适用的限流算法基本都会选择令牌桶,并且这里基于Spring Cloud Gateway Redis本身默认就是基于令牌桶算法实现
  • 限流按照类型分为:单机、分布式
  • 限流按照请求流量的路径分为:nginx、gateway、微服务
  • 如果仅仅使用于单机环境:谷歌guava的RateLimiter、(AtomicInteger、Semaphore)【AQS】都是可以选择的; 但是在说到高并发基本已经是分布式环境,此时的常用方案可以基于nginx的ngx_http_limit_req_module模块、 gateway层基于 redis(底层使用lua脚本)、阿里的sentinel(需要单独搭建服务)等方案
  • 该方案选择使用spring cloud gateway RequestRateLimiter进行限流,可选择的策略有:基于访问的ip进行控制,基于访问的请求参数进行控制(前提是接口需要有对应的访问参数),基于actuator实时监控进行控制(比如服务器的cpu达到80%),基于hystrix配置的策略进行控制等

当前选择的方案在是 Spring Cloud Gateway层使用 redis作为分布式的协作中心,默认底层使用令牌桶方式实现,一定要清楚,当前在这个位置:

?如果再细分一下,当前位于gateway的内部的这个位置:

?实现(这个省略了gateway的搭建和配置等):

1、在gateway网关服务进入redis的pom

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

2、yml配置

spring:
  application:
    name: kevin-gateway
  redis:
    host: 82.156.54.7
    port: 6379
    password: 123456
  cloud:
    nacos:
      discovery:
        server-addr: 82.156.54.7:8848
    gateway:
      globalcors:
        cors-configurations:
          '[/**]':
            allowCredentials: true
            allowedOrigins: "*"
            allowedMethods: "*"
            allowedHeaders: "*"
        add-to-simple-url-handler-mapping: true
      # 默认过滤器(对所有route均生效)
      default-filters:
        # 请求限速配置
        - name: RequestRateLimiter
          args:
            # 如果keyResolver返回空key,则拒绝该请求403,默认true表示拒绝,false则表示允许访问
            deny-empty-key: false
            # 令牌桶算法每秒补充的token数量(每秒的请求数量)spring-boot-starter-data-redis-reactive
            redis-rate-limiter.replenishRate: 10
            # 令牌桶算法token最大数量(每秒的最大请求数量)
            redis-rate-limiter.burstCapacity: 15
            # 单次请求消费的token数量
            redis-rate-limiter.requestedTokens: 10
            # 自定义的KeyResolver(从请求exchange解析id,用于区分限流的独立单元,如用户ID、remoteAddr、sessionId等)
            key-resolver: "#{@ipKeyResolver}"
      routes:
        - id: mosty-base
          uri: lb://mosty-base
          predicates:
            - Path=/mosty-base/**
          filters:
            - StripPrefix=1
            - name: RequestRateLimiter
              args:
                redis-rate-limiter.replenishRate: 10
                redis-rate-limiter.burstCapacity: 20
                redis-rate-limiter.requestedTokens: 10
                key-resolver: "#{@ipKeyResolver}"
        - id: mosty-search
          uri: lb://MOSTY-SEARCH
          predicates:
            - Path=/mosty-search/**
          filters:
            - StripPrefix=2

如上,首先需要进入redis的配置

?其次配置限流的Filter配置信息,允许配置全局过滤器对所有的route生效,也可以根据需求对每个route进行单独配置

?

配置参数说明:

name必须写 RequestRateLimiter

args参数:

  • redis-rate-limiter.replenishRate:发送令牌的速率
  • redis-rate-limiter.burstCapacity: 令牌桶的容量
  • reids-rate-limiter.requestedTokens: 每个请求耗费的令牌数
  • key-resolver:如上所示是配置的一个spring bean的名称,如果没有配置则会获取到KeyResolver的默认实现PrincipalNameKeyResolver,并且访问接口都会返回 http 403状态码(与下面的deny-empty-key值相关)
  • deny-empty-key: false 如果keyResolver返回空key,则拒绝该请求403,默认true表示拒绝,false则表示允许访问

1、ip限流策略

yml中配置 keyResolver:"#{@ipKeyResolver}"

@Bean(name = "ipKeyResolver")
public KeyResolver ipKeyResolver() {
   return new KeyResolver() {
      @Override
      public Mono<String> resolve(ServerWebExchange exchange) {
         String hostName = Objects.requireNonNull(exchange.getRequest()
                               .getRemoteAddress()).getHostName();
         System.out.println("hostName:" + hostName);
         return Mono.just(hostName);
      }
   };
}

?基于限流策略,正常访问的效果,以及被限流的效果(返回标准的Http 429编码,Too Many Request)

2、请求参数限流策略

yml中配置 keyResolver:"#{@userKeyResolver}"

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

在下面的微服务的接口中一定要有该参数,即需要能在请求参数中获取到该值

@GetMapping("/getUserNameByUserId")
public String userInfo(@RequestParam("userId") String userId) {
   // 查询数据库获取
   return "user name of" + userId;
}

3、请求路径(即接口)限流

yml中配置 keyResolver:"#{@requestPathKeyResolver}"

@Bean("requestPathKeyResolver")
public KeyResolver requestPathKeyResolver() {
   return exchange -> Mono.just(Objects.requireNonNull(
                        exchange.getRequest().getURI().()));
}

4、基于hystrix熔断进行限流策略

基于上面的引入pom:spring-boot-starter-data-redis-reactive外,还需要引入

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>

将Hystrix配置为全局的过滤器(对所有的 route生效),如下

说明:

? ? name执行过滤器的类型,指向了 Hystrix过滤器

? ? args:default-filters的Hystrix将会使用HystrixCommand打包剩余的过滤器,并命名为fallbackcmd,我们还配置了可选的参数fallbackUri,降级逻辑被调用,请求将会被转发到URI为/fallbackcontroller的控制器处理

spring:
  cloud:
    gateway:
      # 默认过滤器(对所有route均生效)
      default-filters:
        - name: Hystrix
          args:
            name: fallbackcmd
            fallbackUri: forward:/fallbackcontroller

添加 Hystrix的fallback的控制器接口方法

此时需要添加一个fallback的接口,并且返回想要的数据结构

@ResponseBody
@RequestMapping(value = "/fallbackcontroller")
public ResponseResult<Object> fallBackController() {
   return ResponseResult.fail(HttpStatus.TOO_MANY_REQUESTS.value(), "超时限流",  null);
}

生效还需要配置hystrix的超时时间(yml配置如下):hystrix.command.fallbackcmd.execution.isolation.thread.timeoutInMilliseconds

并且记得在启动类上添加Hystrix的启动项

@EnableHystrix

为了实现效果此时将待访问的接口直接进行sleep 5s,测试效果

@Slf4j
@RestController
public class TestController {

    @RequestMapping("/test/fallback")
    public Object fallacak() throws InterruptedException {
        Thread.sleep(5000);
        log.info("熔断处理!!!");
        return "Service Error!!!";
    }
}

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章           查看所有文章
加:2022-05-27 17:14:02  更:2022-05-27 17:15:53 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 20:51:38-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码