【Spring Boot 与 Spring Cloud 深度 Mape 之七】服务容错与流量防护:Sentinel 全方位实战

发布于:2025-03-31 ⋅ 阅读:(18) ⋅ 点赞:(0)

【Spring Boot 与 Spring Cloud 深度 Mape 之七】服务容错与流量防护:Sentinel 全方位实战

#Sentinel #服务容错 #熔断 #降级 #限流 #SpringCloudAlibaba #微服务 #SpringBoot #Java

系列衔接:在 [【深度 Mape 之六】]中,我们成功利用 Nacos Config 实现了配置的集中管理与动态刷新,让微服务架构的运维更加便捷。然而,分布式系统天然存在不确定性,网络延迟、服务宕机、流量洪峰等问题都可能导致服务调用失败,甚至引发连锁反应(雪崩效应),最终拖垮整个系统。本文作为系列的第七篇,将聚焦于提升微服务的韧性 (Resilience),探讨服务容错的核心机制,并重点实战如何使用阿里巴巴强大的流量控制、熔断降级组件——Sentinel,来为我们的服务添加“保险丝”,保护系统免受冲击。

摘要:在微服务架构中,“高可用”并非易事。单个服务的故障或不稳定可能迅速蔓延,导致整个系统瘫痪。为了防止这种情况,我们需要引入服务容错机制,如流量控制(限流)、熔断降级等。Sentinel 作为 Spring Cloud Alibaba 生态中的核心组件,提供了丰富且强大的流量防护能力,并配备了直观的控制台。本文将深入讲解服务容错的必要性,介绍 Sentinel 的核心概念与优势,并通过实战演示如何将其集成到 Spring Boot 应用中,如何使用 Sentinel Dashboard 配置流控规则和熔断降级规则,以及如何结合 @SentinelResource 和 OpenFeign 实现精细化的资源保护与 fallback 处理。


本文目标

  • 理解服务雪崩效应以及引入服务容错机制(限流、熔断、降级)的重要性。
  • 了解 Sentinel 作为流量控制和熔断降级解决方案的核心概念(Resource, Rule)和优势。
  • 掌握 Sentinel Dashboard 的部署和基本使用。
  • 熟练将 Sentinel 集成到 Spring Boot 应用中,并连接到 Dashboard。
  • 学会使用 @SentinelResource 注解定义受保护的资源,并配置 blockHandlerfallback
  • 掌握在 Sentinel Dashboard 上配置流控规则(QPS/线程数)和熔断降级规则(慢调用/异常比例/异常数)。
  • 了解 Sentinel 如何与 OpenFeign 无缝集成,并为 Feign 调用提供保护。
  • 初步了解 Sentinel 规则持久化的概念。

一、 分布式之殇:雪崩效应与容错的必要性

想象一个电商系统中的调用链:用户请求 -> 网关 -> 订单服务 -> 库存服务 & 支付服务。

如果此时支付服务因为某种原因(如数据库慢查询、网络抖动、自身 Bug)响应变得极其缓慢或频繁出错:

  1. 请求堆积:调用支付服务的订单服务线程会被长时间阻塞,等待响应。
  2. 资源耗尽:订单服务的线程池资源(或其他资源,如连接池)很快被耗尽,无法处理新的请求,也无法调用库存服务。
  3. 故障蔓延:网关调用订单服务也会超时或失败,最终导致用户请求失败。
  4. 系统瘫痪:一个服务的局部故障,像雪崩一样迅速蔓延,导致整个调用链甚至整个系统不可用。这就是服务雪崩效应

为了防止这种情况,我们需要引入服务容错机制

  • 流量控制 (限流, Rate Limiting):当某个服务的调用量或并发量超过其处理能力时,主动拒绝超出部分的请求,防止服务被压垮。保证核心服务的稳定。
  • 熔断 (Circuit Breaking):当某个依赖服务持续出错或响应过慢达到阈值时,暂时切断对其的调用("熔断"打开),后续请求直接快速失败或执行降级逻辑,避免资源被无效等待消耗。一段时间后,熔断器会尝试进入半开状态,允许少量请求通过,如果成功则关闭熔断,恢复调用;如果仍然失败,则继续保持打开状态。
  • 降级 (Degradation):当服务熔断或触发限流时,不直接报错,而是执行一个预定义的、简化的备用逻辑(Fallback),提供一种“有损服务”,保证核心功能的基本可用性或给出友好提示。例如,商品推荐服务不可用时,可以降级为返回热门商品列表或空列表。
  • 舱壁隔离 (Bulkhead):模拟船舱的隔离设计,将系统资源(如线程池、信号量)进行隔离划分。例如,为调用不同依赖服务的请求分配独立的线程池,防止一个依赖的故障耗尽所有资源而影响其他调用。

