12、架构-流量治理之服务容错

概述

容错性设计(Design for Failure)是微服务的另一个核心原 则,也是笔者书中反复强调的开发观念转变。不过,即使已经有一定 的心理准备,大多数首次将微服务架构引入实际生产系统的开发者, 在服务发现、网关路由等支持下,踏出了服务化的第一步以后,很可 能仍会经历一段阵痛期,随着拆分出的服务越来越多,随之而来会面 临以下两个问题的困扰。

  • 由于某一个服务的崩溃,导致所有用到这个服务的其他服务都 无法正常工作,一个点的错误经过层层传递,最终波及调用链上与此 有关的所有服务,这便是雪崩效应。如何防止雪崩效应便是微服务架 构容错性设计原则的具体实践,否则服务化程度越高,整个系统反而 越不稳定。
  • 服务虽然没有崩溃,但由于处理能力有限,面临超过预期的突 发请求时,大部分请求直至超时都无法完成处理。这种现象产生的后 果与交通堵塞类似,如果一开始没有得到及时的治理,后面就需要很 长时间才能使全部服务都恢复正常。

本章我们将围绕以上两个问题,提出服务容错、流量控制等一系列解决方案。这些措施并不是孤立的,它们相互之间存在很多联系,其中许多功能必须与此前介绍过的服务注册中心、服务网关、负载均衡器配合才能实现。理清楚这些技术措施背后的逻辑链条,是了解它 们工作原理的捷径。

服务容错

在现代分布式系统的构建中,服务容错设计是一个不可或缺的主题。Martin Fowler与James Lewis提出的"微服务的九个核心特征"是构建微服务系统的指导性原则,但不是技术规范,没有严格的约束力。在实际构建系统时,其中多数特征可能会有或多或少的妥协,比如分散治理、数据去中心化、轻量级通信机制、演进式设计,等等。但也有一些特征是不能妥协的,其中的典型就是今天我们讨论的主题:容错性设计。

容错性设计不能妥协的原因在于分布式系统的不可靠性。一个大的服务集群中,程序可能崩溃、节点可能宕机、网络可能中断,这些"意外情况"其实全部都在"意料之中"。原本信息系统设计成分布式架构的主要动力之一就是为了提升系统的可用性,最低限度也必须保证将原有系统重构为分布式架构之后,可用性不下降才行。如果服务集群中出现任何一点差错都能让系统面临"千里之堤溃于蚁穴"的风险,那分布式恐怕就没有机会成为一种可用的系统架构形式了。

容错性设计的必要性

在一个复杂的分布式系统中,服务之间通过网络进行通信,而网络的不可靠性和服务本身的复杂性使得故障不可避免。常见的故障类型包括硬件故障、软件故障、网络故障和人为错误。这些故障如果没有有效的容错机制,将对系统的可用性和稳定性造成严重影响。

容错性设计的核心理念是"设计中包含对失败的预期和应对措施",这有助于避免系统因单点故障而发生崩溃,从而提升整体系统的稳定性和可靠性。接下来,我们将详细探讨几种常见的容错策略和设计模式。

