【Spring Cloud Alibaba 温故而知新】(十四)基于 SpringCloud Alibaba Sentinel 实现网关动态限流

目录

17-1 SpringCloud Alibaba Sentinel 概览及控制台搭建

  • Sentinel 的概念
    • Sentinel 是面向分布式服务架构的流量控制组件,主要以流量为切入点,从流量控制、熔断降级、系统自适应保护等多个维度来帮助您保障微服务的稳定性
    • Sentinel 的来历
      • 2012年,Sentinel诞生,主要功能为了入口流量控制
      • 2013-2017年,Sentinel 在阿里巴巴集团内部迅速发展,成为基础技术模块,覆盖了所有的核心场景
      • 2018年,Sentinel 开源,并持续演进
  • Sentinel 的基本概念
    • 资源:可以是 Java 应用程序中的任何内容,例如:由应用程序提供的服务,或由应用程序调用的其它应用提供的服务,甚至可以是一段代码
      • 方法签名
      • URL
      • 服务名
    • 规则:围绕资源的实时状态设定的规则,可以包括流量控制规则、熔断降级规则以及系统保护规则;且所有的规则可以动态实时调整
  • Sentinel 控制台
    • Sentinel 提供一个轻量级的开源控制台,它提供机器发现以及健康情况管理、监控(单机和集群),规则管理和推送的功能
    • 获取并启动 Sentinel Dashboard(控制台)
      • 下载控制台 JAR 包: https://github.com/alibaba/Sentinel/releases
      • java -Dserver.port=7777 -Dcsp.sentinel.dashboard.server=localhost:7777 -Dproject.name=edcode-sentinel-dashboard -jar sentinel-dashboard-1.8.1.jar
      • 从 Sentinel 1.6.0 起, Sentinel Dashboard 引入了基本的登录功能,默认的用户名密码都是 sentinel
  • Sentinel 控制台有哪些能力
    • 查看机器列表以及健康情况:收集 Sentinel 客户端发送的心跳包,用于判断机器是否在线
    • 监控(单机和集群聚合):通过 Sentinel 客户端暴露的监控 API,定期拉取并且聚合应用监控信息,最终可以实现秒级的实时监控
    • 规则管理和推送:统一管理推送规则

17.2.1 基于硬编码应用Sentinel的限流功能

  • SpringCloud Alibaba Sentinel 流量控制
    • 服务端需要根据系统的处理能力对流量进行控制,Sentinel作为一个调配器,可以根据需要把随机的请求调整成合适的形状

在这里插入图片描述

  • SpringCloud Alibaba Sentinel 流量控制方向
    • 资源的调用关系,例如资源的调用链路,资源和资源之间的关系
    • 运行指标,例如QPS(每一秒多少请求到达系统)、线程池、系统负载等
    • 控制的效果,例如直接限流、冷启动、排队等

在这里插入图片描述

17.2.1.1 创建项目工程 - sca-commerce-sentinel-client

Maven 依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>sca-commerce</artifactId>
        <groupId>com.edcode.commerce</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>

    <artifactId>sca-commerce-sentinel-client</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>

    <!-- 模块名及描述信息 -->
    <name>sca-commerce-sentinel-client</name>
    <description>Sentinel Client</description>

    <dependencies>
        <!-- 创建工程需要的两个依赖 -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
        </dependency>
        <!-- Sentinel 适配了 Feign, 可以实现服务间调用的保护 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
        <!-- Sentinel 使用 Nacos 存储规则 -->
        <dependency>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-datasource-nacos</artifactId>
        </dependency>
        <!-- web 工程 -->
        <dependency>
            <groupId>com.edcode.commerce</groupId>
            <artifactId>sca-commerce-mvc-config</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
    </dependencies>

    <!--
        SpringBoot的Maven插件, 能够以Maven的方式为应用提供SpringBoot的支持,可以将
        SpringBoot应用打包为可执行的jar或war文件, 然后以通常的方式运行SpringBoot应用
     -->
    <build>
        <finalName>${artifactId}</finalName>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <executions>
                    <execution>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>


</project>

配置文件 - bootstrap.yml

server:
  port: 8100
  servlet:
    context-path: /scacommerce-sentinel-client

