Sentinel应用笔记

概念

当A、B、G、H掉线,其他服务就没法通信了

随着微服务的流行,服务和服务之间的稳定性变得越来越重要。Sentinel 以流量为切入点,从流量控制、流量路由、熔断降级、系统自适应过载保护、热点流量防护等多个维度保护服务的稳定性。

特性:

富的应用场景 :Sentinel 承接了阿里巴巴近 10 年的双十一大促流量的核心场景,例如秒杀(即突发流量控制在系统容量可以承受的范围)、消息削峰填谷、集群流量控制、实时熔断下游不可用应用等。
完备的实时监控 :Sentinel 同时提供实时的监控功能。您可以在控制台中看到接入应用的单台机器秒级数据,甚至 500 台以下规模的集群的汇总运行情况。
广泛的开源生态 :Sentinel 提供开箱即用的与其它开源框架/库的整合模块,例如与 Spring Cloud、Apache Dubbo、gRPC、Quarkus 的整合。您只需要引入相应的依赖并进行简单的配置即可快速地接入 Sentinel。同时 Sentinel 提供 Java/Go/C++ 等多语言的原生实现。
完善的 SPI 扩展机制 :Sentinel 提供简单易用、完善的 SPI 扩展接口。您可以通过实现扩展接口来快速地定制逻辑。例如定制规则管理、适配动态数据源等。

主要用途:围绕资源的实时状态设定规则,所有规则都可以进行动态实时调整。如服务降级熔断、系统流量控制、系统自适应过载保护等。

Sentinel熔断降级会在调用链路中某个资源出现不稳定状态时(例如调用超时或异常比例升高),对这个资源的调用进行限制,让请求快速失败,避免影响到其它的资源而导致级联错误。当资源被降级后,在接下来的降级时间窗口之内,对该资源的调用都自动熔断(默认行为是抛出DegradeException)。

熔断、降级、限流

熔断

服务熔断 的作用类似于我们家用的保险丝,当某服务出现不可用或响应超时的情况时,为了防止整个系统出现雪崩,暂时停止 对该服务的调用。
停止 是说,当前服务一旦对下游服务进行熔断,当请求到达时,当前服务不再对下游服务进行调用,而是使用设定好的策略(如构建默认值)直接返回。
暂时 是说,熔断后,并不会一直不再调用下游服务,而是以一定的策略(如每分钟调用 10 次,若均返回成功,则增大调用量)试探调用下游服务,当下游服务恢复可用时,自动停止熔断。

降级

降级 是指当自身服务压力增大时,采取一些手段,增强自身服务的处理能力,以保障服务的持续可用。比如,下线非核心服务以保证核心服务的稳定、降低实时性、降低数据一致性。

为了预防某些功能出现负荷过载或者响应慢的情况,在其内部暂时舍弃一些非核心接口和数据的请求(如评论、积分),而直接返回一个提前准备好的 fallback(退路) 错误处理信息。释放CPU和内存资源,以保证整个系统的稳定性和可用性。

所谓熔断降级就是为了解决微服务之间调用后产生的异常问题,如A调用了B,而B是微信支付或其他第三方的接口,由于当时的网络原因导致B的响应时长增加,从而造成调用方A的线程池被占用,极端情况下,A的线程池被耗尽,整个服务雪崩。

QPS是对请求的数量进行控制,而无法对于进入服务内的请求是否异常进行控制,熔断降级就是对进入服务之中的请求是否异常来进行控制,从而保护我们的服务。

所以当某个资源的响应时间的线程超过设定线程的阈值时,对于其可以进行熔断降级处理,暂时得关闭访问,熔断器open,当熔断时长到达之后,熔断器进入half-open状态,允许一个请求进入,无论该请求是否正常都会返回,然后如果这个请求正常则熔断器close,如果这个请求异常则熔断器继续open,继续熔断,反复上述步骤。

限流

