Sentinel

目录

1. 官网

https://sentinelguard.io/zh-cn/docs/quick-start.html

2. 概念

2.1. 核心库(java客户端)

2.2. 控制台(Dashboard)

服务端,管理推送规则、监控、管理机器信息。

2.3. 熔断规则

2.3.1. 熔断策略

  • 并发数
    img

  • 慢调用比例
    在“统计时长”1秒内,至少有5个请求,有“比例阈值”3个请求,“最大RT”响应时间达到了2秒,则会开始熔断,“熔断时长”10s,第11秒开始接受新请求,
    请求成功,则结束熔断,否则再次熔断10s。
    img

  • 异常比例
    在“统计时长”1秒内,接受请求数超过了“最小请求数”20,这20个请求中“比例阈值(0-1)”异常请求比例达到50(按100%)即20个,则会开始熔断10秒。
    img

2.4. 流控规则

2.4.1. 影响流控效果得关键因素

  • resource 资源名,Controller得uri,其它方法上需要显示指定
  • count 限流阈值
  • grade 限流类型,QPS和线程数
  • strategy 策略

2.4.2. 资源名

  • 默认为uri,示例:/order/info

2.4.3. 阈值类型

2.4.3.1. 基于QPS/并发数得流量控制

  • 默认处理逻辑在DefaultBlockExceptionHandler
public class DefaultBlockExceptionHandler implements BlockExceptionHandler {
    public DefaultBlockExceptionHandler() {
    }

    public void handle(HttpServletRequest request, HttpServletResponse response, BlockException e) throws Exception {
        response.setStatus(429);
        PrintWriter out = response.getWriter();
        out.print("Blocked by Sentinel (flow limiting)");
        out.flush();
        out.close();
    }
}
2.4.3.1.1. 自定义处理
  • 也实现BlockExceptionHandler
    重写handle();

2.4.4. 针对来源

2.4.5. 流控模式

2.4.5.1. 直接

  • 定义
    配的“资源名”接受请求达到阈值,则触发流控。

2.4.5.2. 关联

  • 定义
    在a资源页面配置,当资源b,达到阈值,触发的是自身资源a进行流控,资源b不流控。
    当关联资源/order/getOrderById/3达到阈值极限,的同时访问/order/getOrder会触发限流。
    img
  • 使用场景
    写请求流量很大时,限流查询请求。

2.4.5.3. 链路

*定义
在c资源页面配置,有a和b在同时调用c,如果设置了“入口资源”为a,当c达到阈值,对入口资源a进行流控,而不会对b进行流控。
如图,当/test2/3,达到阈值后,会触发限流。
img

  • 问题
    调用/test2接口,里面调和不调getOrderById,2种试一下,看看效果
  • 入口资源
    阈值作用的uri。
    *yml配置
    从1.6.3开始,Sentinel Web filter默认收敛所有URL的入口context,导致链路限流不生效。
    从1.7.0开始,官方在CommonFilter引入了webContextUnify属性,用于控制,设为false,才可生效。
    意思就是1.6.3~1.7.0之间无法使用链路限流
    1.8.6版本可以在yml中配置
    哪些版本可以在yml中配置需要查询官方资料
spring.cloud.sentinel.web-context-unify=false

2.4.6. 流控效果

2.4.6.1. 快速失败

  • 含义
    直接拒绝的意思,达到阈值后,新的请求直接拒绝并抛出FlowException异常。

2.4.6.2. Warm Up

  • 含义
    预热,冷启动的意思
  • 预热时长
    配合冷加载因子,请求需要延迟的x秒才逐渐达到最大阈值。
  • 冷加载因子
    codeFactor 默认为3,即QPS从1/3开始,需要经过“预热时长”才逐渐达到最大阈值。
  • 配置示例,QPS瞬时请求就是20,当时服务会从3慢慢的接受到10,其余被拒绝。
    img

2.4.6.3. 等待排队

  • 含义
    入队等待的意思,用到了漏桶算法,用的时间轴方式,当QPS阈值为100,则每10毫秒只处理一个请求。
  • 注意点
    该模式时,QPS > 1000,可自测下什么效果。
  • 超时时间(毫秒)
    服务接受到请求,开始计时,达到此时间,则拒绝请求。

2.5. 实时监控

  • 实时监控仅存储5分钟以内数据,如果要持久化,需要通过调用实时监控接口MetricsRepository 自己实现。
  • sentinel控制台服务和监控的微服务之间得时间需一致,不然可能拉取不到数据!

