背景
爱奇艺除了每天都为数以亿计的用户提供优质的视频服务,同时还有体育、直播、文学等业务服务于更多的圈层用户,海量的业务几乎每天都在进行营销活动,由此带来的流量随时可能会给我们的服务引入不确定性。爱奇艺支付团队为各业务线提供全面的收付款服务,保障用户的付费体验,团队除了保障服务的稳定性外,还要应对随时可能爆发的流量挑战。对于支付系统来说做好准确的容量评估和预案是非常重要的,全链路压测在这方面提供了有力保障。
全链路压测是基于生产环境,模拟业务高峰时的海量请求,对整个系统链路进行压力测试,继而进行有效的容量评估和系统调优。因为支付业务对数据敏感同时业务复杂,使得系统间调用链路难以准确全面评估,实施压测比较困难,在没有实施全链路压测前,我们经常会遇到以下问题:
生产环境流量构成复杂,单机压测结果难以有效评估生产环境容量;
流量转化评估与实际用户行为不匹配,导致预案不能达到预期效果;
公共资源/服务很难在局部压测中暴露瓶颈,需要真实的高峰流量来验证;
链路容量不能对齐导致整体受限于短板服务,同时也产生了严重的资源浪费。
以上问题归结原因主要是没有在生产环境使用真实场景的流量去压测系统,也就无法做出准确评估,为了解决以上问题,我们开始了全链路压测在以支付业务为核心场景的探索与实践。
问题探索与方法实践
开展全链路压测我们主要从几下方面进行了探索与实践:
核心链路梳理, 明确压测目标链路和分支链路,排除压测风险;
压测环境准备, 压测全链路能够透传压测标识并正确处理压测流量;
流量构造, 结合真实的数据和需求策略分析制定压测流量模型;
执行与保护, 实施前做好业务验证,按计划实施,做好监控和复盘。
1 核心链路梳理
核心链路梳理将多个业务线串联到一起,在实施过程中,我们由各业务团队梳理自己的核心链路,明确对下游服务的依赖,同时梳理出旁路依赖。将各业务线的核心链路进行汇总,得到最终的压测全链路。核心链路中可能会耦合外部服务但又不能参与压测,比如支付系统依赖的第三方渠道。在实践中我们通过自建渠道 mock 服务支持了多种渠道的支付请求,同时模拟渠道的支付成功率,支付回调延迟,支付通知等,形成支付全链路的闭环。
旁路依赖的梳理也是重要的一环,准确全面的梳理是后续顺利进行压测的保障。旁路依赖根据实际业务情况评估,如风控系统我们进行了 mock,账务服务通过消息组件实现了服务降级。
在与票务业务的一个抢票场景做链路梳理后,核心点主要涉及用户的登录鉴权、票务活动、出票、收银台、支付和通知 6 个服务,对风控、推荐、push 等旁路依赖评估后做了降级处理,对支付渠道和票务渠道的重要服务指标进行 mock,最终形成一个业务闭环的核心链路,如下图:
2 压测环境准备
核心链路依赖的环境除了业务的服务器外还涉及数据库、消息、缓存、日志等,在这一阶段我们主要对以下几点进行了考虑和支持:
压测标识透传
通过在入口流量中注入约定的标识用于区分压测流量,全链路识别并透传该标识是实现全链路压测的基础。我们的系统通过接入 APM(Application Performance Management)对系统进行监控管理和调用跟踪,天然实现了一次调用在 http、rpc、线程池以及中间件的信息保持,因此 APM 成为压测标识的首选载体,在实践过程中我们通过对 APM 简单改造实现了压测标识的透传和识别。
存储数据隔离
压测流量会影响包含写业务的数据库,造成数据混乱,这一点对支付业务尤为重要。对关系数据库,通过新建与原表结构一致的影子表,并将压测流量引入到影子表,实现压测数据的隔离。如何路由影子流量到影子表看项目的具体情况,我们通过 ShardingJDDC 和 Mybatis 拦截器两种方式实现了影子表的路由。
消息
消息中间件我们没有采用新增 topic 的方式,而是在消息体中加入了压测标识,需要降级的消费端通过订阅策略处理压测消息,例如我们在 RocketMQ 的消息体中附加约定的 UserProperty 属性,消费者按需订阅。
水位
中间件对压测流量的处理基本采用了数据隔离的方式,压测实施前将影子表等填充到与原始表相同的水位是很有必要的。一张空表和一张含有上千万数据的表性能表现是不一样的。
核心链路上可能会有很多技术组件要支持压测流量,原则和方案都是类似的,根据实际业务情况做好数据隔离即可。如 Redis 可以使用影子 key 或者影子集群,MongoDB 使用影子 collection, ElasticSearch 使用影子索引,日志新建影子目录。下图是爱奇艺的支付系统在全链路压测环境准备好后,核心链路对压测流量的处理情况:
3 流量构造
单接口压测时我们会提前生成好一批符合接口规范的数据备用,但这种数据过于单一,并不符合真实的业务场景。比较理想的方式是在网关层抓取生产环境的日志数据进行二次处理后对流量进行回放。我们在初期的探索阶段并没有实现这种方式,我们对已有的数据和接口调用量进行分析,结合业务策略对数据模型进行调整,得到最终的压测模型。例如在支付业务的全链路压测中,我们通过数据分析得出用户在生产环境中选择各支付方式的占比、各服务调用占比,同时结合业务策略对用户购买指数的影响,微调收银台转化率,最终确定下单服务、渠道通知、订单查询等服务调用量配比模型。
4 压测执行与保护
执行压测前,对全链路进行业务和环境验证是必不可少的,各业务确保压测旁路已做好降级和数据隔离,保证压测流量不影响正常业务数据。
监控是全链路压测实施过程中评估系统健康的重要手段,帮助我们发现问题,及时止损。在压测过程中我们事先准备了以下维度的指标:
核心链路服务调用量,成功率,耗时;
消息积压监控,redis 水位、命中率,数据库负载等性能指标;
机器的基础指标。
各业务负责人需要在压测前做好自身的限流和降级,同时还要为正常的业务流量预留安全的 buff,不能完全依靠压测平台的熔断条件。压测也会检验我们的限流值是否合理,降级预案是否能正常执行,是否符合预期。
压测实践与结果
全链路压测能力打通后,我们主要基于以下两个方面实施了全链路压测:
1 业务容量验证
支付团队与直播、票务等团队在营销、抢购活动中进行全链路压测,以满足业务需求容量为目标,有效定位全链路中的短板服务,通过扩容、异步化、降级等方式处理,保证了全链路的容量达到预期目标。同时对限流、降级策略进行验证,保证业务在高峰时的可用性。
压测时支付系统提供多种支付方式的支持,渠道 mock 服务提供贴近真实的拉起延迟、订单成功率 mock、同步响应、异步服务器通知、通知延迟等场景,形成全链路压测闭环。
2 系统极限压测
支付系统本身也是一个结构复杂的系统,收银台、账务、风控、认证、渠道等相关服务都由相关团队维护,任何一个环节保护不到位都可能影响整体系统的稳定性,因此对支付系统的全链路压测是很有必要的。
实施中主要拆分为两个方向:
虚币消费压测
虚币消费的特点是不涉及第三方渠道,但它也是一种标准的支付方式,具有与其他支付方式(如微信、支付宝)一样的生命周期。好处是不依赖第三方渠道,有效验证支付系统自身的容量。
在起初的压测中,我们发现虚币支付的 TPS 只能达到设计容量的 60%,通过对链路的耗时分析发现在订单号生成服务出现了部分降级,拉高了整体的 RT。进一步分析发现是分布式订单号的自增序列依赖 redis,在与 redis 的交互中出现抖动,与中间件团队确认后最终定位到是 RDB 持久化时 fork 子进程引起了服务停顿。根据当前场景的需求,我们关闭了 RDB,配合降级策略的优化,几轮压测调优后支付系统的 TPS 基本接近目前部署服务的可负载容量极限。
混合压测
基于我们对生产环境的数据分析,构造多种支付方式以一定配比对收银台服务进行压测,这个场景可以真实的模拟支付系统的上游流量,覆盖更全面的业务场景。通过压测,定位到一些服务节点容量不匹配问题,通过服务水平扩容和代码优化,最终将容量对齐。
全链路压测需要跨业务部门合作,每一次压测都要做好事前计划:目标是什么,需要哪些数据衡量,需要哪些预案,压测流量策略如何设置和执行等,同时做好复盘和结果跟进,保障压测在有序可控的前提下实施。
未来规划
在整个全链路压测实践中涉及到的需求点很多而且分散,如数据模型、流量调度、监控跟踪、性能分析等,很多细节处于探索阶段。后续结合更多的实践经验,进行统一规划形成一站式的解决方案,降低全链路压测的接入难度和实施成本。
对于涉及支付系统的全链路压测,流量来自上游业务,对支付方式多样性的构建是有一定成本的,后续计划支持将上游单一流量自动配比为多样化的支付请求。支付相关业务对数据比较敏感,提供支付压测数据报告给上游业务以及账务等相关业务,可以在必要时满足核对需求。
本文转载自公众号爱奇艺技术产品团队(ID:iQIYI-TP)。
原文链接:
评论 1 条评论