MK
摩柯社区 - 一个极简的技术知识社区
AI 面试

基于阿里 Sentinel 的微服务容错实践

2024-04-193.7k 阅读

微服务架构下的容错挑战

在微服务架构盛行的当下,应用被拆分成众多小的服务单元,各服务独立开发、部署与维护,这虽带来了诸如敏捷开发、技术栈多样化等诸多优势,但也引入了一系列新的挑战,其中容错便是关键一环。

分布式系统故障常态

在传统单体应用中,所有功能模块都在同一个进程内运行,故障范围相对集中且易于定位。然而,微服务架构下,服务之间通过网络进行通信,这就引入了网络的不确定性。网络延迟、超时、丢包等情况时有发生,同时,每个微服务自身也可能因为代码漏洞、资源耗尽等原因出现故障。例如,一个电商系统中,订单服务依赖库存服务和支付服务,若库存服务因瞬间流量过大导致响应缓慢,订单服务就可能长时间等待,甚至超时,影响整个订单流程。

故障传播风险

微服务之间存在复杂的依赖关系,一个服务的故障很容易像多米诺骨牌一样传播到其他依赖它的服务上。假设在一个社交媒体平台中,用户服务依赖好友关系服务,好友关系服务又依赖消息推送服务。若消息推送服务出现故障,好友关系服务可能因为等待消息推送的反馈而积压请求,进而导致自身资源耗尽,最终影响到用户服务,使得用户无法正常查看好友信息或接收消息通知,严重影响用户体验。

服务雪崩效应

当一个微服务出现故障,大量请求因无法得到及时响应而被阻塞,这些请求会占用系统资源,如线程、连接等。随着故障服务的请求积压越来越多,资源被耗尽,依赖它的上游服务也会受到影响,最终可能导致整个微服务生态系统崩溃,这就是可怕的服务雪崩效应。例如,在一个在线教育平台中,课程播放服务出现故障,大量学生的播放请求无法处理,这些请求会积压在承载课程列表服务的服务器上,导致课程列表也无法正常展示,进而影响到平台的其他功能,如课程购买、学习资料下载等,整个平台陷入瘫痪。

Sentinel 简介

面对微服务架构中的种种容错挑战,阿里开源的 Sentinel 应运而生,它为微服务提供了丰富的容错解决方案。

Sentinel 核心能力

  1. 流量控制:Sentinel 能够根据预先设定的规则,对进入微服务的流量进行精准控制。例如,可以设置每秒只允许 100 个请求进入某个服务,当请求量超过这个阈值时,多余的请求将被拒绝或者以特定的策略进行处理,如排队等待。这有助于防止因瞬间高流量导致服务过载。
  2. 熔断降级:当依赖的服务出现故障或者响应时间过长时,Sentinel 可以自动触发熔断机制,暂时切断对故障服务的调用,避免故障的进一步传播。同时,还能提供降级策略,比如返回一个预设的默认值,保证系统的基本可用性。比如在一个音乐播放应用中,若歌词获取服务出现故障,Sentinel 可以直接返回一个“暂无歌词”的提示,而不是让用户一直等待,影响音乐播放体验。
  3. 系统自适应保护:Sentinel 可以实时监控系统的负载情况,如 CPU 使用率、内存使用率等。当系统负载过高时,自动调整流量控制规则,优先保证系统的稳定性,避免因持续高负载导致系统崩溃。

Sentinel 架构

  1. 核心库:Sentinel 的核心库提供了基本的流量控制、熔断降级等功能的实现。它可以与各种主流的微服务框架集成,如 Spring Cloud、Dubbo 等。通过在应用中引入 Sentinel 的核心库依赖,即可快速为微服务添加容错能力。
  2. 控制台:Sentinel 控制台是一个可视化的管理界面,通过它可以方便地配置规则、查看实时监控数据以及进行系统诊断。在控制台中,可以针对不同的微服务设置个性化的流量控制、熔断降级规则,并且实时查看每个服务的请求量、响应时间、熔断状态等信息,便于运维人员及时发现和处理问题。
  3. 数据源:Sentinel 支持多种数据源来存储规则,如本地文件、远程配置中心(如 Nacos、Zookeeper 等)。使用远程配置中心可以实现规则的动态更新,无需重启应用即可生效新的规则,极大地提高了运维效率。例如,在生产环境中,可以根据实际流量情况,通过 Nacos 动态调整某个服务的流量阈值。

