微服务架构使得可以通过明确定义的服务边界来隔离故障。但是像在每个分布式系统中一样,发生网络、硬件、应用级别的错误都是很常见的。由于服务依赖关系,任何组件可能暂时无法提供服务。为了尽量减少部分中断的影响,我们需要构建容错服务,来优雅地处理这些中断的响应结果。

本文介绍了基于RisingStack 的 Node.js 咨询和开发经验构建和操作高可用性微服务系统的最常见技术和架构模式。

微服务架构的风险

微服务架构将应用程序逻辑移动到服务,并使用网络层在它们之间进行通信。这种通过网络间通信代替单应用程序内调用的做法,会带来额外的延迟,以及需要协调多个物理和逻辑组件的系统复杂度。分布式系统的复杂性增加也将导致更高的网络故障率。

microservices allow you to achieve graceful service degradation as components can be set up to fail separately.

微服务体系结构的最大优势之一是,团队可以独立设计,开发和部署他们的服务。他们对服务的生命周期拥有完全的所有权。这也意味着团队无法控制他们依赖的服务,因为它更有可能由不同的团队管理。

使用微服务架构,我们需要记住,提供者服务可能会临时不可用,由于其他人员发行的错误版本,配置以及其他更改等。

优雅的服务降级

微服务架构的最大优点之一是您可以隔离故障,并在当组件单独故障时,进行优雅的服务降级。例如,在中断期间,照片共享应用程序中的客户可能无法上传新图片,但仍可以浏览,编辑和共享其现有照片。

在大多数情况下,由于分布式系统中的应用程序相互依赖,因此很难实现这种优雅的服务降级,您需要应用几种故障转移的逻辑(其中一些将在本文后面介绍),以为暂时的故障和中断做准备。

变更管理

Google的网站可靠性小组发现,大约70%的中断是由现有系统的变化引起的。当您更改服务中的某些内容时,您将部署新版本的代码或更改某些配置 - 这总有可能会造成故障,或者引入新的bug。

在微服务架构中,服务依赖于彼此。这就是为什么你应该尽量减少故障并限制它的负面影响。要处理变更中的问题,您可以实施变更管理策略和自动回滚机制。

例如,当您部署新代码或更改某些配置时,您应该先小范围的进行部分的替换,以渐进式的方式替换服务的全部实例。在这期间,需要监视它们,如果您发现它们对您的关键指标有负面影响,应立即进行服务回滚,这称为“金丝雀部署”。

另一个解决方案可能是您运行两个生产环境。您始终只能部署其中一个,并且在验证新版本是否符合预期之后才,将负载均衡器指向新的。这称为蓝绿或红黑部署。

回滚代码不是坏事。你不应该在生产中遗留错误的代码,然后考虑出了什么问题。如果必要,越早回滚你的代码越好。

健康检查与负载均衡

实例由于出现故障、部署或自动缩放的情况,会进行持续启动、重新启动或停止操作。它可能导致它们暂时或永久不可用。为避免问题,您的负载均衡器应该从路由中跳过不健康的实例,因为它们当前无法为客户或子系统提供服务。

应用实例健康状况可以通过外部观察来确定。您可以通过重复调用GET /health端点或通过自我报告来实现。现在主流的服务发现解决方案,会持续从实例中收集健康信息,并配置负载均衡器,将流量仅路由到健康的组件上。

自我修复

自我修复可以帮助应用程序从错误中恢复过来。当应用程序可以采取必要步骤从故障状态恢复时,我们就可以说它是可以实现自我修复的。在大多数情况下,它由外部系统实现,该系统会监视实例运行状况,并在较长时间内处于故障状态时重新启动它们。自我修复在大多数情况下是非常有用的。但是在某些情况下,持续地重启应用程序可能会导致麻烦。当您的应用程序由于超负荷或其数据库连接超时而无法给出健康的运行状况时,这种情况下的频繁的重启就可能就不太合适了。

对于这种特殊的场景(如丢失的数据库连接),要实现满足它的高级自我修复的解决方案可能很棘手。在这种情况下,您需要为应用程序添加额外的逻辑来处理边缘情况,并让外部系统知道实例不需要立即重新启动。

故障转移缓存

