降级熔断:如何屏蔽非核心系统故障的影响?

目录

前言

一、熔断是什么?

二、服务降级

三、雪崩是如何发生的

四、hystrix使用

五、降级机制要如何做

总结


前言

在“双十一”的巨大流量中,商品促销过程中出现了几次短暂的服务不可用,这给部分用户造成了不好的使用体验。事后,你们进行了细致的复盘,追查出现故障的根本原因,你发现,原因主要可以归结为两大类。

第一类原因是由于依赖的资源或者服务不可用,最终导致整体服务宕机。举例来说,在你的电商系统中就可能由于数据库访问缓慢,导致整体服务不可用。

另一类原因是你们乐观地预估了可能到来的流量,当有超过系统承载能力的流量到来时,系统不堪重负,从而出现拒绝服务的情况。

那么,你要如何避免再次出现这两类问题呢?我建议你采取降级、熔断以及限流的方案。今天这节课,我主要讲一下解决第一类问题的思路:降级和熔断。

限流、熔断和降级都是系统容错的重要设计模式。


一、熔断是什么?

是在流量过大时(或下游服务出现问题时),可以自动断开与下游服务的交互,并可以通过自我诊断下游系统的错误是否已经修正,或上游流量是否减少至正常水平,来自我恢复。熔断更像是自动化补救手段,可能发生在服务无法支撑大量请求或服务发生其他故障时,对请求进行限制处理,同时还可尝试性的进行恢复。

二、服务降级

主要是针对非核心业务功能,而核心业务如果流程超过预估的峰值,就需要进行限流。降级一般考虑的是分布式系统的整体性,从源头上切断流量的来源。降级更像是预估手段,在预计流量峰值前提下,提前通过配置功能降低服务体验,或暂停次要功能,保证系统主要流程功能平稳响应。

三、雪崩是如何发生的

局部故障最终会导致全局故障,这种情况有一个专业的名词儿,叫做“雪崩”。那么,为什么会发生雪崩呢?我们知道,系统在运行的时候是需要消耗一些资源的,包括 CPU、内存等系统资源,也包括执行业务逻辑的时候,需要的线程资源。

举个例子,一般在业务执行的容器内,都会定义一些线程池来分配执行任务的线程,比如在Tomcat 这种 Web 容器的内部,定义了线程池来处理 HTTP 请求;RPC 框架也给 RPC 服务端初始化了线程池来处理 RPC 请求。

这些线程池中的线程资源是有限的,如果这些线程资源被耗尽,那么服务自然也就无法处理新的请求,服务提供方也就宕机了。比如,你的垂直电商系统有四个服务 聚合服务A、商品服务B、促销服务C、评论服务D,A调用 B,B 调用 C 和 D。其中,聚合服务A、商品服务B、促销服务C是系统的核心服务,论服务D 是非核心服务。

所以,一旦作为入口的 A 流量增加,你可能会考虑把 A、B 和 C 服务扩容,忽略 D。那么D 就有可能因为无法承担这么大的流量,导致请求处理缓慢,进一步会让 B 在调用 D 的时候,B 中的请求被阻塞,等待 D 返回响应结果。这样一来,B 服务中被占用的线程资源就不能释放。

久而久之,B 就会因为线程资源被占满,无法处理后续的请求。那么从 A 发往 B 的请求,就会被放入 B 服务线程池的队列中,然后 A 调用 B 响应时间变长,进而拖垮 A 服务。你看,仅仅因为非核心服务 D 的响应时间变长,就可以导致整体服务宕机,这就是我们经常遇到的一种服务雪崩情况。

那么我们要如何避免出现上面这种情况呢?从我刚刚的介绍中你可以看到,因为服务调用方等待服务提供方的响应时间过长,它的资源被耗尽,才引发了级联反应,发生雪崩。所以在分布式环境下,系统最怕的反而不是某一个服务或者组件宕机,而是最怕它响应缓慢,因为,某一个服务或者组件宕机也许只会影响系统的部分功能,但它响应一慢,就会出现雪崩拖垮整个系统。

