zoukankan      html  css  js  c++  java
  • 网关之SpringCloudGateway高级应用

    一、熔断降级

    1.1 为什么要实现熔断降级?

    在分布式系统中,网关作为流量的入口,因此会有大量的请求进入网关,向其他服务发起调用,其他服务不可避免的会出现调用失败(超时、异常),失败时不能让请求堆积在网关上,需要快速失败并返回给客户端,想要实现这个要求,就必须在网关上做熔断、降级操作。

    1.2 基于 hystrix 熔断降级

    1. 添加依赖
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
    </dependency>
    
    1. 配置
    server:
      # 配置应用端口
      port: 8080
      
    spring:
      application:
        # 配置应用名称
        name: gateway
      cloud:
        nacos:
          discovery:
            # 注册服务中心地址
            server-addr: 192.168.205.10:8848
        gateway:
          routes:
            - id: order-service
              uri: lb://order-service
              predicates:
                - Path=/order/**
              filters:
                # 配置 Hystrix
                - name: Hystrix
                  args:
                    name: fallbackCmdA
                    # 降级调用 URI
                    fallbackUri: forward:/fallbackA
    # 设置超时时间,单位:ms
    hystrix.command.fallbackCmdA.execution.isolation.thread.timeoutInMilliseconds: 5000
    
    1. 创建降级回调方法
    @RestController
    public class FallbackController {
    
        @GetMapping("/fallbackA")
        public String fallbackA() {
            return "服务暂时不可用";
        }
    }
    
    
    1. 启动 OrderServicegateway 服务,并访问 http://localhost:8080/order/create 返回:
    订单创建成功
    
    1. 关闭OrderService 访问 http://localhost:8080/order/create 返回:
    服务暂时不可用
    

    证明熔断降级已生效。

    二、限流

    2.1 为什么需要限流?

    • 防止大量的请求使服务器过载,导致服务不可用
    • 防止网络攻击

    2.2 常见的限流算法

    计数器算法

    在指定时间内对请求数做累计,当数量大于设置的值时,后续的请求都将被拒绝。当指定时间过去后,将计数重置为0,重新开始计数。
        
    弊端:如果在单位时间1s内只能允许100个请求访问,在前10ms已经通过了100个请求,那后面的990ms所有的请求都会被拒绝,这种现象称为“突刺现象”。    
    

    漏桶算法

    漏桶算法可以消除"突刺现象",漏桶算法内部有一个容器,类似生活用到的漏斗,当请求进来时,相当于水倒入漏斗,然后从下端小口慢慢匀速的流出。不管上面流量多大,下面流出的速度始终保持不变。不管服务调用方多么不稳定,通过漏桶算法进行限流,每10毫秒处理一次请求。因为处理的速度是固定的,请求进来的速度是未知的,可能突然进来很多请求,没来得及处理的请求就先放在桶里,既然是个桶,肯定是有容量上限,如果桶满了,那么新进来的请求就丢弃
        
    弊端:无法应对短时间的突发流量。    
    

    令牌桶算法

    在令牌桶算法中,存在一个桶,用来存放固定数量的令牌。算法中存在一种机制,以一定的速率往桶中放令牌。每次请求调用需要先获取令牌,只有拿到令牌,才有机会继续执行,否则选择选择等待可用的令牌、或者直接拒绝。放令牌这个动作是持续不断的进行,如果桶中令牌数达到上限,就丢弃令牌,所以就存在这种情况,桶中一直有大量的可用令牌,这时进来的请求就可以直接拿到令牌执行,比如设置qps为100,那么限流器初始化完成一秒后,桶中就已经有100个令牌了,这时服务还没完全启动好,等启动完成对外提供服务时,该限流器可以抵挡瞬时的100个请求。所以,只有桶中没有令牌时,请求才会进行等待,最后相当于以一定的速率执行。
    

    2.3 Gateway 限流支持

    Spring Cloud Gateway 中,有 Filter 过滤器,因此可以在 pre 类型的 Filter 中自行实现上述三种过滤器。但是限流作为网关最基本的功能,Spring Cloud Gateway 官方就提供了 RequestRateLimiterGatewayFilterFactory 这个类,适用在 Redis 内的通过执行 Lua 脚本实现了令牌桶的方式。具体实现逻辑在 RequestRateLimiterGatewayFilterFactory 类中,lua 脚本在如下图所示的文件夹中:

    2.4 实例

    1. 添加 redis 依赖
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-redis-reactive</artifactId>
    </dependency>
    
    1. 在配置文件中配置
    server:
      # 配置应用端口
      port: 8080
    
    
    spring:
      application:
        # 配置应用名称
        name: gateway
      cloud:
        nacos:
          discovery:
            # 注册服务中心地址
            server-addr: 192.168.205.10:8848
        gateway:
          routes:
            - id: order-service
              uri: lb://order-service
              predicates:
                - Path=/order/**
              filters:
                - name: RequestRateLimiter
                  args:
                    # 用于限流的键的解析器的 Bean 对象的名字,通过 SpEL 表达式从 Spring 容器中获取 
                    key-resolver: '#{@hostAddrKeyResolver}'
                    # 令牌桶每秒填充平均速率
                    redis-rate-limiter.replenishRate: 1
                    # 令牌桶的上限
                    redis-rate-limiter.burstCapacity: 3
      redis:
        host: localhost
        port: 6379
        database: 0
    
    1. 自定义限流策略,通过实现 KeyResolver 接口

    基于 hostAddress 限流:

    public class HostAddrKeyResolver implements KeyResolver {
    
        public Mono<String> resolve(ServerWebExchange exchange) {
            return Mono.just(exchange.getRequest().getRemoteAddress().getAddress().getHostAddress());
        }
        
    }
    

    基于 URI 限流:

    public class UriKeyResolver implements KeyResolver {
    
        public Mono<String> resolve(ServerWebExchange exchange) {
            return Mono.just(exchange.getRequest().getURI().getPath());
        }
    
    }
    

    基于用户 限流:

    public class UserKeyResolver implements KeyResolver {
    
        public Mono<String> resolve(ServerWebExchange exchange) {
            return Mono.just(exchange.getRequest().getQueryParams().getFirst("user"));
        }
    
    }
    

    只允许一个策略生效,这里我们采用 HostAddrKeyResolver :

    @Bean
    public HostAddrKeyResolver hostAddrKeyResolver() {
    	return new HostAddrKeyResolver();
    }
    
    1. 启动 OrderServicegateway 服务,通过 jmeter 并发访问

    可以看到请求部分成功,部分失败。

  • 相关阅读:
    [原] JT SQL Server 性能调优札记之三
    [转]SQL Server 2000执行计划成本(4/5)
    [转]Oracle的Online Redo Log 相关操作
    [原]成功在ESX上搭建SQL Server 2005集群
    我的软设、系分考试经验(书)
    [转]Linux软RAID的技术概要及实现
    [原]Console小技巧——七彩输出
    SQL SERVER 2005 压缩日志及数据库文件大小
    [转]SQL Server 2000执行计划成本(2/5)
    [原]在SQL Server 2005 中使用.net程序集的一项注意
  • 原文地址:https://www.cnblogs.com/markLogZhu/p/13627261.html
Copyright © 2011-2022 走看看