一文读懂熔断器和重试机制

2,608 阅读5分钟
原文链接: mp.weixin.qq.com

导语:随着微服务的流行,熔断作为其中一项很重要的技术也广为人知。当微服务的运行质量低于某个临界值时,启动熔断机制,暂停微服务调用一段时间,以保障后端的微服务不会因为持续过负荷而宕机。本文作者介绍了熔断的原理和机制,并用例子说明了熔断如何使用。

今天,让我们讨论一下微服务架构的弹性伸缩。总的来说,各个服务之间可以通过同步或者异步的方式通讯。我们假定把一个大的单个系统拆分成若干小的模块以便解偶服务。事实上,这样可能更加难以管理内部服务之间的通讯。

这里有两个你们可能听过的概念:熔断器和重试机制。

熔断器

设想一个简单的场景,其中用户的请求调用服务A,随后调用另一个服务。我们可以把B称作A的下游服务。服务B前面有负载均衡器。

后端服务可能因为各种原因出问题。例如:数据库慢查询,网络波动,或者内存争用。在这个情况下,如果服务A超时或者报错,用户很可能会重试。在如此混乱的情况下我们可以做什么来保护下游服务呢?

熔断器为资源和失败率提供更多的控制。断路器被设计为在不等待TCP连接超时的情况下快速而优雅地处理错误。这种快速失败机制将保护下游服务。这个机制最重要的部分是熔断器能够快速对下游服务作出一些响应。线程池不会因为慢请求而阻塞,没有超时,而且也可能会给终端用户更有意义的返回数据。熔断器也给了下游服务足够的时间恢复正常。完全避免报错是很困难的,但是减少错误的影响完全可行。

通过使用hystrix熔断器,我们可以在上游服务中增加降级行为。例如,服务B可以访问副本服务或缓存,而不是调用服务C。引入这种方法需要整合测试,因为我们可能无法在好的链路上模拟这种方式。

状态

在熔断器里面有3种主要的状态:

  • 关闭:让请求通过的默认状态。如果请求成功/失败但低于阈值,则状态保持不变。可能出现的错误是超过最大并发数和超时错误。

  • 打开:当熔断器打开的时候,所有的请求都会被标记为失败;这是故障快速失败机制,而不需要等待超时时间完成。

  • 半开:定期的尝试发起请求来确认系统是否恢复。如果恢复了,熔断器将转为关闭状态或者保持打开。

理论上的熔断器

这里有5个控制熔断设置的主要参数。

阀值可以从两个服务的SLA中得到。当测试服务与其它依赖的稳定性时,这些值应该合理设置。

一个好的熔断器命名应该指明相应的服务连接报错了。实际上,你可能有许多API endpoint在同一个服务。所以针对每个API endpoint需要配置单独的熔断器。

 

生产环境的熔断器

一个熔断器通常被部署在多个节点。即使熔断器提供一个快速报错机制,我们依然需要确认备用的降级逻辑是生效的。因为我们觉得这是一个小概率事件而不测试对应的降级策略是冒险的行为。在最简单的运行中,我们也需要确定阀值是合理的。从我的个人经历来说,在日志里面打印出配置参数将让调试更加简单。

Demo

这个样例代码使用hystrix-go库,这是golang的hystrix Netflix库实现。

运行这个测试,你将看到2次的返回结果不同。

重试机制

对上面的熔断器模型,如果B服务减小它的实例数量,将发生什么?许多A发起的请求可能遇到5XX报错。这将触发熔断器的失败报警。这就是为什么我们需要重试以避免间歇性网络抽风。

简单的重试代码:

重试模式

为了实现乐观的并发控制,我们可以编排不同的服务在不同的时间重试。立即重试可能不太合适,因为这样会对依赖服务的突然大量的请求。增加暂停时间将有助于缓解这种情景。也可以让暂停时间在一定范围内随机(或者说在等待阶段抖动一下)。

让我们想一下下面这个算法:

  • 指数: 基数* 2^尝试次数

  • 全抖动: 休眠时间 = rand(0 , 基数* 2^尝试次数)

  • 等抖动: 临时 = 基数 * 2^尝试次数; 休眠时间= 临时/2+rand(0 , 临时/2)

  • 不相关抖动: 休眠时间= rand(基数, 休眠时间\*3);

客户端数量与负载总量和完成时间之间存在相关性。要确定最适合系统的方法,有必要在客户端数量增加时进行基准测试。详细的实验可以在本文中找到。我的建议是在去抖动和全抖动之间。

两种工具的结合

断路器通常用于无状态在线交易系统,尤其是在关键节点上。重试应该用于调度不受超时约束的任务或节点。我们可以考虑同时使用两者。在大型系统中,service mesh将是一种更好地协调大规模异构系统的理想架构。

参考链接:

1. https://github.com/afex/hystrix-go/

2. https://github.com/eapache/go-resiliency

3. https://github.com/Netflix/Hystrix/wiki

4. https://www.awsarchitectureblog.com/2015/03/backoff.html

5. https://dzone.com/articles/go-microservices-part-11-hystrix-and-resilience

原文地址:

https://medium.com/@trongdan_tran/circuit-breaker-and-retry-64830e71d0f6

本文作者 Dan Tran,由朱毅堃翻译。转载本文请注明出处,欢迎更多小伙伴加入翻译及投稿文章的行列,详情请戳公众号菜单「联系我们」。