本文转载自IPD-Chat,IPD-Chat为京东商城基础平台部门官方公众号,扫一扫二维码进行关注。 诞生背景 伴随着京东业务的不断扩张,研发体系的系统也随之增加,各核心系统环环相扣,尤其是强依赖系统,上下游关系等紧密结合,其中一个系统出现瓶颈问题,会影响整个系统链路的处理性能,直接影响用户购物体验。 往年的618、双11大促备战至少提前3个月时间准备,投入大量的人力物力去做独立系统的线上压力评测,带来的问题就是各个性能压测团队工作量非常大,导致压测任务排期,压测的数据跟线上对比不够准确,各个强依赖系统上下游需要在压测中紧密配合,一不小心就会影响线上,有的在线下测试环境压测,压测出的数据更是跟线上差距太大,只能作为参考。 更重要的一个问题是各系统容量规划,每次大促前备战会必不可少的讨论话题就是服务器资源申请扩容问题,各团队基本都是依据往年经验和线上资源使用率给出评估量,提出一个扩容量需求,导致各个业务系统每次促销扩容量非常大。为了解决以上各种苦恼,2016年基础平台部整体牵头启动了ForceBot全链路压测(备战常态化)这个项目,此项目牵扯到所有京东研发体系团队,各系统必须改造识别压测过来的流量和线上正式流量进行区分标记特殊处理,不能因为压测流量影响正常用户体验和污染线上数据等工作,由于跨团队协作之多、跨系统协调改造等工作量非常大,挑战性可想而知! 2016年主要实现了订单前的所有黄金链路流程高并发压测用户行为模拟,包括模拟用户操作:首页、登陆、搜索、列表、频道、产品详情、购物车、结算页、京东支付等。在黄金链路中有各种用户行为场景,比如一般用户首先访问首页,在首页搜索想要产品,翻页浏览,加入购物车、凑单、修改收货地址、选择自提等等。 各系统压测量依据往年双11峰值作为基础量,在此基础上动态增加并发压力;同时要区分对待两个大的场景,日常流量和大促流量。大促场景下抢购活动集中,交易中心写库压力最大,另外用户行为和日常有很大的反差,比如用户会提前加入购物车,选择满减凑单,集中下单等等场景。 2016年启用的链路较短,在2017年将实现订单后生产的全链路。 ForceBot在2016年双11替代往年各系统独自优化、性能压测备战状态,目前所有的备战数据和各系统性能承载能力、资源规划等都由ForceBot给出直接数据作为依据,在军演压测过程中,秒级监控到压测源、压测中、京东所有的黄金链路系统、接口响应时间、TPS、TP99等数据,军演完成后提供丰富的压测报告,准确的找到各系统并发瓶颈。 同时也承担了内网单一系统的日常压测任务,开放给研发和压测团队,支撑京东所有的压测场景统一压测平台,对公司内压测资源的整合和提高利用率。 工欲善其事,必先利其器。全链路压测必须要有一套功能强大的军演平台,来实现自动化、全链路、强压力的核心目标。 基于Ngrinder做定制开发。Ngrinder是一个java语言开源的、分布式性能测试平台。它由一个controller、多个agent组成,在controller建立测试场景,分发到agent进行压力测试,压力源将压测数据上报给controller。Ngrinder基于开源的java负载测试框架grinder实现,并对其测试引擎做了功能提升,支持python脚本和groovy脚本;同时提供了易用的控制台功能,包括脚本管理、测试计划和压测结果的历史记录、定时执行、递增加压等功能。 我们根据京东的业务场景对Ngrinder进行了优化,以满足我们的功能需求。比如:提升agent压力,优化controller集群模式,持久化层的改造,管理页面交互提升等。Ngrinder能胜任单业务压测,但很难胜任全链路军演压测。分析其原因是controller功能耦合过重,能管理的agent数目有限。原因如下:
说的通俗点,controller干的活又多又慢,整体压力提升不上去。尽管我们优化了controller集群模式,可以同时完成多种测试场景。但是,集群之间没有协作,每个controller只能单独完成一个测试场景。由此,我们着手研发全链路军演压测系统(ForceBot)。 新平台在原有功能的基础上,进行了功能模块的解耦,铲除系统瓶颈,便于支持横向扩展。
这样极大的减轻了controller的负载压力,并且提升了压测数据的计算能力,还可以获取更多维度的性能指标。 在此基础上,还融合进来了集合点测试场景、参数下发、tps性能指标等新特性。下面将重点介绍以下几个功能: 为了快速的创建测试集群,Agent采用docker容器通过镜像方式进行自动化部署。这样做好处如下:
问题:Git测试脚步如何在各个Docker之间共享。 解决方案:采用外挂宿主机的共享磁盘实现 用户在管理端创建一个测试场景,主要包括:压力源(分布在不同机房的压力机)、虚拟用户数、测试脚本、定时执行时间、process的jvm参数,压力源,启动模式,集合点设置,选择测试脚本。这个测试场景保存到db后,controller按照时间顺序,扫描发现有测试场景了,会根据标签算法寻找当前存活的空闲的agent资源,并计算agent的每个worker process启动的线程数。 任务分配时,要考虑集合点的计算,就是虚拟用户数在不同的时间点不断变化。目前有两种方式:毛刺型和阶梯型。毛刺型,就是在某个时间点有大量的请求瞬时访问业务系统,这样做可以测试系统的并发能力和吞吐量。阶梯型,就是在相等时间间隔,虚拟用户数等值递增。 比如:一个测试场景在今天9点执行10000个虚拟用户数,执行到9点01分要虚拟用户数变为20000个,到9点05分虚拟用户数又变为40000个,到9点07分虚拟用户数变为10000个。虚拟用户数像毛刺一样上下变化。 上面的表格就是对应表结构设计,每个压力线会按照顺序保存到db中。在这张表中,只记录的持续时间,具体的执行时间是由controller根据开始压测时间累加持续时间逐一计算出来。execType还包含了缓慢加压减压两种类型,覆盖了阶梯型,默认时间间隔为5秒。 controller要计算出每个间隔的执行时间点,递增的虚拟用户数。controller将计算结果分给每个agent,保存到db中,由agent定时来拉取。 动态加压减压目前只支持采用Agent的增减方式来实现。 问题:由于购物车是用户共享的,在压测下单过程中,同一个用户并发操作会出现冲突。 解决方案:为每个压测线程绑定使用不同的用户。在任务分配过程中,为每个process进程中的线程分配线程编号。不同的线程根据编号,按照映射规则,找到相应的压测用户。 task service为agent提供了任务交互和注册服务,主要包括agent注册、获取任务、更新任务状态。 agent启动后就会到task service注册信息,然后每个几秒就会有心跳拉取一次任务信息。controller会根据注册的信息和最近心跳时间来判断agent是否存活。 agent拉取任务和执行任务过程中,会将任务状态汇报给task service。controller会根据任务状态来判断任务是否已经结束。 task service采用了GRPC框架,通过接口描述语言生成接口服务。GRPC是基于http2协议,序列化使用的是protobuf3, java语言版采用netty4作为网络IO通讯。使用GRPC作为服务框架,主要原因有两点:
agent职责主要是注册,获取任务信息,更新任务状态,执行和停止worker process进程,同时上报压测数据。通信协议主要是GRPC。
问题:一台物理机上多个Docker实例,如何减少更新测试脚步造成的GIT压力 解决方案:测试脚步存放到宿主机共享存储,更新前,按照测试任务编号进行文件锁,如果锁成功则调用Git更新。同一个测试任务就可以减少GIT压力。 问题:如何模拟在某一个瞬间压力达到峰值 解决方案:通过集合点功能实现,提前开启峰值所需足够数量的线程,通过计算确定各个时间点上不需要执行任务的线程数量,通过条件锁让这些线程阻塞。当压力需要急剧变化时,我们从这些阻塞的线程中唤醒足够数量的线程,使更多的线程在短时间进入对目标服务压测的任务。 实现秒级监控。数据的收集工作由monitor service完成,也是采用GRPC作为服务框架。agent每秒上报一次数据,包括性能,JVM等值。 monitor service将数据经JMQ发送给dataflow平台,进行数据的流式计算后,产生TPS,包括TP999,TP99,TP90,TP50,MAX,MIN等指标存储到ES中进行查询展示。 问题:为了计算整体的TPS,需要每个Agent把每次调用的性能数据上报,会产生大量的数据,如果进行有效的传输。 解决方案:对每秒的性能数据进行了必要的合并,组提交到监控服务。 首期识别从用户浏览到下单成功的黄金流程,其包含的核心业务如下: 压测流量是模拟真实用户行为,要保障在军演过程中不能污染线上各种统计等数据,比如:PV UV 订单量等,更不能影响正常用户下单购物体验。 首先要对用户、商品进行打标,以便于各个系统进行测试流量识别。针对下单压测,库存系统需要根据测试用户和商品提前准备好库存量。风控系统需要放行测试用户和商品的操作。 业务系统识别出压测数据后,根据不同的场景,采用两种方式来存放压测数据。
ForceBot未来的路还很长,要做的优化、功能也很多,比如有:
在线全链路压测,军演备战常态化,将是我们的终极目标。 =============相关阅读============= |