一、前言

在微服务架构中,流量突增、下游服务超时、报错雪崩是线上最常见的稳定性问题。Sentinel 作为阿里开源、经过双11大促打磨的流量防护组件,相比 Hystrix 更轻量、功能更强、配置更灵活,是目前国内微服务限流、熔断、降级的主流方案。

本文带来零残缺、可直接运行、可上线的 Sentinel 完整实战案例,包含:

  • 完整 Maven 依赖
  • 全量 YAML 配置
  • 限流 + 熔断双功能代码实现
  • blockHandler / fallback 精准区分(面试高频)
  • 代码硬编码规则 + 控制台动态规则两种方式
  • OpenFeign 跨服务调用限流熔断识别实战
  • 全套线上测试场景 & 问题总结

二、核心核心概念

1. 兜底方法区别

  • blockHandler:Sentinel 框架拦截异常,只处理 限流、熔断、系统保护、黑白名单拦截 触发的 BlockException
  • fallback:捕获业务代码所有异常,包含空指针、自定义异常、接口报错等业务异常

2. 核心能力

  • 限流:QPS 限流、并发线程限流、链路限流、热点参数限流
  • 熔断:慢调用比例、异常比例、异常数三种熔断策略
  • 降级:故障自动隔离,避免服务雪崩
  • 系统防护:整机 CPU、负载、QPS 全局保护

三、环境与依赖

适配版本:SpringBoot 2.7.x + SpringCloud Alibaba 2021.0.1.0(稳定生产版本)

完整 pom.xml 依赖

xml
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.7.15</version>
    <relativePath/>
</parent>

<dependencies>
    <!-- Spring Web -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <!-- Sentinel 流量防护核心依赖 -->
    <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
        <version>2021.0.1.0</version>
    </dependency>

    <!-- Nacos 配置中心(用于规则持久化,生产必备) -->
    <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
        <version>2021.0.1.0</version>
    </dependency>

    <!-- OpenFeign 远程调用 -->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-openfeign</artifactId>
    </dependency>
</dependencies>

四、项目配置文件 application.yml

配置控制台地址、开启服务预热初始化,适配开发、生产环境

yaml
server:
  port: 8080

spring:
  application:
    name: sentinel-demo-service
  cloud:
    sentinel:
      # Sentinel 控制台地址
      transport:
        dashboard: 127.0.0.1:8085
        port: 8719
      # 关闭懒加载,项目启动直接初始化Sentinel
      eager: true
    nacos:
      config:
        server-addr: 127.0.0.1:8848

# 开启feign对sentinel的支持
feign:
  sentinel:
    enabled: true

五、启动类

java
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;

@SpringBootApplication
@EnableFeignClients
public class SentinelDemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(SentinelDemoApplication.class, args);
    }
}

六、核心业务代码(限流+熔断+双兜底完整实现)

统一资源名,区分限流熔断兜底、业务异常兜底,代码完全解耦,符合生产规范。

java
import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class OrderController {

    /**
     * Sentinel 资源名:createOrder
     * blockHandler:限流、熔断、系统保护、授权拦截兜底(Sentinel 框架异常)
     * fallback:业务代码异常兜底(代码报错、自定义异常等)
     */
    @GetMapping("/order/create/{goodsId}")
    @SentinelResource(
            value = "createOrder",
            blockHandler = "blockHandlerCreateOrder",
            fallback = "fallbackCreateOrder"
    )
    public String createOrder(@PathVariable Long goodsId) {
        // 模拟业务异常场景:商品999无库存
        if (goodsId == 999) {
            throw new RuntimeException("商品库存不足,下单失败");
        }

        // 模拟慢接口(用于测试慢调用比例熔断)
        try {
            Thread.sleep(300);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }

        return "下单成功,商品ID:" + goodsId;
    }

    /**
     * 限流、熔断兜底方法
     * 规则:参数与原方法一致,最后追加 BlockException
     */
    public String blockHandlerCreateOrder(Long goodsId, BlockException ex) {
        // 区分限流、熔断异常,返回精准提示
        if (ex instanceof com.alibaba.csp.sentinel.slots.block.flow.FlowException) {
            return "【限流兜底】当前下单人数过多,请稍后重试";
        } else if (ex instanceof com.alibaba.csp.sentinel.slots.block.degrade.DegradeException) {
            return "【熔断兜底】服务暂时繁忙,已开启熔断保护,请稍后重试";
        } else {
            return "【服务防护拦截】请求被限制:" + ex.getClass().getSimpleName();
        }
    }

    /**
     * 业务异常兜底方法
     * 捕获所有业务代码异常
     */
    public String fallbackCreateOrder(Long goodsId, Throwable throwable) {
        return "【业务异常兜底】商品" + goodsId + "下单失败:" + throwable.getMessage();
    }
}

