likes
comments
collection
share

【微服务】- 分布式系统的流量防卫兵 - sentinel

作者站长头像
站长
· 阅读数 9

Sentinel流量防卫兵

【微服务】- 分布式系统的流量防卫兵 - sentinel

前言

预谋学习springcloud-alibaba组件这么久,由于自身以及工作的原因脱了这么久,近期就开始逐步恢复学习,学完了nacos组件、openfeign组件以及负载均衡,接下来就是对流量控制的学习sentinel组件。

服务雪崩与容错机制

学习sentinel首先要知道什么是服务雪崩与容错机制,最后再来通过集成Sentinel来提供服务治理和容错的能力。

(1)、服务雪崩

服务雪崩就是当一个或多个服务出现故障或不可用时,这些故障会导致其他服务也因为等待或依赖这些服务而崩溃,最终整个系统不可用的情况。服务雪崩通常发生在高并发的情况下,当请求量增加时,一些服务可能会因为超负荷而变得不稳定或不可用,导致其他服务也因此被阻塞或超时,从而使整个系统出现连锁反应,最终导致系统崩溃。 【微服务】- 分布式系统的流量防卫兵 - sentinel

服务雪崩的原因

导致雪崩的原因有许多

  • 服务间的依赖关系:在分布式系统中,服务与服务之间存在依赖关系,如果其中一个服务出现故障或延迟,会导致其他服务等待或阻塞的连锁反应,从而引发雪崩效应。
  • 负载均衡问题:当请求量过大时,如果负载均衡策略不合理或者负载均衡器本身出现故障,就可能导致某些服务的压力过大,从而引发服务雪崩。
  • 缓存问题:如果系统中的缓存出现问题,例如缓存击穿、缓存雪崩等,会导致请求直接落到数据库,从而引发数据库压力过大,最终导致服务雪崩。
  • 数据库问题:当数据库出现故障、网络延迟等情况时,会影响到相关服务的响应能力,从而导致整个系统的不可用。
  • 代码问题:如果代码质量不高,存在一些潜在的问题,例如死循环、内存泄漏等,会导致服务出现问题,最终引发服务雪崩。

当大量得请求造成了请求失败,会不断得重试,这反而还会加重请求流量,造成雪崩效应。归根到底也就是大量得线程同步等待造成的资源耗尽。

(2)、容错机制

容错机制是指在分布式系统中,通过设计和实现一些技术手段和策略,使系统能够在出现故障、错误或异常的情况下仍然能够继续运行,保证系统的可用性和可靠性。

服务限流

当服务达到一定的临界值的时候,有可能会导致服务宕机。常见使用的是服务限流,首先会对服务进行压测,测出最大的QPS(每秒处理的请求数量),当开启限流时,大于规定限流的QPS就会被限流,对于这些限流的请求,可以是进行流量降级,或者是直接拒绝。

超时机制

超时机制就是当大量的请求得不到相应会线程等待,如果检测到超时,就会释放资源。

熔断机制

当服务不稳定或者暂时关闭,这就是服务熔断。在现实中,这就好比如空气开关在电路出现过载、短路等故障时,及时切断电路,以保护电气设备和人身安全,防止电路烧坏。而在软件上,服务熔断的实现原理通常是通过对服务请求进行监控,当服务请求的失败率达到一定的阈值时,服务熔断器会自动打开,将后续请求快速失败返回,而不是一直等待服务超时。当服务熔断器处于打开状态时,一部分请求会快速失败返回,而另一部分请求则会被拦截,从而避免服务雪崩的发生。

服务降级

所谓降级,就是当某个服务熔断之后,服务将不再被调用,此时客户端可以自己准备一个本地的fallback(回退)回调, 返回一个缺省值。 例如:(备用接口/缓存/mock数据) 。这样做,虽然服务水平下降,但好歹可用,比直接挂掉要强,当 然这也要看适合的业务场景。服务降级是通过削减服务的负载或者降低服务的质量来保证系统的稳定性。

sentinel简介

Sentinel是一个轻量级的开源框架,它提供了实时监控、流量控制、熔断降级等功能,可以在微服务架构中用于保护服务的稳定性和可靠性。在Spring Cloud中,可以通过集成Sentinel来提供服务治理和容错的能力。 官方网站:sentinelguard.io/zh-cn/docs/… 功能包括如下: 1.流量控制:通过限流的方式来控制服务的请求量,防止系统超负荷而导致的故障和错误。 2.熔断降级:当服务出现故障或异常时,可以通过熔断机制来控制请求量,保护服务的可用性和稳定性。 3.实时监控:可以通过Dashboard界面来实时监控服务的运行情况,包括流量、响应时间、异常等信息。 4.异常处理:可以通过定义规则来处理各种异常情况,例如超时、限流、熔断等,提高服务的容错能力。 5.集成Spring Cloud:Sentinel可以和Spring Cloud的组件集成,也可以是由springboot集成,例如Eureka、Ribbon、Feign等,方便在微服务架构中使用。