spring:
  application:
    name: sca-commerce-sentinel-client # 应用名称也是构成 Nacos 配置管理 dataId 字段的一部分 (当 config.prefix 为空时)
  cloud:
    nacos:
      # 服务注册发现
      discovery:
        enabled: true # 如果不想使用 Nacos 进行服务注册和发现, 设置为 false 即可
        #server-addr: ${NACOS_ADDR:127.0.0.1}:8848
        server-addr: ${NACOS_ADDR_1:127.0.0.1}:8848,${NACOS_ADDR_2:127.0.0.1}:8858,${NACOS_ADDR_3:127.0.0.1}:8868 # Nacos 服务器地址
        namespace: ${NAMESPACE_ID:1adcfdd8-5763-4768-9a15-9c7157988950}
        metadata:
          management:
            context-path: ${server.servlet.context-path}/actuator
    sentinel:
      # 配置 sentinel dashboard 地址
      transport:
        dashboard: ${SENTINEL_ADDR:127.0.0.1}:${SENTINEL_WEB_PORT:7777}
        port: ${SENTINEL_PORT:8719} # 会在应用对应的机器上启动一个 Http Server, 该 Server 会与 Sentinel 控制台做交互
      # 服务启动直接建立心跳连接
      eager: true
  redis:
    database: 0
    host: ${REDIS_HOST:localhost}
    port: ${REDIS_PORT:6379}
    timeout: 5000

# 暴露端点
management:
  endpoints:
    web:
      exposure:
        include: '*'
  endpoint:
    health:
      show-details: always

启动类 - SentinelClientApplication

@EnableFeignClients
@EnableDiscoveryClient
@SpringBootApplication
public class SentinelClientApplication {

    public static void main(String[] args) {
        SpringApplication.run(SentinelClientApplication.class, args);
    }

}

17.2.1.2 流控规则硬编码

自定义通用的限流处理逻辑

@Slf4j
public class BlockHandler {

    /**
     * 需要静态方法,才能被调用
     */
    public static CommonResponse<String> handleBlockException(BlockException exception) {
        log.error("触发块处理程序: [{}], [{}]", JSON.toJSONString(exception.getRule()), exception.getRuleLimitApp());
        return new CommonResponse<>(
                -1,
                "流规则触发块异常",
                null
        );
    }

}

流控规则硬编码的 Controller

@Slf4j
@RestController
@RequestMapping("/code")
public class FlowRuleCodeController {

    /**
     * 初始化流控规则
     */
    @PostConstruct
    public void init() {
        // 流控规则集合
        List<FlowRule> flowRules = new ArrayList<>();
        // 创建流控规则
        FlowRule flowRule = new FlowRule();
        // 设置流控规则 QPS, 限流阈值类型 (QPS(每秒请求数多少), 并发线程数)
        flowRule.setGrade(RuleConstant.FLOW_GRADE_QPS);
        // 流量控制手段
        flowRule.setControlBehavior(RuleConstant.CONTROL_BEHAVIOR_DEFAULT);
        // 设置受保护的资源
        flowRule.setResource("flowRuleCode");
        // 设置受保护的资源的阈值
        flowRule.setCount(1);
        flowRules.add(flowRule);
        // 加载配置好的规则
        FlowRuleManager.loadRules(flowRules);
    }

    /**
     * 采用硬编码限流规则的 Controller 方法
     */
    @GetMapping("/flow-rule")
//    @SentinelResource(value = "flowRuleCode")
//    @SentinelResource(value = "flowRuleCode", blockHandler = "handleException")
    @SentinelResource(
            value = "flowRuleCode", blockHandler = "handleBlockException",
            blockHandlerClass = BlockHandler.class
    )
    public CommonResponse<String> flowRuleCode() {
        log.info("request flowRuleCode");
        return new CommonResponse<>(0, "", "edcode-sca-ecommerce");
    }

    /**
     * 兜底策略
     * 当限流异常抛出时, 指定调用的方法
     * @param exception
     * @return
     */
    public CommonResponse<String> handleException(BlockException exception) {
        log.error("has block exception: [{}]", JSON.toJSONString(exception.getRule()));
        return new CommonResponse<>(
                -1,
                "flow rule exception",
                exception.getClass().getCanonicalName()
        );
    }

}

HTTP 请求测试

### 硬编码的流控规则
GET 127.0.0.1:8100/scacommerce-sentinel-client/code/flow-rule
Content-Type: application/json

记得启动 Sentinel 服务

java -Dserver.port=7777 -Dcsp.sentinel.dashboard.server=192.168.3.250:7777 -Dproject.name=edcode-sentinel-dashboard -jar sentinel-dashboard-1.8.3.jar

