标签归档:混沌工程

关于后台稳定性建设的系统性思考

后台系统具有 24 小时全天候运行、用户访问量大、数据处理复杂等特点,其稳定性对企业的业务连续性和用户体验至关重要。

影响后台系统稳定性的因素有很多,包括但不限于:

  • 硬件故障:服务器、网络、存储等硬件设备出现故障。
  • 软件缺陷:操作系统、中间件、应用程序等软件存在 bug。
  • 人为失误:系统维护、变更操作不当造成的问题。
  • 网络攻击:黑客入侵、DDoS 攻击等外部安全威胁。
  • 突发流量:业务量突增导致系统过载,或者调用不当导致的后台流量突增
  • 架构缺陷:系统架构不合理,存在性能瓶颈和单点故障.

稳定性建设的根本目标是保证后台系统持续、可靠地为业务提供服务。具体来说,需要从以下几个维度来考虑:

  • 可用性:系统在约定时间内正常提供服务的能力
  • 可靠性:系统在规定条件下和时间区间完成规定功能的能力
  • 可维护性:系统易于进行故障诊断和修复的能力
  • 可扩展性:系统能够通过扩容来适应业务量增长的能力
  • 安全性:系统抵御各种外部攻击、非法访问、数据泄露的能力

只有在这些维度上达到一定的要求,才能称得上建设了一个高稳定性的后台系统。而要实现这些目标,需要从技术、管理、流程等多个层面入手,进行系统性的建设。

基于过去的一些经验,对稳定性的建设做一个相对系统性的思考,总共有 7 点:运维、高可用架构、容量治理、变更管理、风险治理、故障管理、混沌工程。

1 运维:稳定性的基础

运维是指在信息系统的生命周期中,对系统进行日常管理、维护和优化的过程。运维工作的核心目标是确保系统的稳定、高效和安全运行。

在稳定性建设中运维起着至关重要的作用,其主要包括标准运维和运维合规两大方面。

1.1 标准运维

标准运维是指根据行业最佳实践和企业自身需求,制定统一的运维流程、规范和标准,并严格遵循执行。标准运维的目的是提高运维效率,降低人为失误风险,保障系统稳定性。

标准运维通常包括以下 3 个大的方面:

1.1.1 运维标准与规范

制定包括环境管理、监控告警、数据备份和安全加固在内的一系列运维标准,形成统一规范。通过标准化建设,实现运维环境的一致性和可控性,减少各种差错和风险。

运维标准与规范通常包括以下几个方面:

  1. 环境管理标准:涵盖服务器硬件配置、网络架构设计、存储资源配置和环境部署规范等,确保基础设施环境的标准一致性。
  2. 监控告警规范:定义关键监控指标,合理设置告警阈值,规范告警处置流程,并建设统一的监控平台,实现全栈全链路的实时监控与告警。
  3. 数据备份策略:根据数据的重要性分级制定差异化的备份策略,选择合适的备份方式、周期和保留期限,并定期开展备份可用性检查,确保数据的安全性和可恢复性。
  4. 安全加固基线:针对操作系统、中间件等进行安全加固配置,制定安全加固检查表和配置基线,并建立补丁管理流程和安全合规审计机制,降低系统的安全风险。

除此之外,运维标准与规范还可能涉及资源命名与编码规则、文档管理要求、工具使用指引等各个方面的标准化要求,形成一套全方位、多层次、相互关联的标准规范体系。

1.1.2 运维流程管理

运维流程管理包括变更管理、事件响应、问题管理和服务请求等各个运维流程,形成规范化、标准化的工作模式。通过流程的贯通执行和持续改进,提升运维效率和质量,快速响应业务需求。

运维流程管理通常包括以下几个方面:

  1. 变更管理流程:规范变更需求提交、评审、审批、实施、验证等各个环节,确保变更过程可控、风险可控,最大限度减少变更对业务的影响。
  2. 事件响应流程:明确事件报告渠道、分类机制、处理流程、升级机制等,确保事件能够得到及时发现、准确定位、快速处理和彻底解决,将事件影响降到最低。
  3. 问题管理流程:建立问题发现、记录、分析、解决、验证等闭环流程,并通过知识库的建设和持续优化,不断提升问题管理效率和问题解决能力,预防问题的再次发生。
  4. 服务请求流程运维日常工作的重点,规范服务请求的受理、分类、派单、跟踪、解决、确认等环节,提供标准化、高效化的运维服务,提升用户满意度。
  5. 容量管理流程:定期开展系统容量评估和趋势分析,合理规划和调配各项IT资源,满足业务增长需求,避免出现资源瓶颈和性能降级。
  6. 配置管理流程:全面梳理和管控IT基础设施的配置信息,包括软硬件版本、参数设置、逻辑关系等,确保配置信息的准确性、一致性和可审计性。
  7. 发布管理流程:规范应用系统和基础设施的发布活动,包括发布计划、发布实施、发布验证等,确保发布过程安全、平稳、高效,降低发布风险。

运维流程管理的核心在于将各项运维活动标准化、规范化、流程化,通过 PDCA(计划-执行-检查-处置)的循环来不断优化流程、提升效率、改进质量,进而为业务发展提供高水平的运维保障。

还要注重流程间的协同和贯通,构建起一套相互关联、环环相扣的运维流程体系,实现端到端的运维服务管理

1.1.3 运维质量保障

建立应急预案管理和运维巡检两大质量保障机制,最大限度规避和控制运维风险。

通过应急演练和故障复盘,不断优化应急处置能力;通过规范化巡检和数据分析,实现运维质量的可视化和可管理性。