2.6. 簇点链路

  • 展示当前服务有哪些资源(url)

2.7. 热点规则

  • 作用
    自动监控,将该uri自动触发升级为限流接口

2.7.1. 注意点

  • 1:代码需要显式添加@SentinelResource,否则不生效
  • 2:参数必须是7种基本数据类型
    img

2.8. 系统规则

  • 官方文档
    img
  • 作用域
    全局的,兜底的。
参数 说明 默认值
LOAD load1 触发值,用于触发自适应控制阶段 -1 (不生效)
RT 所有入口流量的平均响应时间 同上
线程数 入口流量的最大并发数 同上
入口 QPS 所有入口资源的 QPS 同上
CPU 使用率 当前系统的 CPU 使用率(0.0-1.0) 同上

2.9. 授权控制规则

  • 官方文档
    img
    *如何生效
    和【流控规则】-【针对来源】的使用很像,也需要实现RequestOriginParser接口。

2.10. 集群规则

  • 开源版没有生效,没有实现。
  • 云上版本ASAS 付费版提供开箱即用。

3. 安装控制台

3.1. 默认端口8080

3.2. 下载jar包

3.3. 运行jar包

官网--文档--Sentinel控制台有“启动命令”

// 用户、密码都是 sentinel
// -Dcsp.sentinel.dashboard.server=localhost:8587 用于指定访问ip和端口
// Dproject.name=sentinel-dashboard 是左边菜单栏名称
java -Dserver.port=8587 -Dcsp.sentinel.dashboard.server=localhost:8587 -Dproject.name=sentinel-dashboard -jar sentinel的jar文件

4. 控制台

4.1. 菜单说明

image

4.2. 规则持久化问题

默认流控规则是存于内存,重启即清除

4.2.1. 三种规则推送模式

4.2.1.1. 原始模式

  • 默认模式
    浏览器控制台通过api将规则推送给订单服务,更新到内存中。
  • 优点
    简单,无依赖。
  • 缺点
    sentinel的jar包重启会消失,生产不适合。
  • 改造方式
    扩展数据源( WritableDataSource ),参考源码:com.alibaba.csp.sentinel.command.handler.ModifyRulesCommandHandler#handle();

4.2.1.2. 拉模式

  • 实现
    订单微服务主动向某个 规则管理中心,定时3s轮询拉取规则,这个规则中心可以是RDBMS,文件等。
  • 优点
    简单,无依赖,规则又持久化了。
  • 缺点
    不保证一致性,实时性不保证,拉取过于频繁有性能问题。
  • 改造方式
    扩展写数据源( WritableDataSource )
    官方方案:基于文件实现拉取,demo : sentinel-demo/sentinel-demo-dynamic-file-rule
    基于Nacos的拉模式,实现写数据源,当浏览器控制台推送规则到内存后,就将规则发布到Nacos配置中心,可参考com.alibaba.nacos.client.config.NacosConfigService

4.2.1.3. 推模式

  • 实现
    规则管理中心(浏览器控制台)统一推送,订单服务通过注册监听器,接受最新规则,使用Nacos、Zookeeper等配置中心。
  • 优点
    更好的实时性和一致性,规则又持久化了。
  • 缺点
    需要引入第三方依赖
  • 改造方式
    扩展读数据源(ReadableDataSource)
    官方实现方案:Nacos配置中心控制台推送--官方demo: sentinel-demo-nacos-datasource

4.2.1.4. 官方实现

此方案无法实现,修改sentinel浏览器控制台,更新到nacos持久化

  • 1:引入依赖
 <dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-datasource-nacos</artifactId>
</dependency>
  • 2:yml添加从Nacos读取流控规则配置
    img

  • rule-type的值
    详情见:com.alibaba.cloud.sentinel.datasource.RuleType

  • 3:nacos配置中心配置流控规则

4.2.1.4.1. 如何解决浏览器控制台修改规则,同步到Nacos
  • 方案1
    【不建议】改源码(可能不同版本,需要改的地方不一样),重新打一个Jar包,修改规则时同时推送给Nacos配置中心。
  • 方案2
    自己在微服务端扩展写数据源(WritableDataSource),将规则保存到Nacos配置中心。
    思路:推拉结合,使用官方提供的读数据源扩展,自己实现Nacos写数据源。
    代码:gitee,v2.4.2版本。

5. 微服务如何整合

5.1. pom加入依赖

 <dependency>
	<groupId>com.alibaba.cloud</groupId>
	<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>