由于网络问题和我们系统的变化,服务经常会失败。然而,由于自我修复和负载均衡的保障,它们中的大多数中断是临时的,我们应该找到一个解决方案,使我们的服务在这些故障时服务仍就可以工作。这就是故障转移缓存 (failover caching)的作用,它可以帮助并为我们的应用程序在服务故障时提供必要的数据。

故障转移缓存通常使用两个不同的过期日期; 较短的时间告诉您在正常情况下缓存可以使用的过期时间,而较长的时间可以在服务故障时缓存依旧可用的过期时间。

请务必提及,只有当服务使用过时的数据比没有数据更好时,才能使用故障转移缓存。

要设置缓存和故障转移缓存,可以在 HTTP 中使用标准响应头。

例如,使用 max-age 属性可以指定资源被视为有效的最大时间。使用 stale-if-error 属性,您可以明确在出现故障的情况下,依旧可以从缓存中获取资源的最大时间。

现代的 CDN 和负载均衡器都提供各种缓存和故障转移行为,但您也可以为拥有标准可靠性解决方案的公司创建一个共享库。

重试逻辑

在某些情况下,我们无法缓存数据,或者我们想对其进行更改,但是我们的操作最终都失败了。对于此,我们可以重试我们的操作,因为我们可以预期资源将在一段时间后恢复,或者我们的负载均衡器将请求发送到了健康的实例上。

您应该小心地为您的应用程序和客户端添加重试逻辑,因为大量的重试可能会使事情更糟,甚至阻止应用程序恢复,如当服务超载时,大量的重试只能使状况更糟。

在分布式系统中,微服务系统重试可以触发多个其他请求或重试,并启动级联效应。为了最小化重试的影响,您应该限制它们的数量,并使用指数退避算法来持续增加重试之间的延迟,直到达到最大限制。

当客户端(浏览器,其他微服务等)发起重试,并且客户端不知道在处理请求之前或之后操作失败时,您应该为你的应用程序做好幂等处理的准备。例如,当您重试购买操作时,您不应该再次向客户收取费用。为每个交易使用唯一的幂等值键可以帮助处理重试。

限流器和负载降级

流量限制是在一段时间内定义特定客户或应用程序可以接收或处理多少个请求的技术。例如,通过流量限制,您可以过滤掉造成流量峰值的客户和服务,或者您可以确保您的应用程序在自动缩放无法满足时,依然不会超载。

您还可以阻止较低优先级的流量,为关键事务提供足够的资源。

有一个不同类型的限流器,叫做并发请求限制器。当您有重要的端点,您不应该被调用超过指定的次数,而您仍然想要能提供服务时,这将是有用的。

负载降级的一系列使用,可以确保总是有足够的资源来提供关键交易。它为高优先级请求保留一些资源,不允许低优先级的事务使用它们。负载降级开关是根据系统的整体状态做出决定,而不是基于单个用户的请求量大小。负载降级有助于您的系统恢复,因为当你有一个偶发事件时(可能是一个热点事件),您仍能保持核心功能的正常工作。

要了解有关限流器和负载降级的更多信息,我建议查看这篇Stripe的文章。

快速失败原则与独立性

在微服务架构中,我们想要做到让我们的服务具备快速失败与相互独立的能力。为了在服务级别上进行故障隔离,我们可以使用舱壁模式。你可以在本文的后面有关舱壁的内容。

我们也希望我们的组件能够快速失败,因为我们不希望对于有故障的服务,在请求超时后才断开。没有什么比挂起的请求和无响应的 UI 更令人失望。这不仅浪费资源,而且还会影响用户体验。我们的服务在调用链中是相互调用的,所以在这些延迟累加之前,我们应该特别注意防止挂起操作。

你想到的第一个想法是对每个服务调用都设置明确的超时等级。这种方法的问题是,您不能知道真正合理的超时值是多少,因为网络故障和其他问题发生的某些情况只会影响一两次操作。在这种情况下,如果只有其中一些超时,您可能不想拒绝这些请求。

我们可以说,在微服务种通过使用超时来达到快速失败的效果是一种反模式的,你应该避免使用它。取而代之,您可以应用断路器模式,依据操作的成功与失败统计数据决定。

舱壁模式