运维质量保障通常包括以下几个方面:

  1. 应急预案管理

    • 应急预案分类:根据故障类型和影响程度,制定不同级别的应急预案,如系统级、业务级、组件级等,明确各类场景下的应急处置流程和方案。
    • 应急资源准备:梳理应急处置所需的人员、备件、工具等资源,并进行合理配置和管理,确保在应急状态下能够快速调用和使用。
    • 应急演练计划:制定定期的应急演练计划,模拟各种故障场景,检验应急预案的可行性和完备性,并根据演练结果不断优化和完善应急预案。
    • 故障复盘与优化:故障处理完成后,及时进行复盘分析,总结故障原因、处理过程、恢复时间等关键信息,并针对性地优化应急处置流程和方法,提升故障处理效率和效果。
  2. 运维巡检机制

    • 巡检对象与周期:明确运维巡检的对象和范围,如硬件设备、网络设备、操作系统、应用系统等,并根据不同对象的特点和重要性,合理设置巡检周期,如日巡检、周巡检、月巡检等。
    • 巡检内容与标准:制定详细的巡检内容和操作规范,包括各项指标的正常范围、检查方法、异常处置等,确保巡检过程的规范性和准确性,保证巡检结果的可比性和可追溯性。
    • 巡检工具与平台:充分利用自动化运维工具和智能巡检平台,提高巡检效率和覆盖率,减少人工巡检的遗漏和误差,实现对关键指标的实时监测和趋势分析。
    • 巡检结果管理:规范巡检结果的记录和报告格式,建立巡检结果的审核和问题整改机制,对巡检发现的异常和隐患及时处置和跟踪,形成闭环管理,防止小问题演变成大故障
  3. 持续服务改进

    • 服务绩效评估:建立完善的服务绩效评估体系,从系统可用性、事件处理效率、用户满意度等多个维度,定期评估运维服务的质量和水平,并将评估结果可视化呈现。
    • 优化改进机制:针对绩效评估中发现的问题和不足,进行原因分析和改进措施制定,形成持续优化、持续改进的良性循环,不断提升运维管理成熟度和服务质量。
    • 质量管理体系:建立规范的 IT 服务管理体系(如ITIL)和质量管理体系,贯穿运维各个环节,从制度、流程、工具等方面入手,实现运维工作的标准化、规范化、精细化。

运维质量保障是一个持续不断的过程,需要从应急管理、日常巡检、服务改进等多个角度入手,建立起完善的质量保障体系和机制,从而在提高运维效率的同时,保证业务系统的高可用性和稳定性,更好地支撑企业业务的发展。

1.2 运维合规

运维合规是指在 IT 系统和业务运营过程中,严格遵守各项法律法规、行业标准、企业内控制度等合规要求,并围绕安全生产这一核心目标,从流程、工具、规范等方面入手,对各类运维操作进行安全预防、过程监控、结果稽查等全流程管控,确保运维工作的规范性、安全性、可审计性,防范各类违规操作和安全风险。

运维合规的范围涵盖了 IT 运维的方方面面,包括但不限于:

  1. 统一账户权限管理:对所有运维人员的账户进行统一管理,根据岗位职责和业务需求设置相应的操作权限,并定期进行权限复核和调整。特别是对于 DevOps 平台、云平台、堡垒机等关键系统,要从严管控运维人员的访问权限,防止越权操作和数据泄露。

  2. 规范化运维操作:建立标准化的作业指导书和操作规范,明确各类运维操作的流程、注意事项和风险点,并通过运维平台等工具进行统一管理和执行,杜绝私自运行脚本、登录宿主机进行命令操作等不规范行为,确保运维操作的透明化和可追溯性。

  3. 高危操作管控:对数据库删表、Redis 清库等高危操作进行严格管控,通过黑白名单机制、命令审批流程等方式进行有效拦截和禁止,并建立高危操作台账,定期进行安全评估和优化改进。

  4. 运维审计与稽查:建立完善的运维操作日志管理机制,对运维人员的所有操作进行详细记录和跟踪,并定期开展运维合规性稽查和安全审计,及时发现和整改各类违规操作和安全隐患。

  5. 外包商管理:对第三方运维服务商进行合规性管理,明确相关安全要求和责任界定,并通过合同约束、过程监管等方式,确保外包运维服务的合规性和安全性。

运维合规是一项系统性、持续性的工作,需要从制度、流程、技术、人员等多个层面入手,形成完善的合规管理体系。

2 高可用架构:稳定性的核心

如果说运维是稳定性建设的基础,为业务系统的稳定运行提供必要的环境和保障,那么高可用架构则是直接决定了业务系统能够达到怎样的稳定性和连续性的关键所在。高可用架构从系统自身的角度出发,通过合理的架构设计和技术手段,最大限度地规避各种潜在的故障风险,即便在发生局部故障的情况下,也能够确保业务流程的连续性和数据的完整性,将故障影响控制在最小范围内

那么,如何构建高可用架构呢?我们可以从预防和容灾两个维度来展开。

2.1 预防:从架构层面提高系统可用性

预防措施旨在从架构层面预防稳定性问题,提高系统可用性。主要包括以下几个方面:

2.1.1 依赖治理

在复杂的分布式系统中,服务之间的依赖关系错综复杂,如果不加以治理,极易形成服务间的强依赖和紧耦合,一旦某个服务发生故障,就会迅速蔓延至整个依赖链路,造成连锁反应和大面积不可用。因此,依赖治理是预防性措施中极其重要的一环。

