腾讯大讲堂隆重推出【100亿次的挑战】系列海量服务之道2.0讲座,覆盖技术、产品、项目管理、支撑、支付5个维度。第一场【技术篇】3000名鹅厂员工参与,场面火爆!从今天起,大讲堂将陆续推出回顾文章,回馈广大用户。

 

 

支付是个人发红包的必经环节,在除夕这个全国人民最热闹的一个节日里,让大家能顺利把钱花出去,变成红包到达亲朋好友的手中,甚至于在钱包中看自己收到了多少钱,顺便到处点点体验一下微信支付这个产品,在这个过程中,作为后端服务,如何让各项体验可以稳定可靠,成了我们重要的一个课题。

 

 

大家都知道,在除夕发红包的这个当口,会面临两个极端情况:一个是请求量大,一个是用户容忍度低。我们通过做到可控、柔性、应变三个方面,来平稳度过除夕这个红峰:

 

 

一、  如何做到可控?

 

系统在随着业务需求的快速迭代上线过程中,会渐渐变得荆棘密布,而且这些也许都发生在不经意间,当你回头去仔细再看的时候,会大大出乎自己的意料。其中大量的非核心调用、基础模块的重复调用、随意的跨城调用,淹没了核心的关键路径,加重了路径的重度和长度。当巨大的流量通过这条路径的时候,会压垮那些准备不足的分支岔路。我们从最朴素的想法出发,为了解决这个问题,那只有让到达目标的路径尽量短(核心路径),尽量宽(容量评估),尽量稳(冗余多活)。

 

1.    核心路径

 

我们通过在服务框架层增加染色信息,并层层进行上报收集,生成出完整的调用关系图。对着调用关系图,通过尽量做减法,将其中最核心的路径进行标记出来。怎么做减法?我们有以下几招:

 

  • 异步非核心调用;
  • 消灭重复调用;
  • 合并相关调用;
  • 减少跨城调用;
  • 裁剪静态信息调用(针对红包特殊处理);

 

 

通过做减法,我们优化了核心路径,为下一步的容量评估做了基础准备工作。

 

2.    容量评估

 

通过路径染色,在确定核心路径(资源)后,我们按照业务预期,从用户进入每个业务场景的每秒触发次数作为源头,分解到各场景内操作的核心路径,制定了容量核算表,从而评估出为了满足业务预期所需要的容量:

 

  • 单接口QPS
  • 模块整体QPS
  • 模块带宽流量;
  • 跨城穿越带宽流量;

 

 

基于这个容量评估,以及一些压测数据,我们可以给出运维上需要提供的各模块机器数,同城带宽和跨城带宽的需求。这样可以明明白白指导各项扩容工作开展,既避免了盲目拍脑袋定扩容机器数,也避免了评估不充分而边压测边扩容带来的效率低下。

 

3.    冗余多活

 

做完了核心路径和容量评估,是不是就做到了可控呢?答案是否的。大家都知道墨菲定律:只要有可能的事情就一定会发生,而且历史也无数次警告了我们这一点。我们当然不希望在除夕败给墨菲定律,所以我们还需要针对每个核心资源,尽可能来做到消除单点和单策略,以降低坏事情发生的可能。除了大家都很熟悉的多点冗余部署的无状态逻辑层,一方面负载均衡,一方面消除单点以外,我们还有如下一些策略:

 

  • 多套调用方式(按客户端用户触发顺序调用、前序接口预加载调用);
  • 多套数据获取(直接接口获取、进程内cache、集中化cache、准静态配置);
  • 多套访问链路(内网直接访问、跨城加速、通过内网接力点绕过故障链路、通过外网绕过故障链路);

 

通过对核心资源做到冗余多活,系统模块之间的层层保护,使得在系统层面基于并非完全可靠的各个模块实现了整体上可靠的系统。

 

二、  如何做到柔性?

 

虽然我们做到了对系统的把控,但是由于一些原因,比如除夕晚上大家的热情超出了预期,再比如扩容的某个资源由于和别的业务混用而无法提供评估预期的支撑,从而导致最终超出了我们前期准备的核心路径的资源。在这种情况下,我们的应对策略是:尽量保最核心的功能(体验降级)和一定不能(过载保护)。

 

1.    体验降级

 

