Sentinel 服务保护
一、Sentinel 安装与集成
Sentinel是阿里巴巴开源的一款服务保护框架,目前已经加入SpringCloudAlibaba中。官方网站:Sentinel中国官网
1.1 Sentinel 安装
-
下载 Sentinel 控制台 JAR 包,
-
通过命令启动重命名为
sentinel-dashboard.jar的jar包:-
启动命令示例:
bashjava -Dserver.port=8090 -Dcsp.sentinel.dashboard.server=localhost:8090 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard.jar -
其它启动时可配置参数可参考官方文档:
-
-
sentinel控制台的当前访问地址:http://localhost:8090。
- 输入账号和密码,默认都是:sentinel
1.2 项目集成配置
引入依赖
xml
<!--sentinel-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
服务配置
开启feign对sentinel的支持,配置Sentinel服务信息,开启请求方式前缀:
yaml
feign:
okhttp:
enabled: true # 开启OKHttp连接池支持
sentinel:
enabled: true # 开启feign对sentinel的支持
spring:
cloud:
sentinel:
transport:
dashboard: localhost:8090
http-method-specify: true # 开启请求方式前缀
二、服务保护方案配置
2.1 请求限流 (Flow Control)
作用
- 流量平滑:控制接口访问的并发流量,使请求曲线平稳
- 故障预防:避免流量激增导致系统故障
配置方式
服务中配置:
java
// 通过注解配置
@SentinelResource(value = "resourceName", blockHandler = "blockHandlerMethod")
public String yourMethod() {
// 业务逻辑
}
// 限流处理方
public String blockHandlerMethod(BlockException ex) {
return "请求过于频繁,请稍后重试";
}
控制台配置:在流控规则中设置QPS或线程数阈值
2.2 线程隔离 (Thread Isolation)
作用
- 资源隔离:限定接口可用资源范围,防止单服务影响整体系统
- 故障隔离:避免服务故障扩散到整个系统
配置实现
服务中配置:
java
@SentinelResource(
value = "threadIsolationDemo",
fallback = "fallbackMethod",
blockHandler = "blockHandlerMethod"
)
Sentinel控制台配置:
- 设置线程数限制
- 配置超时时间
- 定义降级策略
2.3 服务熔断 (Circuit Breaker)
作用
- 异常熔断:当服务提供方异常比例过高时,自动拒绝调用
- 降级保护:执行预设的降级逻辑,避免异常调用影响系统
FallbackFactory 降级实现方案
FallbackFactory,可以对远程调用的异常做处理,我们一般选择这种方式。
思路流程如下:
- 自定义类实现FallBackFactory并编写fallback逻辑
- 注册自定义的FeignClientFallBackFactory为Bean
- 在FeignClient接口中配置fallbackFactory属性
自定义降级工厂处理类
在api模块中给ItemClient定义降级处理类,实现FallbackFactory:
java
package com.hmall.api.client.fallback;
import com.hmall.api.client.ItemClient;
import com.hmall.api.dto.ItemDTO;
import com.hmall.api.dto.OrderDetailDTO;
import com.hmall.common.exception.BizIllegalException;
import com.hmall.common.utils.CollUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.openfeign.FallbackFactory;
import java.util.Collection;
import java.util.List;
@Slf4j
public class ItemClientFallback implements FallbackFactory<ItemClient> {
@Override
public ItemClient create(Throwable cause) {
return new ItemClient() {
@Override
public List<ItemDTO> queryItemByIds(Collection<Long> ids) {
log.error("远程调用ItemClient#queryItemByIds方法出现异常,参数:{}", ids, cause);
// 查询购物车允许失败,查询失败,返回空集合
return CollUtils.emptyList();
}
@Override
public void deductStock(List<OrderDetailDTO> items) {
// 库存扣减业务需要触发事务回滚,查询失败,抛出异常
throw new BizIllegalException(cause);
}
};
}
}
注册自定义的FeignClientFallBackFactory为Bean
在api模块中的com.hmall.api.config.DefaultFeignConfig类中将ItemClientFallback注册为一个Bean:
java
package com.hmall.api.config;
import com.hmall.api.client.fallback.ItemClientFallBackFactory;
import com.hmall.common.utils.UserContext;
import feign.Logger;
import feign.RequestInterceptor;
import feign.RequestTemplate;
import org.springframework.context.annotation.Bean;
public class DefaultFeginConfig {
@Bean
public Logger.Level feignLogLevel(){
return Logger.Level.FULL;
}
@Bean
public RequestInterceptor userInfoRequestInterceptor(){
return new RequestInterceptor() {
@Override
public void apply(RequestTemplate requestTemplate) {
// 获取用户信息
Long userId = UserContext.getUser();
if (userId == null){
return;
}
// 将用户信息传递给下一个微服务
requestTemplate.header("user-info", userId.toString());
}
};
}
@Bean
public ItemClientFallBackFactory itemClientFallBackFactory(){
return new ItemClientFallBackFactory();
}
}
在FeignClient接口中配置fallbackFactory属性
在api模块中的ItemClient接口中使用ItemClientFallbackFactory:
java
package com.hmall.api.client;
import com.hmall.api.client.fallback.ItemClientFallBackFactory;
import com.hmall.api.config.DefaultFeginConfig;
import com.hmall.api.dto.ItemDTO;
import com.hmall.api.dto.OrderDetailDTO;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
import java.util.Collection;
import java.util.List;
/**
* @author Peter Pang
*/
@FeignClient(value = "item-service",
configuration = DefaultFeginConfig.class,
fallbackFactory = ItemClientFallBackFactory.class)
public interface ItemClient {
@GetMapping("/items")
List<ItemDTO> queryItemByIds(@RequestParam("ids")Collection<Long> ids);
@PutMapping("/items/stock/deduct")
void deductStock(@RequestBody Collection<OrderDetailDTO> items);
}
断路器状态机工作原理
| 状态 | 描述 | 行为 |
|---|---|---|
| Closed | 关闭状态 | - 放行所有请求 - 统计异常比例和慢调用比例 - 超过阈值时切换到Open状态 |
| Open | 打开状态 | - 服务调用被熔断 - 请求快速失败,直接执行降级逻辑 - 持续一段时间后进入Half-Open状态 |
| Half-Open | 半开状态 | - 放行一次试探请求 - 成功:切换到Closed状态 - 失败:切换回Open状态 |
三、核心配置参数
3.1 限流参数
- QPS:每秒请求数限制
- 线程数:并发线程数限制
- 流控模式:直接、关联、链路
- 流控效果:快速失败、Warm Up、排队等待
3.2 熔断参数
- 慢调用比例:响应时间超过阈值的请求比例
- 异常比例:请求异常的比例阈值
- 异常数:时间窗口内的异常数量
- 最小请求数:触发熔断的最小请求数
- 统计窗口时间:熔断统计的时间范围
四、最佳实践建议
- 合理设置阈值:根据系统实际承载能力配置限流参数
- 分级降级:设计多级降级策略,保证核心功能可用
- 监控告警:配置Sentinel监控告警,及时发现问题
- 测试验证:定期进行压力测试,验证保护策略有效性
- 日志记录:完善降级日志,便于问题排查和分析
通过以上配置,Sentinel能够有效保护微服务系统,提高系统的稳定性和容错能力。