这些机制共同构成了微服务架构的“安全网”。

二、 Sentinel:不止于熔断的流量防护利器

Sentinel 是阿里巴巴开源的,面向分布式服务架构的轻量级流量控制、熔断降级库。它以流量为切入点,从流量控制、熔断降级、系统负载保护等多个维度保护服务的稳定性。

为何选择 Sentinel (相较于 Hystrix/Resilience4j)?

  • 功能更丰富:除了熔断降级,提供了强大的流量控制能力(基于 QPS、线程数、关联资源、调用链路),以及系统自适应保护(根据系统负载动态调整)。
  • 易用的控制台 (Dashboard):提供实时监控、规则配置与管理的可视化界面,非常方便。
  • 生态整合:与 Spring Cloud Alibaba 深度集成,对 Spring Cloud、Dubbo、gRPC、Zuul、Spring Cloud Gateway 等框架有良好支持。
  • 扩展性好:提供了 SPI 接口,方便自定义数据源(用于规则持久化)、规则管理器、处理器插槽等。
  • 性能优异且轻量:核心库无额外依赖,对应用性能影响小。
  • 社区活跃:由阿里主导,持续迭代更新。

Sentinel 核心概念:

  • 资源 (Resource):是 Sentinel 要保护的对象,可以是任何东西,如一个方法、一段代码、一个服务接口、甚至是一个 URL。在 Spring Cloud 应用中,通常是 Controller 的端点、@SentinelResource 标记的方法、或 Feign 客户端的方法。资源用一个唯一的资源名 (Resource Name) 来标识。
  • 规则 (Rule):定义了如何保护资源。Sentinel 支持多种规则:
    • 流控规则 (Flow Rule):定义资源的访问流量控制策略(QPS 或并发线程数限制)。
    • 熔断降级规则 (Degrade Rule):定义何时触发熔断以及熔断策略(慢调用比例、异常比例、异常数)。
    • 系统保护规则 (System Rule):从整个应用的维度进行保护(如限制总 QPS、总线程数、系统平均负载、入口 QPS)。
    • 访问控制规则 (Authority Rule):基于请求来源(调用方)进行黑白名单控制。
    • 热点参数流控规则 (Param Flow Rule):对包含特定参数值的请求进行精细化限流,常用于防止“热点数据”刷爆。
  • 上下文 (Context):用于管理资源调用的入口和出口,以及存储调用链路信息。

三、 Sentinel Dashboard 部署与启动

Sentinel 提供了一个开箱即用的 Dashboard,用于监控和管理规则。

  1. 下载 Dashboard JAR 包:
    访问 Sentinel 的 GitHub Release 页面:https://github.com/alibaba/Sentinel/releases
    下载最新稳定版的 sentinel-dashboard-x.x.x.jar

  2. 启动 Dashboard:
    在命令行中运行 JAR 包:

    java -Dserver.port=8899 -Dcsp.sentinel.dashboard.server=localhost:8899 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard-x.x.x.jar
    
    • -Dserver.port=8899: 指定 Dashboard 运行的端口(可以自定义)。
    • -Dcsp.sentinel.dashboard.server: 指定 Dashboard 自身的地址,用于内部通信。
    • -Dproject.name: 指定 Dashboard 应用的名称。
  3. 访问 Dashboard:
    打开浏览器,访问 http://localhost:8899 (或你指定的端口)。
    默认用户名和密码都是 sentinel

登录后,你会看到一个简洁的界面,但此时 “应用列表” 应该是空的,因为还没有应用接入。

四、 应用接入 Sentinel:连接 Dashboard

我们将 Sentinel 集成到之前的 nacos-provider-demo 项目中。