5.2. 如何让资源(方法)受保护

  • mvc接口自动埋点,自动支持
  • 非mvc接口需要加@SentinelResource,官方说需要配合 Spring AOP 或者 AspectJ 一起使用。
  • 微服务的Controller的所有uri会自动被扫描
    通过在控制台,动态配置流控、熔断规则

5.3. application.yml添加 sentinel 控制台地址

spring:
  application:
    name: tlmall-order
  cloud:
    sentinel:
      transport:
        # 添加sentinel的控制台地址
        # 控制台jar包 启动命令行参数 -Dcsp.sentinel.dashboard.server=的值
        dashboard: localhost:8587

6. 常见问题

6.1. 微服务限流没生效

  • 如果Sentinel部署在公网,业务微服务在本地,本地需要内网穿透暴露一个公网可访问地址。

7. 服务雪崩问题

7.1. 解决方案

7.1.1. 超时机制

  • openFeign 配置连接和读取超时时间

7.1.2. 服务限流

  • 限制QPS

7.1.3. 资源隔离

  • 进程隔离,线程隔离,信号量隔离

7.1.4. 服务熔断降级

8. 注解

8.1. @SentinelResource

  • 解析SentinelResource注解逻辑在:SentinelResourceAspect

9. 单独使用

  • 非微服务项目,未引alibaba cloud

9.1. 引入依赖

  • 2个依赖
<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-core</artifactId>
    <version>1.8.6</version>
</dependency>

AOP依赖
<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-annotation-aspectj</artifactId>
    <version>1.8.6</version>
</dependency>

与控制台通信依赖
<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-transport-simple-http</artifactId>
    <version>1.8.6</version>
</dependency>

9.2. 注册bean

@Configuration
public class SentinelAspectConfiguration {

    @Bean
    public SentinelResourceAspect sentinelResourceAspect() {
        return new SentinelResourceAspect();
    }
}

9.3. 方法上加@SentinelResource

  // ---------------- 方法在本类的用法 ----------------
  // handleException和fallbackException方法参数需要和hello2的保持一致,最后再加上BlockException或Throwable
  // blockHandler = "handleException" 这种是当该方法抛出BlockException执行handleException方法
  // fallback = "fallbackException" 代表:该方法抛出Throwable 执行fallbackException
  // blockHandler满足优先执行
    @SentinelResource(value = RESOURCE_NAME, blockHandler = "handleException",
        fallback = "fallbackException")

//   ---------------- 方法在其它类的用法 ----------------
// 该方法触发了BlockException异常,会调用ExceptionUtil的handleException()方法。
//    @SentinelResource(value = RESOURCE_NAME,
//            blockHandler = "handleException",blockHandlerClass = ExceptionUtil.class,
//            fallback = "fallbackException",fallbackClass = ExceptionUtil.class)
    @RequestMapping("/hello2")
    public String hello2() {

        int i = 1 / 0;

        return "helloworld ";
    }


    // Block 异常处理函数,参数最后多一个 BlockException,其余与原方法hello2一致.
    public String handleException(BlockException ex){
        return "被流控了";
    }

    // Fallback 异常处理函数,参数与原方法hello2一致或加一个 Throwable 类型的参数.
    public String fallbackException(Throwable t){
        return "被异常降级了";
    }
}

10. 在微服务中使用

10.1. 引入依赖

<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>

10.2. 配置哪些方法需要保护

  • springMVC Controller层自动识别

10.3. 配置yml

feign:
  sentinel:
    enabled: true  #开启Sentinel 对 Feign 的支持
spring:
    cloud:
      nacos:
        discovery:
          server-addr: tlmall-nacos-server:8848
      sentinel:
        transport:
          # 添加sentinel的控制台地址
          dashboard: tlmall-sentinel-dashboard:8888
          # 指定应用与Sentinel控制台交互的端口,应用会起一个HttpServer占用该端口
          port: 8719

10.4. 和openFeign整合

10.4.1. 整合源码

  • com.alibaba.cloud.sentinel.feign.SentinelInvocationHandler

10.4.2. @FeignClient

@FeignClient(value = "tlmall-order-sentinel-demo",path = "/order",fallback = FallbackOrderFeignService.class)
public interface OrderFeignService {


    /**
     * 根据用户id查询订单信息
     * @param userId
     * @return
     */
    @GetMapping("/getOrder")
    Result<?> getOrder(@RequestParam("userId") String userId);
}

10.4.2.1. fallback使用示例

@Component   //必须交给spring 管理
public class FallbackOrderFeignService implements OrderFeignService {
    @Override
    public Result getOrder(String userId) {
        return Result.failed("=======服务降级了========");
    }

