分布式系统中的故障处理与高可用性探究

57 阅读10分钟

高可用性.png

背景介绍

分布式系统中通过网络通信,而它们是不可靠的。因此,分布式系统的建设需要具有容错以及优雅的故障处理的能力。分布式系统中有若干的服务相互通信,我们需要确保任意服务的故障不会破坏整个系统的可用性。同时,我们还应该在短时间内、优雅的恢复各种系统故障。这将会提升整个系统的高可用能力、容灾能力,以及客户的信心指数。 如果不设计和实现能保证容错的技术,那么即使是很短的故障时间也会被放大。 例如,50 个依赖项,每个具有 99.99% 的可用性,因为这种连锁效应,每个月会产生几个小时的故障时间。 如果微服务依赖项在处理大量请求时出现失败错误,那么该失败错误可能会迅速蔓延到每个服务中的所有可用请求线程,然后导致整个应用程序出现故障。

策略维度

  • 全面(网络、存储、服务等多个方面)冗余 - 好的系统都是围绕故障路由
    • 反思
      • 标识应用程序中的关键路径,该路径中的每个点是否都存在冗余?
      • 当子系统发生故障时,应用程序是否会故障转移到其他冗余节点?
    • 措施
      • 负载均衡 - 如果任何服务实例变得不可用,负载均衡器会向其余正常运行的服务实例分配流量。
      • 部署到多个区域 - 当某个问题影响到整个区域时,应用程序可以故障转移到另一区域。
      • 启用异地复制 - 异地复制在一个或多个次要区域中创建数据的可读次要副本,出现故障时,数据库可以故障转移到供写入的次要区域。
      • 自动故障转移 - 使用流量管理器用于自动故障转移
    • 方案
      • 两地三中心(2+1) - 同城双活,异地灾备。

Multi AZ.drawio.png 多个或两个数据中心都处于运行当中,运行相同的应用,具备同样的数据(为了避免数据同步冲突,将用户与数据中心绑定,避免跨数据库方案,变相的实现单元化),能够提供跨中心业务负载均衡运行能力,实现持续的应用可用性和灾难备份能力, 所以称为“双活 ”和“ 多活 ”;后者是生产数据中心投入运行,灾备 数据中心处在不工作状态,只有当灾难发生时,生产数据中心瘫痪,灾备中心才启动。 * 三地五中心(2+2+1)- 异地多活,异地灾备 满足了分布式系统中共识算法最小节点的需求,3,最大程度的解决了系统级的容灾问题。

  • 优点
    • 拓展能力
    • 容灾能力
    • 灰度能力
  • 缺点
    • 成本高
    • 数据一致性
  • 总结
    • 冗余 + 自动故障 = 高可用
  • 故障恢复 故障恢复能力是指从故障中恢复并继续工作,不是避免失败,而是接受会发生失败这一事实,并以能够避免停机或者数据丢失的方式对失败做出相应。 恢复的目标是使应用程序在发生故障后回到完全正常运行的状态。 微服务需要具有应对故障时的恢复能力(部分),并且能够在另一台计算机上重启获得可用性。这要求微服务需要具有保存状态(服务状态、应用数据复原能力,包括数据一致性)和重启成功(进程可以随时重新启动)的能力。

目标制定

  • 注意事项
    • 服务是否可以支持百万或者千万的用户?
    • 是否存在突发的大流量?
    • 可以接受的服务故障级别是什么?
  • 业务要求
    • 业务目标 - 恢复时间目标 (RTO)、恢复点目标 (RPO) 和可容忍的最长中断时间 (MTO)。例如,如果业务要求较低的 RTO,可以向次要区域实施自动故障转移。 但如果业务可以接受较高的 RTO,则可能不需要该程度的冗余。
    • 服务级别协议 (SLA) 和服务级别目标 (SLO),包括可用性和性能指标。 例如,可以提供 99.95% 的可用性。
    • 管理成本 - 包括网络带宽使用情况、存储、IP 地址和服务消耗。

故障场景

  • 代码错误、异常
  • 部署错误
  • 配置问题
  • 硬件故障,例如服务A无法写文件系统
  • 数据中心问题,例如数据库无法链接
  • 网络不可靠,例如ServiceA无法访问ServiceB
  • 依赖服务不可用,例如服务B过载,无响应
  • 基础组件不可用,例如Redis宕机

应对策略

  • 面向故障设计
  • 避免单点故障 - 描述了一个特定的故障点,如果在任何位置发生故障,会导致整个应用程序停止运行,“串联”->“并联”
  • 避免级联故障
  • 主动故障防御
  • 服务故障恢复
  • 故障注入测试

策略细节

  • 程序设计
    • 定义可用性和恢复目标以满足业务要求。
    • 通过收集需求,在应用中融入恢复能力和可用性。
    • 关键资源隔离 ,如果某个故障导致某些资源(例如线程或套接字)无法及时释放,导致资源耗尽,则可能就会发生连锁反应。
    • 识别系统中可能的故障点以实现故障恢复能力。
    • 确保应用程序可以在没有依赖项的情况下运行。
  • 应用防御