依赖治理的首要任务是全面梳理系统中的核心链路的服务依赖关系,绘制出清晰的服务依赖拓扑图。

请注意,这里需要明确核心链路,并不是所有的链路都需要做依赖治理,我们做的每一项动作对于企业来说都是成本,需要基于成本意识来做这些工作。

在完成梳理的基础上,我们要审慎评估每一处依赖的必要性和合理性,对于非关键性的依赖或者弱依赖,在实现层面做成可丢弃;对于不可避免的依赖则要制定完善的服务降级和熔断预案,确保在依赖服务不可用时,不会殃及到当前服务的核心功能

同时,还要注重服务接口的健壮性设计,包括入参校验、结果校验、异常处理等,避免由于接口问题引发的依赖方故障。

2.1.2 容量治理

在第 4 节详细展开讲

2.1.3 隔离设计

隔离设计的本质是避免局部问题殃及全局

在复杂的分布式系统中,「部分」和「整体」往往是一对矛盾体。一方面,我们希望通过分而治之的思想,将系统拆分为相对独立的模块和服务,以降低单个组件的复杂度;另一方面,过多的服务化拆分又不可避免地带来服务间的频繁交互和紧密耦合,使得局部的故障极易扩散至整个系统。因此,合理的隔离设计就显得尤为重要。

隔离设计的第一要义是界定好故障域。故障域是指在故障发生时可能受到波及的一个逻辑区域。我们要尽可能缩小每个故障域的范围,避免出现「木桶效应」,即一个薄弱的故障域导致整个系统的不可用。具体到系统架构设计中,就是要遵循「高内聚、低耦合」的原则,将容易产生故障的组件划分在同一个故障域内,而不同故障域之间则尽可能解耦和隔离。

要做好故障域内的容错和隔离设计。对于无状态服务,主要通过负载均衡将请求分散到多个实例,避免单点故障;对于有状态服务,则要采用主备、集群等模式,确保在部分节点失效时,服务依然能够正常运转。而对于一些关键的资源,如带宽、连接池、线程池等,则要做好资源隔离和限制,避免被某个服务或请求独占而影响其他服务。

数据隔离。 一方面,不同业务数据和用户数据要进行合理的拆分,存储在不同的数据库实例乃至物理机器上,避免由于表结构设计不合理、SQL 语句执行异常等原因,导致整个数据库实例不可用。另一方面,对于缓存、消息队列等中间件,也要根据业务边界和数据特征,设置不同的实例或 topic,避免相互干扰。

2.1.4 「无损」变更

在系统的日常迭代和升级中,变更引入的风险往往是稳定性问题的重要诱因。为了最大限度规避这些风险,「无损」变更的架构设计至关重要。

现在成熟可靠的变更策略已经非常普遍,如灰度发布、蓝绿部署等,需要我们在实际工作中抓紧落实。灰度发布是指在生产环境中划出一部分实例作为灰度服务器,先在灰度服务器上进行新版本部署,经过一段时间的监控和验证后,再逐步扩大范围,最终实现全量发布。而蓝绿部署则是准备两套完全相同的生产环境,一套作为当前运行版本,另一套作为待发布版本,通过调整负载均衡配置将流量在两套环境间切换,实现平滑的版本升级。

要在关键链路设计可回滚机制,确保在变更出现问题时能快速恢复。这需要我们在需求实现,方案设计时就考虑在数据存储、服务接口等方面采用向前兼容的设计,并且对变更过程中可能出现的数据不一致、请求异常等情况制定完善的应对预案和回滚脚本,确保变更失败时,系统能够快速回退到之前的稳定状态。

最后,还要不断完善变更管理流程和工具链,提高变更的标准化和自动化水平。通过引入变更管理系统/发布系统对变更进行全生命周期追踪,规范变更申请、审核、发布、验证等各个环节;通过实施 CI/CD,将构建、测试、部署等步骤以流水线的方式固化下来,减少人工操作带来的不确定性。同时,还要加强变更过程的监控和告警能力,第一时间感知和应对潜在的风险。

2.1.5 压力测试

压力测试的目的是:模拟极限场景,找出系统瓶颈

不论是线上运行的系统,还是正在开发的新功能,我们都需要对其进行充分的压力测试,模拟各种极限场景,全面评估系统的性能表现和稳定性水平。

压力测试的关键是全面覆盖和贴近真实。测试场景要覆盖正常流量、峰值流量、异常流量等不同强度,以及不同的并发数、请求类型、数据量级等维度。测试数据则要尽量贴近真实的业务数据分布,避免「垃圾进,垃圾出」。

同时,压力测试还要协同监控体系。在施加压力的同时,要持续监控系统的 CPU、内存、网络等关键指标,找出可能存在的瓶颈和隐患。一旦发现问题,要及时分析原因,并制定优化方案,如优化代码、参数调优、扩充资源等。

通过反复的压力测试和优化,我们可以不断提升系统的性能上限和稳定性水平,做到「未雨绸缪」。当然,压力测试也要把握「度」,避免对线上系统造成过大影响

2.1.6 健康检查

在分布式系统中,服务实例的数量动辄成百上千,如果某些实例出现异常,既影响自身服务能力,又可能带来连锁反应。因此,必须建立完善的健康检查机制,及时发现和隔离这些异常实例。

健康检查的对象,既包括服务实例本身,也包括实例所依赖的下游组件,如数据库、缓存、消息队列等。检查的内容则要全面覆盖服务的核心功能和基础资源,如接口响应时间、错误率、CPU 使用率、内存占用等。

