可用性提升大作战-从阿里的哨兵中间件谈谈服务降级

目录

服务可用性
Sentinel的限流、熔断降级与隔离
保证服务稳定的几种策略
  • 限流
  • 降级
  • 隔离
  • 超时
  • 重试
  • 集群
服务限流的几种算法
  • 计时器算法
  • 滑动窗口算法
  • 漏桶算法
  • 令牌桶算法
隔离设计的几种思路
  • 线程池隔离
  • 信用量隔离
其他
  • dubbo的服务降级实现原理
  • Hystrix的隔离策略
  • Guava

正文

1.从阿里的Sentinel说起

笔者特别喜欢阿里的中间件,缘由很简单,在于他详尽的文档说明,无论Dubbo也好,还是今天聊的哨兵中间件也好,官网里都很详细地描述了它们的设计思路。比起阅读它们的源码,我更愿意关注设计者将要解决的问题以及围绕着这个问题给出的答案。

Sentinel是阿里的中间件团队研发的面型分布式服务架构的轻量级高可用的流量控制组件,其核心目的则是为了保障服务的稳定性。
那么它以流量控制为切入点,从以下几个维度提供了技术方案:

  • 限流与流量控制
    • 集群限流
    • 热点限流
    • 调用关系限流
  • 降级
    • 异常降级
  • 熔断降级
  • 负载保护

由于本文主要围绕Sentinel的限流以及隔离,并不打算针对Sentinel的每一个功能特性一一展开描述,感兴趣的童鞋可以自行前往官网学习。

1.1 流量控制

笔者总结了Sentinel的流量控制设计的思路,其解决方案包含以下几方面:
(1)根据什么指标来判断需要进行流量控制?
(2)一旦触发了流量控制所设置的阈值,采取的什么手段?
(3)流量控制的范围?

首先来回答第一个问题:
流量控制主要有两种统计的类型,一种是统计并发线程数,另一种则是统计QPS。

并发线程数流量的控制,主要还是作用于保护业务线程数不被耗尽,这种情况往往发生于下游的应用由于某种原因导致服务不稳定,响应延迟,一旦遇到下游这种情况,上游则很容易因为线程无法得到释放,导致线程池Crash掉。业内一种解决的方案是通过线程池的隔离,比如Hystix则是采用这种方式,但是这种方式本身有线程切换的额外成本。Sentinel给出另一种解决方案,则是做一层简单的统计,如果线程池的使用已经达到了阈值了,此时则直接拒绝。

基于QPS的流量控制,针对流量达到阈值后,采用的手段有以下:
(1)直接拒绝
(2)Warm up
(3)匀速排队

直接拒绝无需过多的展开,重点探讨Warm up和匀速排队。

Warm up

预热/冷启动方式,这个词并非Sentinel独有,在很多中间件和框架(比如Dubbo)都会有这个过程。之所以采用Warm up的方式,主要是为了防止系统流量突增,直接将系统冲垮,因此通过缓慢增加流量的方式,将系统做好充分的预热,防止冲垮系统。那么为什么系统会分冷热呢?
这里我们经常会遇到以下这种场景,我们通常为了减少开销,会构造线程池或者数据库连接池,在一开始,初始创建阶段,创建连接的成本是十分高的,因此我们在系统刚启动时,则会有这些额外开销。

Sentinel在这里采用了令牌桶算法的方式进行限流。令牌桶算法由于在下面限流算法章节会提到,这里不再赘述。

匀速排队

匀速排队采用的则是另一种思路,如果说令牌桶的算法是控量,那么对于匀速排队采用的漏桶算法则是采用控制速度的方式。匀速排队使用的场景往往是请求以突刺状来到,此时对于系统来说,不希望一下子就把系统给击穿,以均衡稳定的速度对请求进行处理,此时会让系统更加稳定。

关于流量控制的对象

在一个调用关系中,会有两种角色,调用方与被调用方。在进行流量控制时,Sentinel采用的时针对调用关系不同资源的流量控制:

  • 调用方限流
  • 调用链路的入口限流
  • 关联资源的流量控制

限流的几种算法

在这里,汇总了下当前业内主要限流框架的一些常用的算法,除了漏桶算法和令牌桶算法,常用的限流算法还有以下几种

  • 计数器算法
  • 滑动窗口算法
  • 漏桶算法
  • 令牌桶算法
(1)计数器算法

在一定时间范围内,对请求进行计数,如果该段时间内,请求总数超过阈值,则进行限流操作。
计算器算法就是一个很简单的统计单位时间请求数的算法。