工业中使用舱壁将船舶划分为几个部分,以便在船体破坏的情况下,可以将船舶各个部件密封起来。

舱壁的概念在软件开发中可以被应用在隔离资源上。

通过应用舱壁模式,我们可以保护有限的资源不被耗尽。例如,对于一个有连接数限制的数据库实例来说,如果我们有两种连接它的操作,我们采用可以采用两个连接池的方式进行连接,来代替仅采用一个共享连接池的方式。由于这种客户端与资源进行了隔离,超时或过度使用池的操作页不会使其他操作失败。

泰坦尼克号沉没的主要原因之一是其舱壁设计失败,水可以通过上面的甲板倒在舱壁的顶部,导致整个船体淹没。

断路器

为了限制操作的持续时间,我们可以使用超时。超时可以防止挂起操作并保持系统响应。然而,在微服务中使用静态、精细的超时是一种反模式,因为我们处于高度动态的环境中,几乎不可能提出在每种情况下都能正常工作的正确的时间限制。

替代这种静态超时的手段是,我们可以使用断路器来处理错误。断路器以现实世界的电子元件命名,因为它们的作用是相同的。您可以保护资源,并帮助他们使用断路器进行恢复。它们在分布式系统中非常有用,因为在分布式系统中,重复故障可能导致雪球效应并使整个系统瘫痪。

当特定类型的错误在短时间内多次发生时,断路器会被断开。开路的断路器可以防止进一步的请求 - 就像我们平时所说的电路跳闸一样。断路器通常在一定时间后关闭,在这期间可以为底层服务提供足够的空间来恢复。

请记住,并不是所有的错误都应该触发断路器。例如,您可能希望跳过客户端问题,例如具有4xx响应代码的请求,但不包括5xx服务器端故障。一些断路器也具有半开状态。在这种状态下,服务发送第一个请求以检查系统可用性,同时让其他请求失败。如果这个第一个请求成功,它将使断路器恢复到关闭状态并使流量流动。否则,它保持打开。

测试故障

您应该不断测试您系统的常见问题,以确保您的服务可以抵抗各种故障。您应经常测试故障,让您的团队具备故障处理的能力。

对于测试,您可以使用外部服务来标识实例组,并随机终止此组中的一个实例。这样,您可以准备单个实例故障,但您甚至可以关闭整个区域来模拟云提供商的故障。

最流行的测试解决方案之一是 Netflix 的 ChaosMonkey 弹性工具。

结尾

实施和运行可靠的服务并不容易。您需要付出很多努力,同时公司也要有相应的财力投入。

可靠性有很多层次和方面,因此找到最适合您团队的解决方案很重要。您应该使可靠性成为您的业务决策流程中的一个因素,并为其分配足够的预算和时间。

关键点

  • 动态环境和分布式系统(如微服务)会导致更高的故障机率;

  • 服务应该做到故障隔离,到达优雅降级,来提升用户体验;

  • 70%的中断是由变化引起的,代码回滚不是一件坏事;

  • 做到服务快速失败与独立性。团队是无法控制他们所依赖的服务情况;

  • 缓存、舱壁、断路器和限流器等架构模式与技术有助于构建可靠的微服务架构。

原文: Designing a Microservices Architecture for Failure
翻译: by Jason Geng

·················· END ··················

关注公众号,免费领取程序员成长大礼包

十年研发路,大厂架构师,CSDN博客专家

专注架构技术学习及分享,职业与认知升级

坚持分享接地气儿的干货,期待与你一起成长

推荐阅读

消息中间件

架构应用汇总

认知升级迭代

MySQL实用探秘


「架构精进之路」专注架构研究,技术分享

点“赞”和“在看”哦

