微服务架构中,服务间调用链路复杂,单一服务故障可能引发雪崩效应。接口限流控制请求速率防止服务过载,熔断降级在依赖服务不可用时快速失败避免级联故障。Sentinel是阿里巴巴开源的流量治理组件,提供限流、熔断、系统自适应保护等功能。本文讲解Sentinel在Spring Boot微服务中的集成配置、规则定义和降级策略实现。
Sentinel Spring Boot集成配置
Sentinel通过Starter方式集成到Spring Boot项目。以下是一个Spring Boot 3.x项目的Maven依赖和配置:
<!-- pom.xml -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
<version>2023.0.1.0</version>
</dependency>
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-annotation-aspectj</artifactId>
<version>1.8.8</version>
</dependency>
# application.yml
spring:
cloud:
sentinel:
transport:
dashboard: 192.168.1.100:8858
port: 8719
eager: true
datasource:
flow:
nacos:
server-addr: 192.168.1.100:8848
dataId: ${spring.application.name}-flow-rules
groupId: SENTINEL_GROUP
rule-type: flow
degrade:
nacos:
server-addr: 192.168.1.100:8848
dataId: ${spring.application.name}-degrade-rules
groupId: SENTINEL_GROUP
rule-type: degrade
规则持久化到Nacos是生产环境的必要配置。Sentinel默认将规则存储在内存中,应用重启后规则丢失。通过Nacos数据源,规则变更后自动推送到所有应用实例,实现集中式规则管理。
接口限流规则定义与注解配置
Sentinel限流通过@SentinelResource注解标注需要保护的方法或接口。结合BlockException处理器实现限流后的自定义响应:
@RestController
@RequestMapping("/api/v1/orders")
public class OrderController {
@Autowired
private OrderService orderService;
@PostMapping("/create")
@SentinelResource(
value = "createOrder",
blockHandler = "createOrderBlockHandler",
blockHandlerClass = {OrderBlockHandler.class},
fallback = "createOrderFallback",
exceptionsToIgnore = {IllegalArgumentException.class}
)
public Result<OrderDTO> createOrder(@RequestBody @Valid CreateOrderRequest request) {
OrderDTO order = orderService.createOrder(request);
return Result.success(order);
}
public Result<OrderDTO> createOrderFallback(CreateOrderRequest request, Throwable e) {
log.warn("订单创建降级触发, userId={}, reason={}", request.getUserId(), e.getMessage());
return Result.fail("系统繁忙,请稍后重试");
}
}
public class OrderBlockHandler {
public static Result<OrderDTO> createOrderBlockHandler(
CreateOrderRequest request, BlockException ex) {
if (ex instanceof FlowException) {
return Result.fail(429, "请求过于频繁,请稍后再试");
}
if (ex instanceof DegradeException) {
return Result.fail(503, "服务暂时不可用,已降级处理");
}
if (ex instanceof ParamFlowException) {
return Result.fail(429, "操作过于频繁");
}
return Result.fail("请求被限流");
}
}
blockHandler和fallback的区别需要明确:blockHandler处理Sentinel限流降级抛出的BlockException(包括流控、熔断、热点参数限流等),fallback处理业务方法抛出的其他异常。exceptionsToIgnore排除的异常类型不触发fallback,直接向上抛出。
QPS限流与并发线程数限流的区别
Sentinel支持两种限流阈值类型:QPS(每秒请求数)和并发线程数。两者的适用场景不同:
// 编程方式定义流控规则
public class FlowRuleConfig {
@PostConstruct
public void initFlowRules() {
List<FlowRule> rules = new ArrayList<>();
// 规则1:QPS限流 - 每秒最多100个请求
FlowRule qpsRule = new FlowRule("createOrder");
qpsRule.setGrade(RuleConstant.FLOW_GRADE_QPS);
qpsRule.setCount(100);
qpsRule.setLimitApp("default");
qpsRule.setControlBehavior(RuleConstant.CONTROL_BEHAVIOR_DEFAULT);
rules.add(qpsRule);
// 规则2:并发线程数限流 - 同时最多20个线程在执行
FlowRule threadRule = new FlowRule("createOrder");
threadRule.setGrade(RuleConstant.FLOW_GRADE_THREAD);
threadRule.setCount(20);
threadRule.setLimitApp("default");
rules.add(threadRule);
// 规则3:预热限流 - 冷启动后逐步放开QPS
FlowRule warmUpRule = new FlowRule("queryOrders");
warmUpRule.setGrade(RuleConstant.FLOW_GRADE_QPS);
warmUpRule.setCount(200);
warmUpRule.setControlBehavior(RuleConstant.CONTROL_BEHAVIOR_WARM_UP);
warmUpRule.setWarmUpPeriodSec(10);
rules.add(warmUpRule);
// 规则4:匀速排队 - 请求匀速通过
FlowRule queueRule = new FlowRule("processPayment");
queueRule.setGrade(RuleConstant.FLOW_GRADE_QPS);
queueRule.setCount(50);
queueRule.setControlBehavior(RuleConstant.CONTROL_BEHAVIOR_RATE_LIMITER);
queueRule.setMaxQueueingTimeMs(2000);
rules.add(queueRule);
FlowRuleManager.loadRules(rules);
}
}
QPS限流适用于保护接口不被瞬时洪峰击垮。并发线程数限流适用于慢SQL、外部HTTP调用等阻塞型操作——这些操作即使QPS不高,但单个请求耗时很长,线程池容易被耗尽。当请求处理时间不可控时,线程数限流比QPS限流更有效。
预热模式适合冷启动场景。应用刚启动时数据库连接池、JIT编译、缓存等尚未就绪,直接放开QPS上限可能导致性能下降。预热模式在设定的时长内逐步放大允许的QPS,给系统足够的预热时间。匀速排队模式将突发请求转化为匀速流,配合消息队列消费场景使用。
熔断降级规则配置与异常比例策略
Sentinel熔断策略有三种:慢调用比例、异常比例、异常数。根据业务场景选择合适的策略:
@Configuration
public class DegradeRuleConfig {
@PostConstruct
public void initDegradeRules() {
List<DegradeRule> rules = new ArrayList<>();
// 策略1:慢调用比例熔断
DegradeRule slowCallRule = new DegradeRule("callExternalApi");
slowCallRule.setGrade(CircuitBreakerStrategy.SLOW_REQUEST_RATIO.getType());
slowCallRule.setCount(500);
slowCallRule.setSlowRatioThreshold(0.5);
slowCallRule.setMinRequestAmount(10);
slowCallRule.setStatIntervalMs(10000);
slowCallRule.setTimeWindow(15);
rules.add(slowCallRule);
// 策略2:异常比例熔断
DegradeRule exceptionRatioRule = new DegradeRule("queryDatabase");
exceptionRatioRule.setGrade(CircuitBreakerStrategy.ERROR_RATIO.getType());
exceptionRatioRule.setCount(0.3);
exceptionRatioRule.setMinRequestAmount(20);
exceptionRatioRule.setStatIntervalMs(10000);
exceptionRatioRule.setTimeWindow(30);
rules.add(exceptionRatioRule);
// 策略3:异常数熔断
DegradeRule exceptionCountRule = new DegradeRule("sendNotification");
exceptionCountRule.setGrade(CircuitBreakerStrategy.ERROR_COUNT.getType());
exceptionCountRule.setCount(5);
exceptionCountRule.setMinRequestAmount(10);
exceptionCountRule.setStatIntervalMs(60000);
exceptionCountRule.setTimeWindow(60);
rules.add(exceptionCountRule);
DegradeRuleManager.loadRules(rules);
}
}
minRequestAmount是重要参数。设为0时,即使只有1-2个请求出现异常也会立即触发熔断,这在低流量场景下容易误判。设置最小请求数后,只有达到足够样本量才进行比例统计,避免偶发抖动导致误熔断。
熔断器的状态机为:CLOSED(正常)→ OPEN(熔断中,拒绝所有请求)→ HALF_OPEN(半开,放行少量探测请求)。熔断时长到期后自动进入HALF_OPEN状态,如果探测请求成功则恢复CLOSED,失败则重新进入OPEN。timeWindow控制OPEN状态的持续时间,应根据下游服务的恢复时间设置。
热点参数限流实现
某些场景下需要针对特定参数值进行限流。例如秒杀活动中,不同商品的限流阈值不同。Sentinel的热点参数限流支持方法参数级别的细粒度控制:
@GetMapping("/products/{productId}")
@SentinelResource(value = "getProduct", blockHandler = "getProductBlockHandler")
public Result<ProductDTO> getProduct(@PathVariable Long productId) {
return Result.success(productService.getById(productId));
}
@PostConstruct
public void initParamFlowRules() {
ParamFlowRule rule = new ParamFlowRule("getProduct")
.setParamIdx(0)
.setGrade(RuleConstant.FLOW_GRADE_QPS)
.setCount(100);
ParamFlowItem item = new ParamFlowItem();
item.setObject("10086");
item.setClassType(String.class.getName());
item.setCount(10);
rule.setParamFlowItemList(List.of(item));
ParamFlowRuleManager.loadRules(List.of(rule));
}
热点参数限流原理是对方法参数值建立独立的滑动窗口统计。参数值10086的商品请求统计在独立窗口中,与其他商品的QPS互不影响。秒杀场景中,热门商品的ID可以通过配置动态下发到热点规则中,实现精准的流量控制。
全局异常处理与限流响应标准化
Sentinel的BlockException需要统一捕获处理,避免直接返回500错误码。通过实现BlockExceptionHandler接口实现Web环境下的全局处理:
@Component
public class GlobalBlockExceptionHandler implements BlockExceptionHandler {
@Override
public void handle(HttpServletRequest request, HttpServletResponse response,
BlockException e) throws Exception {
response.setStatus(429);
response.setContentType("application/json;charset=UTF-8");
Result<?> result = switch (e) {
case FlowException fe -> Result.fail(429, "请求频率超限,请稍后重试");
case DegradeException de -> Result.fail(503, "服务降级中,请稍后重试");
case ParamFlowException pfe -> Result.fail(429, "操作过于频繁");
case SystemBlockException sbe -> Result.fail(503, "系统过载保护已触发");
case AuthorityException ae -> Result.fail(403, "无访问权限");
default -> Result.fail(429, "请求被限流");
};
response.getWriter().write(JsonUtils.toJson(result));
}
}
统一的429状态码和标准化JSON响应,让前端能区分限流错误和系统错误,给出不同的用户提示。配合监控告警系统,当429响应比例超过阈值时触发告警,运维人员可及时发现流量异常并调整限流规则。
原创文章,作者:小编,如若转载,请注明出处:https://www.yunthe.com/springboot-wei-fu-wu-jie-kou-xian-liu-rong-duan-shi-xian/