《深入浅出分布式技术原理》 学习笔记 day7

134 阅读5分钟

大家好,我是砸锅。一个摸鱼八年的后端开发。熟悉 Go、Lua。今天和大家一起学习分布式技术😊

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 18 天,点击查看活动详情

避免雪崩

在分布式系统中,局部故障是不可避免的。但是如果不把局部故障控制好,很容易导致其演变为全局系统故障,这就是分布式系统中雪崩场景的问题

雪崩出现的原因

雪崩是整个系统中,一个很小的部分出现故障从而导致不断放大的连锁故障

首先服务的处理能力开始出现过载。服务过载是指服务器只能处理一定 QPS 请求,当发往该服务器的 QPS 超出之后,由于资源不足就会出现超时、内存增加等各种异常情况。导致服务的请求处理能力下降

然后服务由于资源耗尽而不可用。当服务严重过载后,会出现大量请求的积压,导致服务消耗更多的内存、CPU、线程和文件描述符等资源。等这些资源被消耗完之后,服务将出现严重超时和崩溃的异常情况,最终对外表现为不可用。

当服务的某一个实例崩溃之后,负载均衡器会将请求发送给其他实例,导致其他实例也出现过载,从而造成整个服务过载的故障。服务调用方也出现大量请求积压导致资源耗尽,整个系统出现雪崩

想要避免雪崩,要么快速减少系统负载,例如熔断、降级、限流等快速失败和降级机制;要么通过弹性扩容机制快速增加系统的服务能力来避免雪崩发生

利用熔断机制避免雪崩

Untitled

在熔断机制的模式下,服务调用方需要为每个调用对象(服务、实例、接口)维护一个状态机,在这个状态机中有三种状态:

  1. 闭合状态。这种状态下需要一个计数器来记录调用失败的次数和总的请求次数。在一个时间窗口内,请求的特定错误码的比例达到预设的阈值,就切换到断开状态
  2. 断开状态。在该状态下发起请求时会立刻返回错误,也可以返回一个降级的结果。在断开状态下,会启动一个超时计时器,当计时器超时后,状态切换到半打开状态
  3. 半打开状态。在该状态下允许应用程序将一定数量的请求发往被调用服务。如果调用正常则可以认为被调用服务恢复正常,此时熔断器可以切换到闭合状态且重置计数器。如果仍然调用失败,则认为被调用方仍然没有恢复,熔断器切换到断开状态,然后重置计数器。所以半打开状态可以有效防止正在恢复的服务被突然出现的大量请求再次打垮的情况

熔断机制的关键点

粒度控制

粒度控制就是想将监控资源过载的粒度控制在一个什么范围里,这个范围有服务、实例、接口三个维度

Untitled

实现熔断机制时,推荐选择“实例的接口”这个维度的熔断粒度,原因是:

  1. 熔断的敏感度高
  2. 熔断的误伤范围小

错误类型

由于熔断机制是用来消除系统过载的,那么需要识别出与系统过载相关的错误,例如:

  1. 系统被动对外表现的过载错误。例如接口过载之后响应时间变长了,熔断器捕获到的错误类型就是“响应超时”之类的错误
  2. 系统主动对外表现出来的过载错误。例如请求的流量触发了限流等机制返回的错误码

注意熔断机制一定不能关注应用层的错误,例如余额不足之类的,这些和系统过载没关系

过载和存活区别

存活一般是指机器或者服务是否存活,对于机器是否存活,一般是通过定期 ping 机器的 IP。如果超过一定时间不能 ping 通,则认为该机器不存活了

判断过载的方式一般是依据请求在队列中的平均等待时间来计算服务的负载,不能选择请求的平均处理时间,因为有可能是下游服务过载了导致请求处理时间增加。在熔断场景下,判断服务过载最好是直接通过服务接口请求的结果来进行判断

总体来讲,过载是关心服务当前的状态好不好,存活只关心服务是否能活着

熔断和重试的关系

重试是指在一个请求失败后,我们认为这次请求失败是因为系统临时错误导致的,为了提高系统的可用性,会重新发起请求

熔断则是认为当前系统的这一个接口已经出现过载的情况,为了确保系统不会出现雪崩,而对当前接口的请求进行快速失败,直接返回失败,而不是真正发起请求,以此来减少系统当前的过载情况

熔断和重试是两个层面的操作,它们之间是相互独立,不需要相互干扰

此文章为2月Day14学习笔记,内容来源于极客时间《深入浅出分布式技术原理》