SpringCloud学习笔记(二)

122 阅读8分钟

4.Sentinel

4.1. 简介

  • Sentinel是阿里开源的流量控制组件,以流量为切入点,从流量控制、熔断降级、系统负载保护等多个维度保护服务的稳定性。

Sentinel简介

4.2. 常见服务故障

  • 服务雪崩:由于多个微服务之间存在互相调用的情况,当其中一个微服务出现故障时,这个故障模块还调用其他模块,这样就会发生级联故障,可能会导致整个微服务架构出现故障,这种现象被称为服务雪崩。

  • 服务降级: 当服务出现故障时,为了防止故障的继续扩散,需要将故障服务进行降级处理,降级处理的方式就是将故障服务返回一个默认值(托底方案),从而保证其他服务正常运行。

  • 服务熔断:如果下游服务因为访问压力过大导致相应很慢或者一直调用失败,上游服务为了防止因为等待下游服务响应而造成线程阻塞,会暂时断开与下游服务的连接,这种方式称为熔断。

    • 闭合状态:熔断器不进行拦截,直接将请求转发到下游服务。
    • 打开状态:熔断器拦截所有请求,上游服务不再钓友下游服务,直接返回预定方法。
    • 半开状态:上游服务会根据规则,尝试恢复对下游服务调用。上游服务会以有限的流量调用下游服务,同时会监控调用的成功率。如果成功率达到阈值,则说明下游服务已经恢复,熔断器会进入闭合状态,否则熔断器会重新进入打开状态。
  • 服务限流:当服务访问压力过大时,为了保证服务的稳定运行,需要对访问服务的流量进行限制,这种限制称为限流。

    • 请求总量计数
    • 时间窗口限流:令牌桶算法、漏牌桶算法
  • 服务超时:在上游服务调用下游服务时,设置一个最大响应时间,如果超过这个时间,下游服务没有响应,上游服务就会断开与下游服务的连接,这种方式称为服务超时。

4.3. 安装Sentinel

Sentinel控制台

4.4. Sentinel组件

  • Sentinel的核心库,不依赖JDK和任何框架/库,能够运行于所有Java运行时环境,同时对Dubbo、Spring Cloud等框架也有较好的支持。端口默认为8719。
  • Sentinel-Dashboard:Sentinel的可视化控制台,提供机器发现、单机资源实时监控、集群资源汇总、规则管理等功能。端口默认为8080。默认用户名和密码都是sentinel。

4.5. Sentinel示例代码

4.5.1. 引入依赖(使用Nacos做服务注册)
<!--SpringCloud Alibaba Sentinel-->
<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-datasource-nacos</artifactId>
</dependency>
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
4.5.2. 配置文件
server:
  port: 8401
spring:
  application:
    name: cloudalibaba-sentinel-service
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848
    sentinel:
      transport:
        dashboard: localhost:8080
        port: 8719
4.5.3. 启动类
@SpringBootApplication
@EnableDiscoveryClient
public class SentinelApplication {
    public static void main(String[] args) {
        SpringApplication.run(SentinelApplication.class, args);
    }
}
4.5.4. 控制层
@RestController
public class FlowLimitController {
    @GetMapping("/testA")
    public String testA() {
        return "------testA";
    }

    @GetMapping("/testB")
    public String testB() {
        return "------testB";
    }
}
}
4.5.5. 测试

4.6. Sentinel流控规则

  • 流控模式:直接、关联、链路
  • 流控效果:快速失败、Warm Up、排队等待
4.6.1. 直接流控
  • 直接流控:当请求的QPS超过设定的阈值时,新的请求就会被限流。
4.6.2. 关联流控
  • 关联流控:当关联的资源达到阈值时,就限流自己。(B扛不住压力,A限流)
4.6.3. 链路流控
  • 链路流控:只记录指定链路上的流量,指定资源从入口资源进来的流量,如果达到阈值,就进行限流。(例如同一个controller下不同的service可以指定不同的流控规则)
4.6.4. 流控效果
  • 快速失败:直接失败,抛出异常。
  • Warm Up:预热模式,根据codeFactor(冷加载因子,默认为3)的值,从阈值codeFactor,经过预热时长,才达到设置的QPS阈值。应用场景:商品秒杀阶段,避免冷启动导致系统流量暴增,系统压力过大。
  • 排队等待:让请求以均匀的速度通过,对应的是漏桶算法。用于处理间隔性突发的流量,让突发的流量可以放到空闲状态时进行处理,例如消息队列。突然的请求会排队处理,设置排队阈值后会把请求带入空闲时间处理,如果请求超时则抛弃请求。

4.7. Sentinel熔断规则