如何设计一个容错的微服务架构相关推荐

  1. 阿里云MVP:如何设计实现一个通用的微服务架构?

    最近有看到"微服务,分久必合.合久必分"的言论,我同意,微服务不是架构演变的终点,细说还有Serverless.FaaS等方向.但纠结要不要拆分是没有必要的,拆往往是随着业务变化不 ...

  2. 如何设计高可用的微服务架构

    http://www.infoq.com/cn/articles/designing-a-microservices-architecture-for-failure 要点 动态的环境和分布式的系统, ...

  3. 设计一个成功的微服务,堪称必备的9个基础知识

    点击上方"方志朋",选择"设为星标" 回复"666"获取新整理的面试文章 人体是不同系统的组合,其中大多数系统是独立的,并且作为一个整体协同 ...

  4. 设计一个成功的微服务,堪称必备的9大基础知识

    人体是不同系统的组合,其中大多数系统是独立的,并且作为一个整体协同工作.每个系统都有自己的特定功能.所有具有多种其他支持框架的器官构成了一个功能完备的机构.现在,如果应用于软件系统,这就是微服务架构的 ...

  5. 如何快速搭建一个 “简单模式” 的微服务架构

    何谓微服务架构的简单模式? 相对于大型互联网平台动辄几万并发的访问量,或者每天多次的在线版本发布,绝大多数企业和项目并没有这样的需求.他们关注的是如何更好地提高开发效率,如何更快地实现新需求,如何更便 ...

  6. 微服务架构设计总结实践

    -     目录    - 一.微服务架构介绍 二.出现和发展 三.传统开发模式和微服务的区别 四.微服务的具体特征 五.SOA和微服务的区别 六.如何具体实践微服务 七.常见的微服务设计模式和应用 ...

  7. 微服务架构与领域驱动设计应用实践

    本篇文章一共分为三个部分,分别是微服务架构的演进过程.具体实践微服务的应用技术和领域驱动设计的意识转变.微服务架构已经渗透到互联网应用的方方面面,而领域驱动设计也逐渐被业界所接收. 微服务架构几乎都是 ...

  8. 大项目微服务架构设计

    根据目前产品存在的问题,针对快速开发.海量用户.大量数据.低延迟等互联网应用的实际需要,通过对业务架构.系统架构.基础架构.技术架构进行分析,采用先进实用的微服务SOA架构重构智慧校园.数字化校园等产 ...

  9. 微服务_SpringCloud微服务架构实战:高并发微服务架构设计

    高并发微服务架构设计 作为一个 IT 从业人员,我们经常会碰到类似于下面的一些问题: 单个项目巨大而沉重,难以维护. 系统稳定性得不到更有效的保证. 怎样才能持续地提升系统的性能. 怎样才能快速地响应 ...

最新文章

  1. IBM 火雪挺:人工智能如何影响衣食住行?
  2. svr公式推导_支持向量回归(SVR)的详细介绍以及推导算法
  3. 341期计算机开机号总汇,◆341期谜语汇总 ◆
  4. HyperLogLog 命令详解
  5. Python学习入门基础教程(learning Python)--6 Python下的list数据类型
  6. matlab 常用 api(七)—— 常见判断(返回 logical)
  7. 高德定位html,Ionic3 高德Web定位
  8. 使用IDEA,利用SpringMVC框架建立HelloWorld项目
  9. MODSCAN32的应用
  10. 计算机与食品科学与工程关系,计算机在食品科学与工程中的应用课程标准.doc...
  11. android感应不了夜神模拟器,夜神模拟器使用(检测不到)
  12. 排序负数排在左边非负数排在右边
  13. “网络相亲”三大纪律八项注意
  14. 一. Mybits简单使用
  15. 题解 乃爱与城市拥挤程度
  16. frequency bins解释
  17. ubuntu14.04安装谷歌输入法
  18. matlab如何去除图像白边_MATLAB去除白边
  19. 关于“智能出价“的一些探索和实践
  20. 7月30日—31日英特尔开源物联网大会直播,欢迎收看

热门文章

  1. Discuz留言墙等祝福墙实现:纯js+html
  2. C# WinForm 设置DataGridView选中指定行
  3. 用java画爱心图_Java画心形线
  4. 数电学习(三、半导体二极管门电路)(三)
  5. 在html中,书写多个连续的空格,但在页面中无效的问题
  6. Impala 中invalidate metadata和refresh
  7. 08.Unity ShaderGraph实例(使用PBR渲染精灵动画)
  8. python 单通道wav转成双通道wav
  9. 读养生四要有感《法时篇》
  10. Android仿淘宝历史搜索功能,使用localStorage实现历史记录搜索功能也便是天猫app历史记录存储方便浏览...