Sentinel网关限流 与Spring Cloud Gateway 整合

网关如何限流?

Spring Cloud Gateway本身自带的限流实现,过滤器是RequestRateLimiterGatewayFilterFactory,不过这种比较简单,有兴趣的可以实现下。
今天的重点是集成阿里的Sentinel实现网关限流,sentinel顾名思义:卫兵;在Redis中叫做哨兵,用于监控主从切换,但是在微服务中叫做流量防卫兵。Sentinel 以流量为切入点,从流量控制、熔断降级、系统负载保护等多个维度保护服务的稳定性。
Sentinel 具有以下特征:

  • 丰富的应用场景:Sentinel 承接了阿里巴巴近 10 年的双十一大促流量的核心场景,例如秒杀(即突发流量控制在系统容量可以承受的范围)、消息削峰填谷、集群流量控制、实时熔断下游不可用应用等。
  • 完备的实时监控:Sentinel 同时提供实时的监控功能。您可以在控制台中看到接入应用的单台机器秒 级数据,甚至 500 台以下规模的集群的汇总运行情况。
  • 广泛的开源生态:Sentinel 提供开箱即用的与其它开源框架/库的整合模块,例如与 Spring Cloud、Apache Dubbo、gRPC、Quarkus 的整合。您只需要引入相应的依赖并进行简单的配置即可快速地接入 Sentinel。同时 Sentinel 提供 Java/Go/C++ 等多语言的原生实现。
  • 完善的 SPI 扩展机制:Sentinel 提供简单易用、完善的 SPI 扩展接口。您可以通过实现扩展接口来快速地定制逻辑。例如定制规则管理、适配动态数据源等。

Sentinel 的主要特性如下图:
Sentinel网关限流 与Spring Cloud Gateway 整合_第1张图片
从1.6.0版本开始,Sentinel提供了SpringCloud Gateway的适配模块,可以提供两种资源维度的限流:
**route维度:**即在配置文件中配置的路由条目,资源名为对应的routeId,这种属于粗粒度的限流,一般是对某个微服务进行限流。
**自定义API维度:**用户可以利用Sentinel提供的API来自定义一些API分组,这种属于细粒度的限流,针对某一类的uri进行匹配限流,可以跨多个微服务。

项目实践

新建一个gateway-service模块,添加如下依赖:

<!--nacos注册中心-->
    <dependency>
      <groupId>com.alibaba.cloud</groupId>
      <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
    </dependency>

    <!--spring cloud gateway-->
    <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-gateway</artifactId>
    </dependency>

    <!--    spring cloud gateway整合sentinel的依赖-->
    <dependency>
      <groupId>com.alibaba.cloud</groupId>
      <artifactId>spring-cloud-alibaba-sentinel-gateway</artifactId>
    </dependency>

    <!--    sentinel的依赖-->
    <dependency>
      <groupId>com.alibaba.cloud</groupId>
      <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
    </dependency>

配置文件

配置文件中主要指定以下三种配置:

  • nacos的地址
  • sentinel控制台的地址
  • 网关路由的配置

配置如下:

server:
  port: 8100
logging:
  path: d:/
spring:
  application:
    name: gateway-service
  cloud:
    nacos:
      server-addr: localhost:8848
    sentinel:
      transport:
        dashboard: localhost:8080
    gateway:
      routes:
        - id: mqtt-service-route
          uri: lb://mqtt-service
          predicates:
            - Path=/mqtt/**
        - id: usermgr-service-route
          uri: lb://usermgr-service
          predicates:
            - Path=/usermgr/**

上述配置中设置了一个路由usermgr-service-route,只要请求路径满足http://127.0.0.1:8100/usermgr/user/id都会被路由到usermgr-service这个服务中

限流配置

经过上述两个步骤其实已经整合好了Sentinel,此时访问一下接口:http://127.0.0.1:8100/usermgr/user/id
然后在sentinel控制台可以看到已经被监控了,监控的路由是usermgr-service,如下图:

Sentinel网关限流 与Spring Cloud Gateway 整合_第2张图片
上图中对usermgr-service这个路由做出了限流,QPS阈值为1。

此时快速访问:http://127.0.0.1:8100/usermgr/user/id,看到已经被限流了,如下图:
Sentinel网关限流 与Spring Cloud Gateway 整合_第3张图片

以上route维度的限流已经配置成功,小伙伴可以自己照着上述步骤尝试一下。

API分组限流

首先需要定义一个分组,API管理-> 新增API分组,如下图:
Sentinel网关限流 与Spring Cloud Gateway 整合_第4张图片
匹配模式选择了精确匹配(还有前缀匹配,正则匹配),因此只有这个uri:http://127.0.0.1:8100/usermgr/user/id会被限流。

第二步需要对这个分组添加流控规则,流控规则->新增网关流控,如下图

Sentinel网关限流 与Spring Cloud Gateway 整合_第5张图片
API名称那里选择对应的分组即可,新增之后,限流规则就生效了。

如何自定义限流异常信息?

从上面的演示中可以看到默认的异常返回信息是:“Block…”,这种肯定是客户端不能接受的,因此需要定制自己的异常返回信息。
下面介绍两种不同的方式定制异常返回信息,开发中自己选择其中一种。

直接配置文件中定制

开发者可以直接在配置文件中直接修改返回信息,配置如下:

spring:
  cloud:
    ## 整合sentinel,配置sentinel控制台的地址
    sentinel:
      #配置限流之后,响应内容
      scg:
        fallback:
          ## 两种模式,一种是response返回文字提示信息,
          ## 一种是redirect,重定向跳转,需要同时配置redirect(跳转的uri)
          mode: response
          ## 响应的状态
          response-status: 200
          ## 响应体
          response-body: '{"code": 200,"message": "请求失败,稍后重试!"}'

上述配置中mode配置的是response,一旦被限流了,将会返回JSON串

{
    "code": 200,
    "message": "请求失败,稍后重试!"
}

重定向的配置如下:

spring:
  cloud:
    ## 整合sentinel,配置sentinel控制台的地址
    sentinel:
      #配置限流之后,响应内容
      scg:
        fallback:
          ## 两种模式,一种是response返回文字提示信息,一种是redirect,重定向跳转,需要同时配置redirect(跳转的uri)
          mode: redirect
          ## 跳转的URL
          redirect: http://www.baidu.com

一旦被限流,将会直接跳转到:http://www.baidu.com

编码定制

这种就不太灵活了,通过硬编码的方式,完整代码如下:

package com.spacetime.gateway.config;

import com.alibaba.csp.sentinel.adapter.gateway.sc.callback.BlockRequestHandler;
import com.alibaba.csp.sentinel.adapter.gateway.sc.callback.GatewayCallbackManager;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.server.ServerResponse;

import javax.annotation.PostConstruct;
import java.util.HashMap;
import java.util.Map;

@Configuration
public class GatewayConfig {
    /**
     * 自定义限流处理器
     */
    @PostConstruct
    public void initBlockHandlers() {
        BlockRequestHandler blockHandler = (serverWebExchange, throwable) -> {
            Map map = new HashMap();
            map.put("code",200);
            map.put("message","请求失败,稍后重试!");
            return ServerResponse.status(HttpStatus.OK)
                    .contentType(MediaType.APPLICATION_JSON_UTF8)
                    .body(BodyInserters.fromObject(map));
        };
        GatewayCallbackManager.setBlockHandler(blockHandler);
    }
}

总结

文章介绍了Spring Cloud Gateway整合Sentinel对网关层进行限流,以及关于限流的一些思考。

你可能感兴趣的:(服务器相关,微服务,spring,boot,java,spring)