大促活动前团购系统流量预算和容量评估
本文整理自美团点评技术沙龙第11期:移动端测试分享。
美团点评技术沙龙由美团点评技术团队主办,每月一期。每期沙龙邀请美团点评及其它互联网公司的技术专家分享来自一线的实践经验,覆盖各主要技术领域。
目前沙龙会分别在北京、上海和厦门等地举行,要参加下一次最新沙龙活动?赶快关注微信公众号“美团点评技术团队”。
本期沙龙首次在上海举行,包括四场讲座:一直被呼吁开源的测试工具Spider;移动端用户体验数据如何量化;大促活动前团购系统如何评估流量和容量;腾讯P图App的测试。其他几场讲座的图文实录会陆续发表,请继续关注。
引言
O2O行业高速发展,团购业务的流量和用户数也有了不止一个数量级的飞跃,单日交易额数以亿计,日均订单量也到了百万量级。目前团购产品形态稳定,产品运营会策划各种大促活动,为业务带来更多的流量和用户,以提升交易额。给力的大促活动能为业务带来千万级的PV和百万级的购买用户数,大促活动的瞬时流量可能是平时流量的几十倍,这对我们的系统来说是一个不小的挑战。
概述
这次分享的主要内容包括以下4个部分:
介绍相关背景,包括大促活动的特点和团购系统架构的演进过程。
建立大促活动期间团购系统核心路径的流量模型,推算活动峰值流量。
分层评估系统容量时,如何制定压力测试策略、选择合适的测试环境。
分层评估系统容量时,执行压力测试过程中的工具选型、场景设计和数据准备。
背景介绍
1. 大促活动的特点
大促活动的三个关键词:瞬时流量、热点团单和核心路径。
瞬时流量:大促活动的一般形态是在活动日的某个时间节点(比如上午10点),开放一批0元抢购团单;这时大量用户会从H5活动页点击“免费吃”按钮(静态页面,用户会提前打开),跳转到Native团购详情页,给团购系统带来一个瞬间流量高峰。某次活动统计数据显示,瞬时高峰流量达到了平时流量的33倍。
热点团单:活动日上午10点开放的这批0元抢购团单,可以称之为是热点团单。
核心路径:活动高峰期大部分用户行为会集中在这些热点团单的购买流程上,而不是去搜索一个团单或者给团单写评价;这个热点团单的抢购流程就是大促活动的核心路径。
2. 大促活动前的准备——扩容
面对这个瞬时流量高峰,首先要回答的问题是系统能不能扛住;如果抗不住的话,最有效提升系统容量的方式是进行扩容。假设在系统没有瓶颈、可水平扩展的前提下,单个应用的扩容可以使用以下公式:
为了制定扩容计划,我们需要知道分子“活动峰值流量”和分母“单机容量”。大促活动准备期间,运营会根据活动预算、Push发送量和Push转化率等数据,推算出活动页的PV和UV;根据往期活动的经验数据,推算出抢购或秒杀活动的用户点击量,以此数据作为系统的入口峰值访问量。有了入口峰值访问量,结合系统的流量模型,就可以推算出每个应用节点的活动峰值流量。通过对系统的压力测试,可以得出每个应用节点的单机容量极限值。
3. 团购系统架构的演进
在开始正式讲流量预算和容量评估之前,先介绍下团购系统架构的演进。
早期的团单系统架构
早期的团购系统如下图所示,Web层和Service层都是单应用架构。Web层的团购MAPI应用,提供了包括团购首页、团购列表、购买流程、团购订单/券、退款流程等200多个接口(包括读接口和写接口),所有业务耦合在一起。Service层的团单服务也是类似的。
针对这样的系统架构做流量预算很简单,可以直接用运营同学给的入口峰值访问量做分子(活动峰值流量)即可。
但是要获取分母(单机容量)是比较困难的事情。针对这样的架构,在线上或者线下做一次有效的压力测试成本比较高——如果通过线上引流的方式做压力测试,读流量和写流量必须区分开;如果在线下模拟搭建一套压力测试环境,依赖的服务较多,搭建环境成本高;另外业务耦合在一起,线下也比较难模拟线上的接口分布等情况。
根据木桶短板理论,不需要压力测试也可以知道当时的团单系统性能不会很好。这样系统架构下,评估系统的容量的办法基本上只有拍脑袋。
现在的团单系统架构
现在的团单系统架构有了比较大的改进。如下图所示,团单服务做了“拆弹项目”,复杂的团单服务按照业务领域拆分成了基础服务、价格服务、库存服务、属性导航服务等。从服务名称可以看出来,一个应用拆分成了多个应用,每个应用单独负责某个领域;缓存集群和团购数据库也按照业务领域做了拆分。随后,大而全的Web层MAPI应用也按照业务领域拆分成了团购详情应用、团购交易应用和个人中心应用。
总结下的话,就是整体上逻辑耦合在一起的业务按微服务化拆分出来,每个服务独立专注的做一件事情。
下面两张图可以比喻团购系统架构的演进。左图是早期的团购系统,业务混杂在一起,难以量化;右图是拆分之后的团购系统,分层架构清晰合理,这个时候对系统建立模型、量化分析变成了一件可行的事。
活动流量预算
流量模型分析是流量预算的关键,只有清楚了系统的流量模型,才可能对系统每个节点的峰值流量做准确的评估。
团购系统在不同的场景有不同的流量模型。如下图所示,左图是系统平时的流量模型,右图是大促时的流量模型,其中中间人最多的路径是大促活动核心路径的流量模型。下面会介绍如何针对这条核心路径建立流量模型。
大促活动时的业务核心路径是:用户首先访问H5活动页,点击“免费抢”按钮到达热点团购详情页,然后通过点击团购详情页的“立即抢购”按钮进入提交订单页,并最终完成支付流程。
这个是大促活动的业务核心路径对应的系统架构图,用户跳转到团购详情页时,客户端会向Web层的团购详情API应用请求数据,团购详情API应用再向聚合服务层发起请求,聚合服务层分别异步调用团单价格服务、团单库存服务、团单属性服务等基础服务,并将这些基础数据组装好返回给上层应用,最终返回数据到客户端,展示在用户的移动设备上。
根据系统架构图,可以从上至下梳理调用关系链,建立核心路径的流量模型。
第一步:梳理活动页跳转到App Native页面的接口调用链。用户从活动页点击“免费吃”按钮进入团购详情页,会发起6个API接口请求。其中3个接口——团购基本信息接口,团购购买须知接口和团购适用商户接口——会对用户的购买决策起决定性作用,是团购详情页的核心路径。
团购详情页下方还有三个非核心模块会发起3个接口请求,分别为本店其他团购接口、网友评价接口和团购推荐的接口,这几个模块可以给用户购买决策提供参考,但是不是必须的,在大促活动场景下是非核心路径。这些接口可以通过开关关闭(关闭非核心场景是一种有效的降级方案),下面的分析假设非核心路径接口开关关闭。
第二步:梳理Web层接口之间的调用次数和调用顺序
用户打开团购详情页时,客户端会先发起团购基础信息接口,再获取团购基本信息(如:标题、价格、销量等)之后,会异步发出其他5个模块的接口请求。
第三步:通过代码分析和CAT调用堆栈分析,梳理Web层接口对下游服务的调用顺序和调用次数,汇总成对服务层各应用的调用倍数。(注:CAT是美团点评技术团队开源的实时监控平台,已在许多业界公司生产环境得到应用,详情参见GitHub)
假设团购详情页的PV是1,会发出3个API请求;除了团购商户API之外,团购基础信息API和团购详情API会分别调用团购基础服务1次,另外在大促的场景下会在创建订单和支付等场景对团购基础服务有5次调用,即总共会有7次的团购基础服务的调用。
通过分析代码和调用堆栈,可以得知团购详情页的PV对团单价格服务和团单库存服务的调用次数也是1:7的关系。
这样我们可以得到大促活动核心路径的流量模型:假设详情页的流量单位为1,团购系统各个应用节点的流量构成如下表所示。
同理,大促活动核心路径对缓存和DB的最大访问次数也可以分析出来。
这时可以根据运营给到的入口峰值流量数据,推算出大促活动时团购系统从上到下(Web层、服务层、缓存和数据持久层)每一个应用节点可能会达到的最高流量。
最终给到运维的会是这样一份扩容计划表。综上所述根据流量模型可以推算出系统每个应用节点的活动峰值流量以及需要提供的集群容量(活动峰值流量*余量系数)。另外系统当前机器数是已知的,那么要完成扩容计划表,下一步要做的事情是进行容量评估,即通过压力测试,评估系统每个应用节点的单机容量。
系统容量评估
系统容量主要通过线上环境或者线下环境的压力测试来评估。首先会介绍压力测试策略的制定,大促活动期间压力测试的目的,以及压力测试环境的选择(重点介绍性能测试环境PTP)。然后通过实例介绍压力测试执行中的压测工具的选择、压测场景的设计和压测数据的准备。
压力测试的目的
大促活动准备期间的压力测试,与平时应用上线前的性能测试或负载测试的目的有所不同,平时性能测试的目的主要是查看系统各指标是否达到预期,以及在高并发下验证功能测正确性。大促活动准备期间的压力测试目的是找到系统针对混合场景的最大处理能力,具体有以下四个方面:
压力测试这件事情没有最好只有更好,为了评估线上的系统容量,理想的压力测试方案是在线上环境做系统全链路的压测。但是线上全链路压测的时间、人力成本比较高(做一次线上全链路压测要参与或周知的人数要30+)。线上压测有一定风险,为了评估系统容量把线上服务压挂了是一件得不偿失的事情。另外,全链路线上压测可以发现系统的瓶颈,但是不能得到每个应用节点的单机容量。我们最终采用的压测方案基本原则是在保证压测数据有效性的基础上,做性价比最高的压力测试。
压力测试的环境
在PTP环境出现之前,我们做压力测试主要在BETA环境、PPE环境或线上环境(BETA和PPE环境是我们用来做功能测试的两套线下测试环境),这三种环境都有些局限或风险,导致压力测试有效性不如人意。
BETA环境:主要用作QA功能集成测试,服务和中间件部署完备(一般每个应用部署一台虚拟机),有专人维护,专门的BETA环境数据库
可靠性:硬件环境与线上差异较大,数据与线上差异较大
稳定性:被测服务和依赖服务容易被压挂,影响日常功能测试
易用性:一般用JMeter脚本,在本地执行压测
局限:只能评估单机容量,无法对集群进行压测
PPE环境:主要用作应用线上发布之前的功能验证
可靠性:硬件环境与线上差异较大,部分数据库定期同步线上数据库
稳定性:被测服务和依赖服务容易被压挂,影响应用上线前功能验证
易用性:一般用JMeter脚本,在本地执行压测
局限:只能评估单机容量,无法对集群进行压测
线上环境
可靠性:数据可靠,无环境差异,可以压测集群。
稳定性:线上被测服务或依赖服务可能被压挂。
易用性:需运维辅助操作,在线上缩减集群规模或者复制流量。
局限:风险高;时间人力成本高;不是所有类型的应用都适合。
下面重点介绍下我们做压力测试主要用到的PTP性能测试环境。
PTP性能测试环境,实际上是一个平台+环境,包括了性能测试的环境搭建、测试执行和测试结果展示的整体功能。
PTP性能测试环境与传统的性能测试环境有很大的区别。它是一个基于Docker的虚拟机器池,需要对某个应用做压力测试时,可以一键部署该被测应用;测试完成后可以释放清理环境,不需要专人维护一套完整的测试环境,从而解决了传统性能测试环境机器数量有限、维护成本高、资源利用率低等问题。
PTP性能测试环境可以通过智能依赖和依赖回流的功能,把被测服务直接依赖和间接依赖的服务也部署起来。
具体步骤如下图所示:
另外PTP提供了配置虚拟机CPU核数和内存大小的功能,还提供了同步线上数据库表的功能,可以做到性能环境数据库和线上数据内容和量级保持一致。
综上所述,PTP性能测试环境在数据可靠性、稳定性和易用性方面,解决了BETA环境、PPE环境或线上环境压测时存在的大部分问题。
下面介绍下压力测试执行过程中的压测工具的选择、压测场景的设计和压测数据的准备。
压测方法的选择
线上压测方法——逐步减小集群规模
通过逐台摘机器,使得单台机器的访问量不断提升,来达到压力测试的目的。
优点:
应用无需读写接口分离。
缺点:
逐个摘机器有风险。
对流量规模有要求,不能太小,否则压不到瓶颈。
需要运维人员的密切配合。
线上压测方法——线上TCPCopy
在集群中挑选A、B两台机器,A为被压机,B为施压机。
将A配置一个泳道(机器不对外提供服务),通过TCPCopy将B的流量逐渐放大至A。
优点:
流量比例真实、风险小。
可以随时调整比例,模拟梯度加压。
缺点:
要求被压的服务只能是纯读服务,不能有写接口,否则会带来脏数据
TCPCopy工具限制,放大40倍会挂掉,若线上流量太小,则需要首先摘掉部分机器以提高单机的QPS
线下压测方法
PTP搭建性能测试环境
设计测试场景
准备测试脚本(JMeter)
准备测试数据
执行压力测试
测试结果分析
压测场景的设计
实例一
针对服务提供的接口的比例分布设计场景
例如:团购基础查询服务提供了两种查询方式:单个查询和批量查询
设计测试场景时需要考虑两种接口的比例分布
可以使用JMeter比例控制器来控制请求比例
实例二
针对批量接口参数的个数设计场景
例如:团购库存查询服务的批量接口参数个数
需要设计调用批量查询接口时传入的团单id个数。
可以通过线上日志统计“批量接口参数列表长度”分布。
实例三
针对对应用性能有影响的参数类型、逻辑分支设计场景
例如:团购销量查询服务区分品类
A品类团单要展示聚合销量、B品类团单要展示分城市销量。
不同的逻辑分支,查询不同的缓存和数据库。
压测数据的构造
实例一 流量回放
被测应用:团购详情Web应用(纯读服务)
压测环境:性能测试环境
压测数据:TCPDump复制线上流量在性能环境做回放
压测方法:
选择合适的时间段(流量不要太低)。
dump流量时间足够长,流量翻倍时数据离散度需满足要求。
实例二 日志回放
被测应用:个人中心Web应用(读+写)
压测环境:性能测试环境
压测数据:Nginx Access Log
压测方法:
将最近通过App的访问Nginx Access Log进行分类(读、写)
线上到线下token的解析问题
实例三 人工构造数据
被测应用:团购基础信息服务
压测环境:性能测试环境
压测数据:人工构造数据(csv文件)
压测方法:
人工构造的数据应模拟线上的缓存命中率
缓存命中率比线上环境偏低,需要进行缓存预热
缓存命中率比线上环境偏高,需要尽量模拟线上团单的离散程度
压测结果的采集
总结
在团购的一次大促活动前,我们会主要做这两件事情:首先会进行一个基于流量模型的流量预算,以获取扩容公式的分子——即从上到下评估流量;然后制定压力测试策略、执行压力测试、输出压力测试报告,对每个应用进行单机容量极限评估,以获取扩容公式的分母——即从下到上提供能力。最终的目的是为了保证大促期间核心用户的用户体验。
更多技术博客:美团点评技术博客。
PS:正文中标绿的名词均为释义链接,可点击查询。