Sentinel初体验-通过API实现

Sentinel 可以简单的分为 Sentinel 核心库和 Dashboard。核心库不依赖 Dashboard,但是结合 Dashboard 可以取得最好的效果。 首先使用核心库的方式。

流量控制规则 (FlowRule)

导入依赖

引入sentinel的核心库依赖

<!-- 整合sentinel-核心库,支持分布式系统,并不一定需要微服务,因此可以不添加springcloud -->
<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-core</artifactId>
    <version>1.8.6</version>
</dependency>

定义资源和流控规则

根据sentinel官方文档说的来,需要先定义资源,定义规则,接着校验规则是否生效的步骤。 定义资源: 资源 是 Sentinel 中的核心概念之一。在本次demo,定义一个资源名称为:RESOURCE_NAME = "test",我们需要把需要控制流量的代码用Sentinel API SphU.entry("HelloWorld")entry.exit() 包围起来即可。通过SphU.entry(RESOURCE_NAME)来指定流量控制的资源。

Entry entry = null;
    try {
        // sentinel对指定的资源进行流控
        entry = SphU.entry(RESOURCE_NAME); // 配置流控规则
        // 业务...
        log.info(">>>执行正常业务流程>>>");
        return "执行业务";
    } catch (BlockException be) {
        // 阻止资源访问,被限流或者降级
        log.info("block");
        return "流量控制";
    } catch (Exception ex) {
        // 若需要配置降级规则,需要通过这种方式记录业务异常
        Tracer.traceEntry(ex, entry);
    } finally {
        if (entry != null) {
            entry.exit();
        }
    }
    return null;

定义规则: 通过initFlowRules方法来定义规则,因为流控规则可以有多个,因此使用一个流控集合,FlowRule就是流控规则。可以设置需要控制的资源以及流控规则(本次设置的是QPS),定义完规则之后,在通过FlowRuleManager.loadRules方法加载规则。 从官网中可以知道流量控制规则可以设置的参数如下: 【微服务】- 分布式系统的流量防卫兵 - sentinel

/**
 * 定义规则
 */
@PostConstruct
private static void initFlowRules() {
    // 设置流控规则 流控规则可以多个
    List<FlowRule> rules = new ArrayList<>();
    // 流控规则
    FlowRule rule = new FlowRule();
    // 设置流控资源
    rule.setResource(RESOURCE_NAME);
    // 设置流控规则 - QPS
    rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
    // 设置阈值
    rule.setCount(1);
    rules.add(rule);
    // 加载配置的规则
    FlowRuleManager.loadRules(rules);
}

运行几次之后,可以看到被限流了

【微服务】- 分布式系统的流量防卫兵 - sentinel

*通过注解优化使用流量控制

由以上例子可以看得出使用Sentinel API SphU.entry("HelloWorld") entry.exit() 包围起来写起来非常麻烦,在实际开发中,用这样写是相当麻烦的。好在sentinel中提供了注解的方式来进行流量控制的使用。

添加依赖

需要添加sentinel-annotation-aspectj的pom依赖

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

配置SentinelResourceAspect的Bean

为了方便使用,就在启动类中配置SentinelResourceAspect

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

配置资源与规则

前一个demo是通过SphU.entry来配置资源,而现在就只需要添加在注解的value属性上。通过blockHandler设置流控降级的处理方法,需要注意的是注解方式埋点不支持 private 方法,blockHandler指定的方法需要在当前类中来定义,如果在其他类,就需要额外参数**blockHandlerClass = ""**来指明类的地址。这里还有个fallback属性,这是用来指定接口异常执行的方法。

@SentinelResource属性如下

  • value:资源名称,必需项(不能为空)
  • entryType:entry 类型,可选项(默认为 EntryType.OUT)
  • blockHandler/blockHandlerClass :blockHandler 对应处理 BlockException 的函数名称,需要用public修饰,并且参数和返回类型要与原函数相同,需要在同个类中;如果不在同个类,就需要使用blockHandlerClass属性,为对应的类的 Class 对象,注意对应的函数必需为 static 函数
  • fallback/ fallbackClass:fallback 函数名称,可选项,用于在抛出异常的时候提供 fallback 处理逻辑。函数的相关条件与blockHandler一样。
  • defaultFallback:默认的 fallback 函数名称。
  • exceptionsToIgnore:用于指定哪些异常被排除掉,不会计入异常统计中,也不会进入 fallback 逻辑中,而是会原样抛出。

