云集全链路压测自动化实践
背景
云集过往在516、双11大促备战都要花费好几个月的时间去精心准备,做监控梳理、报警梳理、预案梳理、容量规划等等,形成了很多可以参照的套路。为了保障系统稳定运行,云集参照同行做了非常多的努力:有完善的监控体系可以对服务和业务进行各环节实时监控,有在线和离线的统计分析可以做到实时告警,有容量规划系统对日常机器数量进行评估,有覆盖系统和业务的应急&降级预案降低故障影响范围。
随着业务不断发展以及大促保障措施日趋完善,需要协调的人员也越来越多,执行的任务体系也越来越庞杂。如何验证这些措施的有效性?最有效的方式是进行大促演练。为了演练评估数据真实可靠,需要全方位还原系统大促时所处的环境。大促期间系统除了要面对用户的流量冲击,还可能面临其他的流量冲击:外部请求(外部系统流量、异常流量)、内部请求(员工运营操作、定时任务、消息消费等)。因此,云集各条业务线针对性的全链路压测越来越多。随着压测需求增多,不得不面临以下痛点:
在同一个压测窗口,可能会排入多个业务,原来凌晨4点能完成的压测任务,经常持续到6-7点,给最后做收尾验收工作同事带来巨大压力;
云集的C端系统都是采用微服务化,服务之间环环相扣,如果是强依赖的服务,上下游关系更是紧密结合。一个服务出现问题就会影响到整个压测链路的性能,阻碍压测链路下游系统性能的评估。而一个问题的发现,通常只是表象,对于重点问题需要重复压测,才能确保问题的彻底解决。随着大促时间的临近,压测的需求暴增,经常出现排期冲突,预留给研发人员的解决时间很少。
不同业务在实施写压测时,有非常多的重复工作:准备用户数据、准备订单数据、准备用户资产(云币、优惠券)
造数据需要在凌晨执行,避免影响用户,因此DBA、运维、测试同学、架构师在大促期间需要连续通宵支持
大促期间,系统会进行频繁的变更操作(运维配置变更、机器伸缩容、服务器升降配、限流值更改等等),需要能快速验证
目标
通过对以上问题的分析,可以归纳为三个要求:减少资源投入,满足更多业务,时间要灵活;并重新拆分出相对应的功能需求:
提供数据构造功能,实现压测链路所涉及到的数据一键构造、反复构造。数据库构造过程中,需要能监控服务的运行状态,自主决定任务的启停动作,避免因为无人值守导致服务不稳定
提供流量构造功能,满足不同业务灵活组合并生成压测流量;满足流量录制以外的针对特定场景、全场景、个性化压测流量构造需求
避免业务针对压测的特殊改造,达到100%真实还原业务场景的能力
自动化压测的数据需要和真实数据进行隔离,避免影子标记丢失或配置错误导致脏数据的产生
实现一键压测,并自动生成报告,报告内容包括:压测包含的链路入口、压测期间大盘总流量、各服务耗时排行、服务器各种告警信息收集
每次压测需要有历史记录,可以进行后续问题跟进
实现日常周期性压测,验证常规机器伸缩容、限流值配置、系统迭代等动作是否会影响线上服务的稳定,尽早发现系统存在的风险
减少不同业务压测重复工作,对任务进行建模形成可重复使用的模块,通过灵活组合实现个性化压测需求
实现压测时的系统隔离,让业务方任何时间点都可以进行压测
目标:实现全链路压测的工具化&自动化,让参与压测的研发人员、测试人员、架构师从中解放出来;实现全链路压测的常态化,避免压测窗口排期冲突,及时发现系统的性能腐化。
总体模块设计
数据构造
数据准备做为压测工作的重要一环,目前主要依赖人工零碎化的处理,为响应公司战略,协助自动化压测系统的落地,数据准备工作的自动化工作也呼之欲出。但前期因为积累少,所以需从头至尾实现数据准备的自动化工作。基于公司目前的体系,为方便日后系统扩展,决定选用GO语言作为开发语言来完成数据自动准备的系统。目前已经完成自动化的数据准备功能,包括但不局限于Mysql,Redis,MongoDB的数据准备。后续也可以提供其它产品的数据准备及一些附加功能。
关键词
1,数据克隆:是指将数据在生产服务器上克隆一份出来作为影子数据,影子数据放在和生产数据库不一样的数据库中,但是在同一 个实例中。
2,数据初始化:数据克隆后,有些数据是需要通过指定的脚本来生成的,这部分数据是通过刷脚本的方式来生成。
3,数据拉取:titan系统有时需要拉取部分数据来做为原始数据,从而生成影子流量。
4,队列:在数据准备过程中,titan系统可以同时发送多个指令到达数据系统,数据系统是通过队列的形式并发或者顺序处理接收到的指令。
5,任务:titan系统是通过socket短连接机制发送指令到数据准备系统上,每个指令代表一个任务,相当于一个动作,可能是数据克隆、初始化、读取等。
6,批次:titan系统一次性可能连续发送多个任务到数据准备系统上,几个连续的任务组成一个批次,批次一旦创建将不再接收新的任务,新的任务发送过来又将会组成一个新的批次。
批次之间是并发执行,批次中的任务是顺序执行。
系统设计
1,主要模块
系统总体分成6大块:
2,指令类型及其实现
ghost:数据克隆指令类型,实现方式:
MySQL:生成一个影子库,生产数据克隆到影子库,影子数据库名为:生产库名_shadow
Redis:将所有的Key克隆,新的Key名称为在原有的Key名称前面加上"st:"前缀
MongoDB:实现方式同MySQL,也是生成一个新的影子库,命名规则也是加上shadow后缀,中间用下划线相连。
init:数据初始化指令类型,此种类型需提前准备好脚本,目前只有mysql和redis两种产品有此需求。
modify:实现方式和init类似,更多的是为了区分脚本的功能。
customset:这是定制化的一些功能,多用于临时的需求,如果新增此类指令也要求在代码层面实现。
set,zadd,hset,del:redis相关的指令,用于实现redis的数据处理需求。
3,指令的具体实现
指令作为一种通信格式,是整个系统的基石,好的指令设计对系统的扩展,逻辑处理等都有好处,下面简单介绍下指令的基本内容。
124_12345678:500#ghostyunjisclivefansmy
124:具体的指令编码
12345678:时间戳,加上时间戳是为了区分相同指令不同的执行时间
500:批次
ghostyunjisclivefansmy:具体的指令
type instInfo struct{
instruction string //具体的指令名
dbtype string //数据库类型:mysql redis mongodb
dbname string //数据库名
db_shdw string //影子库名,对mysql,mongodb有效
host string //主机地址
port string //端口
insttype string //指令类型
project string //项目
path string //路经
sqlfile string //SQL文件名
}
4,系统流程
5,风险控制及措施
在数据准备过程中,因数据处理需要消耗服务器资源,从而有可能引起生产事故,故需要小心谨慎,主要需注意以下几个方面:
磁盘空间
内存大小
CPU负载
以上都有可能造成服务器资源不可用,从而造成生产事故。我们目前主要的避免方式为在数据处理之前增加检测。并持续到整个压测过程。同时设置时间窗口,让数据准备在业务低峰期进行。
数据准备系统作为公司全自动压测中关键一环,在自动化,智能化上发挥重要的作用,同时大大减少了人力投入。使大家从频繁的加班熬夜中解放出来,因此意义重大。目前我们已经完成了大部分场景所需数据的自动化准备工作,包括Mysql,Redis,MongoDB。指令类型包括克隆,导入脚本,拉取数据等。同时,我们对服务器的资源也做了基本的监控,以保证尽可能的不引起生产事故,保障生产的稳定性。
流量构造
全链路压测需要对要压测的目标链路准备大量的参数,这里我们称之为流量数据。对于读压测来说,请求参数可复用,因此对流量数据要求不大,通常是几百到几千个用户请求数据,让请求能更好的路由到不同的中间件、缓存、数据库,以便让流量打的更均匀避免数据热点问题。对于写压测来说,它针对的是写接口,而写接口一般都会有幂等性的校验,参数只能使用一次。因此,一次写压测下来,可能需要成百上千万的流量参数。过去,一个写接口的流程,会经过许多业务线,每条业务线需要提前为写压测准备影子数据。例如复制缓存、造用户数据、造优惠券等等。这些操作没有统一的管控,全部分散在各个业务线,一次写压测协调和人力耗费巨大。因此Titan流量构造模块和数据工厂应运而生,它的目的就是来解决这个痛点,并将写压测的整个流程和逻辑整合起来。
传统模式
压测参数由压测业务负责人手工造、通过脚本和DBA手工拉取数据等,每一个环节的缓存、影子数据等,手工通知dba进行复制。这种模式目前效率慢,非常容易遗漏。
流量构造工厂
流量构造工厂将数据准备、数据组合构造、数据重置、模板导出等全部组合在了一起,用户可在流量构造模块根据需求进行这些数据的准备与重置。
何为数据准备,最终请求参数是是多样性的,举个例子,现在下单逻辑需要包含,用户id,优惠券,云币,商品等信息,这个最终请求的参数是通过多种参数进行拼接的,如下:
buyerName=xxx&buyerProvince=xxx&buyerCity=xxx&buyerArea=&buyerId=&unionId=&buyerNick=&buyerPhone=13000000000
&consumerId=${consumerId}
&shopId=${shopId}&seqId=${seqId}
&voucherId=${voucherId}
&secretKey=${secretKey}
&itemLists=${itemList}
....more
我们看到这条请求参数中有很多参数,构造这些数据需要上述4种业务数据,这些数据需要提前准备,并且有依赖关系:
多样的数据支持
二、 Http接口 在http请求获取数据的时候,支持传入参数的方式,例如上文我们已经获取了20w个用户,那么接下来,要根据获取到的用户信息,逐个去拉取每个用户的优惠券数。假设每个用户拥有5张优惠券,那么这一次优惠券的数据准备量为100w,并存入到数据库中。
四、 空任务 空任务指的是数据已经构造好,并放入到数据库了,但是为什么还需要空任务呢?因为在最终的参数组合阶段,其参数的获取来源于前面的多个任务,这里空任务的作用就是提供给你要的字段的数据在哪里,在哪个库,主要是方便参数组合时使用。例如,预售下单流程需要分订金、尾款两个阶段;为了100%还原业务场景,写压测需要订金订单下单完成后,更改活动状态为尾款阶段,然后取出订金订单进行尾款压测,此时就需要提前将订金订单存储到指定的的数据表,流量构造时直接使用。
灵活的流量构造
从各种数据源获取到所需数据后,还需要根据定义的逻辑进行参数组合,目前流量构造组合引擎支持的组合形式有:可重用、不可重用、随机等。例如:现在有400w用户数据,希望每个用户分别组合使用云币和优惠券(假设分别5张),然后再从1000条商品中随机选择一个商品进行下单。这样组合最终可以获得的参数数据为400w x 5 =2000w条数据。一图胜千言:
常态化的链路压测
最初云集的写压测是通过开源的压测脚本工具来进行写压测的,每次都需要提前将数据按照模板配置好。数据准备时间很久,且需要专门的测试进行脚本开发,才能进行写压测;不过也有好处,就是可以满足任何场景的压测,非常灵活。但为了减少压测的资源投入,从去年开始做全链路压测的时候,云集就将压测工具化、自动化、常态化提上了日程。经过半年的准备,目前云集的Titan已经支持定时自动化压测,日常业务方可以根据要求随时实施压测需求,达到了常态化压测目标。有图有真相:
以真实流量QPS排名Top300为例,通过Titan-CIA 抓取到真实线上请求链路信息,然后同比例缩小后,将数据存储在 Influxdb 中,可以通过 Titan 一健生成线上 Top N的链路。支持过滤,可以预先配置好规则,将不需要压测的接口自动排除,topN 后的链路向前移一位;也可以手动添加接口。常态化压测出现各类异常时,都会通过办公软件机器人和邮件双重通知对应负责人,做到出现问题立即汇报,具体包括以下几类情况:
扩容通知
需要压测的场景如果QPS如果过高,超过部署压测Agent的阀值,则会提前通知运维对机器进行扩容。这里可以通过回调运维给的接口,自动完成扩容。异常通知
自动化压测出现压测失败的情况时,及时进行通知。
直观的自动化压测报告
云集系统各个组件的监控都接入到了 grafana 上,之前每次压测的过程中,运维人员需要随时观察 grafana上的监控信息,并对关键监控指标进行截图,形成压测报告。
现在,Titan增加了自动化压测报告收集的功能,可通过配置化去收集 grafana 等外部监控指标。并且通过 chrome-headless 技术实现了服务端自动截图功能,如下图:
该功能可以自动进行截图并最终生成 docx 的压测报告输出,直观,简洁,也十分符合业务需求。这个功能也彻底解放了运维人员。
总结
在3月份tiantan的流量构造功能上线,并实现读写压测工具化第一步开始,就为业务系统发现了大量的问题。
交易数据
问题分类 | 问题发现数量 | 备注 |
---|---|---|
配置问题 | 4 | 涉及:扩容脚本、rocket mq、数据库连接池 |
性能问题(数据库、消息、日志、线程、缓存) | 20 | 涉及:订单、库存、活动、优惠券、云币、推荐、用户、积分 |
系统影子流量支持问题 | 2 | 涉及拼团、商品 |
业务重复调用问题 | 1 | 涉及:订单 |
基础组件问题 | 4 | 涉及:日志收集组件、分布式调用链、限流组件 |
压测工具问题 | 6 | 涉及:titanx、扩容工具 |
监控工具 | 3 | 涉及:grafana |
接口性能或限流未配置问题 | 10 | 几乎全部业务涉及 |
直播数据
问题分类 | 问题发现数量 | 备注 |
---|---|---|
缓存 | 8 | 客户端缓存、本地缓存、Nginx缓存、redis缓存, 缓存单点增加多个桶处理, 缓存击穿, NG缓存导致NG限流不生效采用tomcat限流 |
性能问题(数据库、消息、日志、线程、缓存) | 10+ | 主要为数据库慢查询, 读写分离, Mongodb集群剥离直播数据库, 腾讯回调消息快速失败处理 |
性能保障 | 4 | 预案(10+)、操作功能开关、定时任务(70+)、接口性能或限流未配置问题(200+个接口) |
云集已经实现压测常态化的部门:交易;实现写压测工具化的部门:直播;其他更多的业务也正在接入中。云集全链路压测这半年跨越式的走过了四个阶段:手工、工具化、自动化、常态化,但仍然还有许多需要改善的:
个性化指令:目前指令配置需在后台进行,同时部分自定义的指令可能需做代码层面的修改。所以我们定了一个目标就是让指令可能在前台配置,同时将指令设计得更加灵活
流程化压测:目前自动化压测是通过提前构造好的、固定的请求流量对单一接口进行压测;如果要更真实的评估系统容量,需要模拟用户真实购买行为,如:商品浏览>购物车->下单->下单完成->支付->查看订单→修改/退货退款
智能化报告:目前的压测报告主要是监控系统的实时截图,后续需要做到通过读取系统异常指标做出判断,给出实质性的结论
关注一下,更多精彩等着你!