健康检查的实施,需要贯穿服务的整个生命周期。在服务上线前,要对健康检查脚本进行充分的测试和验证,确保检查结果的准确性。在服务运行时,要配置合理的检查频率和阈值,既要及时发现问题,又要避免过度消耗资源。一旦发现异常实例,要立即将其从服务调用链路中隔离出去,并生成告警通知,直至异常情况消除后再恢复。

此外,还要定期巡检和优化健康检查规则本身,动态调整检查粒度和阈值标准,确保其始终与系统的实际情况相匹配。

通过全面而细致的健康检查体系,我们可以最大限度减少异常实例带来的影响,为整个分布式系统构筑一道坚实的「免疫屏障」。

2.2 容灾:最大限度保障业务连续性

容灾措施旨在最大限度减少故障影响范围,保证关键业务的连续性。主要包括以下几个方面:

2.2.1 弹性伸缩

弹性伸缩的作用是动态调整资源应对流量突增

在互联网系统中,流量的波动往往是不可预测的。一旦出现流量突增,系统资源如果不能及时扩容,就极易出现服务不可用的情况。因此,弹性伸缩是容灾措施中极其重要的一环。

弹性伸缩的核心是「随需而变」。当流量增加时,系统能够自动检测到资源使用率的变化,并迅速启动新的服务实例来分担压力;当流量回落时,多余的实例也会被自动释放,以节约成本。这个过程通常是全自动的,无需人工干预。

实现弹性伸缩的关键是对服务进行合理的拆分和解耦。首先,要将服务拆分为独立的、无状态的组件,使其能够灵活地进行水平扩展。其次,要解除这些组件之间的强依赖关系,使其能够独立地进行扩缩容,而不会相互牵制。再次,还要实现组件与资源的解耦,使得组件不与特定的物理资源绑定,而是可以自由地在资源池中调度。

同时,弹性伸缩还需要一套完善的配套设施。比如监控系统,能够实时采集服务的各项指标,及时发现需要扩容的场景;调度系统,能够根据预设的策略自动完成实例的创建和销毁;配置管理系统,能够管理新实例的各项配置,确保其顺利加入服务集群。

以上的这些系统以及伸缩的逻辑在公有云上已经有比较成熟的方案,包括监控、发现、调度扩容等。

通过弹性伸缩,我们可以让系统在流量洪峰中从容应对,避免因资源不足而引发的可用性问题,同时也能在流量回落时自动「瘦身」,提高资源利用率。

2.2.2 过载保护

过载保护的作用是避免过载请求拖垮系统,属于及时止损,保证部分用户可用的一种降级策略。其主要手段是限流熔断。

在复杂的分布式系统中,某些服务或资源可能会不可避免地出现响应缓慢、不可用等情况。如果任由上游的请求持续涌入,往往会加剧这些服务或资源的负荷,最终可能导致整个系统被拖垮。此时我们就需要实施限流熔断。

限流的目的是对请求的并发数进行控制,避免服务因过载而崩溃。常见的限流算法有漏桶算法、令牌桶算法等,通过设置一个固定的「流量阈值」,超出阈值的请求要么排队等待,要么直接拒绝。限流可以在不同的粒度上实施,如针对某个 API 接口、某个服务实例、某个用户等。

熔断的作用则是在服务出现问题时,自动切断上游请求,避免问题进一步恶化。熔断机制通常基于「断路器」模式实现。当被调用服务的错误率或响应时间超出某个阈值时,断路器会自动「打开」,后续的请求会直接返回错误,而不会真正发往后端服务;经过一段时间后,断路器会进入「半开」状态,尝试发送部分请求到后端,如果调用成功,就自动「关闭」断路器,恢复正常调用,否则重新进入「打开」状态。

限流和熔断往往是配合使用的。限流避免了过多的请求压垮服务,而熔断则在服务已经出现问题时,自动隔离故障影响。两者相互补充,共同构筑起一道坚实的「屏障」,维护系统稳定性。

在实施限流熔断时,关键是设置合理的阈值和策略。既要避免阈值过高而失去保护作用,也要避免阈值过低而过度拒绝正常请求。通常可以先设置一个相对宽松的阈值,再根据系统实际运行情况不断进行调优和优化。同时,限流和熔断的设计还要考虑用户体验,对不同的请求进行区分处理,确保核心功能不受影响。

通过科学的限流熔断,实施过载保护,我们可以有效防止「雪崩效应」的发生,避免局部的故障演变为整体的故障,为系统稳定性提供有力保障。

2.2.3 柔性可用

柔性可用强调的是在保证核心功能可用的前提下,允许非核心功能出现一定程度的降级或不可用,从而避免因局部问题影响整体可用性。这是一种更加灵活、务实的容灾思路。

传统的容灾设计往往追求「刚性可用」,即不允许任何功能出现任何失效。这种追求「完美」的做法,看似合理,实则过于理想化。在复杂的分布式系统中,局部的故障在所难免,过度追求「零容忍」反而可能适得其反。

而柔性可用的理念则更加务实。它认为,在确保核心业务连续性的基础上,可以容忍非核心功能的局部失效,或者出现一定程度的服务降级。这种「有控制的失效」,虽然可能在一定程度上影响用户体验,但却能避免因局部问题引发全局瘫痪,是一种值得权衡的策略。