基于 Sentinel 的流量控制实践

流量控制是 Sentinel 最基础也是最重要的功能之一,合理的流量控制能够有效避免服务因过载而导致故障。

流量控制规则详解

  1. 资源名:每个需要进行流量控制的微服务接口或者方法都可以定义为一个资源。例如,在一个用户管理微服务中,“/user/register”接口可以定义为一个资源,对这个接口的请求流量进行控制。
  2. 阈值类型:Sentinel 支持两种阈值类型,即 QPS(每秒请求数)和并发线程数。
    • QPS 阈值:当设置 QPS 阈值为 100 时,意味着该资源每秒最多只能处理 100 个请求。若超过这个阈值,后续请求将按照预设的流控策略进行处理。
    • 并发线程数阈值:若设置并发线程数阈值为 50,当该资源的并发处理线程数达到 50 时,新的请求将被拒绝。这种方式适用于对资源消耗较大,需要严格控制并发访问量的场景。
  3. 流控模式:Sentinel 提供了三种流控模式。
    • 直接:直接针对当前资源进行流量控制,当请求量超过阈值时,直接拒绝多余的请求。例如,对于“/product/detail”接口,设置直接模式下 QPS 阈值为 200,当每秒请求量超过 200 时,多余的请求将被立即拒绝。
    • 关联:当关联的资源达到阈值时,对当前资源进行流量控制。比如,在一个电商系统中,“/product/comment”接口与“/product/purchase”接口关联,若“/product/purchase”接口的请求量过高,为了保证购买功能的正常运行,可以对“/product/comment”接口进行限流,降低其请求处理速度。
    • 链路:根据调用链路来进行流量控制。例如,在一个复杂的业务流程中,有多个服务依次调用,若某个特定链路的请求量过高,可以对该链路涉及的资源进行限流,而不影响其他链路的正常请求。
  4. 流控效果:Sentinel 提供了三种流控效果。
    • 快速失败:当请求量超过阈值时,直接返回错误信息,拒绝多余的请求。这是最常用的流控效果,响应速度快,但可能会给用户带来不好的体验。
    • Warm Up:这种效果适用于系统冷启动阶段。在开始时,阈值较低,随着时间推移,阈值逐渐升高到预设值。例如,设置 Warm Up 时间为 60 秒,初始阈值为 50,最终阈值为 200,在启动后的 60 秒内,阈值会从 50 逐渐增加到 200,避免系统在启动瞬间因高流量而崩溃。
    • 排队等待:当请求量超过阈值时,多余的请求会进入队列等待处理。可以设置队列的超时时间,若在超时时间内请求未能得到处理,则返回错误。这种方式可以保证请求的有序处理,但可能会增加请求的响应时间。

代码示例(以 Spring Cloud 为例)

  1. 引入依赖:在 Spring Boot 项目的 pom.xml 文件中添加 Sentinel 依赖。
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
  1. 定义资源:在需要进行流量控制的方法上使用 @SentinelResource 注解来定义资源。
import com.alibaba.csp.sentinel.annotation.SentinelResource;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class UserController {

    @GetMapping("/user/info")
    @SentinelResource("userInfoResource")
    public String getUserInfo() {
        return "User information";
    }
}
  1. 配置流量控制规则:可以通过 Sentinel 控制台或者代码动态配置流量控制规则。以下是通过代码动态配置的示例。
import com.alibaba.csp.sentinel.Entry;
import com.alibaba.csp.sentinel.SphU;
import com.alibaba.csp.sentinel.slots.block.RuleConstant;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;

import java.util.ArrayList;
import java.util.List;

public class SentinelFlowRuleInit {

    public static void initFlowRules() {
        List<FlowRule> rules = new ArrayList<>();
        FlowRule rule = new FlowRule();
        rule.setResource("userInfoResource");
        rule.setCount(100);
        rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
        rule.setLimitApp("default");
        rules.add(rule);
        FlowRuleManager.loadRules(rules);
    }
}

在上述代码中,定义了一个针对“userInfoResource”资源的流量控制规则,QPS 阈值为 100。在应用启动时,可以调用 SentinelFlowRuleInit.initFlowRules() 方法来加载这些规则。

基于 Sentinel 的熔断降级实践

熔断降级是微服务容错的重要手段,它能够在依赖服务出现故障时,快速切断调用,避免故障传播。

