当前位置: 首页 > 后端技术 > Java

微服务架构如何避免大规模故障?

时间:2023-04-01 19:24:45 Java

微服务架构通过良好的服务边界划分,可以有效隔离故障。但与任何其他分布式系统一样,在网络、硬件或应用程序级别出现问题的可能性更高。服务的依赖性使得任何组件的暂时不可用对于它们的消费者来说是可以接受的。为了减少部分服务中断的影响,我们需要构建一个容错服务,优雅地处理某些类型的服务中断。本文基于在RisingStack的一些咨询和开发经验,介绍如何使用一些最常用的技术和架构模型来构建和维护一个高可用的微服务系统。如果您不熟悉本文中的模式,并不意味着您做错了什么。毕竟,构建一个高可用的系统需要付出很多额外的努力。*TheRiskoftheMicroservicesArchitecture微服务架构的风险微服务架构将应用的逻辑移动到服务中,服务通过网络层进行通信和交互。网络通信交互的方式代替了内存的调用,同时需要多个物理和逻辑组件之间的协作,给系统带来了额外的延迟和复杂性。分布式系统复杂性的增加导致某些网络故障的可能性更大。微服务允许您实现优雅的服务降级,因为组件可以单独设置为失败。微服务的最大优势之一是团队可以独立设计、开发和部署他们的服务。他们完全拥有服务的整个生命周期,这也意味着团队无法控制他们的服务依赖性,因为这些服务更有可能由不同的团队管理。我们需要记住,由于发布中断、配置更改等原因而导致服务暂时不可用的提供者受控于其他人并且彼此独立行动。*优雅的服务降级GracefulServiceDegradation微服务最大的优势之一,当一个组件单独出现故障时,可以实现优雅的服务降级和故障隔离。例如,对于照片共享应用程序,用户可能由于中断而无法上传新照片,但他们仍然可以浏览、编辑和共享他们现有的照片。大多数情况下,在应用程序相互依赖的分布式系统中,很难实现服务的优雅降级,需要采用各种故障转移逻辑(其中一些将在本文后面讨论。讨论)来处理临时故障和中断。*变更管理变更管理GoogleSites的可靠性团队(SRE)发现大约70%的中断是由实时系统变更引起的。当您更改服务中的某些内容时-您部署新版本的代码或更改某些配置-失败或引入新错误的可能性总是更高。在微服务架构中,服务相互依赖。这就是为什么您应该尽量减少失败并限制其负面影响。如果要处理变更带来的问题,可以使用变更管理策略和自动升级。例如,当您需要部署新代码或更改某些配置时,您应该逐渐将这些更改应用于实例子集,监控它们,甚至在您发现对关键指标产生负面影响时自动回滚它们。另一种解决方案是运行两个生产环境。只部署其中一个,只有在验证新版本按预期工作后,才将负载均衡器指向新版本。这称为蓝绿部署或红黑部署。恢复代码不是坏事。您不应该在生产中留下错误的代码,然后想知道哪里出了问题。始终在必要时恢复您的更改(回滚),越快越好。*HealthCheckandLoadBalancingHealth-checkandLoadBalancing实例由于故障、部署或自动缩放而不断启动、重新启动和停止。这可能会导致服务暂时或永久不可用。为避免出现问题,您的负载均衡器应跳过不健康的实例,因为它们无法满足您的用户或子系统的需求。应用程序实例的健康状况可以通过外部观察来确定。您可以反复调用GET/health来请求埋葬或自我报告。现代服务发现解决方案将持续从实例中收集健康信息并配置负载均衡以确保健康的组件路由流量。*自我修复自我修复可以帮助恢复应用程序。当我们谈论自我修复时,我们的意思是应用程序可以执行必要的步骤从崩溃中恢复。在大多数情况下,这是通过一个外部系统来完成的,该系统监视实例的健康状况,并在它们长时间处于错误状态时重新启动应用程序。自我修复非常有用,但在某些情况下,不断重启应用程序会造成麻烦。由于高负载或数据库连接超时,您的应用程序不断重启,这将无法提供正确的健康状态。实施为微妙情况(例如丢失数据库连接)准备的高级自我修复解决方案可能很棘手。在这种情况下,您需要向应用程序添加额外的逻辑来处理一些极端情况,并让外部系统知道该实例不需要立即重启。*故障转移缓存故障转移缓存服务通常会因网络问题和系统更改而失败。由于自我修复和先进的负载平衡,大多数中断只是暂时的,但我们也应该找到一个解决方案,让我们的服务在这些故障期间正常工作。这是故障转移缓存,它帮助应用程序提供一些必要的数据。故障转移缓存通常使用两个不同的过期时间。设置较短的时间以显示缓存在正常情况下可用多长时间,并设置较长的时间以显示缓存数据在故障期间可用多长时间。当陈旧数据比什么都不做要好时,只运行故障转移缓冲区很重要。可以使用HTTP中的标准响应标头设置缓存和故障转移缓存。例如,通过设置header参数max-age来指定资源刷新的最长时间;也可以设置header参数stale-if-error来决定服务失败时需要多长时间从缓存中获取数据。现代CDN和负载均衡器提供了多种缓存和故障转移方法,您还可以建立一个共享标准库,其中包含公司统一的可靠性解决方案。*重试机制RetryLogic在某些特定场景下,我们可能无法缓存数据,或者我们想对其进行一些更改,但我们的操作最终会失败。在这些情况下,我们可以重试我们的操作,因为我们可以期待资源在一段时间后恢复,或者我们的负载均衡器将我们的请求转发到一个健康的实例。在向您的应用程序和客户端添加重试逻辑时要谨慎,因为大量重试会使事情变得更糟,甚至会阻止您的应用程序恢复。在分布式系统中,微服务系统重试会触发多个其他请求或重试,造成级联效应。为了尽量减少重试的影响,您应该尽量减少重试的次数,并使用指数退避算法不断增加重试之间的延迟。重试由客户端(浏览器、其他微服务等)发起,客户端不知道操作失败是在请求处理之前还是之后,你应该准备你的应用程序来处理幂等性。例如,当操作重试购买时,不应向用户收取两次费用。对于每笔交易,使用一个唯一的幂等性令牌(idempotency-key),它可以帮助处理重试。*RateLimitersandLoadSheddersRateLimitersandLoadShedders当前限制是指特定用户或应用程序在一段时间内可以接收或处理多少请求的技术。例如,通过节流,您可以识别导致流量高峰的用户和微服务,或者您可以确保应用程序不会在负载过高时通过自动缩放来挽救。您还可以限制较低优先级的流量,为核心业务提供足够的资源。另一种类型的速率限制器称为并发请求限制器。当有一些昂贵的端点不应被调用超过指定次数,但您仍想为流量提供服务时,选择此类操作很有用。快速降级确保始终有足够的资源可用于服务关键事务。它为高优先级的请求保留一些资源,不允许低优先级的事务使用所有资源。是否降级是根据系统的整体状态来判断的,而不是根据单个用户的请求桶大小来判断的。服务降级用于帮助恢复系统,当出现问题时,它们可以使核心功能保持正常运行。有关速率限制和降尺度的更多信息,建议访问https://stripe.com/blog/rate-...并阅读Stripe的文章。*FailFastandIndependentlyFailFastandIndependently在微服务架构中,我们希望我们的服务能够快速且独立地失败。为了隔离服务级别的问题,我们可以使用隔板模式。您可以在本文后面阅读有关隔板的更多信息。我们还希望我们的组件快速失败,因为我们不想等待坏实例超时。没有什么比挂起的请求和无响应的UI更令人沮丧的了。这不仅浪费资源,而且影响用户体验。我们的服务正在互相调用,因此在这些延迟过去之前,应格外小心以防止挂起的操作。想到的第一个想法是在每个服务调用上应用良好的超时级别。这种方法的问题是你无法真正知道什么是好的超时值,因为在某些情况下,网络故障和其他问题只会影响一两个操作。在这种情况下,如果只有少数请求超时,您可能不想拒绝请求。我们可以说在微服务中使用超时来快速失败的例子是一种反模式,你应该避免它。您可以依赖操纵成功/失败统计信息的断路器模式,而不是超时。*舱壁舱壁用于将船分成几个部分,以便在船体破裂时可以关闭部分。隔离墙的概念可以应用在软件开发中,实现资源隔离。通过采用舱壁模式,我们可以保护有限的资源不被耗尽。例如,如果我们有两个操作,它们与同一个数据库实例交互,并且我们的连接数量有限,那么我们可以使用两个连接池而不是共享连接池。由于客户端资源的这种分离,当发生超时或过度使用连接池的操作时,不会导致所有其他操作关闭。泰坦尼克号沉没的主要原因之一是其舱壁存在设计故障,导致水通过舱壁顶部的甲板注入,淹没了整个船体。*CircuitBreakersCircuitBreakers为了限制操作的持续时间,我们可以使用超时。超时可防止挂起操作并保持系统响应。然而,在微服务通信中使用静态的、微调的超时是一种反模式,因为我们处于高度动态的环境中,几乎不可能发现正确的时间限制以确保在每个场景中都具有良好的性能。好好工作。我们可以使用断路器来处理错误,而不是使用小的特定于事务的静态超时。断路器以现实世界的电子元件命名,因为它们的行为相同(简单地说,这个模型基本上是一个熔断的参考电路,如果一根线太高,保险丝就会熔断,从而防止火灾)。您可以使用断路器保护资源并帮助它们恢复。它们在分布式系统中非常有用,在分布式系统中,重复的故障会导致滚雪球效应,从而导致整个系统瘫痪。当特定类型的错误在短时间内多次发生时,断路器打开。断路器的打开会阻止进一步的资源请求——就像字面上停止电流一样。断路器通常会在一定时间后关闭,从而为底层服务的恢复留出足够的空间。请记住,并非所有错误都应触发断路器。例如,您可能希望跳过客户端问题,例如具有4xx状态代码响应的请求,而不是具有5xx服务器端错误的请求。一些断路器也可以有半开状态,在这种状态下,服务发送第一个请求以检查系统的可用性,同时让其他请求失败。如果第一个请求成功,它将断路器返回到关闭状态并允许流量进入。否则,它将打开。*TestingfailuresTestingforFailures您应该不断地测试您的系统以防止常见问题,以确保您的服务能够承受各种故障。你应该经常让你的测试失败,让你的团队为事故做好准备。对于测试,您可以使用外部服务来识别实例组并随机终止该组中的实例。有了这个,您可以为单个实例的故障做好准备,您甚至可以关闭整个可用区来模拟云提供商的中断。最受欢迎的测试解决方案之一是Netflix提供的ChaosMonkey弹性工具。*结束实施和运行可靠的服务并不容易。这需要您付出很多努力,并使您的公司损失很多钱。可靠性有很多层次和方面,因此为您的团队找到最佳解决方案很重要。您应该将可靠性纳入业务决策过程,并为其分配足够的预算和时间。*主要收获动态环境和分布式系统——例如微服务——导致更大的失败机会。服务应该单独失败并优雅地降级以改善用户体验。70%的中断是由更改引起的,恢复代码并不是一件坏事。快速且独立的故障。团队无法控制其服务的依赖性。缓存、隔板、节流、熔断等架构模式和技术有助于构建可靠的微服务。原文:https://blog.risingstack.com/...翻译:https://blog.csdn.net/xushuai...推荐近期文章:1.1,000+Java面试题及答案(2021最新版)2.别再满脑子if/else了,试试策略模式,真的很好吃!!3.操!Java中xx≠null的新语法是什么?4、SpringBoot2.5发布,深色模式太炸了!5.《Java开发手册(嵩山版)》最新发布,赶快下载吧!感觉不错,别忘了点赞+转发!