举个简单的例子,假设一个电商平台的下单功能出现故障。如果采用「刚性可用」的策略,可能会直接禁止下单操作,甚至关闭整个平台。而如果采用「柔性可用」的策略,可能会暂时屏蔽优惠券、礼品卡等非核心功能,同时简化下单流程,确保用户能够完成基本的购买行为。这样虽然可能影响部分用户的购物体验,但却能保住大部分订单,避免更大的经济损失。

实施柔性可用需要对系统有清晰的分层认知。通常我们可以将系统分为多个「可用性层级」,每个层级对应不同的业务重要性和容错标准。对于最核心的功能,要确保 99.99% 以上的高可用;而对于次要功能,可以适当降低标准,允许 99.9% 或 99% 的可用性。同时,还要在不同层级之间设置合理的隔离措施,避免低层级的故障向高层级蔓延。

此外,柔性可用的理念还强调「快速止损」和「平滑降级」。「快速止损」是指当故障发生时,要迅速判断影响范围,并采取措施阻断故障扩散,将损失控制在最小范围内。而「平滑降级」则强调要给用户适当的提示和引导,避免服务骤降或直接不可用,造成用户困惑和恐慌。比如,可以在下单时给出「优惠券功能暂不可用」的温馨提示,引导用户继续完成购买。

柔性可用的本质是一种「务实」的容灾哲学。它认为,与其追求不切实际的「完美」,不如脚踏实地地做好「权衡」。通过对核心业务和非核心业务的分层处理,通过对不可用场景的提前预演和定义,在保证核心功能的前提下,适度容忍局部的缺陷和失效,换取整体的韧性和稳定性。这种务实的态度和方法,对于构建复杂系统的容灾能力至关重要。

当然,柔性可用绝不意味着对故障和缺陷的放纵。它更强调要建立完善的监控预警机制,对各种指标进行实时的采集和分析,尽快发现和定位问题。同时,还要通过压测、混沌工程等手段,对系统进行持续的「健康检查」,主动发现和暴露问题。只有在平时就养成对问题「零容忍」的态度,在故障来临时才能从容应对,做到「柔中有刚」

2.2.4 应急预案

凡事预则立,不预则废。

应急预案是指提前制定故障处理方案。

在复杂的系统中,意外和故障在所难免。而区分一个团队的优秀与否,很大程度上在于面对危机时的反应能力。这就需要我们未雨绸缪,提前制定完善的应急预案。

应急预案的第一步是要全面梳理系统可能出现的各种故障场景,从服务层面、数据层面、基础设施层面等不同维度,尽可能穷尽所有的风险点。在此基础上,还要分析每种故障场景的影响范围、严重程度、发生概率等,进行必要的风险评估和分级。

然后,针对每一种故障场景,都要制定周密的应对措施。这包括监控预警、故障诊断、应急处置、恢复验证等不同阶段的工作流程和操作规范。在设计应对措施时,要本着「快速止损、降低影响」的原则,注重实效性和可操作性。同时,还要明确各个环节的职责分工和协作机制,确保在危机发生时,能够快速形成合力。

应急预案形成后并非一劳永逸,还需要定期进行推演和演练。一方面,通过不断地练习,可以找出预案中的漏洞和不足,并加以改进;另一方面,也能锻炼团队的应急反应能力,提高实战水平。演练的过程也是一次全面的「体检」,能够发现平时难以察觉的问题,可谓「治未病」的良方。

2.2.5 异地多活

以上提到的容灾措施,大多是针对系统内部的纵向防御。然而,在现实中,我们还必须面对各种不可抗力的外部风险,如自然灾害、断电断网等,它们可能导致整个机房、乃至整个地域的长时间不可用。因此,在容灾体系中,我们还必须考虑横向扩展,通过异地多活的架构,实现跨地域的容灾能力

异地多活的本质是将服务分布到多个地理位置上,每个位置都有独立完整的基础设施和应用部署,将横向扩展实现跨地域容灾。这些不同位置的服务相互之间是对等的,它们共同承担生产流量,同时互为备份。当任何一个位置出现故障时,其流量可以自动切换到其他位置,保证服务的连续可用。

实现异地多活需要考虑方方面面的因素。首先,要选择合适的地理位置。通常应该选择多个距离适中、网络连通性好的城市,并尽量避开容易发生自然灾害的区域。其次,要做好数据同步。由于不同位置的服务是独立运作的,它们的数据在一定程度上是分离的。因此,必须建立高效可靠的数据同步机制,确保不同位置的数据最终一致性。再次,还要设计好流量调度策略。正常情况下如何在不同地域间分配流量,故障发生后又如何进行切换,都需要制定完善的规则和算法。

异地多活的关键挑战在于如何平衡「容灾能力」和「系统复杂度」。一方面,地理位置越多,容灾能力就越强,但同时系统的复杂度也就越高,对网络带宽、数据同步、运维管理等方面的要求也越高。另一方面,如果盲目追求「异地」而忽视了「多活」,可能会适得其反。比如一味增加机房数量,但没有做好同城双活,反而可能降低单个机房的可用性。因此,异地多活方案的设计需要全盘考虑,权衡利弊,找到最佳的平衡点。

并且,异地多活还对应用架构提出了更高的要求。为了实现流量的无缝切换,应用必须具备横向扩展的能力,能够灵活调整服务实例的数量和分布。同时,应用还必须尽可能实现「无状态」,将状态数据托管到外部的存储服务中,以方便不同地域的实例共享数据。这就需要我们在应用设计之初就铭记异地多活的需求,合理划分服务边界,松耦合、可扩展、易维护。