而我们在部门内部讨论方案的时候,会格外注意这个问题,解决的思路就是在检测到某一个服务的响应时间出现异常时,切断调用它的服务与它之间的联系,让服务的调用快速返回失败,从而释放这次请求持有的资源。这个思路也就是我们经常提到的降级和熔断机制。那么降级和熔断分别是怎么做的呢?它们之间有什么相同点和不同点呢?你在自己的项目中要如何实现熔断降级呢?

四、Hystrix简介

        Spring Cloud Hystrix是一款优秀的服务容错和保护组件,也是Spring Cloud的重要组件之一。

    Spring Cloud Hystrix是基于Netfilx公司的开源组件Hystrix实现的。提供熔断器功能,能够有效阻止分布式服务系统中出现联动故障,以提高微服务系统的弹性。Spring Cloud Hystrix具有服务降级,服务熔断,线程隔离,请求缓存,请求合并以及实时故障监控等强大功能。

Hystrix能做什么

  • 保护线程资源:防止单个服务的故障耗尽系统中所有的线程资源。
  • 快速失败机制:当某个服务发生了故障,不让服务调用方一直等待,而直接返回一个可预期的,可处理的降级响应。
  • 提供降级(FallBack)方案:在请求失败后,提供一个设计好的降级方案,当请求失败后调用此方法。
  • 防止故障扩散:使用熔断机制,防止故障扩散到其他服务。
  • 提供熔断器故障监控组件Hystrix Dashboard,随时监控熔断器的状态。
     

Hystrix服务熔断 

熔断机制是为了应对雪崩效应而出现一种微服务链路保护机制。

当微服务系统的某个微服务不可用或响应时间太长时,为了保护系统的服务整体可用性,熔断器会暂时切断对该服务的请求调用,并快速返回一个友好的错误响应信息。这种熔断状态不是永久的,在经历了一定时间后,熔断器会再次检测该微服务是否恢复正常,若恢复正常则恢复调用链路。

  • 熔断关闭状态(Closed):当服务访问正常时,熔断器处于关闭状态,服务调用方可以正常地对服务进行调用。
  • 熔断开启状态(Open):默认情况下,在固定时间内接口调用出错比率达到一个阈值(例如 50%),熔断器会进入熔断开启状态。进入熔断状态后,后续对该服务的调用都会被切断,熔断器会执行本地的降级(FallBack)方法。
  • 半熔断状态(Half-Open): 在熔断开启一段时间之后,熔断器会进入半熔断状态。在半熔断状态下,熔断器会尝试恢复服务调用方对服务的调用,允许部分请求调用该服务,并监控其调用成功率。如果成功率达到预期,则说明服务已恢复正常,熔断器进入关闭状态;如果成功率仍旧很低,则重新进入熔断开启状态。

Hystrix实现熔断机制

在SpringCloud中,熔断机制是通过Hystrix实现的。Hystrix会监控微服务间调用的情况,当失败调用达到一定比例时(例如5秒内失败20次),就会启动熔断机制。

  1. 当服务的调用出错率达到后超过Hystirx规定的出错比率(默认为50%),熔断器进入熔断开启状态。
  2. 熔断器进入熔断开启状态后,Hystrix会启动一个休眠时间窗,在这个时间窗内,该服务的降级逻辑会临时充当业务主逻辑,而原来的业务主逻辑不可用。
  3. 当有请求再次调用该服务时,会直接调用降级逻辑快递返回失败效应,以避免系统雪崩。
  4. 当休眠时间窗到期后,Hystrix会进入半熔断状态,允许部分请求对由原来的业务主逻辑进行调用,并监控其成功率。
  5. 如果调用成功率达到预期,说明服务恢复正常,Hystrix进入熔断关闭状态,服务原来的业务逻辑恢复。否则Hystrix将进入熔断开启状态,休眠时间窗口重新计时。

Hystrix熔断实现 

在pom.xml导入Hystrix依赖

         <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId><version>2.7.12</version></dependency>
WebApplication 启动类 开启Hystrix
@EnableHystrix
@SpringBootApplication
public class WebApplication {public static void main(String[] args) {SpringApplication.run(WebApplication.class, args);}
}

