在Ben Schmaus早些时候的一篇文章中,我们分享我们的断路器实现背后的原则。在那篇文章中Ben讨论了在我们的面向服务的体系结构中Netflix API如何与几十个系统交互,这使得API本身更容易受到系统故障或堆栈延迟的影响。本篇文章的其余部分将深入的讨论我们的接口如何与其他系统的故障隔离,负载均衡并能保持故障弹性恢复。 容错是一个必须项,而不是一个特性Netflix API每天接收超过10亿次调用,并每天几十亿次调用(平均比例为1:6)数十个底层子系统,峰值超过100 k依赖请求每秒。
|
太多的依赖项导致整个系统间歇性失效时常发生,即使每一个依赖项本身具有良好的可用性和正常运行时间。 如果没有容错机制,30个依赖项的系统,即使每个正常运行时间为99.99%,也将导致系统每月2个多小时停机时间(99.99%^30 = 99.7%正常运行时间= 2 +小时/月)。 当一个API的依赖项在高容量下的延迟不断增加(造成阻塞请求线程),它会迅速(秒或次秒级)使所有可用的Tomcat(或其他容器如Jetty)请求线程饱和,然后整个API就挂了。
因此,架构设计是构建容错机制是一个高容量、高可用性应用程序的必须项,千万不要寄希望于基础设施来解决它。 |
Netflix依赖项操作的实现Netflix的面向服务的体系结构允许每个团队根据他们的需求自由选择最合适的传输协议和格式(XML、JSON、Thrift、Protocol Buffer等),所以在不同的服务中传输协议和格式可能不同。
|
每一个容错方法都有其利弊,但将其组合起来就可以在用户请求和底层依赖项之间架起全面的保护屏障。
|
我们决定将依赖调用隔离在独立的线程的好处多于缺点(在大多数情况下)。同时,API也可逐步提高并发能力,这是一个双赢的方案,既能提高容错性,又能提高并发性能。换句话说,单独线程的使用在很多用例中起到了积极的作用,它提升了执行调用的并发性,提升了Netflix的用户体验。
|
如果依赖项发生延迟(子系统最坏类型的故障),它可以使线程池中的所有的线程饱和,但是Tomcat请求线程将超时或立即被拒绝,而不是阻塞。
点击放大 除了隔绝性这个好处和并发执行依赖项调用外,我们也利用了单独的线程启用请求崩溃的机制(自动批处理)来提高整体效率,降低用户请求延迟。 如果已知依赖项不会执行网络调用(比如只做内存缓存查找),则使用信号量而不是线程来做容错处理,这些类型的操作开一个单独的线程的开销太大。 |
我们还使用信号来保护对非信任的回退。每个依赖命令能够确定这是对主叫用户线程执行,不应执行网络调用备用功能(详见下文讨论)。相反,相信所有的实现将正确地遵守本合同的,它也被信号灯保护的,所以,如果一个实现完成,涉及网络呼叫,并成为潜在的,后备本身将无法取下来的整个应用程序因为这将在多少线程限于它就能阻止。 |
当一段时间内的请求错误率超过阀值时触发跳闸回路(例如:10秒内错误率超过50%),拒绝所有请求,直到心跳恢复正常。 这主要用于释放潜在的系统压力(例如:流负载),当服务出现问题使用快速失败(或者返回一个失效值)的方式来减轻用户请求延迟。这种方式本质上是使用失败来代替用户请求超时。 任何一种描述超时,线程池或信号量拒绝,或者短路的方式都不是最佳方式来回答用户。 比快速抛出异常(或返回一个失效值)的方式来避免服务过载直至服务回复正常,更好的是把请求“堆积”后慢慢处理,这样能使Tomcat能从一次失败中快速恢复,并且保证Tomcat一致有可用线程去处理当前请求。 |
但是, 还有比直接返回失效更好的选项,提供一个“失效模式”来减少故障对用户的影响。 无论是什么原因(超时,拒绝请求,短路等)造成的失效或者中断,请求都通过一个失效逻辑(在上面流程图的第8步) ,在返回用户信息之前,尝试进行处理(使用户不会察觉出异常)。 下面是针对“失效模式”的解决办法,以对用户造成的影响进行排序。
以上所有的工作是为我们的用户保持最大正常运行时间与此同时为用户保持最多功能让他们有可能享受深的Netflix体验。最终,我们的目标是失效时传递的信息尽可能的接近系统正常时。 |
示例用例 下边是一个怎样配置线程,网络超时和重试机制相结合的例子:
上边的图表显示了一个示例配置,使用这种配置基本不会到达99.5 line(99.5 line:99.5%的用户都会在该时间内返回),该配置不仅会减少网络层的延迟,还会立即重试。大多数情况下,不仅请求会在平均延迟时间内完成,还会在300ms的线程超时内完成。 如果依赖于该配置,有合理的理由达到99.5 line的情况(例如,懒加载情况下缓存失效),这时网络超时需要设置的高过该情况的耗时,例如,进行一次0或1重试需要325ms,此时线程超时需要设置的高一点(350ms以上)。 |
在DependencyCommand层正确地配置超时应该是很少见的,为了防止网络延迟造成的影响,结合了连接+读数据+重试+连接+读数据,在最坏的情况下仍然会超过超时配置的。 进取性的配置和在每个方向上的折衷取决于每个不同的依赖。 |
结论在这篇文章中讨论的方法对我们系统的容错能力和弹性恢复能力有巨大的影响,基础设施和应用程序级别的失败不会影响(或有限的影响)用户体验。 |
本文转自:开源中国社区 [http://www.oschina.net]
本文标题:高容量分布式系统的容错
本文地址:http://www.oschina.net/translate/fault-tolerance-in-high-volume
参与翻译:雪落无痕xdj, 混元归一, BStorm, 无若
英文原文:Fault Tolerance in a High Volume, Distributed System
PS:特别鸣谢 赵今 同学让小编在译文的基础上补全了图片