容错策略

  1. 故障转移(Failover): 故障转移是指当某个服务节点发生故障时,系统会自动切换到其他服务副本,以保证服务的连续性。实现这种策略需要使用负载均衡器或服务注册发现工具(如Consul、Eureka)。例如,当服务A所在的节点出现故障时,负载均衡器会将流量重定向到服务A的另一副本。这种机制保证了即使某个节点故障,用户的请求仍能被正常处理。然而,故障转移策略需要限制重试次数,以避免因频繁切换导致的系统不稳定。

  2. 快速失败(Failfast): 在某些情况下,服务不允许进行故障转移,因为故障转移可能会导致重复数据或其他问题。快速失败策略在检测到故障后立即返回错误,而不是进行重试,以避免进一步的问题。举例来说,在一个实时支付系统中,如果服务B发生故障,与其反复重试导致延迟增加,不如快速返回错误,让上游服务进行处理。

  3. 安全失败(Failsafe): 对于一些非关键服务或旁路逻辑,即使发生故障,也不会影响核心业务的正常运行。安全失败策略允许这些非关键服务在发生故障时返回默认值或零值,以保证系统的稳定性。例如,在一个推荐系统中,如果推荐服务出现问题,可以返回一个空列表,而不影响用户的购物流程。

  4. 沉默失败(Failsilent): 当某个服务出现大量超时时,系统会默认该服务在一定时间内无法提供服务,从而将其隔离,避免对系统其他部分造成影响。例如,如果服务C的响应时间显著增加,系统可以将其标记为不可用,暂时不再发出请求。

  5. 故障恢复(Failback): 在故障发生后,系统会自动尝试重试调用,并在后台异步处理这些请求,直到成功。故障恢复通常与快速失败结合使用。例如,在订单处理系统中,如果某个订单处理服务失败,系统可以将失败的订单放入队列中,并在后台进行重试,直到处理成功。

  6. 并行调用(Forking): 系统同时向多个服务副本发起调用,只要其中一个返回成功,就认为调用成功。这种策略增加了成功的概率和响应速度,适用于关键业务场景。例如,在支付系统中,可以同时向多个支付网关发起请求,哪个先返回成功就采用哪个的结果。

  7. 广播调用(Broadcast): 系统同时向多个服务副本发起调用,所有调用必须成功才认为此次调用成功。这种策略通常用于需要确保数据一致性的场景,如刷新分布式缓存。例如,在数据同步系统中,向所有节点广播更新指令,确保每个节点的数据都得到更新。

容错设计模式

  1. 断路器模式(Circuit Breaker): 断路器模式通过监控服务调用的成功和失败次数,当故障次数达到阈值时,将断路器状态切换为"OPEN",直接返回失败,不再发出远程请求,从而避免因持续失败导致系统资源消耗和请求堆积。这种模式有三个状态:

    • 关闭(Closed):服务正常运行,所有请求正常通过。
    • 打开(Open):检测到连续多次失败,断路器打开,直接拒绝请求。
    • 半开(Half-Open):经过一段时间,断路器尝试部分请求,若成功则恢复正常状态,否则继续保持打开。

    例如,Netflix的Hystrix库实现了断路器模式,当某个服务的错误率超过设定阈值时,Hystrix会打开断路器,短时间内不再向该服务发起请求,从而保护系统不被单个服务的故障拖垮。

  2. 舱壁隔离模式(Bulkhead Isolation): 舱壁隔离模式通过将系统资源隔离成多个独立的部分,防止某一部分的故障影响整个系统。比如,可以为不同的服务分配独立的线程池、连接池等资源,确保某个服务的资源消耗不会影响其他服务。就像船只的舱壁一样,即使一个舱壁进水,也不会影响整艘船的浮力。

    例如,假设系统中有服务A和服务B,它们分别使用独立的线程池。如果服务A由于突发流量导致线程池耗尽,服务B仍然可以正常工作,因为它不受服务A的影响。

  3. 重试模式(Retry): 重试模式在请求失败后自动重试,增加请求成功的概率。可以在调用逻辑中实现重试机制,设置重试次数和间隔时间。例如,在一个文件上传系统中,如果上传失败,可以设置重试三次,每次间隔五秒,以增加上传成功的几率。

  4. 服务降级(Fallback): 服务降级策略在服务发生故障时提供降级逻辑,确保系统在某种程度上仍能提供服务。例如,当推荐服务发生故障时,可以返回缓存的推荐结果或默认推荐列表,而不是返回错误。通过这种方式,系统在部分功能失效的情况下仍能提供基本服务。