熔断降级规则详解

  1. 熔断策略:Sentinel 支持三种熔断策略。
    • 慢调用比例:当请求的平均响应时间超过设定的阈值,并且慢调用比例超过设定的比例时,触发熔断。例如,设置平均响应时间阈值为 500 毫秒,慢调用比例为 50%,当在统计时间窗口内,平均响应时间超过 500 毫秒的请求比例达到 50%时,该服务将进入熔断状态。
    • 异常比例:当请求的异常比例超过设定的值时,触发熔断。比如,设置异常比例为 20%,在统计时间窗口内,若异常请求数占总请求数的比例达到 20%,则该服务将被熔断。
    • 异常数:当请求的异常数超过设定的值时,触发熔断。例如,设置异常数为 100,在统计时间窗口内,若异常请求数达到 100 个,该服务将进入熔断状态。
  2. 统计时间窗口:用于统计请求的响应时间、异常比例等数据的时间范围,单位为秒。例如,设置统计时间窗口为 10 秒,Sentinel 会在这 10 秒内统计相关数据,以判断是否触发熔断。
  3. 熔断时长:当服务触发熔断后,进入熔断状态的持续时间,单位为秒。在熔断时长内,对该服务的请求将直接被熔断,返回降级结果。例如,设置熔断时长为 60 秒,在这 60 秒内,所有对该服务的调用将不会真正执行,而是直接返回预设的降级内容。
  4. 最小请求数:在统计时间窗口内,只有请求数达到这个最小值,才会进行熔断规则的判断。若请求数过少,统计数据可能不准确,通过设置最小请求数可以避免误熔断。例如,设置最小请求数为 100,在 10 秒的统计时间窗口内,若请求数小于 100,即使出现部分慢调用或异常,也不会触发熔断。

代码示例(以 Spring Cloud 为例)

  1. 定义降级方法:在使用 @SentinelResource 注解时,指定降级方法。
import com.alibaba.csp.sentinel.annotation.SentinelResource;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class OrderController {

    @GetMapping("/order/detail")
    @SentinelResource(value = "orderDetailResource", fallback = "orderDetailFallback")
    public String getOrderDetail() {
        // 实际调用订单详情服务的逻辑
        return "Order detail information";
    }

    public String orderDetailFallback() {
        return "Sorry, the order detail service is currently unavailable.";
    }
}

在上述代码中,当“orderDetailResource”资源触发熔断时,会调用 orderDetailFallback 方法,返回降级提示信息。 2. 配置熔断降级规则:同样可以通过 Sentinel 控制台或者代码动态配置熔断降级规则。以下是代码动态配置的示例。

import com.alibaba.csp.sentinel.Entry;
import com.alibaba.csp.sentinel.SphU;
import com.alibaba.csp.sentinel.slots.block.RuleConstant;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRule;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRuleManager;

import java.util.ArrayList;
import java.util.List;

public class SentinelDegradeRuleInit {

    public static void initDegradeRules() {
        List<DegradeRule> rules = new ArrayList<>();
        DegradeRule rule = new DegradeRule();
        rule.setResource("orderDetailResource");
        rule.setGrade(RuleConstant.DEGRADE_GRADE_EXCEPTION_RATIO);
        rule.setCount(0.2);
        rule.setTimeWindow(10);
        rule.setMinRequestAmount(100);
        rules.add(rule);
        DegradeRuleManager.loadRules(rules);
    }
}

在上述代码中,定义了一个基于异常比例的熔断降级规则,异常比例阈值为 20%,统计时间窗口为 10 秒,最小请求数为 100。在应用启动时,调用 SentinelDegradeRuleInit.initDegradeRules() 方法加载这些规则。

基于 Sentinel 的系统自适应保护实践

除了对单个微服务进行流量控制和熔断降级,Sentinel 还能从系统层面进行自适应保护,确保整个系统的稳定性。

系统自适应保护规则详解

  1. Load 自适应:Sentinel 可以根据系统的 Load(负载)情况自动调整流量控制规则。系统 Load 反映了系统的繁忙程度,当 Load 过高时,说明系统处于高负载状态,需要降低进入系统的流量。例如,设置系统 Load 阈值为 1.5,当系统 Load 超过 1.5 时,Sentinel 会自动降低相关微服务的流量阈值,以减轻系统负担。
  2. CPU 使用率自适应:通过监控系统的 CPU 使用率来动态调整流量。当 CPU 使用率过高时,表明系统计算资源紧张,需要限制流量。比如,设置 CPU 使用率阈值为 80%,当 CPU 使用率超过 80%时,Sentinel 会自动调整流量控制规则,减少请求进入,保证系统的稳定性。
  3. 内存使用率自适应:除了 CPU 和 Load,内存使用率也是衡量系统健康状况的重要指标。当内存使用率过高,可能导致系统性能下降甚至出现 OOM(Out Of Memory)错误。Sentinel 可以根据内存使用率设置相应的自适应保护规则,当内存使用率达到预设阈值时,自动调整流量。