4.7.1. 熔断策略
  • 慢调用比例 (SLOW_REQUEST_RATIO):选择以慢调用比例作为阈值,需要设置允许的慢调用 RT(即最大的响应时间),请求的响应时间大于该值则统计为慢调用。当单位统计时长(statIntervalMs)内请求数目大于设置的最小请求数目,并且慢调用的比例大于阈值,则接下来的熔断时长内请求会自动被熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求响应时间小于设置的慢调用 RT 则结束熔断,若大于设置的慢调用 RT 则会再次被熔断。

    • 示例:1秒内,至少收集5个请求,在这些请求中,超过200ms的比例超过0.1,就开启熔断

    慢比例

  • 异常比例 (ERROR_RATIO):当单位统计时长(statIntervalMs)内请求数目大于设置的最小请求数目,并且异常的比例大于阈值,则接下来的熔断时长内请求会自动被熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求成功完成(没有错误)则结束熔断,否则会再次被熔断。异常比率的阈值范围是 [0.0, 1.0],代表 0% - 100%。

  • 异常数 (ERROR_COUNT):当单位统计时长内的异常数目超过阈值之后会自动进行熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求成功完成(没有错误)则结束熔断,否则会再次被熔断。

4.7.2. 熔断恢复

1.熔断状态:在熔断时长内,请求都会被拒绝,
2.熔断时长结束后,熔断器会进入探测恢复状态(HALF-OPEN 状态)
3.若接下来的一个请求成功完成(没有错误)则结束熔断,否则会再次被熔断。

4.8. @SentinelResource注解

  • @SentinelResource用于标识资源,其value属性用于指定资源名称,blockHandler属性用于指定sentinel配置后出现违规情况时的处理方法,fallback属性用于指定程序异常了JVM抛出的异常时的服务降级方法,且Sentinel的fallback处理方法优先级高于配置的全局异常处理,资源内抛出的异常不会被全局异常处理。
  • 按SentinelResource资源名称限流+自定义限流返回,示例代码:
@GetMapping("/rateLimit/byResource")
@SentinelResource(value = "byResourceSentinelResource",blockHandler = "handlerBlockHandler")
public String byResource() {
    return "按照资源名称SentinelResource限流测试";
}


public String handlerBlockHandler(BlockException exception) {
    return "服务不可用,触发了@SentinelResource,blockHandler";
}
  • 按SentinelResource资源名称限流+自定义限流返回+程序异常返回fallback服务降级,示例代码:
@GetMapping("/rateLimit/doAction/{p1}")
@SentinelResource(value = "doActionSentinelResource",blockHandler = "doActionBlockHandler", fallback = "doActionFallback")
public String doAction(@PathVariable("p1") Integer p1) {
    if (p1 == 0) {
        throw new RuntimeException("p1不能为0");
    }
    return "doAction";
}

public String doActionBlockHandler(@PathVariable("p1") Integer p1, BlockException exception) {
    log.error("sentinel配置自定义限流:{}", exception);
    return "sentinel配置自定义限流";
}

public String doActionFallback(@PathVariable("p1") Integer p1, Throwable e) {
    log.error("程序逻辑异常了:{}", e);
    return "程序逻辑异常了" + "\t" + e.getMessage();
}

4.9. Sentinel热点规则

  • 热点规则:热点即经常访问的数据。很多时候我们希望统计某个热点数据中访问频次最高的 Top K 数据,并对其访问进行限制。比如下面的例子,对某个参数进行限制。
  • 参数例外项:可以配置例外项,例外项表示参数值等于例外项时,即使热点参数的限流阈值被打满,也不会触发限流。
  • 热点规则配置示例:
@GetMapping("/testHotKey")
@SentinelResource(value = "testHotKey",blockHandler = "testHotKeyBlockHandler")
public String testHotKey(@RequestParam(value = "p1", required = false) String p1,
                          @RequestParam(value = "p2", required = false) String p2) {
    return "testHotKey";
}

public String testHotKeyBlockHandler(String p1, String p2, BlockException exception) {
    return "testHotKeyBlockHandler";
}

4.10. Sentinel授权规则

  • 根据请求的来源判断是否允许本次请求通过
  • 配置示例代码:
@Component
public class MyRequestOriginParser implements RequestOriginParser {

    @Override
    public String parseOrigin(HttpServletRequest httpServletRequest) {
        return httpServletRequest.getParameter("serverName");
    }
}
  • 授权规则对serverName进行判断,在流控应用中加入对应的serverName,然后在请求时即可在路径中加入参数实现黑白名单。

4.11. Sentinel持久化

  • Sentinel的规则默认是内存态的,重启后就会消失,所以需要持久化规则。
  • 持久化需要将限流配置规则写入到Nacos中,只要刷新某个rest地址,sentinel控制台的流控规则就能看到,Nacos中规则一旦发生变化,sentinel控制台就会更新显示。
  • 持久化配置示例代码:
4.11.1. 引入依赖
<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-datasource-nacos</artifactId>
</dependency>
4.11.2. 配置文件
datasource:
  ds1:
    nacos:
      server-addr: localhost:8848
      dataId: ${spring.application.name}
      groupId: DEFAULT_GROUP
      data-type: json
      rule-type: flow #具体类型见com.alibaba.cloud.sentinel.datasource.RuleType

      #flow: 流控规则
      #degrade: 熔断降级规则
      #system: 系统保护规则
      #authority: 访问控制规则
      #param-flow: 热点规则
4.11.2. Nacos配置文件
[
    {
        "resource": "/rateLimit/byUrl",
        "limitApp": "default",
        "grade": 1,
        "count": 1,
        "strategy": 0,
        "controlBehavior": 0,
        "clusterMode": false
    }
]