一、什么是Sentinel?
随着微服务的流行,服务和服务之间的稳定性变得越来越重要。Sentinel 以流量为切入点,从流量控制、熔断降级、系统负载保护等多个维度保护服务的稳定性。
Sentinel 的主要特性:
二、整合Sentinel#
Spring Cloud Alibaba整合Sentinel文档:https://github.com/alibaba/spring-cloud-alibaba/wiki/Sentinel
1、导入依赖#
<!--alibaba cloud Sentinel -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
2、下载控制台 https://github.com/alibaba/Sentinel/releases 页面 下载最新版本的控制台 jar包 版本要对应好 jar包下载到本地,放到我们服务路径,然后启动服务:
cd /Users/kaiyiwang/javaweb/guli/develop/sentinel java -jar sentinel-dashboard-1.6.3.jar --server.port=8333 访问这个服务: http://localhost:8333/#/dashboard/home
3、配置控制台地址信息#
# === Sentinel ===
# 暴露端口,别人就可以访问了
spring.cloud.sentinel.transport.dashboard=localhost:8333
三、导入信息审计模块actuator#
- actuator 审计模块,可以实时统计Springboot健康状态,包括整个请求的调用信息等,Sentinel通过统计拿到的这些信息最终做整个数据的监控功能能。
//pom.xml
<!-- 审计信息模块 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
//application.properties
# === Sentinel ===
# 暴露端口,别人就可以访问了
management.endpoints.web.exposure.include=*
Sentinel Endpoint 里暴露的信息非常有用。包括当前应用的所有规则信息、日志目录、当前实例的 IP,Sentinel Dashboard 地址,Block Page,应用与 Sentinel Dashboard 的心跳频率等等信息。
四、自定义 Sentinel流控返回数据#
- 2.1.0 cloud 版本方法
@Configuration
public class GulimallOrderSentinelConfig {
public GulimallOrderSentinelConfig() {
WebCallbackManager.setUrlBlockHandler(new UrlBlockHandler() {
@Override
public void blocked(HttpServletRequest request, HttpServletResponse response, BlockException ex) throws IOException {
R error = R.error(BizCodeEnum.TO_MANY_REQUEST.getCode(), BizCodeEnum.TO_MANY_REQUEST.getMsg());
response.setCharacterEncoding("UTF-8");
response.setContentType("application/json");
response.getWriter().write(JSON.toJSONString(error));
}
});
}
}
- 2.2.0之后版本
@Configuration
public class SeckillSentinelConfig implements BlockExceptionHandler {
@Override
public void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, BlockException e) throws Exception {
R error = R.error(BizCodeEnume.TO_MANY_REQUEST.getCode(), BizCodeEnume.TO_MANY_REQUEST.getMsg());
httpServletResponse.setCharacterEncoding("UTF-8");
httpServletResponse.setContentType("application/json");
httpServletResponse.getWriter().write(JSON.toJSONString(error));
}
}
返回 固定json
- 设置流控:
QPS设置为3,即每秒最多请求3个,如果超过会由Sentinel直接返回流量过大信息:
五、全服务引入Sentinel#
六、熔断降级#
- 使用sentinel来保护feign远程调用,熔断: 1)、调用方的熔断保护,feign.sentinel.enabled=true 2)、调用方手动指定远程服务的降级策略(在 sentinel管理后台配置),远程服务被降级处理,触发我们的熔断回调方法。 3)、超大流量的时候,必须牺牲一些远程服务,在服务的提供方(远程服务)指定降级策略。 提供方是在运行,但是不运行自己的业务逻辑,返回的是默认的降级数据(限流的数据)。
给我们每个服务都开启 feign远程调用的熔断功能:
application.properties
feign.sentinel.enabled=true
A调用B服务 但是B服务宕机了 进行熔断保护 不在调用
@Slf4j
@Component
public class FallBack implements SeckillFeignService {
@Override
public R getSkuSeckilInfo(Long skuId) {
log.info("熔断调用 getSkuSeckilInfo.");
return R.error(BizCodeEnume.TO_MANY_REQUEST.getCode(),BizCodeEnume.TO_MANY_REQUEST.getMsg());
}
}
降级
A调用B服务 A RT-1毫秒内没收到响应 时间窗口-10秒内 进行降级保护 不在调用
自定义 受保护资源
方法一 注解方式 但是要配置blockHandler 前面方法要一致, 在同一级class类中
public List<SeckillSkuRedisTo> blockHandlerM(BlockException e) {
System.out.println("getCurrentSeckillSkus 被限流了");
return null;
}
/**
* 获取到当前可以参加秒杀商品的信息
*
* @return
*/
@SentinelResource(value = "getCurrentSeckillSkusReasource",blockHandler = "blockHandlerM")
方法二
try(Entry entry = SphU.entry("getCurrentSeckillSkus")){
//保护的代码
}catch (BlockException e){
System.out.println("保护的代码 被限流了");
}
七、网关流控#
https://github.com/alibaba/Sentinel/wiki/%E7%BD%91%E5%85%B3%E9%99%90%E6%B5%81 Sentinel允许在网关层进行流控。 网关服务引入网关控流依赖:
<!-- sentinel网关流控 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-sentinel-gateway</artifactId>
<version>2.2.0.RELEASE</version>
</dependency>
网关流控精确特定限制 流控分组
- 网关流控返回
spring.cloud.sentinel.scg.fallback.content-type=application/json
spring.cloud.sentinel.scg.fallback.response-status=400
或
@Configuration
public class SentinelGatewayConfig {
public SentinelGatewayConfig(){
GatewayCallbackManager.setBlockHandler(new BlockRequestHandler() {
/**
* 网关限流了请求,就会调用此回调
* Mono Flux
* @param serverWebExchange
* @param throwable
* @return
*/
@Override
public Mono<ServerResponse> handleRequest(ServerWebExchange serverWebExchange, Throwable throwable) {
R error = R.error(BizCodeEnume.NO_STOCK_EXCEPTION.getCode(), BizCodeEnume.NO_STOCK_EXCEPTION.getMsg());
String errJson = JSON.toJSONString(error);
Mono<ServerResponse> body = ServerResponse.ok().body(Mono.just(errJson), String.class);
return body;
}
});
}
}
// todo
- Mono Flux