限流是指上游服务对本服务请求 QPS 超过阙值时,通过一定的策略(如延迟处理、拒绝处理)对上游服务的请求量进行限制,以保证本服务不被压垮,从而持续提供稳定服务。常见的限流算法有滑动窗口、令牌桶、漏桶等。

docker安装Sentinel

java 复制代码
docker pull bladex/sentinel-dashboard:1.8.0

docker run --name sentinel --restart=always -d  -p 8858:8858  bladex/sentinel-dashboard:1.8.0

账号/密码都是 sentinel

项目中应用

注册到sentinel(服务监控)

java 复制代码
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
    <version>2021.1</version>
</dependency>
java 复制代码
spring:
  cloud:
    sentinel:
      transport:
        client-ip: 192.168.56.1
        dashboard: 192.168.56.10:8858    //sentinel  仪表盘地址
        port: 8719    //默认 sentinel api 端口

实时监控

感觉不需要有这个也可以实时监控啊

java 复制代码
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

Actuator默认情况下,只有/info和/heath端点是启用的。因为Actuator本身没有保护,所以大多数端点默认是禁用的,需要我们来选择对外暴露哪些端点。通过这2个属性management.endpoints.web.exposure.include和management.endpoints.web.exposure.exclude(排除哪些)。通过management.endpoints.web.exposure.include属性,可以指定哪些端点想要暴露出来。

我理解的端点指的是需要监控的API接口

java 复制代码
management:
  endpoints:
    web:
      exposure:
        include: '*'

限流

流控规则

流控规则主要分为QPS 和 线程数两大控制方向, 而其后的处理方式有: 直接,关联,链路三种方式,处理效果又分为:快速失败,Warm Up(冷启动),匀速排队。

  • QPS (Query per second) : 即每秒的请求数量

  • 线程数: 即服务中的并发量,值得注意的是,线程数就是并发量,而QPS不一定是并发量,如QPS为1000,而由于服务的耗时操作少,线程执行后归还到线程池的速度快,可能只需要10个线程即可完成,所以要明确QPS与线程数的区别

  • 直接: 顾名思义,即是直接进行接下来的操作,是对被保护的服务进行操作

  • 关联: 在关联资源触碰到阈值时对被保护资源进行操作

  • 链路: 在多个调用中,针对某一条调用链路进行操作,如果触碰到阈值,则该条链路无法访问请求的资源

  • 快速失败: 直接拒绝请求

  • Warm Up: 冷启动,如果启动需要耗时操作时可以如此设置,防止在刚开始进行耗时操作时过多的访问压垮服务,而给与一定的时间进行预热,之后达到处理峰值

  • 匀速排队: 是为了针对访问在不同的时间内,访问量不同,因此设置一个时间长度,来匀速的处理请求,实现削峰填谷,让程序平稳的进行,使用到了漏桶算法,值得注意的是该处理方式不支持QPS> 1000 的场景

    java 复制代码
    访问某个资源超过阈值时,该资源被保护不让访问
    java 复制代码
      我理解warm up 作用预防在于再短时间内一下子过多qps导致压垮服务
      在服务启动时,对该资源直接进行流控操作,在某段预热时长(单位秒)内,慢慢达到设定的阈值,期间超出的部分直接拒绝,如此达到保护目标资源的目的,Warm Up 的起始值为设定阈值的 1/3(如设定300,则起始阈值为100)
    java 复制代码
    在访问目标资源时,由于访问在不同时间段内的访问量不同,设置此操作
    在设定的时间段内(单位:毫秒),处理 阈值 个数的请求 , 每一个请求的处理时间为: 设置的超时时间 / 阈值
    java 复制代码
    如果关联资源的QPS超过阈值,则被保护资源拒绝访问
    注意点: 关联资源之间不一定就是调用关系,可能并没有关系,而设置之后是控制关联资源的QPS阈值来限制目标资源的访问权限
    java 复制代码
    也是对关联资源在超过设定的QPS阈值时,对目标资源进行冷启动处理,初始阈值依然是设定阈值的 1/3
    而后在预热时长内达到设定阈值,预热时间内超出阈值的请求直接快速失败
    java 复制代码
    关联资源在超过设定阈值时,对于目标资源进行匀速排队的操作
    java 复制代码
    machine-root
       /       \
      /         \
    Entrance1     Entrance2
     /             \
    /               \
    DefaultNode(nodeA)   DefaultNode(nodeA)