17.4.1 基于Sentinel Dashboard配置工程流控规则

17.4.1.1 基于 Sentinel 控制台配置流控规则

@Slf4j
@RestController
@RequestMapping("/dashboard")
public class RateLimitController {

    /**
     * 在 dashboard 中 "流控规则" 中按照资源名称新增流控规则
     *
     * @return
     */
    @GetMapping("/by-resource")
    @SentinelResource(
            value = "byResource",
            blockHandler = "handleBlockException",
            blockHandlerClass = BlockHandler.class
    )
    public CommonResponse<String> byResource() {
        log.info("按资源进入速率限制控制器");
        return new CommonResponse<>(0, "", "byResource");
    }

    /**
     * 在 "簇点链路" 中给 url 添加流控规则
     *
     * @return
     */
    @GetMapping("/by-url")
    @SentinelResource(value = "byUrl")
    public CommonResponse<String> byUrl() {
        log.info("通过 url 进入速率限制控制器");
        return new CommonResponse<>(0, "", "byUrl");
    }

}

17.4.1.2 rate-limit.http

### 根据资源名称限流
GET 127.0.0.1:8100/scacommerce-sentinel-client/dashboard/by-resource
Content-Type: application/json

### 根据 URL 限流
GET 127.0.0.1:8100/scacommerce-sentinel-client/dashboard/by-url
Content-Type: application/json

Sentinel 是懒加载的, 先去请求一下这里接口, 就可以在 Sentinel Dashboard 看到了

17.4.1.3 Sentinel 控制台界面配置

【流控规则】模块进入
在这里插入图片描述
【簇点链路】模块进入

在这里插入图片描述

请求 rate-limit.http 里面的接口

17.5.1 Sentinel对服务调用的保护-RestTemplate篇

  • SpringCloud Alibaba Sentinel 对降级功能的支持
    • Sentinel 支持对 RestTemplate 服务调用进行保护,实现流控降级和异常降级

在这里插入图片描述

17.5.1.1 使用 Sentinel 保护 RestTemplate 服务间调用

bootstrap.yml 添加支持

# 开启或关闭 @SentinelRestTemplate 注解
resttemplate:
  sentinel:
    enabled: true

开启服务间的调用保护, 需要给 RestTemplate 做一些包装

@Slf4j
@Configuration
public class SentinelConfig {

    /**
     * 包装 RestTemplate
     */
    @Bean
    @SentinelRestTemplate(
            fallback = "handleFallback", fallbackClass = RestTemplateExceptionUtil.class,
            blockHandler = "handleBlock", blockHandlerClass = RestTemplateExceptionUtil.class
    )
    public RestTemplate restTemplate() {
        // 可以对其做一些业务相关的配置
        return new RestTemplate();
    }
}

RestTemplate 在限流或异常时的兜底方法

@Slf4j
public class RestTemplateExceptionUtil {

    /**
     * 限流后的处理方法
     */
    public static SentinelClientHttpResponse handleBlock(HttpRequest request,
                                                         byte[] body,
                                                         ClientHttpRequestExecution execution,
                                                         BlockException ex) {
        log.error("处理 RestTemplate 异常: [{}], [{}]",
                request.getURI().getPath(), ex.getClass().getCanonicalName());
        return new SentinelClientHttpResponse(
                JSON.toJSONString(new JwtToken("edcode-sca-block"))
        );
    }

    /**
     * 异常降级之后的处理方法
     */
    public static SentinelClientHttpResponse handleFallback(HttpRequest request,
                                                            byte[] body,
                                                            ClientHttpRequestExecution execution,
                                                            BlockException ex) {
        log.error("处理 RestTemplate 回退异常: [{}], [{}]",
                request.getURI().getPath(), ex.getClass().getCanonicalName());
        return new SentinelClientHttpResponse(
                JSON.toJSONString(new JwtToken("edcode-sca-block"))
        );
    }
}

API

@Slf4j
@RestController
@RequestMapping("/sentinel-rest-template")
@RequiredArgsConstructor
public class SentinelRestTemplateController {

    private final RestTemplate restTemplate;

