构建能够应对分布式系统中不可避免的故障是工程师面临的基本挑战。当软件跨网络和服务器部署时,故障不再是例外,而是必然的。硬件可能会出现故障,网络可能会分区,整个数据中心可能会离线。随着复杂性的增加,潜在的故障点也会增加。
这就是容错的用武之地。容错是指即使组件出现故障,系统也能继续正常运行的能力。它专注于优雅地处理故障,并致力于在出现中断的情况下实现高可用性。容错系统能够通过策略性地处理故障点来抵御故障风暴。
在这篇文章中,我们将探讨常见的故障来源、容错策略以及有助于平息混乱的工具。最后,您将了解构建经得起时间和动荡考验的弹性分布式系统的关键技术。对于任何从事生产级软件的工程师来说,这是必不可少的知识,尤其是在 Web 服务、数据库和云基础设施等领域。
失败的根源
故障的根源
我们首先来看看系统失败的原因以及常见的失败原因。这通常可以追溯到硬件故障、软件错误、人为错误或这些因素的组合。了解这些根本原因对于设计即使在充满挑战的条件下也能抵抗故障并有效运行的强大系统至关重要。
硬件故障- 物理组件可能会以多种方式出现故障:
- 服务器崩溃:断电、硬件故障、温度过高
- 磁盘故障:RAID 系统可以缓解,但磁盘仍可能出现故障
- 网络问题:数据包丢失、延迟峰值、断开连接
- 数据损坏:宇宙射线、信号噪声、磨损的介质
软件故障- 代码中的错误也会破坏系统:
- 崩溃 - 未处理的异常、无限循环、死锁
- 逻辑错误 - 竞争条件、无效状态转换
- 性能问题 - 内存泄漏、数据峰值、阻塞调用
人为错误- 管理系统的人员也可能会犯错误:
- 配置错误 - 应用的错误设置不一致
- 部署失败 - 意外副作用、服务中断
- 操作事故——意外动作、保障措施不足
容错策略
有许多策略可以帮助在分布式系统中构建容错能力。
冗余
冗余旨在通过提供备用容量来消除单点故障,备用容量可以在任何组件发生故障时接管。这可以跨服务器、网络、数据存储和地理区域来实现。关键是避免硬件和数据丢失,并且没有单点故障。
- 主动-被动冗余:在需要之前空闲运行备份服务器/组件
- 主动-主动冗余:将负载分散到活动的主数据库和备份数据库中。
- 复制:维护跨节点分布的数据的多个副本。
- 负载均衡:将请求分布到多个服务器上。
- 备用容量:额外的网络链接、服务器、存储空间。
- 热插拔:无需停机即可更换故障组件。
- 故障转移:如果主数据库发生故障,自动切换到备份数据库。
- 回滚:如果检测到错误,则恢复到上次已知的良好状态。
错误检测
这里的重点是主动监控系统,以便在错误发生级联之前快速捕获错误。这允许故障转移到冗余并尽早隔离问题。测试组件的健全性和健康状况是在整个系统中应用错误检测的重要方法。
- 健康检查:监控系统指标并测试关键组件功能。
- 心跳消息:节点频繁地相互 ping 以检查可用性。
- 警报:当关键指标违反安全阈值时收到通知。
- 故障检测器:可靠检测崩溃节点的算法。
- 健全性检查:验证输出和内部状态的一致性。
- 日志记录:记录足够的调试信息以事后诊断故障。
- 综合监控:模拟用户交易,主动发现问题。
优雅的降级
优雅降级的目标是保持系统正常运行,即使在出现问题期间功能受到选择性限制。其重点是定义必要与非必要的操作,并制定策略以在发生故障时保护关键功能。
- 负载卸载:过载时丢弃不太重要的请求。
- 优先级队列:对任务进行排序并首先处理优先级较高的任务。
- 回退重试:在失败重试之间逐渐等待更长的时间。
- 渐进增强:先支持基本功能,再增强。
- 功能退化:定义最小可行模式并根据需要删除未使用的功能。
隔离
隔离的目标是限制任何给定故障的传播和影响。这是通过设计解耦组件、安全故障模式和操作边界来实现的,这些边界可以防止局部问题导致整个系统崩溃。
- 隔离:单独的组件部署以遏制故障
- 断路器:禁用有问题的端点以阻止级联故障。
- 速率限制:自动限制资源使用以保护关键工作。
- 沙盒:将未经测试的新代码与生产环境分开。
- 故障遏制:为请求设计显式故障域。
- 池化:重用一组有限的资源,而不是无限制的创建。
- 性能隔离:遏制和控制重负载和拥塞。
一些场景中包括对有风险的代码进行沙箱处理、性能隔离以及设计失败时不会影响其他服务的微服务。隔离是一种减少干扰影响范围的强大技术。
工具和框架
有许多工具和框架为容错策略提供实现支持。在代码级别,语言和库具有异常、承诺和监督树等抽象。这些使得编写健壮的组件和快速处理错误变得更加容易。
语言和库
- Java - 使用 try/catch 进行异常处理。强大的库,如Reslience4j,用于断路器、重试、隔离和速率限制。
- Go:用于panic处理,以及像hystrix-go和goresilienceRecover()这样的库。
- 功能染色:有助于沙箱,适用于大多数主要语言。例如,OpenFeature、Unleash和Flipit。
- 基础设施:特别是在云中,通过使用自动扩展组、负载均衡器、可用性区域可以更轻松地管理冗余和隔离。
测试:
- 混沌工程和故障注入:混沌测试工具有目的地注入故障,以确保系统优雅地处理中断。这是建立信心的强大技巧。
- E2E 测试:像playwright这样的工具可以轻松编写端到端测试,以持续验证系统是否仍按预期工作。
结论
我们对容错能力的探索有几个关键要点:
- 容错能力保证了可靠性。通过对不可避免的故障进行规划,系统可以在出现中断的情况下继续正常运行。这种弹性对于分布式系统至关重要。
- 组合策略是最有效的。冗余、错误检测、优雅降级和隔离一起使用时可以相辅相成。不同的故障需要不同的技术。
- 整体设计使容错变得栩栩如生。从架构到部署再到监控,让容错成为整个软件生命周期的首要关注点。
- 卓越运营永无止境。不断从事件、不断发展的设计和测试假设中学习,以适应新出现的故障模式。
容错思想为可靠的分布式系统提供了基础。通过预先关注弹性,您的软件可以承受随着时间的推移而扩展的混乱。利用这些知识来构建将故障视为平常生活事实的系统。