代码示例(以 Spring Cloud 为例)

  1. 配置系统自适应保护规则:通过代码动态配置系统自适应保护规则。
import com.alibaba.csp.sentinel.slots.system.SystemRule;
import com.alibaba.csp.sentinel.slots.system.SystemRuleManager;

import java.util.ArrayList;
import java.util.List;

public class SentinelSystemRuleInit {

    public static void initSystemRules() {
        List<SystemRule> rules = new ArrayList<>();
        SystemRule rule = new SystemRule();
        rule.setHighestSystemLoad(1.5);
        rule.setAvgRt(1000);
        rule.setMaxThread(1000);
        rule.setQps(200);
        rules.add(rule);
        SystemRuleManager.loadRules(rules);
    }
}

在上述代码中,设置了系统 Load 阈值为 1.5,平均响应时间阈值为 1000 毫秒,最大线程数为 1000,QPS 阈值为 200。在应用启动时,调用 SentinelSystemRuleInit.initSystemRules() 方法加载这些规则。

  1. 结合其他规则使用:系统自适应保护规则通常与流量控制、熔断降级规则结合使用。例如,在一个高并发的电商系统中,当系统 Load 超过阈值时,不仅可以通过系统自适应保护降低整体流量,还可以针对某些关键服务,如订单服务,进一步加强流量控制和熔断降级策略,确保核心业务的稳定性。

基于 Sentinel 的微服务容错监控与运维

在实际生产环境中,对微服务的容错情况进行监控和有效的运维是保障系统稳定运行的关键。

Sentinel 控制台监控

  1. 实时监控数据:Sentinel 控制台提供了丰富的实时监控数据,包括每个微服务的 QPS、响应时间、成功请求数、失败请求数等。通过这些数据,运维人员可以实时了解每个服务的运行状态。例如,在控制台中可以看到某个商品服务的 QPS 突然飙升,这可能意味着有异常流量或者某个促销活动引发了高并发访问,运维人员可以及时采取措施,如调整流量控制规则。
  2. 熔断降级状态监控:可以直观地查看每个服务的熔断降级状态,包括是否处于熔断状态、熔断开始时间、熔断剩余时间等。若发现某个服务频繁进入熔断状态,运维人员可以深入分析原因,如是否依赖的服务存在性能问题,或者当前服务自身的资源配置不合理等。
  3. 热点数据监控:Sentinel 能够监控热点参数,即统计一段时间内访问次数最多的参数值。例如,在一个新闻资讯应用中,通过热点数据监控可以发现用户最常访问的新闻分类,从而针对这些热点分类的接口进行更精细化的流量控制和优化。

运维优化策略

  1. 规则动态调整:根据监控数据,运维人员可以在 Sentinel 控制台动态调整流量控制、熔断降级等规则。比如,在电商大促期间,根据实时流量情况,逐步提高某些关键服务的 QPS 阈值,确保系统能够承载高并发请求。同时,对于依赖的第三方服务,若其稳定性出现波动,可以适当调整熔断降级规则,如缩短熔断时长,以便在服务恢复后尽快恢复正常调用。
  2. 故障预警与通知:结合监控数据,可以设置故障预警机制。例如,当某个服务的失败请求数连续 5 分钟超过一定阈值时,通过邮件、短信等方式通知运维人员。这使得运维人员能够在故障影响扩大之前及时介入,采取相应的修复措施,如重启服务、调整资源配置等。
  3. 性能优化:通过分析 Sentinel 提供的响应时间等数据,运维人员可以发现性能瓶颈。对于响应时间较长的服务,可以进一步深入分析代码逻辑、数据库查询等,进行针对性的优化。比如,优化数据库索引、调整代码中的算法,以提高服务的响应速度,减少因慢调用导致的熔断风险。

通过以上基于 Sentinel 的微服务容错实践,从流量控制、熔断降级、系统自适应保护到监控与运维,全面构建了微服务架构下的容错体系,有效保障了微服务应用的稳定性和可靠性。