HystrixController 代码 

@EnableCircuitBreaker
@RestController
public class HystrixController {@HystrixCommand(fallbackMethod = "fallback", commandProperties ={@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "100"),//指定多久超时,单位毫秒。超时进fallback@HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "10"),//判断熔断的最少请求数,默认是10;只有在一个统计窗口内处理的请求数量达到这个阈值,才会进行熔断与否的判断@HystrixProperty(name = "circuitBreaker.errorThresholdPercentage", value = "10"),//判断熔断的阈值,默认值50,表示在一个统计窗口内有50%的请求处理失败,会触发熔断})@RequestMapping("/test/{id}")public String test(@PathVariable("id") Integer id) throws Exception {Thread.sleep(1000);return "ok";}public String fallback(@PathVariable("id") Integer id) {return "fallback";}
}

启动测试

五、降级机制要如何做

除了熔断之外,我们在听业内分享的时候,听到最多的服务容错方式就是降级,那么降级又是怎么做的呢?它和熔断有什么关系呢?其实在我看来,相比熔断来说,降级是一个更大的概念。因为它是站在整体系统负载的角度上,放弃部分非核心功能或者服务,保证整体的可用性的方法,是一种有损的系统容错方式。这样看来,熔断也是降级的一种,除此之外还有限流降级、开关降级等等(限流降级我会在下一节课中提到,这节课主要讲一下开关降级)。

开关降级指的是在代码中预先埋设一些“开关”,用来控制服务调用的返回值。比方说,开关关闭的时候正常调用远程服务,开关打开时则执行降级的策略。这些开关的值可以存储在配置中心中,当系统出现问题需要降级时,只需要通过配置中心动态更改开关的值,就可以实现不重启服务快速地降级远程服务了。还是以电商系统为例,你的电商系统在商品详情页面除了展示商品数据以外,还需要展示评论的数据,但是主体还是商品数据,在必要时可以降级评论数据。所以,你可以定义这个开关为“degrade.comment”,写入到配置中心中,具体的代码也比较简单,就像下面这样:
 

