掘金 后端 ( ) • 2024-03-28 10:25

意义

系统稳定性直接关系到企业的可靠性、用户满意度、业务连续性以及声誉。

  • 用户满意度:稳定的系统能够提供更好的用户体验,减少服务中断、加载延迟或崩溃等问题,提高用户满意度。
  • 业务连续性:如果系统频繁崩溃或不可用,业务操作将受影响,导致业务中断,损失收入和客户。系统稳定性能够保证业务的连续性。
  • 数据保护:系统不稳定可能导致数据丢失或泄漏,对业务造成严重损害。稳定的系统能够有效保护数据的完整性、可用性和保密性。
  • 企业声誉:稳定的系统代表着专业和可信赖的形象。企业在客户和合作伙伴中建立良好的声誉,有助于增强市场竞争力。
  • 效率和生产力:稳定的系统意味着员工能够无缝地执行任务,不必花费时间应对系统故障。高稳定性的系统,能够提高工作效率和生产力,减少工作中断。
  • 成本控制:不稳定的系统可能需要投入大量的人力、时间和资源,稳定的系统减少了资源投入,降低了企业的维护成本。
  • 业务增长:稳定的系统为业务增长创造了条件。企业可以专注于业务拓展,而不必过多担心系统稳定性问题。

指标

  • 业务可用程度:最通常使用的系统稳定性评价指标,SLA 有两种计算方式:一种是通过时间 维度计算,一种是通过用户请求状态计算。除 SLA 之外,还可以配 合使用 RTO(Recovery Time Objective,复原时间目标),RPO(Recovery Point Objective,复原点目标) 等指标,监测数据的完整性。
  • 用户影响程度:影响程度主要是指受影响的用户数量。
  • 资产损失程度:资产损失程度主要从应用方的角度出发评价故障发生后对组织产生的影响,此处的资产包括有形资产和无形资产。 有形资产包括:资金、设备、人力成本等;无形资产包括:社会形象、 潜在商机等。
  • 业务恢复率
  • RTO 复原时间目标
  • RPO 复原点目标
  • MTTR 故障从发现到恢复的时间

建设方式

监控(Monitoring)一般来说,监控报警分为系统 应用运行 中间件 和业务级别的监控报警 没有监控报警 就只能等问题出现才能感知,所以监控是稳定性的根基。

应急响应(Incident Response),从一个问题被监控发现到最终解决,这期间的耗时直接取决于应急响应机制的成熟度。合理的应急策略能保证当故障发生时,所有问题能得到有序且妥善的处理,而不是慌乱成一锅粥。

事后总结以及根因分析(Postmortem&Root Caue Analysis),即“复盘”,只有当摸清故障的根因以及对应的缺陷,我们才能对症下药,合理进行规避 常用方法如5why分析法等。

测试和发布管控(Testing&Release procedures) 假设一个系统不再进行更新迭代,做好上述三个方面的工作就能基本满足系统对于稳定性的全部需求。可惜目前基本不会存在这样的系统,大大小小的应用都离不开不断的变更与发布,因此要保证系统在这些迭代中持续稳定。测试与发布策略能保障系统所新增功能都处于可控稳定区间内。

容量规划(Capacity Planning) 除了代码逻辑更新,迭代同样可能带来业务规模及流量的变化 则是针对于这方面变化进行的保障策略。现有系统体量是否足够支撑新的流量需求,整体链路上是否存在不对等的薄弱节点,都是容量规划需要考虑的问题。

产品设计(Product)与软件研发(Development),即通过优秀的产品设计与软件设计使系统具备更高的可靠性,构建高可用产品架构体系,从而提升用户体验。

目标

降发生 通过合理的需求评审 技术评审 开发规范 开发规范和测试和发布管控流程,从方案设计阶段即采用面向失败的理念 来设计系统架构,并通过一系列技术手段验证系统稳定性。

高可用 通过冗余设计的思想来实现应用架构的高可用能力保障,同时通过可靠的基础设施组件,将应用的高可用能力转移到基础设施来提供。