异地多活是一把「双刃剑」,实施得当可以大幅提升系统的可用性和稳定性,但实施不善也可能带来更多的不确定性和管理成本。因此,异地多活绝非权宜之计,而是需要长期的规划和建设,需要不断打磨和优化。只有综合应用各种容灾手段,分层设防、纵深防御,才能为关键业务筑牢稳定性的「防护网」,无惧各种突发状况和不确定性的考验。

3 变更管理:稳定性的关键

变更管理是后台系统稳定性建设的关键环节。一个系统当不再变更,线上可能出问题的概率会减少很多。

任何对系统的变更,如果处理不当,都可能引入新的故障点,威胁到线上稳定性。因此需要建立完善的变更管理机制,规范变更流程,最大程度地降低变更风险。从变更前、变更中、变更后三个阶段来详细阐述变更管理的实践。

3.1 变更前

变更执行前的管理包括变更审批、变更评审、风险评估等环节。

通过严格的变更前置管理,可以从源头规避变更引入的稳定性风险,为变更的顺利实施奠定基础。

变更前的管理事项主要包括以下几个方面:

  1. 变更申请与审批:变更申请人填写变更申请单(可以是电子单,也可以是变更群里按规范写的一个描述),详细说明变更原因、目的、内容、影响范围、风险及执行计划等。变更申请提交评审委员会或管理层审批,确保变更的必要性和可行性。有些变更可以不做,或者晚点再做等。
  2. 可行性与风险评估:评估变更的技术可行性,可能带来的风险点以及优先级等。
  3. 制定变更计划:确定变更的实施时间、所需时长,选择业务低峰时段。制定详细的技术实施方案、验证计划和回滚预案。明确参与人员的角色分工和职责。
  4. 准备与通知:准备变更所需的软硬件环境,提前通知所有利益相关方,包括但不限于用户、业务方、运维人员等。

3.2 变更中

变更执行中需要严格按照变更计划操作,并做好应急准备。主要包括以下:

  1. 备份数据:为避免变更失败导致数据丢失或损坏,需提前做好数据备份,必要时准备回滚方案。
  2. 监控变更过程:变更过程中需对系统各项指标进行实时监控,一旦发现异常及时处理。
  3. 灰度发布:对于影响面较大的变更,建议先在小流量进行灰度验证,逐步扩大变更范围。灰度期间密切关注系统状态。
  4. 不在业务高峰期变更:选择业务低峰时段进行变更,尽量减少变更过程中的影响面。
  5. 准备应急预案:针对可能出现的风险,提前准备应急预案和回滚方案。一旦发生严重问题,及时按预案操作,将损失降到最低。

3.3 变更后

变更实施完成后同样需要持续管理,主要包括:

  1. 监控变更效果:持续观察变更对系统造成的影响,密切关注系统稳定性。
  2. 问题处理:如发现变更导致的问题,需深入分析根因,制定解决方案,并纳入知识库。
  3. 更新文档:将变更内容同步到系统文档、操作手册、架构图等材料中,确保文档与系统实际状态一致。很多团队这一环是缺失的,变更完就不管了。
  4. 变更复盘:对变更的效果、问题等进行全面复盘总结,作为经验积累,优化后续变更管理。如有必要的话。

规范的变更管理流程可显著提升系统稳定性。将变更计划、实施、复盘等形成闭环,不断积累优化,持续强化稳定性保障能力,共同守护后台系统这座无法停歇的「永动机」。

4 容量管理:稳定性的保障

容量治理是稳定性建设的保障。通过合理的容量规划和扩展策略,可以避免系统因超负荷而崩溃。

稳定性问题的一个常见诱因是资源不足,如 CPU、内存、磁盘、网络等瓶颈导致的系统不可用。而资源不足的根源,往往在于容量规划不到位,没有提前预估业务增长和资源消耗,或者预估不准,导致资源准备不足。

要做好容量管理,需要从容量评估和规划、监控预警、动态扩缩容来落地。

4.1 容量评估与规划

容量评估和规划是容量管理的起点。主要内容包括:

  1. 容量标准:包括资源池管理、资源使用标准等。全面梳理各类资源,建立统一的资源管理机制。
  2. 业务容量评估:评估当前业务量和增长预期,分析不同时期的容量需求。这里可能需要考虑引入常规压力测试。
  3. 资源使用情况分析:分析当前系统的资源使用情况,包括 CPU、内存、存储、网络等,找出容量瓶颈。
  4. 容量模型建立:根据业务特点和资源使用情况,建立容量模型,预测未来不同时间点的容量需求。需要明确哪些需要建立容量模型。
  5. 制定扩容方案:基于容量评估结果,制定扩容方案。方案需明确扩容时间点、扩容规模、优先级等。

4.2 容量监控与预警

容量监控是动态管理容量的重要手段,主要包括:

  1. 监控指标设置:设置合理的容量监控指标和阈值,如 CPU 使用率、内存占用率、磁盘空间使用率等。
  2. 监控系统搭建:搭建容量监控系统,实时采集和展示系统的容量指标数据。
  3. 性能压测:模拟各种极限场景,全面评估系统的性能表现和稳定性水平。
  4. 预警机制建立:建立容量预警机制,当指标达到预设阈值时,自动触发告警,通知相关人员及时处理。
  5. 故障诊断:当发生容量告警时,需迅速分析诊断问题根因,区分是临时性波动还是长期趋势,并给出解决方案。

4.3 动态扩缩容