Traffic Management.drawio.png

  • 重试 - 间歇性故障,例如短暂的网络链接失败、服务繁忙,应用中使用重试逻辑
  • 超时 - 及时止损,避免过长的请求无响应
  • 熔断 - 非间歇性的故障,避免级联故障
  • 限流 - 过载保护
  • 降级 - 无法解决,提供“缩减版”的能力
  • 缓存 - 请求远程服务失败,使用本地缓存,如果可以缓存的话。
  • 异步 - 减少连锁反应,减少业务中断
  • 黑名单 - 如果客户端持续出错或在其他方面具有不良行为,则需要进行阻止。
  • 基础保障
    • 部署 - 部署应用程序及组件的多个独立副本(横向拓展),包括数据存储
    • 区域 - 部署到不同的地理节点,其中每个节点都可以为任意区域的客户端提供服务(故障转移)
    • 负载 - 为多个服务实例提供基于健康检查的负载均衡,对于故障节点下线
    • 限制 - 设置单个实例、服务资源消耗上限
    • 链接
      • 使用用于跨区域分配流量、故障转移的全局负载均衡器。
      • 对于跨界连接(VPN),确保有来自不同位置的冗余连接。
      • 模拟故障路径,确保可通过备用路径进行连接。
      • 消除数据路径中的所有单一故障点。
    • 测试 - 导致应用程序停机的一个主要原因是由于部署了未充分测试的软件或配置错误而导致的人为错误。
      • 可靠性 - 稳定性、全链路
      • 故障注入 - 通过触发实际故障或模拟故障,来测试系统对故障的复原能力
      • 混沌工程 - 将故障、异常情况随机的注入到生产环境中

故障恢复

  • 故障分析 - 通过标识系统中可能出现的故障点,并将恢复能力内置到系统中
    • 故障点 - 描述了应用程序体系结构中可能发生故障的元素
    • 故障模式 - 捕获了故障点可能发生障碍的各种方式
    • 分析过程
      • 标识系统中所有的组件,维护依赖项的完整列表,包括外部依赖服务,比如标识提供者、第三方服务等
      • 对于每个组件,标识可能发生的潜在故障。每个组件可能有多种故障模式,例如,应该分开考虑读、写失败,因为产生的影响和恢复步骤可能不一样
      • 根据故障风险做出评估和优先级划定,例如,发生故障的概率,对应用程序可用性、数据丢失、业务中断等方面的影响
      • 对于每种故障模式,制订相应的恢复方案,注意成本与应用程序复杂性之间的平衡
  • 能力构建
    • 故障分析
      • 执行上述的故障分析模式,构建故障自愈能力
    • 服务依赖
      • 确保应用程序可以在没有依赖项的情况下运行
      • 确保应用程序的生命周期与其依赖项脱钩
      • 关键依赖项的SLA
  • 处理过程
    • 故障检测
    • 故障恢复
    • 故障诊断
  • 案例分析
    • 服务实例不可用或者不正常
      • 检测 - 配置负载均衡器运行状况探测,以便发信号指示服务实例是否正常。 探测应检查关键功能能否正确响应。
      • 恢复 - 对于每个应用程序层,将多个实例放入同一可用性集中,并在实例前面放一个负载均衡器。 如果运行状况探测失败,负载均衡器会停止向不正常的实例发送新连接。
      • 诊断 - 使用负载均衡器日志分析;配置监视系统,以监视所有运行状况监视终结点。
    • 远程服务调用失败
      • 检测 - HTTP 状态码
      • 恢复 - 重试;重试失败熔断、降级
      • 诊断 - 记录所有远程调用失败
    • 特定用户反复出错或者过载
      • 检测 - 验证用户身份并将用户ID输出到应用程序的日志中
      • 恢复 - 黑名单或者API请求限制
      • 诊断 - 记录所有的的身份请求
    • Redis缓存读/写取失败
      • 检测 - 捕获RedisConnectionException异常
      • 恢复 - 间歇性故障进行重试;非间歇性故障回退到原数据源
      • 诊断 - Rediscli查看Redis实例的运行状况
    • SQL数据库
      • 连接池耗尽
        • 检测 - 捕获InvalidOperationExceptio异常
        • 恢复
          • 重试
          • 资源隔离
          • 增大连接池的上限
        • 诊断 - 应用程序日志
      • 达到数据库链接限制
        • 检测 - 捕获SqlException
        • 恢复 - 间歇性问题,重试,如果持续遇到,缩放数据库
        • 诊断
          • 数据库日志查看返回成功的数据库链接、失败的链接、死锁等
          • 为失败的链接创建告警规则
          • 启动SQL数据库审核并检查失败的登录

方案实施

  • 基础条件
    • 服务无状态
    • 接口幂等
    • 单元化
  • 故障检测
    • 运行状态管理
      • 运行状态检查 - 微服务(包括各个基础组件)可向监视器服务报告它们的状态,以执行适当的操作。在缓解影响应用程序可靠性的问题之前,必须首先检测到这些问题。
        • 运行情况:检查微服务是否处于活动状态,即微服务是否接受请求并作出响应。
        • 就绪情况:检查微服务的依赖项(数据库、查询服务等)是否已就绪,以便微服务可以执行预期操作。
    • 业务告警

Check point Alert .drawio.png * 依赖服务 * 依赖组件

  • 故障恢复
  • 故障防御能力补齐
    • 基于服务网格的流量治理

istio traffic ability.drawio.png

  • 故障自愈能力补齐
    • 基于上述的能力构建篇章建设
  • 应用诊断
  • 应用诊断器 - 基于日志的应用诊断,日志提供应用程序和服务运行的信息,包括异常、告警等信息, 日志输出到第三方平台和分析工具,以提供实时搜索、告警、监控、报告等能力。
  • 微服务平台 - 随着微服务数量的增多,很多复杂的、基础的问题开发团队(聚焦解决商业问题)难以自行解决,因此,微服务平台映入眼帘。微服务平台以解决资源管理、构建服务、运行服务、管理服务等一系列基础、复杂问题为目的,帮助业务团队更好的处理微服务系统中复杂性的问题。