    /**
     * 从授权服务中获取 JwtToken
     * 1. 流控降级:
     * 是针对于簇点链路中的 http://127.0.0.1:7000/scacommerce-authority-center/authority/token
     * 2. 容错降级: 对于服务不可用时不能生效
     * */
    @PostMapping("/get-token")
    public JwtToken getTokenFromAuthorityService(
            @RequestBody UsernameAndPassword usernameAndPassword) {

        String requestUrl = "http://127.0.0.1:7000/scacommerce-authority-center/authority/token";

        log.info("RestTemplate 请求 url 和正文: [{}], [{}]", requestUrl, JSON.toJSONString(usernameAndPassword));

        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        return restTemplate.postForObject(
                requestUrl,
                new HttpEntity<>(JSON.toJSONString(usernameAndPassword), headers),
                JwtToken.class
        );
    }

}

sentinel-rest-template.http

### 获取 Token [Note: 需要启动 AuthorityCenterApplication 服务]
POST 127.0.0.1:8100/scacommerce-sentinel-client/sentinel-rest-template/get-token
Content-Type: application/json

{
  "username": "eddie@qq.com",
  "password": "25d55ad283aa400af464c76d713c07ad"
}

需要提前启动 - 授权微服务,才能请求成功

17.6.1 通过Sentinel实现对请求的熔断降级

  • SpringCloud Alibaba Sentinel 对降级功能的支持
    • @SentinelResource 中 fallback、fallbackClass 指定异常降级类和方法
    • Sentinel 还对 Feign 实现适配,支持 Feign 的容错降级

17.6.1.1 @SentinelResource 中 fallback、fallbackClass 指定异常降级类和方法

bootstrap.yml

# 打开 Sentinel 对 Feign 的支持
feign:
  sentinel:
    enabled: true

SentinelConfig 屏蔽增强 @SentinelRestTemplate 部分

@Slf4j
@Configuration
public class SentinelConfig {

    /**
     * 包装 RestTemplate
     */
    @Bean
//    @SentinelRestTemplate(
//            fallback = "handleFallback", fallbackClass = RestTemplateExceptionUtil.class,
//            blockHandler = "handleBlock", blockHandlerClass = RestTemplateExceptionUtil.class
//    )
    public RestTemplate restTemplate() {
        // 可以对其做一些业务相关的配置
        return new RestTemplate();
    }
}

SentinelFallbackController 提供容错降级的功能

@SuppressWarnings("all")
@Slf4j
@RestController
@RequestMapping("/sentinel-fallback")
@RequiredArgsConstructor
public class SentinelFallbackController {

    /**
     * 注入没有增强的 RestTemplate
     */
    private final RestTemplate restTemplate;

    /**
     *
     * @param usernameAndPassword
     * @return
     */
    @PostMapping("/get-token")
    @SentinelResource(
            value = "getTokenFromAuthorityService",
            fallback = "getTokenFromAuthorityServiceFallback",
            fallbackClass = { FallbackHandler.class }
    )
    public JwtToken getTokenFromAuthorityService(
            @RequestBody UsernameAndPassword usernameAndPassword) {

        String requestUrl =
                "http://127.0.0.1:7000/scacommerce-authority-center/authority/token";
        log.info("RestTemplate request url and body: [{}], [{}]",
                requestUrl, JSON.toJSONString(usernameAndPassword));

        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        return restTemplate.postForObject(
                requestUrl,
                new HttpEntity<>(JSON.toJSONString(usernameAndPassword), headers),
                JwtToken.class
        );
    }

    /**
     * 让 Sentinel 忽略一些异常
     * @param code
     * @return
     */
    @GetMapping("/ignore-exception")
    @SentinelResource(
            value = "ignoreException",
            fallback = "ignoreExceptionFallback",
            fallbackClass = { FallbackHandler.class },
            exceptionsToIgnore = { NullPointerException.class }
    )
    public JwtToken ignoreException(@RequestParam Integer code) {

        if (code % 2 == 0) {
            throw new NullPointerException("you input code is: " + code);
        }

        return new JwtToken("edcode-sca");
    }

}

Sentinel 回退降级的兜底策略

@Slf4j
public class FallbackHandler {

    /**
     * getTokenFromAuthorityService 方法的 fallback
     *
     * @param usernameAndPassword
     * @return
     */
    public static JwtToken getTokenFromAuthorityServiceFallback(
            UsernameAndPassword usernameAndPassword
    ) {
        log.error("从授权服务回退获取令牌: [{}]",
                JSON.toJSONString(usernameAndPassword));
        return new JwtToken("sca-edcode-fallback");
    }