七、全局异常处理器(生产核心:返回429/503标准状态码)

这是跨服务调用能识别限流/熔断的关键
    
1. 限流异常 FlowException → 返回 HTTP 429
   
2. 熔断异常 DegradeException → 返回 HTTP 503
上游 A 服务可通过状态码精准区分「下游限流」还是「下游熔断」

java
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeException;
import com.alibaba.csp.sentinel.slots.block.flow.FlowException;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;

@RestControllerAdvice
public class SentinelGlobalExceptionHandler {

    /**
     * 下游触发限流:429 Too Many Requests
     */
    @ExceptionHandler(FlowException.class)
    @ResponseStatus(HttpStatus.TOO_MANY_REQUESTS)
    public String handleFlowException(FlowException e) {
        return "下游服务触发限流:请求过于频繁,请稍后重试";
    }

    /**
     * 下游触发熔断:503 Service Unavailable
     */
    @ExceptionHandler(DegradeException.class)
    @ResponseStatus(HttpStatus.SERVICE_UNAVAILABLE)
    public String handleDegradeException(DegradeException e) {
        return "下游服务触发熔断:服务暂时不可用,已开启故障隔离";
    }

    /**
     * 通用Sentinel拦截异常
     */
    @ExceptionHandler(BlockException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public String handleBlockException(BlockException e) {
        return "服务流量拦截:" + e.getMessage();
    }
}

八、OpenFeign 跨服务调用(A服务调用B服务,精准识别限流/熔断)

场景说明

微服务最经典场景:A服务 OpenFeign 调用 B服务
B服务接口被 Sentinel 限流/熔断后,抛出对应异常,经过全局异常处理器返回标准 HTTP 状态码,A服务可精准捕获、区分限流/熔断/普通报错,做差异化降级策略。

1. Feign客户端定义(A服务)

java
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;

@FeignClient(name = "sentinel-demo-service")
public interface BOrderFeignClient {

    @GetMapping("/order/create/{goodsId}")
    String createOrder(@PathVariable("goodsId") Long goodsId);
}

2. A服务调用代码(核心:区分429限流 / 503熔断)

java
import feign.FeignException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;

@Slf4j
@RestController
public class AInvokeBController {

    @Resource
    private BOrderFeignClient bOrderFeignClient;

    @GetMapping("/a/call/b/{goodsId}")
    public String aCallB(@PathVariable Long goodsId) {
        try {
            // A服务远程调用B服务带Sentinel防护的接口
            return bOrderFeignClient.createOrder(goodsId);
        } catch (FeignException e) {
            // 通过HTTP状态码精准区分下游异常类型
            int status = e.status();
            if (status == 429) {
                // 下游B服务触发限流
                log.warn("【跨服务降级】B服务接口限流,goodsId:{}", goodsId);
                return "系统繁忙,当前访问人数过多,请稍后重试(限流降级)";
            } else if (status == 503) {
                // 下游B服务触发熔断
                log.error("【跨服务熔断】B服务接口熔断,服务暂时不可用,goodsId:{}", goodsId);
                return "服务暂时异常,已开启熔断保护,请稍后重试(熔断降级)";
            } else {
                // 其他业务异常
                log.error("【远程调用异常】未知错误:{}", e.getMessage());
                return "服务调用异常,请稍后重试";
            }
        }
    }
}

九、规则配置方式一:代码硬编码(快速测试)

无需控制台,项目启动自动加载限流、熔断规则,适合单元测试、快速验证场景。

java
import com.alibaba.csp.sentinel.slots.block.RuleConstant;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRule;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRuleManager;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
import org.springframework.context.annotation.Configuration;

import javax.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.List;

@Configuration
public class SentinelRuleConfig {

    // 与接口资源名保持一致
    private static final String RESOURCE = "createOrder";