1. 添加 Sentinel 依赖

修改 nacos-provider-demopom.xml,添加 spring-cloud-starter-alibaba-sentinel 依赖:

<dependencies>
    <!-- ... 保留 web, nacos-discovery, nacos-config, actuator 依赖 ... -->

    <!-- Sentinel Starter -->
    <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
    </dependency>
</dependencies>

(确保 BOM 配置正确)

2. 配置连接 Dashboard

修改 nacos-provider-demobootstrap.yml (或 application.yml),添加 Sentinel 相关配置:

spring:
  # ... application, nacos config/discovery 配置 ...
  cloud:
    sentinel:
      transport:
        # 指定 Sentinel Dashboard 的地址
        dashboard: localhost:8899
        # 指定 Sentinel 客户端与 Dashboard 通信的端口 (客户端会启动一个 HTTP Server)
        # 如果端口被占用,会自动尝试递增寻找可用端口
        port: 8719 # 默认 8719,可自定义
      # Eager Initialization (可选): 是否立即连接 Dashboard,默认为 false (懒加载)
      # eager: true

# Actuator 配置,Sentinel 会利用 /actuator/sentinel 端点
management:
  endpoints:
    web:
      exposure:
        include: '*' # 建议暴露所有或至少包含 'sentinel', 'health'
  • spring.cloud.sentinel.transport.dashboard: 告诉客户端 Dashboard 在哪里。
  • spring.cloud.sentinel.transport.port: 客户端会启动一个 HTTP Server 在这个端口上,用于接收 Dashboard 推送的规则或进行心跳通信。

3. 启动应用并触发连接

  • 确保 Nacos Server 和 Sentinel Dashboard (localhost:8899) 正在运行。
  • 启动 nacos-provider-demo 应用。

重要:Sentinel 客户端默认是懒加载 (Lazy Initialization) 的。这意味着应用启动后,它并不会立即连接 Dashboard。你需要至少访问一次该应用受 Sentinel 保护的资源(例如,访问一下 Controller 的接口),客户端才会初始化并尝试连接 Dashboard。

访问 http://localhost:8081/provider/echo/TriggerSentinel