    /**
     * ignoreException 方法的 fallback
     *
     * @param code
     * @return
     */
    public static JwtToken ignoreExceptionFallback(Integer code) {
        log.error("忽略异常输入代码: [{}] 有触发异常", code);
        return new JwtToken("edcode-sca-fallback");
    }

}

sentinel-fallback.http

### 获取 token
POST 127.0.0.1:8100/scacommerce-sentinel-client/sentinel-fallback/get-token
Content-Type: application/json

{
  "username": "eddie@qq.com",
  "password": "25d55ad283aa400af464c76d713c07ad"
}

### 忽略异常
GET 127.0.0.1:8100/scacommerce-sentinel-client/sentinel-fallback/ignore-exception?code=2
Content-Type: application/json

17.8.1 Sentinel结合Nacos实现动态限流及限流规则持久化

  • SpringCloud Alibaba Sentinel 整合 Nacos
    • Sentinel Dashboard 将规则保存在内存中,重启之后就会丢失,所以,考虑使用外部持久化方案
    • 在 Nacos 中创建规则,Nacos会推送到客户端
    • Sentinel Dashboard 也会从 Nacos 去获取配置信息
  • SpringCloud Alibaba Sentinel 配置信息
    • Sentinel 存储在 Nacos 中的限流数据结构

在这里插入图片描述

17.8.1.1 Nacos 准备配置文件

在这里插入图片描述

sca-commerce-sentinel-client-sentinel

[
    {
        "resource": "byResource",
        "limitApp": "default",
        "grade": 1,
        "count": 3,
        "strategy": 0,
        "controlBehavior": 0,
        "clusterMode": false
    }
]

说明

[
  {
    "resource": "byResource", // 资源名:com.edcode.commerce.controller.RateLimitController#byResource
    "limitApp": "default", // 流控针对来源
    "grade": 1, // 0=并发线程数、1=QPS(常用)
    "count": 1, // 限流的阈值,这里是一秒钟通过一个请求
    "strategy": 0, // 0=直接、1=关联、2=链路
    "controlBehavior": 0, // 0=快速失败、1=Warm Up 2=排队等待
    "clusterMode": false // 是否集群
  }
]

17.8.1.2 Maven 依赖

<!-- Sentinel 使用 Nacos 存储规则. -->
<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-datasource-nacos</artifactId>
</dependency>

17.8.1.3 完整 Yaml

server:
  port: 8100
  servlet:
    context-path: /scacommerce-sentinel-client

spring:
  application:
    name: sca-commerce-sentinel-client # 应用名称也是构成 Nacos 配置管理 dataId 字段的一部分 (当 config.prefix 为空时)
  cloud:
    nacos:
      # 服务注册发现
      discovery:
        enabled: true # 如果不想使用 Nacos 进行服务注册和发现, 设置为 false 即可
        #server-addr: ${NACOS_ADDR:127.0.0.1}:8848
        server-addr: ${NACOS_ADDR_1:127.0.0.1}:8848,${NACOS_ADDR_2:127.0.0.1}:8858,${NACOS_ADDR_3:127.0.0.1}:8868 # Nacos 服务器地址
        namespace: ${NAMESPACE_ID:1adcfdd8-5763-4768-9a15-9c7157988950}
        metadata:
          management:
            context-path: ${server.servlet.context-path}/actuator
    sentinel:
      # 配置 sentinel dashboard 地址
      transport:
        dashboard: ${SENTINEL_ADDR:127.0.0.1}:${SENTINEL_WEB_PORT:7777}
        port: ${SENTINEL_PORT:8719} # 会在应用对应的机器上启动一个 Http Server, 该 Server 会与 Sentinel 控制台做交互
      # 服务启动直接建立心跳连接
      eager: true
      ########################## 这里开始
      datasource:
        # 名称任意, 代表数据源
        ds:
          nacos:
            # NacosDataSourceProperties.java 中定义
            server-addr: ${spring.cloud.nacos.discovery.server-addr}
            dataId: ${spring.application.name}-sentinel
            namespace: ${spring.cloud.nacos.discovery.namespace}
            groupId: DEFAULT_GROUP
            data-type: json
            # 规则类型: com.alibaba.cloud.sentinel.datasource.RuleType
            # FlowRule 就是限流规则
            rule-type: flow
       ########################## 这里结束
  redis:
    database: 0
    host: ${REDIS_HOST:localhost}
    port: ${REDIS_PORT:6379}
    timeout: 5000