容错实现技术和工具

  1. Netflix Hystrix: Hystrix是Netflix开源的一个库,用于实现熔断、隔离、限流等容错机制。Hystrix能够帮助开发者迅速搭建容错体系。其主要功能包括:

    • 熔断器:实现断路器模式,防止故障扩散。
    • 隔离策略:通过独立的线程池隔离不同的服务,防止资源争用。
    • 请求缓存:在短时间内缓存请求结果,减少重复调用。
    • 监控与报警:提供丰富的监控指标和报警机制,帮助及时发现和处理故障。
  2. Sentinel: Sentinel是阿里巴巴开源的一个高可用防护组件,提供了丰富的流量控制、熔断降级、系统负载保护等功能。其主要功能包括:

    • 流量控制:通过设置流量阈值,防止系统过载。
    • 熔断降级:实现断路器和服务降级功能,保证系统稳定性。
    • 热点参数限流:对热点参数进行限流保护,避免单点压力过大。
    • 系统负载保护:根据系统负载自动调整限流策略,保证系统在高负载下的稳定性。
  3. Resilience4j: Resilience4j是一个轻量级、函数式的容错库,灵感来自于Hystrix,但设计上更为现代化,支持Java 8及以上版本。其主要功能包括:

    • 熔断器:实现断路器模式,防止故障扩散。
    • 重试:实现重试机制,增加请求成功的概率。
    • 限流:对请求进行限流保护,防止系统过载。
    • 缓存:在短时间内缓存请求结果,减少重复调用。

实际应用中的考虑

  1. 监控和报警: 实时监控系统的运行状态,及时发现和处理故障。可以使用Prometheus、Grafana等工具进行监控和报警设置。通过设置关键服务的性能指标,如响应时间、错误率等,可以实时监控系统的健康状况,并根据这些指标设置报警阈值,当指标超过阈值时触发报警,确保故障能够及时被发现和处理。

  2. 容量规划: 通过压力测试和容量评估,合理规划系统资源,确保系统在高并发和高负载下仍能稳定运行。例如,可以通过模拟高并发场景进行压力测试,测试系统的最大承载能力。根据压力测试结果,确定系统需要的资源配置,并设置自动扩展策略,根据系统负载自动调整资源配置。这样可以确保系统在高并发请求下仍能保持稳定和高效。

  3. 分布式事务管理: 在分布式系统中,事务管理是一个复杂的问题。可以使用TCC(Try-Confirm-Cancel)、Saga等模式来管理分布式事务,确保数据的一致性和可靠性。例如,TCC模式将事务拆分为尝试、确认、取消三个阶段,确保事务的一致性。Saga模式则将事务拆分为一系列独立的小事务,通过补偿操作来保证最终一致性。这些模式在需要跨多个服务的事务场景中非常有效,如订单处理、支付流程等。

结论

服务容错是保证分布式系统高可用性和可靠性的重要手段。通过合理使用故障转移、快速失败、安全失败、沉默失败、故障恢复、并行调用、广播调用等策略,以及断路器、舱壁隔离、重试、服务降级等设计模式,并结合实际场景进行优化和调整,可以有效提升系统的稳定性和容错能力。

在分布式系统中,服务容错不仅是技术上的挑战,更是设计理念上的转变。通过前面详述的各种策略和模式,我们可以看到,容错设计不仅仅是为了应对故障,更是为了构建一个具有高弹性和高可用性的系统。这种系统能够在面对各种不确定因素时,仍能保持稳定和可靠,最终为用户提供持续的优质服务。

相关推荐
魔道不误砍柴功2 小时前
Java 中如何巧妙应用 Function 让方法复用性更强
java·开发语言·python
NiNg_1_2342 小时前
SpringBoot整合SpringSecurity实现密码加密解密、登录认证退出功能
java·spring boot·后端
闲晨2 小时前
C++ 继承:代码传承的魔法棒,开启奇幻编程之旅
java·c语言·开发语言·c++·经验分享
_.Switch2 小时前
高级Python自动化运维:容器安全与网络策略的深度解析
运维·网络·python·安全·自动化·devops
2401_850410832 小时前
文件系统和日志管理
linux·运维·服务器
JokerSZ.2 小时前
【基于LSM的ELF文件安全模块设计】参考
运维·网络·安全
芯盾时代3 小时前
数字身份发展趋势前瞻:身份韧性与安全
运维·安全·网络安全·密码学·信息与通信
Chrikk3 小时前
Go-性能调优实战案例
开发语言·后端·golang
幼儿园老大*3 小时前
Go的环境搭建以及GoLand安装教程
开发语言·经验分享·后端·golang·go
canyuemanyue3 小时前
go语言连续监控事件并回调处理
开发语言·后端·golang