主题

主题 02:如何设计系统预案(Preplan)?

1. 引言

所谓预案,是指根据评估分析或经验,对潜在的或可能发生的突发事件的类别和影响程度而事先制定的应急处置方案。预案并不是个新鲜词,《尚书·说命中》:“惟事事,乃其有备,有备无患。”其大意为:事先有防备便可以避免灾祸,强调了做预案的重要性。

在互联网领域,从系统设计、编码实现到后期维护,预案几乎贯穿全程。以下场景读者应该不陌生:

  • 淘宝首页“千人千面”推荐服务,读者应该都体验过。在接入推荐系统时,有一个必须考虑的问题——推荐服务不可用的场景下如何兜底,以最大限度保障用户体验,这就要求系统设计必须有一个 plan-B,详情下文将介绍。
  • 2019“双十一”天猫交易峰值达 54.4 万笔/秒,为了保障交易核心链路的稳定性,做了大量预案,如对非核心业务(如积分奖励)都做了提前降级预案。
  • 支付宝为了提高容灾能力,于 2018 年建成了目前全国唯一的“三地五中心”服务器网络,即在三座城市部署五个机房,一旦其中一个或两个机房发生故障,底层系统可快速识别并将故障机房的流量切换到运行正常的机房,并保障数据一致性和零丢失。

以上这些场景本质上都是为了保障系统稳定性而做的广义预案。在实践中,很多工程师倾向于系统的功能性建设,而忽视那些影响系统稳定性的非功能性建设,而这往往是导致系统故障的深层原因。作为一名工程师,特别是大型应用的工程师,稳定性设计能力尤为重要,鉴于此,笔者将从“预案”的角度切入,与读者一起探讨系统稳定性建设。

本文将围绕以下三个问题展开:

  • 什么是预案?
  • 为什么要做预案?
  • 如何做预案?

2. 为什么要做预案?

2.1 风险如影随形

在互联网领域,风险总是如影随形,没有什么系统是绝对稳定的。按照产生的原因,风险可以大致作如下划分:

  1. 自然风险,即自然因素所造成的风险,如设备老化、地震灾害、天气异常等。例如某个城市发生自然灾害,而造成公司部署在该城市的服务器机房不可用。
  2. 社会风险,即个人或团体在社会上的行为导致的风险,如战争、各地区法律变更、邮政罢工、网络攻击等。例如 2013 年 7 月,微信因上海某施工队挖断通信光缆而导致服务中断 7 小时;支付宝每天受到的网络攻击次数以亿计。
  3. 内部风险,即公司内部人员在设计、开发、变更、发布、运维等环节中引入的缺陷或错误的操作所造成的风险。在互联网领域,这类风险最为常见,如应用发布、调整 DB 结构、发布前端内容、调整网络、修改元数据配置、变更中间件、变更安全配置等等。

2.2 风险可导致严重后果

风险一旦发生,有可能导致一系列事故,引发难以接受的严重后果。

案例 1:2015 年 5 月 27 日,支付宝大规模宕机事故导致大量用户无法登陆或支付,故障持续长达两小时。这起事故给支付宝造成了严重的负面影响,导致用户满意度降低、品牌价值下滑、增长放缓以及经济损失等。

案例 2:2017 年“双十一”,某电商平台大促活动预热启动后不久,App 首页第二屏出现活动楼层“开天窗”的问题,经过定位并重新发布相关接口方才解决,给相关商家带来了巨大经济损失。

2.3 设计预案以应对风险

既然风险是客观存在的,同时又不能对其视而不见,那么,最好的处理方式便是积极地应对。在实践中,应对风险的时间阶段通常划分为事前预防、事中救援、事后处理三个阶段,与之对应的预案分别称为提前预案、应急预案、恢复预案。为了保障稳定性,通常需要在这三个阶段都有针对性地制定有效预案,但是,对于一个具体的系统,可能并不同时具备上述三个风险应对阶段,因此,风险处理预案的制定应结合实际情况决策。

3. 如何设计预案?

3.1 预案的生命周期

预案的生命周期一般可以分为规划阶段、实施阶段、演练阶段、生效阶段及失效阶段。

在这里插入图片描述

在实践中,预案设计在系统设计阶段就开始了,这一步是难点,因为需要识别业务场景的核心链路,以便分析各个环节所存在的风险。如果存在风险,则需要设计对应的预案策略;系统开发完成后,还需进一步通过预案演练来验证预案的有效性,以确保风险发生时预案可以随时生效。此外,考虑到系统变更(如各种优化、迭代),可能导致预案失效,因此需定期验证预案。

3.2 预案规划 & 实施

1. 识别待实施点

针对具体的业务,理清业务的核心链路,整体分析链路中潜在的风险点,这些点便是预案的待实施点。以淘宝 App 首页商品数据投放为例,商品数据来源主要有两个:运营定向投放和算法推荐投放。数据投放的基本链路如下图所示:

在这里插入图片描述

2. 充分分析风险

接续上面的例子,在此单就服务端进行分析,如果算法平台、运营平台或数据平台因故障而导致服务不可用,在没有预案的情况下,商品数据投放将无法正常进行,进而导致客户端异常,影响用户体验。

在这里插入图片描述

3. 思考预案策略

在充分分析风险点之后,下一步便是针对这些风险点制定应对预案(策略)。接续上面的例子,针对算法投放服务和运营投放服务因平台故障而导致不可用的场景,需要制定一个预案来保障商品数据投放的可用性。在此列举几种可行的方案。

  • 策略一