# 暴露端点
management:
  endpoints:
    web:
      exposure:
        include: '*'
  endpoint:
    health:
      show-details: always

# 开启或关闭 @SentinelRestTemplate 注解
resttemplate:
  sentinel:
    enabled: true

# 打开 Sentinel 对 Feign 的支持
feign:
  sentinel:
    enabled: true

17.8.1.4 请求测试

使用 rate-limit.http

### 根据资源名称限流
GET 127.0.0.1:8100/scacommerce-sentinel-client/dashboard/by-resource
Content-Type: application/json

17.8.1.5 通过 Nacos 动态修改限流的阈值

在这里插入图片描述

17.13.1 Gateway集成Sentinel实现网关限流之Nacos篇

  • Gateway 集成 Nacos + Sentinel 实现网关动态限流

在这里插入图片描述

17.13.2 bootstrap.yml

server:
  port: 9001
  servlet:
    context-path: /edcode
    
spring:
  application:
    name: sca-commerce-gateway
  cloud:
    nacos:
      # 服务注册发现
      discovery:
        enabled: true # 如果不想使用 Nacos 进行服务注册和发现, 设置为 false 即可
        #server-addr: ${NACOS_ADDR:127.0.0.1}:8848
        server-addr: ${NACOS_ADDR_1:127.0.0.1}:8848,${NACOS_ADDR_2:127.0.0.1}:8858,${NACOS_ADDR_3:127.0.0.1}:8868 # Nacos 服务器地址
        namespace: ${NAMESPACE_ID:1adcfdd8-5763-4768-9a15-9c7157988950}
        metadata:
          management:
            context-path: ${server.servlet.context-path}/actuator
    sentinel:
      # 配置 sentinel dashboard 地址
      transport:
        dashboard: ${SENTINEL_ADDR:127.0.0.1}:${SENTINEL_WEB_PORT:7777}
        port: ${SENTINEL_PORT:8719} # 会在应用对应的机器上启动一个 Http Server, 该 Server 会与 Sentinel 控制台做交互
      # 服务启动直接建立心跳连接
      eager: true
      datasource:
        # 名称任意, 代表数据源
        ds1:
          nacos:
            # NacosDataSourceProperties.java 中定义
            server-addr: ${spring.cloud.nacos.discovery.server-addr}
            dataId: gateway-flow-rule-sentinel
            namespace: ${spring.cloud.nacos.discovery.namespace}
            groupId: DEFAULT_GROUP
            data-type: json
            # 规则类型: com.alibaba.cloud.sentinel.datasource.RuleType
            # FlowRule 就是限流规则
            rule-type: gw-flow
        ds2:
          nacos:
            server-addr: ${spring.cloud.nacos.discovery.server-addr}
            namespace: ${spring.cloud.nacos.discovery.namespace}
            data-id: gateway-flow-rule-api-sentinel
            group-id: DEFAULT_GROUP
            data-type: json
            rule-type: gw-api-group
# Sentinel 对 Spring Cloud Gateway 的专属配置项,对应 SentinelGatewayProperties 类
      scg:
        order: -2147483648 # 过滤器顺序,默认为 -2147483648 最高优先级
        fallback:
          mode: response # fallback 模式,目前有三种:response、redirect、空(可以实现对 fallback 的自定义处理逻辑)
          response-status: 429 # 响应状态码,默认为 429
          response-body: '{"code":429,"message":"你被限流鸟~"}' # 响应内容,默认为空
          content-type: application/json # 内容类型,默认为 application/json
#          redirect: https://www.baidu.com  # 对应 redirect 模式的配置fallback配置
    # 静态路由
  #    gateway:
  #      routes:
  #        - id: path_route # 路由的ID
  #          uri: 127.0.0.1:8080/user/{id} # 匹配后路由地址
  #          predicates: # 断言, 路径相匹配的进行路由
  #            - Path=/user/{id}
  kafka:
    bootstrap-servers: ${KAFKA_SERVER:127.0.0.1}:${KAFKA_PORT:9092}
    producer:
      retries: 3
    consumer:
      auto-offset-reset: latest
  zipkin:
    sender:
      type: ${ZIPKIN_KAFKA_SENDER:web} # 默认是 web
    base-url: http://${ZIPKIN_URL:localhost}:${ZIPKIN_PORT:9411}/
  main:
    allow-bean-definition-overriding: true  # 因为将来会引入很多依赖, 难免有重名的 bean
  redis:
    database: 0
    host: ${REDIS_HOST:localhost}
    port: ${REDIS_PORT:6379}
    timeout: 5000