传统的容量管理主要依赖事前的容量规划,难以应对突发的流量洪峰。云计算和微服务架构为实现动态扩缩容提供了便利,主要策略有:

  1. 自动扩容:利用云平台的弹性能力,设置自动扩容策略。当业务量超过阈值时自动增加资源,保障服务能力。此处需要考虑常备资源池,因为云平台的弹性能力也是需要资源来扩的,也不是无限制的。
  2. 成本优化:在满足容量需求的同时,需兼顾成本因素,权衡系统冗余度与扩容成本,并进行优化。同时,考虑在业务低谷时自动缩减资源配置,节约运营成本。

随着业务规模和系统复杂度的增加,仅仅依靠事后的纵向扩容已难以满足快速增长的容量需求。需要建立起完整的容量管理体系,综合利用容量规划、监控、预警、动态扩缩容等管理措施,建立起适应业务发展的动态资源供给机制,夯实系统高可用的基础设施,全力保障系统的稳定运行。

5 风险治理:稳定性的屏障

风险治理是稳定性建设的重要防线和屏障,通过系统化的风险管控措施,最大限度规避和降低风险的影响。 风险治理主要包括告警管理和风险冒泡两大板块。

5.1 告警管理

告警是风险的重要信号,高效的告警管理可以显著提升风险发现和处置的效率。告警管理主要包括以下环节:

  1. 告警规则管理
    • 根据系统架构和业务特点,设置合理的告警规则和阈值。
    • 定期评估和优化告警规则,持续提高告警的准确性和时效性。
  2. 告警通知管理
    • 建立告警通知渠道,确保告警及时、准确送达相关责任人。
    • 设置告警通知策略,根据告警级别和时段,采用短信、电话、邮件等多种通知方式。
  3. 告警分析
    • 建立告警分析机制,对告警数据进行统计和分析,识别告警的规律和根因。
    • 对高频告警进行重点关注,找出优化方向,制定改进措施。
  4. 告警闭环管理
    • 建立告警处理流程,明确告警分派、处理、反馈、总结等环节的职责和要求。
    • 跟踪告警处理进展,确保每个告警都得到及时、有效地处置和闭环。

5.2 风险冒泡

风险冒泡是一种主动的风险管理机制,通过自下而上地识别和评估风险,实现风险的早发现、早处置。风险冒泡主要包括以下环节:

  1. 风险识别
    • 在架构设计、变更管理、故障处理等环节中,鼓励团队主动识别风险点。
    • 建立风险登记机制,为风险识别提供渠道和工具支撑。
  2. 风险分析
    • 对识别出的风险进行分析评估,判断风险的可能性和影响程度。
    • 根据风险分析结果,确定风险的优先级和处置策略。
  3. 风险闭环
    • 建立风险处置机制,明确风险处置的流程、职责和要求。
    • 跟踪风险处置进展,确保风险得到有效管控和闭环。
    • 定期回顾风险管理成效,持续优化风险管理流程和机制。

通过告警管理和风险冒泡等机制,提高风险管理的主动性和有效性,筑牢风险防范的堤坝,为系统稳定性提供坚实保障。

风险管理不是某一个人事情,而是所有同学的事情,培养团队的风险意识和防控能力,将风险管理理念渗透到研发、测试、运维等各个环节之中,共同营造稳定可靠的系统环境。

6 故障管理:稳定性的防线

故障管理是稳定性建设的核心防守环节,其目标是在故障发生时,能够在 1 分钟内发现问题,5 分钟内定位到问题点,10 分钟恢复服务。

6.1 流程体系

完善的故障管理流程是高效处置故障的基础,主要包括:

  1. 故障恢复组织
    • 成立专门的故障恢复组织,明确角色分工和职责,如现场总指挥、技术协调、对外沟通等。
    • 建立 7×24 小时值班机制,确保故障发生时能够及时响应和处置。
  2. 故障处理流程
    • 建立标准化的故障处理流程,明确故障报告、分派、处理、恢复、总结等各个环节的工作内容和产出物。
    • 规范故障处理过程的信息同步和沟通机制,确保信息的及时、准确传递。
  3. 故障恢复预案
    • 针对重大故障,提前制定恢复预案,明确故障判断标准、升级机制、恢复步骤等。
    • 定期开展故障恢复演练,检验预案的可行性,提升故障处置能力。

6.2 可观测性

可观测性是故障管理的技术基础,通过完善的监控和度量体系,实现故障的快速发现和定位。主要包括:

  1. 服务级别协议(SLA)
    • 与业务方共同制定 SLA,明确服务的可用性、性能等关键指标和目标值。
    • 将 SLA 指标化,纳入监控范围,实时跟踪 SLA 达标情况。
  2. 监控设计
    • 全面梳理系统的监控需求,设计合理的监控指标和阈值。
    • 建立分层分级的监控体系,覆盖基础设施、中间件、应用、业务等各个层面。
    • 融合黑盒监控和白盒监控手段,实现从用户体验到底层资源的全链路监控。
  3. 根因分析
    • 建设完善的日志、指标、调用链等数据收集和分析平台,为故障诊断提供数据支撑。
    • 规范日志打印和错误码设计,提高故障信息的可读性和可诊断性。
    • 开发智能化的根因分析工具,利用机器学习、大数据等技术,提升问题定位效率。

6.3 持续改进

故障是暴露系统薄弱点的机会,需要通过不断复盘和改进,从根本上提升系统的稳定性水平。主要包括:

  1. 故障复盘
    • 建立故障复盘机制,定期召开故障复盘会,全面回顾故障处理过程。
    • 深入分析故障原因,找出架构设计、变更管理、应急响应等方面的改进点。
    • 形成故障复盘报告,作为知识积累和经验传承的重要载体。
  2. 故障演练
    • 定期开展故障演练,模拟各种故障场景,检验架构和预案的有效性。
    • 针对演练发现的问题,制定整改计划,持续优化系统的容错能力。
  3. 混沌工程
    • 在系统中主动注入故障,观察系统的响应和恢复情况。
    • 验证系统在异常情况下的可用性和可恢复性,找出薄弱环节并加以改进。