以下代码就是在test2接口中通过添加**@SentinelResource注解进行流量控制。 *** blockHandler 函数会在原方法被限流/降级/系统保护的时候调用,而 fallback 函数会针对所有类型的异常。

/**
 * @SentinelResource: 改善接口中资源定义以及流量降级的处理方法
 * value: 资源名称
 * blockHandler: 流量降级的处理方法(默认处理方法要在同类中)
 *              如果不在同个类,就需要额外参数blockHandlerClass = "",来指明类的地址, 并需要用静态方法
 * fallback: 用来指定接口异常执行的方法
 * @return
 */
@GetMapping("/test2")
(value = RESOURCE_NAME2, blockHandler = "blockHandlerTs")
public String test2(String id) {
    log.info("<<<测试2<<<" + id);
    return "正常返回";
}

设置流量降级方法的时候,对于参数以及返回类型,都要与控制类相同。

/**
 * 一定是public, 返回的类型/与参数要与接口的类型相同
 * @param id
 * @param ex
 * @return
 */
public String blockHandlerTs(String id, BlockException ex) {
    ex.printStackTrace();
    return "流量控制";
}

接下来就可看看执行的结果,疯狂请求几次。。。 【微服务】- 分布式系统的流量防卫兵 - sentinel

熔断降级规则 (DegradeRule)

对于熔断降级规则 (DegradeRule)配置如下

【微服务】- 分布式系统的流量防卫兵 - sentinel

定义熔断降级规则

同一个资源可以同时有多个降级规则。通过degradeRule.setGrade(RuleConstant.DEGRADE_GRADE_EXCEPTION_COUNT); 设置熔断策略,它是基于异常数量的熔断降级策略,当系统中某个资源的异常数超过设定的阈值后,触发降级策略,进入熔断状态。接着通过 degradeRule.setStatIntervalMs(60*1000); 设置统计时长1分钟,单位是毫秒,degradeRule.setTimeWindow(10); 这个是将统计时间窗口设置为60秒,表示每隔60秒对该资源的运行状况进行一次统计和计算。这表示一分钟出现两次异常就会熔断降级。10秒过去之后就会变成:半开状态,恢复请求调用,在十秒过后,如果再一次请求异常,就会再次熔断,不会根据设置的条件进行判断。

/**
 * 熔断降级规则
 */
@PostConstruct
private static void initDegradeRules() {
    // 降级规则
    List<DegradeRule> degradeRules = new ArrayList<>();
    DegradeRule degradeRule = new DegradeRule();
    // 设置资源
    degradeRule.setResource(DEGRADE_NAME);
    // 设置熔断策略
    degradeRule.setGrade(RuleConstant.DEGRADE_GRADE_EXCEPTION_COUNT);
    // 统计时长:单位:ms,这里设置1分钟
    degradeRule.setStatIntervalMs(60*1000);
    // 一分钟执行两次,出现两次异常就会熔断降级

    // 熔断持续时长:单位:秒
    // 一旦触发熔断,再次请求对应接口就会调用降级方法
    // 10秒过去之后就会变成:半开状态,恢复请求调用,如果第一次请求异常,再次熔断,不会根据设置的条件进行判断
    degradeRule.setTimeWindow(10);
    degradeRules.add(degradeRule);
    DegradeRuleManager.loadRules(degradeRules);
}

使用sentinel-dashboard

到官网下载jar包 github.com/alibaba/Sen… 用命令窗口运行jar包

java -Dserver.port=1111 -Dcsp.sentinel.dashboard.server=localhost:1111 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard.jar

启动访问http://localhost:1111/ 就能看到登录界面,账号密码都是sentinel 【微服务】- 分布式系统的流量防卫兵 - sentinel 在springcloud项目中的yml添加配置,需要配置服务名以及sentinel-dashboard的地址

server:
  port: 8122
spring:
  application:
    name: order-sentinel
  cloud:
    sentinel:
      transport:
        dashboard: 127.0.0.1:1111

启动项目,访问一个接口,就可以在sentinel控制台看到服务了

【微服务】- 分布式系统的流量防卫兵 - sentinel

总结

sentinel能够很好的对接口请求进行请求控制,能够在一定程度防止服务挂掉,并且不一定是需要依赖spring-cloud。能够通过api的方式以及可视化控制台进行流控、降级管理。

虽然在学习之前,有看过几篇博客,当时是为了启动若依的微服务项目,并不是真正会用sentinel,以上介绍如有错误,请各位大佬评论区指出!