    @Override
    public Result<?> post1(OrderDTO orderDTO) {
        return Result.failed("=======服务降级了========");
    }

    @Override
    public Result<?> post2(OrderDTO orderDTO, String token) {
        return Result.failed("=======服务降级了========");
    }

    @Override
    public Result<?> post3(OrderDTO orderDTO, String userId) {
        return Result.failed("=======服务降级了========");
    }

}

10.4.2.2. fallbackFactory 使用示例

@FeignClient(value = "tlmall-order-sentinel-demo",path = "/order",fallback = FallbackOrderFeignServiceFactory.class)
public interface OrderFeignService {


    /**
     * 根据用户id查询订单信息
     * @param userId
     * @return
     */
    @GetMapping("/getOrder")
    Result<?> getOrder(@RequestParam("userId") String userId);
}
@Component
public class FallbackOrderFeignServiceFactory implements FallbackFactory<OrderFeignService> {
    @Override
    public OrderFeignService create(Throwable throwable) {

        return new OrderFeignService() {
            @Override
            public Result getOrder(String userId) {
                return Result.failed("=======服务降级了========");
            }

            @Override
            public Result<?> post1(OrderDTO orderDTO) {
                return Result.failed("=======服务降级了========");
            }

            @Override
            public Result<?> post2(OrderDTO orderDTO, String token) {
                return Result.failed("=======服务降级了========");
            }

            @Override
            public Result<?> post3(OrderDTO orderDTO, String userId) {
                return Result.failed("=======服务降级了========");
            }


        };
    }
}

11. restTemplete整合Sentinel

11.1. 应用场景

第三方提供接口(微信支付的查询,飞书扫码登录接口),没法用openFeign

11.2. 如何使用

  • 1: 引入依赖
  • 2:yml添加sentinel控制台配置信息
spring:
  cloud:
    sentinel:
      transport:
        # 添加sentinel的控制台地址
        dashboard: tlmall-sentinel-dashboard:8888
        # 指定应用与Sentinel控制台交互的端口,应用会起一个HttpServer占用该端口
        port: 8719
# 开启resttemplate的sentinel流控切面支持【引入依赖后,默认为true】
resttemplate:
  sentinel:
    enabled:true

  • 3:RestTemplate添加@SentinelRestTemplate
@Configuration
public class RestConfig {

    /**
    * handleBlockException和handleFallback的参数是固定的
     */
    @Bean
    @LoadBalanced
    @SentinelRestTemplate(
            blockHandler = "handleBlockException",blockHandlerClass = ExceptionUtil.class,
            fallback = "handleFallback",fallbackClass = ExceptionUtil.class
    )
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
}
  • 4: blockHandler和fallback函数的固定参数写法
    必须为static方法
public class ExceptionUtil {

    public static SentinelClientHttpResponse handleBlockException(HttpRequest request,
                                                                  byte[] body, ClientHttpRequestExecution execution, BlockException ex) {

        Result result = Result.failed("===被限流啦===");
        try {
            return new SentinelClientHttpResponse(new ObjectMapper().writeValueAsString(result));
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        return null;
    }

    public static SentinelClientHttpResponse handleFallback(HttpRequest request,
                                                            byte[] body, ClientHttpRequestExecution execution, BlockException ex) {
        Result result = Result.failed("===被异常降级啦===");
        try {
            return new SentinelClientHttpResponse(new ObjectMapper().writeValueAsString(result));
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        return null;
    }

}

12. 微服务端源码

12.1. 实现原理

  • 基于AOP
    SentinelResourceAspect 负责处理

12.2. 处理顺序

  • 基于spi加载

  • 用责任链依次处理

12.3. 流控

img

12.3.1. 流控效果

  • 快速失败
    算法:滑动时间窗口
    com.alibaba.csp.sentinel.slots.block.flow.controller.DefaultController
  • Warm Up 预热时长
    算法:令牌桶算法
    WarmUpController
  • 排队等待
    算法:漏桶算法
    RateLimiterController

12.4. 熔断

  • 处理类
    com.alibaba.csp.sentinel.slots.block.degrade.DegradeSlot

  • 熔断开关控制类
    com.alibaba.csp.sentinel.slots.block.degrade.circuitbreaker.ExceptionCircuitBreaker

posted @   jf666new  阅读(26)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· SQL Server 2025 AI相关能力初探
· 单线程的Redis速度为什么快?
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
点击右上角即可分享
微信分享提示