通过构建完善的故障管理流程,提升系统的可观测性,加强故障复盘和改进,最终形成 「故障即机会」 的文化氛围,将故障管理打造成组织稳定性建设的核心竞争力。

7 混沌工程:稳定性的试金石

混沌工程是通过在系统中主动注入故障,来检验系统的容错能力和恢复能力的一种方法。

它源自 Netflix 的实践,其核心理念是「通过在生产环境中制造真实的故障,来建设系统抵御真实故障的能力」。

混沌工程可以帮助我们发现系统在异常情况下的薄弱点,并持续优化系统的韧性。

7.1 混沌工程原则

混沌工程的实践需要遵循一些基本原则,主要包括:

  1. 在生产环境中进行实验
    • 只有在生产环境中进行实验,才能真实地验证系统的稳定性。
    • 在其他环境中进行的实验,由于环境差异,可能无法发现真正的问题。
  2. 量化系统行为的稳态假设
    • 在进行混沌实验前,需要定义系统正常行为的量化指标,如延迟、错误率等。
    • 基于这些指标,设定稳态假设,作为判断实验是否成功的依据。
  3. 少量和可控的爆炸半径
    • 混沌实验应该从小规模、低风险开始,逐步增加实验的复杂度和影响范围。
    • 实验需要有完善的监控和回滚机制,确保在发生重大问题时能够及时止损。
  4. 自动化实验过程
    • 混沌实验需要频繁、持续地进行,手工操作难以维持。
    • 通过自动化手段,将实验过程编排为工作流,可以显著提高实验效率。

7.2 混沌工程工具

混沌工程的实施离不开工具的支持,目前业界已经有一些比较成熟的混沌工程工具,如:

  1. Chaos Monkey:Netflix开源的混沌工程工具,可以随机终止虚拟机实例。
  2. Chaos Mesh:一款云原生的混沌工程平台,支持在Kubernetes环境中注入各种故障。
  3. Gremlin:商业化的混沌工程服务,提供主机、容器、网络等多层面的故障注入。
  4. ChaosBlade:阿里巴巴开源的混沌工程工具,支持丰富的故障场景,如CPU满载、网络延迟等。

选择合适的工具,并将其集成到 CI/CD  流程中,可以帮助我们更高效、自动化地开展混沌工程实践。

7.3 混沌工程实践

开展混沌工程实践,一般包括以下步骤:

  1. 定义稳态假设
    • 梳理系统的关键业务指标,定义正常情况下的量化阈值。
    • 设定实验的成功标准,即在故障注入后,系统仍能满足这些阈值。
  2. 设计实验场景
    • 基于系统架构和故障模式,设计实验场景,如服务不可用、数据库延迟等。
    • 实验场景需要尽可能模拟真实的故障情况,但又不能对业务造成不可接受的影响。
  3. 执行实验
    • 在生产环境中,对部分用户或服务实例,执行故障注入。
    • 同时监控系统行为,验证是否满足稳态假设,是否触发了故障恢复机制。
  4. 分析实验结果
    • 收集实验过程中的各项指标数据,分析系统在故障场景下的表现。
    • 若发现问题,则需要深入定位原因,给出优化方案。
  5. 持续优化
    • 基于实验结果,持续优化系统的容错和恢复能力,如改进缓存策略、超时机制等。
    • 将实验场景纳入回归测试,确保优化措施在后续变更中持续生效。

混沌工程的实践是一个持续迭代的过程,需要在不断的实验和优化中,逐步提升系统的稳定性水平。

7.4 混沌工程的挑战

推行混沌工程也面临一些挑战,主要包括:

  1. 对业务的影响
    • 混沌实验本质上是在生产环境中制造故障,可能会对线上业务造成影响。
    • 需要在充分测试的基础上,谨慎评估实验风险,制定完善的应急预案。
  2. 组织文化的转变
    • 混沌工程鼓励主动制造故障,这与传统的「恐惧变更」心态相悖。
    • 需要在组织内部推行「拥抱故障」的文化,鼓励大家主动发现和修复问题。
  3. 工具和实践的成熟度
    • 混沌工程仍是一个相对新兴的领域,工具和实践的标准化程度还不够高。
    • 不同的系统和架构,可能需要定制化的实验场景和工具支持,这对实践者的能力提出了较高要求。

尽管存在挑战,但混沌工程对于提升系统稳定性的价值是毋庸置疑的。越来越多的互联网企业开始拥抱混沌工程,将其作为稳定性建设的重要抓手。相信通过不断的实践和积累,混沌工程必将成为构建高可用系统的利器。

8 小结

稳定性建设不是一个一蹴而就的过程,需要持续的投入。

过程中需要考虑 ROI,需要平衡业务和技术,需要和业务方或公司战略达到一致,不要自己偷偷搞。

过程中需要区分核心链路和非核心链路,我们无法确保所有服务都达到 4 个 9,考虑 ROI,优先保障核心业务的稳定性。

稳定性建设需要建立在真实、可量化的数据基础之上。我们收集并分析系统的各项指标数据,如请求量、错误率、延迟等,用数据说话,找到问题点,一个个去解决,优化。

稳定性无止境,建设无止境。