# 暴露端点
management:
  endpoints:
    web:
      exposure:
        include: '*'
  endpoint:
    health:
      show-details: always

# 网关配置类, 是网关的数据, GatewayConfig.java 读取的配置
nacos:
  gateway:
    route:
      config:
        data-id: sca-commerce-gateway-router
        group: sca-commerce

17.13.2 配置放上 Nacos (限流、API分组)

gateway-flow-rule-api-sentinel.json

[
  {
    "apiName": "nacos-client-api",
    "predicateItems": [
      {
        "pattern": "/edcode/scacommerce-nacos-client/nacos-client/project-config"
      },
      {
        "pattern": "/edcode/scacommerce-nacos-client/**",
        "matchStrategy": 1
      }
    ]
  }
]

没有 matchStrategy字段,默认:精确

gateway-flow-rule-sentinel.json

[
  {
    "resource": "sca-commerce-nacos-client",
    "resourceMode": 0,
    "count": 3,
    "intervalSec": 60
  },
  {
    "resource": "nacos-client-api",
    "resourceMode": 1,
    "count": 1,
    "intervalSec": 60
  }
]

在这里插入图片描述

17.13.3 添加 Maven 依赖

<!-- 集成 Sentinel, 在网关层面实现限流 -->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-alibaba-sentinel-gateway</artifactId>
</dependency>
<!-- Sentinel 使用 Nacos 存储规则 -->
<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-datasource-nacos</artifactId>
</dependency>

17.13.3 nacos-client.http 请求测试

### 查询服务
GET http://127.0.0.1:9001/edcode/scacommerce-nacos-client/nacos-client/service-instance?serviceId=sca-commerce-gateway
Accept: application/json
sca-commerce-user: eyJhbGciOiJSUzI1NiJ9.eyJzY2EtY29tbWVyY2UtdXNlciI6IntcImlkXCI6MTEsXCJ1c2VybmFtZVwiOlwiZWRkaWVAcXEuY29tXCJ9IiwianRpIjoiNjg0ZWRkZmQtNWZmMC00OTJlLWI1M2ItYTlmY2MzZDQzYmU3IiwiZXhwIjoxNjQxNjU3NjAwfQ.eRCnSn9eKPyMN8O1Sky5jGizdnv96xtuo8evOHKwytIrz6aYBAyrGuAnTdDIG7EOdU0wPUom-uU52sPaLAVw0LPbfefGrbKqsuVIsNG2IOiwkwl_fqLm6IxSC8jDEFTTCNH6-01WJ2gKZ2LrRn_ZGizQ3w0Y30KL6mK2vpx31Nb6kf_fospqL1iW7VoQQWgiY9tBQ790M4fMT9IcpEzWD6-w0j4_9nWlArEotrHMb5_FCBzqRBx6v0rQQcNwa667zFfZqn2UOw25Ajz859DmTagvjxPaFVJNwF3udsIIxLGQalE8E3-lDrqAoR-29Apf5uHINHSezqEY6PCmBP8tXg
token: edcode ## HeaderTokenGatewayFilter

按上面 /edcode/scacommerce-nacos-client/** 规则,请求一次之后需要等待 60秒,才能下一次请求

从而达到按照不同的 API接口,或者 通配符来完成 API接口的限流

17.13.4 问题综合

Sentinel 控制台不显示API管理规则

场景1:使用 rule-type: flow 配置是可以显示的,但是换成 rule-type: gw-flow 就不显示了

解决办法:

网关需要设置 -Dcsp.sentinel.app.type=1
在这里插入图片描述
sentinel-dashboard 启动也需要添加 -Dcsp.sentinel.app.type=1

[eddie@zk1 opt]# java -Dcsp.sentinel.app.type=1 -Dserver.port=7777 -Dcsp.sentinel.dashboard.server=192.168.3.250:7777 -Dproject.name=edcode-sentinel-dashboard -jar /opt/sentinel-dashboard-1.8.3.jar

请求链路 - 效果图
在这里插入图片描述

API 分组管理 - 效果图
在这里插入图片描述

参考:https://blog.csdn.net/qq_43437874/article/details/119992770

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

eddie_k2

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值