然后刷新 Sentinel Dashboard (http://localhost:8899)。你应该能在左侧的 “应用列表” 中看到 nacos-provider-service (或你在 spring.application.name 中定义的应用名)。

五、 定义资源与 @SentinelResource

Sentinel 通过资源名 (Resource Name) 来识别和保护资源。默认情况下:

  • Spring MVC 的 Controller 端点会自动注册为资源,资源名是 HTTP Method:Full Path(例如 GET:/provider/echo/{message})。
  • 后续会讲到,开启 Feign 集成后,Feign 接口方法也会自动注册为资源。

但有时我们需要更细粒度地保护某个方法或代码块,或者自定义资源名以及处理逻辑。这时可以使用 @SentinelResource 注解。

修改 ProviderController

package com.example.nacosproviderdemo;

import com.alibaba.csp.sentinel.annotation.SentinelResource; // !! 导入注解 !!
import com.alibaba.csp.sentinel.slots.block.BlockException; // !! 导入 BlockException !!
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.HashMap;
import java.util.Map;

@RestController
@RefreshScope
public class ProviderController {

    // ... serverPort, messagePrefix ...

    // 使用 @SentinelResource 保护方法,并自定义资源名
    // blockHandler: 指定处理 BlockException (限流、熔断、系统保护等) 的方法
    // fallback: 指定处理业务异常 (非 BlockException) 的方法
    @GetMapping("/provider/echo/{message}")
    @SentinelResource(value = "providerEchoResource", // 自定义资源名
                      blockHandler = "handleBlock",   // 指定 BlockException 处理器
                      fallback = "handleFallback")   // 指定业务异常处理器
    public Map<String, String> echo(@PathVariable String message) {
        // 模拟业务异常
        if ("error".equalsIgnoreCase(message)) {
            throw new IllegalArgumentException("Invalid message: " + message);
        }
        Map<String, String> response = new HashMap<>();
        response.put("message", messagePrefix + " Received: " + message);
        response.put("fromPort", serverPort);
        return response;
    }

    // BlockException 处理方法 (限流、熔断等触发时调用)
    // !! 注意:方法必须是 public,返回值类型和参数列表要与原方法一致,
    // !!        可以额外添加一个 BlockException 参数
    public Map<String, String> handleBlock(@PathVariable String message, BlockException exception) {
        Map<String, String> response = new HashMap<>();
        response.put("message", "Request Blocked for message: " + message);
        response.put("blockReason", exception.getClass().getSimpleName());
        response.put("fromPort", serverPort);
        System.err.println("Blocked by Sentinel: " + exception.getMessage());
        return response;
    }

    // Fallback 方法 (处理业务异常时调用)
    // !! 注意:方法必须是 public,返回值类型和参数列表要与原方法一致,
    // !!        可以额外添加一个 Throwable 参数
    public Map<String, String> handleFallback(@PathVariable String message, Throwable throwable) {
        Map<String, String> response = new HashMap<>();
        response.put("message", "Fallback for message: " + message);
        response.put("error", throwable.getMessage());
        response.put("fromPort", serverPort);
        System.err.println("Fallback triggered: " + throwable.getMessage());
        return response;
    }

    // 另一个接口,用于测试默认资源名
    @GetMapping("/provider/hello")
    public String hello(@RequestParam(value = "name", defaultValue="Sentinel") String name) {
        return "Hello, " + name + " from port " + serverPort;
    }
}

注解解释:

  • @SentinelResource("providerEchoResource"): 将 echo 方法标记为一个 Sentinel 资源,并指定资源名为 providerEchoResource。如果不指定 value,默认资源名是完整方法签名。
  • blockHandler = "handleBlock": 当 providerEchoResource 这个资源因为 Sentinel 规则(流控、熔断、系统保护等)被阻止 (Block) 时,会调用当前类中名为 handleBlock 的方法来处理。
  • fallback = "handleFallback": 当 echo 方法内部抛出异常 (除了 BlockException 之外的异常) 时,会调用当前类中名为 handleFallback 的方法。

blockHandlerfallback 方法签名要求:

  1. 必须是 public
  2. 返回值类型必须与原方法 (echo) 兼容。
  3. 参数列表必须与原方法兼容,可以在最后额外添加一个 BlockException (对于 blockHandler) 或 Throwable (对于 fallback) 参数。

注意blockHandlerfallback 可以指定在其他类中(需要指定 blockHandlerClass / fallbackClass 属性,且方法必须是 static)。

重新启动 nacos-provider-demo 并访问 http://localhost:8081/provider/echo/TriggerSentinel,然后在 Sentinel Dashboard 的 “簇点链路” 菜单下应该能看到我们自定义的资源名 providerEchoResource 以及默认的资源名 GET:/provider/hello

六、 实战:配置流控规则 (QPS 限流)

现在我们来限制 /provider/echo/{message} 接口的访问速率。

  1. 找到资源:在 Sentinel Dashboard 左侧菜单选择 “簇点链路”,找到 providerEchoResource (或 GET:/provider/echo/{message} 如果你没用 @SentinelResource)。
  2. 添加流控规则:点击该资源右侧的 “流控” 按钮。
    • 针对来源 (Applicaiton):保持 default (表示不区分调用来源)。
    • 阈值类型 (Threshold Type):选择 QPS
    • 单机阈值 (Threshold):设置为 1 (表示每秒只允许通过 1 个请求)。
    • 流控模式 (Strategy):保持 直接 (Direct) (直接根据 QPS 阈值限流)。
    • 流控效果 (Control Behavior):保持 快速失败 (Fail Fast) (超过阈值直接拒绝)。
    • 点击 “新增”。
  3. 测试限流
    • 快速、连续地在浏览器中访问 http://localhost:8081/provider/echo/TestFlowControl 多次。
    • 你会发现,第一次请求通常能成功返回正常结果。
    • 随后的快速请求会返回我们定义的 handleBlock 方法的结果:
      {
        "message": "Request Blocked for message: TestFlowControl",
        "blockReason": "FlowException", // 被流控规则阻止
        "fromPort": "8081"
      }
      
    • 查看 nacos-provider-demo 的控制台,会打印 “Blocked by Sentinel: …” 的错误日志。
    • 在 Sentinel Dashboard 的 “实时监控” 菜单,可以看到 providerEchoResource 的通过 QPS 被限制在 1 左右,并且有拒绝 (Block) QPS。

七、 实战:配置熔断降级规则 (异常比例)

接下来,我们配置当 echo 方法异常比例过高时触发熔断。

  1. 找到资源:同样在 “簇点链路” 找到 providerEchoResource
  2. 添加降级规则:点击该资源右侧的 “降级” 按钮。
    • 阈值类型 (Strategy):选择 异常比例 (Error Ratio)
    • 异常比例阈值 (Threshold):设置为 0.4 (表示当最近时间窗口内请求的异常比例超过 40% 时触发熔断)。
    • 熔断时长 (Circuit Breaker Recovery Timeout):设置为 10 秒 (熔断状态持续 10 秒后进入半开状态)。
    • 最小请求数 (Minimum Request Amount):设置为 5 (表示只有当时间窗口内请求总数达到 5 个时,才开始计算异常比例并判断是否熔断)。
    • 统计时长 (Statistic Time Window):保持默认 1000 毫秒 (在 1 秒的时间窗口内统计)。
    • 点击 “新增”。
  3. 测试熔断
    • 模拟异常:连续访问接口,其中一部分传入 “error” 来触发业务异常:
      • http://localhost:8081/provider/echo/ok1 (正常)
      • http://localhost:8081/provider/echo/error (触发异常,调用 fallback) -> 返回 {"message": "Fallback for message: error", ...}
      • http://localhost:8081/provider/echo/error (触发异常,调用 fallback)
      • http://localhost:8081/provider/echo/ok2 (正常)
      • http://localhost:8081/provider/echo/error (触发异常,调用 fallback)
        此时在最近 5 次请求中,异常比例达到了 3/5 = 60%,超过了 40% 的阈值,且请求数 >= 5,熔断器打开!
    • 测试熔断状态:在熔断的 10 秒内,立即访问正常的 URL,例如 http://localhost:8081/provider/echo/TryAfterFuse
    • 你会发现,即使这次请求本身不会抛异常,它也会被熔断,并调用 fallback 方法(注意:降级规则触发熔断后,Sentinel 默认也会调用 fallback,如果 fallback 不存在则抛出 DegradeException,可以配置 blockHandler 处理 DegradeException)。返回结果类似:
      {
        "message": "Fallback for message: TryAfterFuse",
        "error": "com.alibaba.csp.sentinel.slots.block.degrade.DegradeException", // 被熔断降级阻止
        "fromPort": "8081"
      }
      
    • 测试恢复:等待超过 10 秒的熔断时长后,再次访问 http://localhost:8081/provider/echo/ok3。请求应该能成功恢复,返回正常结果。熔断器关闭。

八、 Sentinel 与 OpenFeign 的集成

Sentinel 可以非常方便地为 OpenFeign 接口调用提供保护。

  1. 在消费者端启用 Feign 集成
    修改 nacos-consumer-demo (调用方) 的 application.yml,添加配置:

    feign:
      sentinel:
        # 开启 Feign 对 Sentinel 的支持
        enabled: true
    
  2. 为 Feign 接口定义 Fallback
    当对 nacos-provider-service 的调用被 Sentinel (流控或熔断) 阻止时,我们需要一个 Fallback 机制。可以创建一个实现了 Feign 接口的类作为 Fallback:

    package com.example.nacosconsumerdemo.feign;
    
    import org.springframework.stereotype.Component;
    import java.util.HashMap;
    import java.util.Map;
    
    /**
     * ProviderServiceClient 的 Fallback 实现类
     * 需要实现 Feign 接口,并注册为 Spring Bean
     */
    @Component
    public class ProviderServiceFallback implements ProviderServiceClient {
    
        @Override
        public Map<String, String> echo(String message) {
            // 这里是降级逻辑
            Map<String, String> fallbackResult = new HashMap<>();
            fallbackResult.put("message", "Fallback: Provider service unavailable for message: " + message);
            fallbackResult.put("fromPort", "N/A (Fallback)");
            System.err.println("Executing ProviderServiceFallback for echo: " + message);
            return fallbackResult;
        }
    }
    

    然后修改 ProviderServiceClient 接口定义,通过 @FeignClientfallback 属性指定 Fallback 类:

    package com.example.nacosconsumerdemo.feign;
    
    import org.springframework.cloud.openfeign.FeignClient;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.PathVariable;
    import java.util.Map;
    
    // !! 添加 fallback 属性,指向 Fallback 实现类 !!
    @FeignClient(value = "nacos-provider-service", path = "/provider", fallback = ProviderServiceFallback.class)
    public interface ProviderServiceClient {
    
        @GetMapping("/echo/{message}")
        Map<String, String> echo(@PathVariable("message") String message);
    }
    

    注意:如果想区分 BlockException 和其他业务异常,可以使用 fallbackFactory 属性,它允许你访问底层的 Throwable

  3. 在 Dashboard 配置规则

    • 启动 nacos-consumer-demo
    • 访问消费者的接口 http://localhost:8082/consumer/call/echo/TestFeignSentinel 来触发 Feign 调用。
    • 刷新 Sentinel Dashboard,你应该能在应用列表看到 nacos-consumer-service
    • 在 “簇点链路” 下找到 Feign 接口对应的资源名,格式通常是 HttpMethod:http://ServiceName/Path,例如 GET:http://nacos-provider-service/provider/echo/{message}
    • 现在你可以为这个 Feign 调用资源配置流控或降级规则了,就像之前为 Provider 配置一样。
  4. 测试

    • 例如,为 GET:http://nacos-provider-service/provider/echo/{message} 配置 QPS=1 的流控规则。
    • 快速访问消费者的接口 http://localhost:8082/consumer/call/echo/TestFeignFlow 多次。
    • 你会看到成功的请求返回 Provider 的正常响应,而被限流的请求会返回 ProviderServiceFallback 中定义的降级结果:
      {
        "message": "Fallback: Provider service unavailable for message: TestFeignFlow",
        "fromPort": "N/A (Fallback)"
      }
      
    • 查看 nacos-consumer-demo 的控制台,会打印 “Executing ProviderServiceFallback…” 的日志。

九、 规则持久化简介

默认情况下,我们在 Sentinel Dashboard 上配置的规则仅存储在内存中,一旦 Dashboard 或应用重启,规则就会丢失。

为了解决这个问题,需要将规则进行持久化。Sentinel 支持多种数据源来实现规则持久化,常见的方式有:

  • 推模式 (Push):Dashboard 将规则推送到配置中心(如 Nacos, Apollo, Zookeeper),Sentinel 客户端监听配置中心获取规则。这是推荐的方式。
  • 拉模式 (Pull):Sentinel 客户端定期从配置中心或其他存储(如文件、数据库)拉取规则。

配置规则持久化相对复杂,通常需要引入额外的依赖(如 sentinel-datasource-nacos)并进行相应配置,具体步骤请参考 Sentinel 官方文档或 Spring Cloud Alibaba 文档关于 Sentinel 持久化的部分。

十、 总结与展望

本文我们深入学习了服务容错的重要性,并实战演练了如何使用 Sentinel 为微服务提供强大的流量防护能力:

  1. 理解了 Sentinel 的核心概念、规则类型及其优势。
  2. 成功部署并使用了 Sentinel Dashboard。
  3. 将 Sentinel 集成到 Spring Boot 应用,并通过 @SentinelResource 定义资源,配置了 blockHandlerfallback
  4. 在 Dashboard 上为资源配置了流控规则和熔断降级规则,并验证了其效果。
  5. 掌握了 Sentinel 与 OpenFeign 的集成,为 Feign 调用添加了 fallback 保护。
  6. 了解了规则持久化的必要性。

通过 Sentinel,我们的微服务系统在面对流量冲击和依赖故障时将更加健壮。目前我们主要关注的是服务间的同步调用(HTTP REST),但在很多场景下,异步通信和事件驱动能带来更好的解耦和削峰填谷效果。

在下一篇文章【深度 Mape 之八】中,我们将探讨微服务间的异步通信,学习如何使用 Spring Cloud Stream 结合消息队列(如 RabbitMQ 或 Kafka)构建消息驱动的微服务,敬请期待!


你在实践中是如何选择限流或熔断策略的?Sentinel 的哪个特性你认为最有用?欢迎在评论区分享你的经验和看法!