针对同一个资源有两个入口,Entrance1 和Entrance2 ,他们都调用了同一个资源nodeA,那么这样就形成了一个链路,对此,我们可以设置入口资源为Entrance1 或 Entrance2 中的一个,表示在某一个入口的QPS值达到阈值之后,切断这条链路,使该入口无法被访问

复制代码
```java
上述介绍的冷启动和匀速排队的策略相同,只是针对的是链路中的某一个入口达到QPS阈值之后的操作

线程数超过阈值的操作一致

降级规则

java 复制代码
最大 RT (Response Time) : 响应时间,就是在规定什么叫做 "慢" , 单个请求的响应时长大于我们设定的最大RT,那么这个请求就叫做 "慢请求"

比例阈值: 响应时间大于设定RT的线程占总请求数的比例,取值0.0~1.0之间

熔断时长: 达到阈值之后服务请求拒绝的时长(单位:秒)

最小请求数: 1秒钟内发出的最少需要的请求的总数量
java 复制代码
解读: 如果一秒钟内发送了5个请求,而其中 比例阈值 * 最小请求数 的个数的请求超过了最大RT 的时间,那么目标资源就会被熔断降级,熔断时长单位为秒。

断路器的工作流程:
1、达到熔断的阈值之后,断路器的状态为open
2、熔断时长内所有的请求都被拒绝,无法进入
3、熔断时长之后,断路器的状态变为half-open,此时允许一个请求进来
4、若该请求没有异常,则断路器的状态为close,之后回归正常
5、若该请求依然异常,则断路器再次变为open状态,所有请求无法进入,等待下一次熔断时长之后


热点规则

授权规则

熔断降级fegin托底

java 复制代码
@FeignClient(value = "mall-member", fallback = MemberFeginServiceFallBack.class)
@Component
public interface MemberFeginService {


    @PostMapping("/mallmember/member/register")
    public R register(@RequestBody UserRegisterVO userRegisterVO);

    @PostMapping("/mallmember/member/login")
    public R login(@RequestBody LoginVO loginVO);
}
java 复制代码
/**
 * @author guanglin.ma
 * @date 2024-01-26 13:32
 */
@Component
@Slf4j
public class MemberFeginServiceFallBack implements MemberFeginService {

    Logger logger = LoggerFactory.getLogger(MemberFeginServiceFallBack.class);

    @Override
    public R register(UserRegisterVO userRegisterVO) {
        logger.error("注册失败哦");
        return R.error(BizCodeEnume.UNKNOW_EXCEPTION.getCode(),
                BizCodeEnume.UNKNOW_EXCEPTION.getMsg());
    }

    @Override
    public R login(LoginVO loginVO) {
        logger.error("登录失败哦");
        return R.error(BizCodeEnume.UNKNOW_EXCEPTION.getCode(),
                BizCodeEnume.UNKNOW_EXCEPTION.getMsg());
    }
}
java 复制代码
feign:
  sentinel:
    enabled: true

限流

java 复制代码
public class SentinelUrlBlockHandler implements BlockExceptionHandler {
    @Override
    public void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, BlockException e) throws Exception {
        R r = R.error(500,"访问太快,稍后再试!");
        httpServletResponse.setContentType("application/json;charset=UTF-8");
        httpServletResponse.getWriter().write(JSON.toJSONString(r));
    }
}


自定义资源(不前测试没有成功)

java 复制代码
// 1.5.0 版本开始可以利用 try-with-resources 特性(使用有限制)
// 资源名可使用任意有业务语义的字符串,比如方法名、接口名或其它可唯一标识的字符串。
try (Entry entry = SphU.entry("resourceName")) {
  // 被保护的业务逻辑
  // do something here...
} catch (BlockException ex) {
  // 资源访问阻止,被限流或被降级
  // 在此处进行相应的处理操作
}
java 复制代码
// 资源名可使用任意有业务语义的字符串
if (SphO.entry("自定义资源名")) {
    // 务必保证finally会被执行
    try {
        /**
        * 被保护的业务逻辑
        */
    } finally {
        SphO.exit();
    }
} else {
    // 资源访问阻止,被限流或被降级
    // 进行相应的处理操作
}
java 复制代码
<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-annotation-aspectj</artifactId>
    <version>1.8.0</version>
</dependency>

@SentinelResource(value = "test1Resource",blockHandler = "test1BlockHandler")
@Override
public String test1() {
    // 1.5.0 版本开始可以利用 try-with-resources 特性(使用有限制)
// 资源名可使用任意有业务语义的字符串,比如方法名、接口名或其它可唯一标识的字符串。
//        try (Entry entry = SphU.entry("test1Resource")) {
        // 被保护的业务逻辑
        // do something here...
        logger.error("正常访问");
        return "正常访问";
//        } catch (BlockException ex) {
//            // 资源访问阻止,被限流或被降级
//            // 在此处进行相应的处理操作
//            logger.error("限流中");
//            return "限流中";
//
//        }

}

public void test1BlockHandler(BlockException blockException){
    logger.error("限流中");
}

网关流控

java 复制代码
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-alibaba-sentinel-gateway</artifactId>
    <version>2021.1</version>
</dependency>
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
    <version>2021.1</version>
</dependency>
java 复制代码
spring:
  cloud:
    sentinel:
      transport:
        dashboard: 192.168.56.10:8858
        port: 8719
      eager: true

management:
  endpoints:
    web:
      exposure:
        include: '*'

控制仪表可能不显示网关的控制列表,我只这么解决的

持久化

java 复制代码
<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-datasource-nacos</artifactId>
    <version>1.8.0</version>
</dependency>
java 复制代码
spring:
  cloud:
    nacos:
      discovery:
        server-addr: 192.168.56.10:8848 #nacos地址
      config:
        server-addr: 192.168.56.10:8848 #nacos地址 配置中心
        auto-refresh: true # 是否自动刷新,默认为 false
    sentinel:
      transport:
        client-ip: 192.168.56.1
        dashboard: 192.168.56.10:8858
        port: 8719
      eager: true
      # Sentinel 规则持久化
      datasource:
        ds1:
          nacos:
            server-addr: 192.168.56.10:8848
            dataId: test11
            groupId: DEFAULT_GROUP
            data-type: json
#            流控
            rule-type: flow
        degrade:
          nacos:
            server-addr: localhost:8848
            dataId: ${spring.application.name}-degrade-rules
            groupId: SENTINEL_GROUP
  #            降级
            rule-type: degrade
        system:
          nacos:
            server-addr: localhost:8848
            dataId: ${spring.application.name}-system-rules
            groupId: SENTINEL_GROUP
  #            系统
            rule-type: system
        authority:
          nacos:
            server-addr: localhost:8848
            dataId: ${spring.application.name}-authority-rules
            groupId: SENTINEL_GROUP
  #            授权
            rule-type: authority
        param-flow:
          nacos:
            server-addr: localhost:8848
            dataId: ${spring.application.name}-param-flow-rules
            groupId: SENTINEL_GROUP
  #            热点
            rule-type: param-flow
java 复制代码
[
  {
    // 资源名
    "resource": "/test",
    // 针对来源,若为 default 则不区分调用来源
    "limitApp": "default",
    // 限流阈值类型(1:QPS;0:并发线程数)
    "grade": 1,
    // 阈值
    "count": 1,
    // 是否是集群模式
    "clusterMode": false,
    // 流控效果(0:快速失败;1:Warm Up(预热模式);2:排队等待)
    "controlBehavior": 0,
    // 流控模式(0:直接;1:关联;2:链路)
    "strategy": 0,
    // 预热时间(秒,预热模式需要此参数)
    "warmUpPeriodSec": 10,
    // 超时时间(排队等待模式需要此参数)
    "maxQueueingTimeMs": 500,
    // 关联资源、入口资源(关联、链路模式)
    "refResource": "rrr"
  }
]
java 复制代码
[
  {
      // 资源名
    "resource": "/test1",
    "limitApp": "default",
    // 熔断策略(0:慢调用比例,1:异常比率,2:异常计数)
    "grade": 0,
    // 最大RT、比例阈值、异常数
    "count": 200,
    // 慢调用比例阈值,仅慢调用比例模式有效(1.8.0 引入)
    "slowRatioThreshold": 0.2,
    // 最小请求数
    "minRequestAmount": 5,
    // 当单位统计时长(类中默认1000)
    "statIntervalMs": 1000,
    // 熔断时长
    "timeWindow": 10
  }
]
java 复制代码
[
  {
      // 资源名
    "resource": "/test1",
    // 限流模式(QPS 模式,不可更改)
    "grade": 1,
    // 参数索引
    "paramIdx": 0,
    // 单机阈值
    "count": 13,
    // 统计窗口时长
    "durationInSec": 6,
    // 是否集群 默认false
    "clusterMode": 默认false,
    // 
    "burstCount": 0,
    // 集群模式配置
    "clusterConfig": {
      // 
      "fallbackToLocalWhenFail": true,
         // 
      "flowId": 2,
      // 
      "sampleCount": 10,
      // 
      "thresholdType": 0,
      // 
      "windowIntervalMs": 1000
    },
    // 流控效果(支持快速失败和匀速排队模式)
    "controlBehavior": 0,
    // 
    "limitApp": "default",
    // 
    "maxQueueingTimeMs": 0,
    // 高级选项
    "paramFlowItemList": [
      {
          // 参数类型
        "classType": "int",
          // 限流阈值
        "count": 222,
          // 参数值
        "object": "2"
      }
    ]
  }
]
java 复制代码
[
  {
      // RT
    "avgRt": 1,
    // CPU 使用率
    "highestCpuUsage": -1,
    // LOAD
    "highestSystemLoad": -1,
    // 线程数
    "maxThread": -1,
    // 入口 QPS
    "qps": -1
  }
]
java 复制代码
[
  {
    // 资源名
    "resource": "sentinel_spring_web_context",
      // 流控应用
    "limitApp": "/test",
    // 授权类型(0代表白名单;1代表黑名单。)
    "strategy": 0
  }
]
相关推荐
大筒木老辈子3 小时前
Linux笔记---协议定制与序列化/反序列化
网络·笔记
草莓熊Lotso3 小时前
【C++】递归与迭代:两种编程范式的对比与实践
c语言·开发语言·c++·经验分享·笔记·其他
我爱挣钱我也要早睡!6 小时前
Java 复习笔记
java·开发语言·笔记
汇能感知11 小时前
摄像头模块在运动相机中的特殊应用
经验分享·笔记·科技
阿巴Jun11 小时前
【数学】线性代数知识点总结
笔记·线性代数·矩阵
茯苓gao11 小时前
STM32G4 速度环开环,电流环闭环 IF模式建模
笔记·stm32·单片机·嵌入式硬件·学习
是誰萆微了承諾12 小时前
【golang学习笔记 gin 】1.2 redis 的使用
笔记·学习·golang
DKPT12 小时前
Java内存区域与内存溢出
java·开发语言·jvm·笔记·学习
ST.J13 小时前
前端笔记2025
前端·javascript·css·vue.js·笔记
Suckerbin13 小时前
LAMPSecurity: CTF5靶场渗透
笔记·安全·web安全·网络安全