降影响 即降低故障发生后的影响范围。早感知,故障感知最基础和重要的原则就是完善监控告警。通过可视化的监控告警能力,感知系统的异常变化,可以尽早发现甚至预测系统故障。快定位,系统对故障定位明确,故障管理机制定义完整,职责明确,流程清晰,能有效提升故障发生后的处理效率。

急止损 “止血”大于“修复”,故障发生后的第一反应永远是“优先止损”,在完成止损工作之后,再开展故障修复。而为了有效止损,需要提前设立各种故障预案。优改进,及时复盘,实现故障闭环。故障复盘是故障发生后的改进措施, 目的是完成系统韧性提升,实现故障闭环。

稳定性治理-事前

规范

规范可以根据公司编写对应规范,此处不再赘述 包括以下规范

研发流程规范

  • SQL

  • 缓存

  • CR

  • 编码规范

  • 需求评审

  • 技术评审

  • 发布流程规范

  • 测试流程规范

架构设计

容错

调用白/黑名单(应用、IP),调用鉴权,调用量监控

隔离能力

  • 插件隔离、容器隔离
  • 服务器分组隔离
  • 机房、单元隔离

限流能力

限流可以理解为是一个控制流量阈值或调节比例的功能,在前端网站面对大流量访问的时候,可以对流量进行控制,防止大流量对后端核心系统造成破坏,导致服务不可用的情况。即通过调节流量阈值来控制通过系统的最大流量值,保证系统安全可靠运行

快速失败是限流的核心。当流量超过系统承载能力的时候,要能自动拒绝多余的请求,避免资源的浪费:

  • 作为服务端不能被压垮,作为消费端不能被下游拖挂,限流要在关键节点做限制
  • 限流的同时,也要聚焦性能和用户体验,防止自我否定攻击
  • 限流的发现、处理能力
  • 服务限流:出现流量高峰时,超出流控规则所定义的流量上限时,一部分调用方将出现限流异常错误
  • HTTP 限流:出现流量高峰时,一部分调用方将被重定向到一个出错页面

降级能力

  • 当系统对很多服务进行依赖,如果有一个依赖服务发生故障,则系统本身需要对该故障服务进行降级,防止故障扩散
  • 当降级的服务恢复之后,系统能自动恢复对其的调用
  • 所有的弱依赖都是可降级的,降级的前提是不产生脏数据

容量

  • 定期进行单机压测,评估系统容量,建立性能基线
  • 定期进行单链路or全链路压测,确保依赖链条容量
  • 容量冗余50%, 互备机房可以支撑全部流量
  • 关注流量的变化

容灾

消除单点

  • 服务的实现不能有单点,至少双机房部署

系统依赖设计

分析服务实现流程中所依赖的所有应用系统(以及这些系统提供的服务)
需要识别该依赖的以下属性:
依赖强弱:强依赖是指必须的依赖,弱依赖是指可选的依赖;
同步或异步:同步表示需要等待返回,异步指调用发生后无需等
待立即返回;
高等级服务不允许强依赖于低等级的服务或资源(内部服务、外
部服务、数据库、基础技术组件等等)。这里的关键是依赖强弱程度
的判断
最强依赖:当所依赖的服务不可用时,服务不可用,且造成系统
崩溃。对于所有的依赖,不建议最强依赖。如果是核心链路需要考虑降级方案
强依赖:当所依赖的服务不可用时,服务不可用,但系统不会崩
溃,且当所依赖的服务恢复后自动恢复。服务只可强依赖于同等级或
高等级的服务与资源。
弱依赖:当所依赖的服务不可用时,服务继续可用,但损失一些
次级功能。服务允许弱依赖于低等级的服务与资源。
最弱依赖:当所依赖的服务不可用时,服务继续可用,且无任何
功能损失。在成本可控情况下,推荐采用最弱依赖的方式。


按类型和层次提炼出来会有如下几种分类:

系统启动依赖、基础软件依赖、业务域依赖、数据库依赖、硬件依赖、网络依赖。

对于稳定性要求高的关键系统,在成本可接受的情况下,同时维护一套保障主链路可用的备用系统和架构,在核心依赖服务出现问题能做一定时间周期的切换过渡(例如MySQL故障,KV数据库等)。