    @PostConstruct
    public void initSentinelRule() {
        // 1. 限流规则:QPS单机阈值2,每秒最多2次请求
        List<FlowRule> flowRuleList = new ArrayList<>();
        FlowRule flowRule = new FlowRule();
        flowRule.setResource(RESOURCE);
        // 限流维度:QPS
        flowRule.setGrade(RuleConstant.FLOW_GRADE_QPS);
        // 阈值
        flowRule.setCount(2);
        // 流控效果:快速失败
        flowRule.setControlBehavior(RuleConstant.CONTROL_BEHAVIOR_DEFAULT);
        flowRuleList.add(flowRule);
        FlowRuleManager.loadRules(flowRuleList);

        // 2. 熔断规则:慢调用比例熔断
        List<DegradeRule> degradeRuleList = new ArrayList<>();
        DegradeRule degradeRule = new DegradeRule();
        degradeRule.setResource(RESOURCE);
        // 熔断策略:慢调用RT
        degradeRule.setGrade(RuleConstant.DEGRADE_GRADE_RT);
        // 超过250ms判定为慢调用
        degradeRule.setCount(250);
        // 慢调用比例超过50%触发熔断
        degradeRule.setSlowRatioThreshold(0.5);
        // 最小统计请求数
        degradeRule.setMinRequestAmount(5);
        // 熔断窗口期5秒,期间直接降级
        degradeRule.setTimeWindow(5);
        degradeRuleList.add(degradeRule);
        DegradeRuleManager.loadRules(degradeRuleList);
    }
}

十、规则配置方式二:Sentinel 控制台动态配置(生产推荐)

1. 启动控制台

下载 sentinel-dashboard-1.8.8.jar,执行启动命令:

shell
java -jar sentinel-dashboard-1.8.8.jar --server.port=8085

访问地址:http://127.0.0.1:8085,默认账号密码:sentinel / sentinel

2. 配置流控规则

  • 资源名:createOrder
  • 阈值类型:QPS
  • 单机阈值:2
  • 流控效果:快速失败

3. 配置熔断降级规则

  • 资源名:createOrder
  • 熔断策略:慢调用比例
  • 最大RT:250ms
  • 比例阈值:0.5
  • 最小请求数:5
  • 熔断时长:5秒

十一、完整测试场景(含跨服务调用)

1. 本地接口限流测试

快速高频访问:http://localhost:8080/order/create/1

每秒请求超过2次,触发限流,返回429提示信息。

2. 业务异常 fallback 测试

访问:http://localhost:8080/order/create/999

代码主动抛出业务异常,触发 fallback 兜底。

3. 跨服务限流识别测试(A调B)

高频访问:http://localhost:8080/a/call/b/1

B服务触发限流后返回429,A服务捕获状态码,执行限流专属降级逻辑

4. 跨服务熔断识别测试(A调B)

批量并发请求接口,触发B服务慢调用熔断,B返回503,A服务捕获后执行熔断专属降级逻辑,不再重试。

十二、生产核心规范与避坑总结

1. 方法签名硬性规则

  • blockHandler 方法:参数必须和原方法一致,末尾必须追加 BlockException
  • fallback 方法:参数同原方法,可追加 Throwable 捕获所有异常

2. 跨服务调用核心规范(重点)

  • 限流=429:服务正常、流量打满,可短时重试、排队、友好提示
  • 熔断=503:服务异常隔离,禁止重试,直接走本地兜底/缓存
  • 禁止统一返回200状态码+业务码,会导致上游无法精准区分故障类型,丢失降级策略

Feign 底层逻辑:
只要 HTTP 状态码 不是 200~299,不会把 body 正常返回,直接抛出 FeignException;
FeignException 内部会保存原始 HTTP 状态码,通过 e.status() 获取。
 

3. 生产建议

  • 禁止使用代码硬编码规则,务必使用Nacos 持久化规则,支持动态修改、集群统一生效
  • 核心接口配置限流+熔断双重防护,非核心接口可只配置限流
  • 统一 429/503 状态码规范,统一上下游降级逻辑
  • 开启 Sentinel 监控日志,线上快速定位流量、熔断异常

十三、总结

本文实现了 零缺失、可直接投产 的 Sentinel 限流熔断完整案例,覆盖本地接口防护 + OpenFeign跨服务调用、上下游异常识别、差异化降级全场景,厘清了 blockHandlerfallback、限流熔断跨服务传递的核心原理。

Sentinel 凭借轻量、高可用、功能丰富的特性,完全可以替代 Hystrix,作为微服务稳定性防护的核心组件,是中高级开发必备的技术栈。

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