运营定投与算法投放互为灾备方案,即当运营投放服务不可用时,商品数据投放全部依赖算法推荐;当算法推荐服务不可用时,全部采用运营投放服务提供的数据。如此,虽然可以提高服务的可用性,但是,若两个服务同时不可用则仍然存在可用性风险,当然,这种情况概率极低——假设两个服务不可用的概率均为 1%,则同时不可用的概率为 1%*1% = 1/10000。

在这里插入图片描述

  • 策略二

针对首页商品投放位的数据以配置推送的形式兜底,即针对首页商品投放位,预先由运营人员准备好合适的数据(比如普适性商品),当运营定投服务或算法推荐服务不可用时,根据投放位从兜底数据中直接获取商品数据进行兜底,从而保障可用性。

在这里插入图片描述

  • 策略三

针对运营定投服务和算法推荐服务分别设计预案。考虑到运营定投服务数据相对固定,个性化程度低,因此仍采用方案二所述方式进行兜底;相较而言,算法推荐是一种个性化的服务,号称千人千面,因此,宜采用基于用户人群的兜底方案——根据用户的特征数据集将用户划分为不同的人群,相同的人群具有相似的购买倾向,然后针对每个人群分别缓存推荐商品数据并实时更新,当推荐算法服务不可用时,可根据用户所属人群获取相应的数据兜底,从而保障用户体验。相较于方案二,此方案更复杂,但体验更好。

在这里插入图片描述

在实践中,上述三种策略常常组合使用,以求最大限度地保障可用性和用户体验。

4. 预案落地

针对同一个风险点,通常有多种可行的应对预案,对于这些预案应从落地成本、负面影响、可维护性等多个维度考量,确定最合适的预案(最好的预案未必是最合适的)。确定预案之后,下一步便是将其落地,不同的预案涉及的技术细节和要点大相径庭,本文不做展开。

3.3 预案演练

预案规划并实施完成后,为了确保预案的有效性,必须进行预案演练。演练需要注意以下事项:

  • 预案演练之前应通知上下游,知会其预案演练过程中可能对其造成的影响;
  • 预案相关的业务应配置监控,以便实时监控预案的执行效果;
  • 预案演练应准备对应的回滚预案,一旦预案演练出现问题,可以及时回滚止血;
  • 演练应在线上环境进行,以确保场景真实;
  • 对于会影响用户体验的预案,演练应在流量低谷进行,如凌晨三点至六点,持续时间不宜过长,以尽量降低对用户的影响;
  • 预案演练完成后,应注意收集、记录演练数据,并充分评估预案的有效性;
  • 如果预案演练结果不符合预期,在修复问题后应重新演练,直到符合预期。

3.4 预案生效 & 预案失效

预案演练完成并通过有效性验证后,预案就正式生效了。在大型互联网企业,通常有专门的预案平台负责管理预案,预案可以由预设的条件触发执行,也可以人工手动执行。

预案不是一次性工作,生效后需要定期维护和更新。在实践中,由于业务逻辑的变更、技术方案的更迭,有可能导致现有预案失效而需要我们替换预案或者对原有预案作优化,甚至重新设计预案。

3.5 补充说明

预案的类型和处理方式有很多,上文所举例子中仅仅涉及“灾备预案”、“兜底预案”,更常见的如“多级缓存预案”、“限流降级预案”等,读者可以根据自身所负责业务的特点,针对性地分析和处理。

须知,方式和工具不是预案的重点,重点在于稳定性思维的培养,所谓预案,实则为保障系统稳定性的 Plan-B。

4. 扩展:“三维”开发

预案本质上是为保障系统稳定性服务的,在阿里、腾讯、华为等一线企业核心部门,有一个普遍共识:稳定压倒一切,是第一原则。这不难理解,试想一个不稳定的系统,无论提供的服务多么亮眼,你敢把“后背”交给它吗?

作为一名工程师,在职业生涯中会经历下图所示的三个阶段:

  • 初级阶段,仅考虑如何实现需求,聚焦于功能层面,缺乏设计能力和抽象能力。
  • 中级阶段,开始考虑系统扩展性,在开发中注重模型抽象和接口设计,善于运用一些设计模式优化业务实现逻辑。
  • 高级阶段,在抽象和实现的基础上,注重系统稳定性考量,能敏锐洞悉系统潜在的风险点,同时将应对策略融入系统设计中。

在这里插入图片描述

阅读本文的读者,相信大都已经历过前两个阶段,而第三个阶段作为进阶之路必须具备的能力却往往被忽视。在此,特别强调,在开发中须养成“三维开发”的意识,实现、抽象、稳定,全面考量。

5. 总结

本文以三个 W(什么是预案?为什么要做预案?如何设计预案?)为主线展开,介绍了系统预案相关的内容,其中,结合案例重点介绍了系统预案的设计方法。

文中曾提及:预案的本质是为系统稳定性服务的。换句话说,设计预案的前提一定是系统的稳定性存在风险,且一旦风险发生,所导致的结果将难以接受。在设计系统的时候,稳定性是必须充分考虑的,但是,预案却并非必须。

预案通常是从系统层面考虑,但落实到具体的开发实践中则不然,比如代码容错设计本身也可划归预案的范畴。预案可大可小,可上可下,在实践中,读者不必拘泥、纠结,一切为保障系统稳定性而做的设计都可归属于广义的预案。

上一篇
下一篇
内容互动
写评论
加载更多
评论文章