强依赖的服务越少,系统整体基础稳定性就越高。部分特殊数据依赖多于逻辑依赖的系统,做去依赖架构设计也是一个思路,将依赖服务数据统一整合到自有服务的数据存储中,通过消息 或定时更新的方式更新,做到不依赖 或少依赖其他系统,进而提高稳定性,但这样做也会有副作用:数据冗余可能会引发不同程度一定时间窗口数据不一致性。

无状态原则

服务分为有状态的服务和无状态服务,其判断依据是指来自相同发起者的请求在服务端是否具备上下文关系。有状态服务是指服务端要保存请求的相关信息,每个后续的请求都可以默认地的使用以前的请求信息。无状态服务是指服务端不保存请求的相关信息,服务端处理的数据全部来自请求所携带的信息。当前主流架构的应用服务都是无状态服务。

故障自愈

  • 当下游依赖的存储集群,由于不可用而触发代码中的失败次数或失败时间阈值时,自动切换到备用的存储集群。
  • 当下游依赖的核心服务,由于不可用而触发代码中的失败次数或失败时间阈值时,自动降级到备用方案,如:将请求切换到存储非实时数据的ES中,接受有损。
  • 当系统由于响应时间激增而导致服务不可用时,自动对下游依赖的非核心服务进行降级熔断,减少服务接口的整体响应时间,保证可用。

警惕无边界

设置合理的系统边界值,确保不会因为过大边界值带来突发性的性能下降、内存暴增等可用性问题:

  • 当循环的参数来源自网络,务必对阀值进行限制,在服务接口层面会做一层阈值设置
  • 避免一次性加载数据,查询数据库默认要有limit限制,供应链这边的查询语句都带了limit限制,通过洛基会做未带limit限制的风险提示
  • 设置HTTP访问的最大缓冲区大小
  • 不要让系统存在无边界的队列或数据结构,比如线程池的队列设置了最大值

防止超时问题引起的故障

设置恰当的网络超时时间,可以有效的保障系统调用者不被临时性故障拖垮:

  • 在调用超时的情况下,正常QPS流量刚好消耗完可以接受的线程数量
  • 注意不要设置太长也不在要设置太短,以满足正常流量为佳
  • 警惕超时重试陷阱、确保依赖链路超时的对齐、并发API设置timeout

可使用开关&预案可动态调整线上系统运行状态

  • 各种有风险的业务或者模块上线的时候需要有开关控制,关键时刻可以手工关闭功能,
  • 开关当前状态要能被监控
  • 开关的使用频率可能比较低,要做好预案的全生命周期管理
  • 尽量少使用内存态预案
  • 预案要用自动执行和恢复

具备热点保护机制

对已知热点(爆发式的增量访问请求)进行主动保护,如:

  • 提前预热
  • 服务端缓存
  • 客户端缓存
  • 限流

具备弹性伸缩能力

分布式集群管理中,很重要的一个运维能力是能敏锐的感知集群内各个服务器的状态,并根据状态实时的实现集群扩容、缩容,在保证服务质量的同时,提升集群系统的可用率。

服务分级

高可用能力 P0 P1 P2 P3 无状态架构 ✔ ✔ ✔ ✔ 分布式架构,可横向水平扩展 ✔ ✔ ✔ ✔ 具备自动化运维工具能力 ✔ ✔ ✔ ✔ 同城容灾 ✔ ✔ ✔ 异地灾备 ✔ ✔ ✔ 租户隔离 ✔ ✔ ✔ ✔ 防止无边界陷阱 ✔ ✔ 超时问题处理 ✔ ✔ 限流 ✔ ✔ ✔ 降级 ✔ ✔ ✔ 开关&预案 ✔ 动态配置推送 ✔ 热点保护 ✔ ✔ 就近调用原则 ✔ 日志追踪 ✔ ✔ ✔ 容量规划 ✔ ✔ ✔ ✔ 弹性伸缩 ✔ 服务治理 ✔ ✔ 灰度发布 ✔ ✔ ✔ ✔ 监控报警 ✔ ✔ ✔ ✔ 调用链路跟踪 ✔ ✔ 线上压测 ✔ ✔ 故障演练 ✔ ✔