 boolean switcherValue = getFromConfigCenter("degrade.comment"); // 从配置中心获取if (!switcherValue) { List<Comment> comments = getCommentList(); // 开关关闭则获取评论数据} else {  List<Comment> comments = new ArrayList(); // 开关打开,则直接返回空评论数据}

当然了,我们在设计开关降级预案的时候,首先要区分哪些是核心服务,哪些是非核心服务。因为我们只能针对非核心服务来做降级处理,然后就可以针对具体的业务,制定不同的降级策略了。我给你列举一些常见场景下的降级策略,你在实际的工作中可以参考借鉴。针对读取数据的场景,我们一般采用的策略是直接返回降级数据。比如,如果数据库的压力比较大,我们在降级的时候,可以考虑只读取缓存的数据,而不再读取数据库中的数据;如果非核心接口出现问题,可以直接返回服务繁忙或者返回固定的降级数据。对于一些轮询查询数据的场景,比如每隔 30 秒轮询获取未读数,可以降低获取数据的频率(将获取频率下降到 10 分钟一次)。

而对于写数据的场景,一般会考虑把同步写转换成异步写,这样可以牺牲一些数据一致性和实效性来保证系统的可用性。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/151067.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

大数据架构设计理论与实践

大数据架构设计理论与实践 大数据处理系统概述 传统数据处理系统存在的问题 大数据处理系统面临的挑战 大数据处理系统的属性/特征 典型的大数据架构 Lambda架构 Lambda定义 优缺点 应用场景 Lambda的体系结构( Batch Layer (批处理层)、Speed Layer (加速层)、Serving Lay…

(el-Table)操作(不使用 ts):Element-plus 中 Table 多选框的样式等的调整

Ⅰ、Element-plus 提供的 Table 表格组件与想要目标情况的对比&#xff1a; 1、Element-plus 提供 Table 组件情况&#xff1a; 其一、Element-ui 自提供的 Table 代码情况为(示例的代码)&#xff1a; // Element-plus 自提供的代码&#xff1a; // 此时是使用了 ts 语言环境…

轮转数组(Java)

大家好我是苏麟 , 这篇文章是凑数的 ... 轮转数组 描述 : 给定一个整数数组 nums&#xff0c;将数组中的元素向右轮转 k 个位置&#xff0c;其中 k 是非负数。 题目 : 牛客 NC110 旋转数组: 这里牛客给出了数组长度我们直接用就可以了 . LeetCode 189.轮转数组 : 189. 轮…

[SQL开发笔记]UPDATE 语句:更新表中的记录

一、功能描述&#xff1a; UPDATE 语句&#xff1a;用于更新表中的记录 二、UPDATE 语句语法详解&#xff1a; UPDATE 语法 UPDATE table_nameSET column1value1,column2value2,...WHERE some_columnsome_value; 参数说明&#xff1a; 1.table_name&#xff1a;要修改的表…

Jetpack:019-Jetpack的导航二(传递数据)

文章目录 1. 知识回顾2. 使用方法2.1 通过参数传递数据2.2 获取参数中的数据2.3 共享导航控制器 3. 示例代码4. 内容总结 我们在上一章回中介绍了Jetpack中导航相关的内容&#xff0c;本章回中 继续介绍导航相关的内容。闲话休提&#xff0c;让我们一起Talk Android Jetpack吧…

夯实c语言基础

夯实c语言基础 转义字符 • \? &#xff1a;在书写连续多个问号时使⽤&#xff0c;防⽌他们被解析成三字⺟词&#xff0c;在新的编译器上没法验证了。 • \ &#xff1a;⽤于表⽰字符常量 • \" &#xff1a;⽤于表⽰⼀个字符串内部的双引号 • \\ &#xff1a;⽤于表…

Linux下protobuf和 protobuf-c安装使用

如果在 C语言中使用 protobuf&#xff0c;就需要使用 protobuf-c这个库。 protobuf使用详解&#xff1a;https://blog.csdn.net/qq_42402854/article/details/134066566 下面在 Linux下安装 protobuf和 protobuf-c。 一、下载 protobuf和 protobuf-c 官方的 Protocol Buffer提…

SpringMVC(四)域对象共享数据

pageContext:表示的是jsp页面的范围 HttpServletRequest:表示的是一次请求的范围 HttpSession:表示的是一次会话的范围 ServletContext:表示的是整个应用的范围 一、向请求域中共享数据&#xff1a; 1.1使用ServletAPI向request域对象共享数据 RequestMapping("test…

汇总区间(Java)

大家好我是苏麟 , 这篇文章也是凑数的 ... 描述 : 给定一个 无重复元素 的 有序 整数数组 nums 。 返回 恰好覆盖数组中所有数字 的 最小有序 区间范围列表 。也就是说&#xff0c;nums 的每个元素都恰好被某个区间范围所覆盖&#xff0c;并且不存在属于某个范围但不属于 n…

@Lazy注解的原理

1.ContextAnnotationAutowireCandidateResolver是主要逻辑类 2.当Lazy与Autowired或者Resource合用时&#xff0c;依赖创建的是代理对象(目标对象是TargetSource),在执行时&#xff0c;执行的是代理对象&#xff0c;在invoke(Object proxy,Method method,Object[] args)中执行…

区块链技术的未来:去中心化应用和NFT的崛起

区块链技术正在以前所未有的速度改变着金融和数字资产领域。它的演进为去中心化应用和非替代性代币&#xff08;NFT&#xff09;的崛起提供了坚实的基础。在本文中&#xff0c;我们将深入探讨这一数字革命的关键方面&#xff0c;从区块链的基本原理到它如何改变金融领域&#x…

网络架构学习1

文章目录 网络架构学习11. 传统CNN卷积神经网络1.1 基本思想1.2 VCG16(经典CNN网络架构之一) 2. 两种经典的网络架构2.1 FCN网络2.2 U-Net网络 3. FCNVMB(基于U-Net架构)3.1 FCNVMB 主要思想3.2 FCNVMB 提供的其他思想 网络架构学习1 1. 传统CNN卷积神经网络 1.1 基本思想 C…