优点

  • 实现简单

缺点:

  • 存在被人恶意攻击的漏洞,即在时间临界点攻击者恶意提交不高于阈值的请求,在过了时间临界点继续提交大量请求,造成限流失效。
(2)滑动窗口算法

如果说计数器算法是固定时间窗口内对请求进行统计的一种算法,它会产生上述的临界值的问题,而滑动窗口算法则是固定窗口算法的一种特例,它将计数器算法的时间窗口进行细分,同时也不是对时间计数器暴力清零,而是一种更加平滑的手段进行对计数器进行更新。
它是否可以解决上述的计数器算法的缺陷呢?
答案是可行的。我们将1s划分为四个窗口,此时每一个窗口为250ms,假设依然有攻击者企图在1s的临界值进行攻击,他先放出100个请求,之后准备在临界点过后再放出100个请求,此时他会面临什么样的情况呢?当滑动窗口向前滑动一个时间块,此时由于之前的100个请求仍属于整个滑动窗口以内,此时滑动到下一个时间块时,统计到的请求为200个,成功监测到超过阈值。

优点

  • 有效规避掉固定窗口的临界点问题

缺点

  • 时间片切得越细,越耗时。
(3)漏桶算法(Leaky Bucket)

漏桶算法,我的理解其实它是一个控制流出速度的算法。
请求以不确定的速度进入到漏桶里,然后漏桶以一定的速度响应请求,如果请求总量超过了阈值导致了溢出,此时会强行限制请求。这里其实就是访问频率超过接口响应速率一定时间后,就拒绝请求了。
因此可以看到影响漏桶的两个要素:

  • 桶容量
  • 出水速率

优点

  • 通过强行限定请求传输的速率,来达到限制流量。

缺点

  • 无法充分利用资源。漏出速度是固定的,导致了如果出现突刺状的流量,但是机器的资源又是充足的,此时对于这种突发流量的消化食低效的。(当然从另一方面讲,如果机器资源是不充足的,漏桶算法的限制正是我们所期望的)
(4)令牌桶算法

令牌桶假设我们有一个固定容量的桶,桶里存放着令牌,令牌会随着时间不断地往桶里填充,直到桶的容量,请求过来时,只有获取到桶里的令牌,则允许通过,否则则拒绝通过。

优点

  • 允许一定程度的突发
  • 能防止临界点问题。
  • 实现简单

1.2 熔断降级

如果说限流是针对外部请求流量的一种干预,是围绕外部来做的优化策略,那么熔断降级则是针对调用链路中某个资源出现不稳定时,自身对该调用进行降级优化的处理。

那么要做好熔断降级处理,这里是存在几个关键问题:
(1)什么时候触发熔断降级机制?什么指标
(2)降级后采用什么策略

先来回答第一个问题,其实无论限流也好,还是熔断也好,指标无非是以下几个:
(1)平均响应时间
(2)异常比例
(3)异常数
一旦上述的指标超过阈值,Sentinel则对资源的调用采用默认的行为,进行自动熔断,默认抛出DegradException。

关于隔离的几种设计思路

熔断降级常用到的一个库是Netflix Hystrix。我们可以通过对Hystrix和Sentinel的比对,进一步加深我们对熔断降级的理解。

Hystrix的隔离策略有两种:线程池隔离、信号量隔离

线程池的隔离方式是十分常用的一种方式,也是比较好理解的。在流量大的情况下,由于请求无法及时响应,直接反映出来的就是线程池资源被耗尽。那么我们是否可以针对不同的服务调用,划分级别,然后使用各自不同的线程池呢,线程池隔离就是基于这种思路。但是线程池隔离的代价也是高昂的,上下文切换的成本太高,会对调用有较大的影响。

另一种隔离策略为信号量隔离。本身也不难理解,给定固定个数的信号量,如果调用请求时,先获取信号量,如果获取到,则进行服务的调用,否则则进入队列进行排队。由于没有线程切换,因此开销比较小。

Sentinel 可以通过并发线程数模式的流量控制来提供信号量隔离的功能。

关于熔断的设计模型

无论是Sentinel还是Hystrix,采用的都是熔断器模式。熔断器模式不展开说明,如果有兴趣的童鞋,可以参考这篇文章:熔断器模式

参考资料

Sentinel官网
聊聊服务稳定性保障这些事
剖析暴增流量下的限流算法和最强哨兵Sentinel
Sentinel 与 Hystrix 的对比

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值