这个策略随着海量课程的普及,已经深入人心:在无法提供最好的服务的时候,先解决用户最最核心的需求。在核心路径中,我们继续分解出一些非核心的特性,对于这些特性所依赖的系统调用,分两个级别来做应对策略:

 

  • 旁路(异常容忍):通过设置较小超时值,当发现出现少量毛刺,资源受限无法在预期时间内完成调用返回时,将其结果忽略,而不影响最核心的功能;
  • 降级(彻底关闭):通过设置毛刺阈值,当出现大量超时,对整体系统的吞吐和并发能力产生影响时,直接将特性关闭,不再进行调用;

 

 

 

 

2.    过载保护

 

和体验降级一样,这个也是大家所熟知的面对海量请求下的对系统的保护策略:系统尽可能提供自己所能的服务,当压力过大时,丢弃无法处理的请求(做好前端的友好提示)而使得系统活下来,避免出现雪崩:

 

  • 接口限频(事前保护):提前按准备好的处理能力,设置服务可达到的QPS,超过则直接拒绝;
  • 快速拒绝(事中保护):通过对服务质量的监控(机器负载、队列等待长度,接口耗时等),当发现监控指标超过阈值时,则触发对待处理请求的快速拒绝;

 

 

三、  如何做到应变?

 

天有不测风云,即使做了万全的打算和准备,还是会发生预料中或者预料外的情况。我们对除夕当晚的预期是悲观的,大家常说的一句话就是:肯定哪里会出问题,就看能救多快。而对各种可能发生的应变上,我们是充分准备的,展现出各种“奇淫巧计”,并且我们最终证明了:成功是留给有准备的人的。

 

1.    应急预案

 

针对前文说到的冗余多活和柔性策略的切换,有两种实施策略,一种是系统自动触发,一种是人工干预。由于实际情况可能决策比较复杂,自动触发的验证很难覆盖全,而除夕又容不得任何出错,因此我们最终决策还是基于充分的监控,在除夕当晚通过人工进行干预。为了避免人工干预时的手忙脚乱,忙中出错,我们做了如下两个事情:

 

  • 应急预案:针对各种异常下的操作控制,进行了梳理,并形成《应急预案手册》,便于做出快速决策;
  • 按策略快速生效:针对上述应急预案策略的人工干预操作,我们做了一套快速下发系统,并提前设计好变更策略,届时直接按策略推送。避免了临时进行多个配置项的变更和上线流程,节约了处置时间并且使得操作不易出错;

 

在除夕当晚,其中一个策略得到了显著效果,这个策略是冗余多活中说到的多套访问链路。除夕当晚,上海访问深圳的底层链路服务出现抖动,我们在定位问题后,将链路切换到其他冗余方式上,恢复了业务:

 

 

 

2.    巧妙卸力

 

在系统中,有一些特定性能短板的场景,在这些特定场景下,通过分析制定适用的巧妙策略,有的时候是非常有效的,需要一定的业务敏感性,有的时候也是灵光一现,这里分享红包支付中的一个巧妙的乾坤大挪移。大家都知道,在支付中如果使用零钱,那么请求是在内部系统就可以完成。如果是使用银行卡,那么支付请求必须发送到银行进行扣款。很显然,银行接口的性能对于整个系统来说是一个局部短板。在跨年支付红峰冲击最大的时候,其实很多人通过前几天的红包游戏,已经积累了不少的零钱。而业务上正好有默认支付方式的特性,所以通过合理引导压力,在跨年时刻到来前,只要用户零钱足够,我们就优先引导用户使用零钱:

 

 

从曲线看出,在策略生效后,银行卡支付请求量几乎下降了50%,并且在跨年到来时,叠加上请求量的上涨30%,系统能力也可以cover住,这样就巧妙地保护了银行接口的短板,也同时保护了用户体验的流畅。

 

四、  小结

 

面对不容出错的海量应用项目,怎样在后台侧可以优雅地做到稳定的用户体验,我们根据自己的工作,得出来如下的总结,也希望给大家以后在处理类似问题时有一点帮助:

 

  • 可控:对核心支撑的评估梳理 – 一切尽在掌握
  • 柔性:对系统可靠的质疑态度 – 保护无处不在
  • 应变:对极端情况的充分准备 – 气定神闲镇场