【易测试201604】电商大促性能测试实践

阿凡达2018-08-21 09:26

文/侯本文

1 背景

大促是电商的一个重要推广方式,它通过各种活动实现人气、销售额与品牌的全方位提升。一个促销活动成功与否取决于吸引了多少用户,创造了多少收入,让多少人了解到你这个品牌。所以大促的特点是:

  • 多样化的运营活动;
  • 庞大的用户群体。

一次大促的成功不仅取决于市场的推广、运营的设计,和产品的稳定性更是密不可分,对于测试和开发来说,同样面临巨大的挑战:

  • 保证各种推广活动没有性能问题;
  • 保证用户的体验友好,不会各种报错各种卡顿;
  • 保证高并发用户访问的情况下,系统的稳定性。

那针对这些挑战,我们是怎么应对的呢?

2 大促性能测试应对策略

我们以一张图来描述应对一次电商大促性能测试的主要流程以及相关工作内容。


图1 大促性能测试基本流程

从上图中可以看到,整个流程中需要进行需求抽取,包含得到一些预期指标以及测试场景等。然后针对需求进行方案设计,包括场景设计以及选取测试手段等。在方案设计的基础上,即可进行测试执行。最后,根据测试的结果整理测试报告并提出潜在的风险。

下面我们以一次电商大促为例,介绍下大促性能测试的完整过程以及遇到的一些问题和解决方法。

2.1 大促活动需求分析

需求分析中的重点是沟通,和运营以及市场推广的同事进行沟通,和相关功能开发同事进行沟通。 和运营以及市场同事沟通的目的在于确定大促期间会有哪些活动以及活动期间预期的UV、PV数。例如,本次大促期间有以下活动:一元秒杀、省钱榜、炫富、买就送等。且经过市场的推广,预计日UV在300W左右,PV数在1500w左右。

在活动确定以后,和相关业务开发沟通哪些活动需要进行性能压测。一般情况下我们遵循以下三个原则进行场景的筛选:高频调用的请求,业务逻辑实现复杂度高的请求,以及涉及电商的核心业务,如下单、支付等。

基于这些原则和上面的活动,我们确定这次大促需要覆盖以下场景:

  • 一元秒杀:活动力度较大,预估参与秒杀的人会比较多,且涉及到下单支付等核心业务,需要进行性能压测;
  • 炫富中的好友点赞:可能存在有用户通过作弊手段点赞的情况,需要测试验证下反垃圾是否生效;
  • 省钱榜:在活动主会场中动态显示省钱最多的用户,因为嵌套在活动主会场,访问量比较大,属于高频调用的请求;
  • 买就送:在活动期间购买商品后就送一定额度的优惠券大礼包,属于支付核心业务,需要进行性能压测。

2.2 大促活动性能测试方案设计

确定好本次大促的测试场景后,需要对测试场景设计测试方案,在设计测试方案之前,我们需要先基于了解到的UV、PV预估下并发量。

并发量的预估一般基于历史统计:

例如秒杀的UV大约是日UV的0.5%~1%,则可以预估参与这次秒杀人数为1.5w~3w人;主会场的PV是日PV的3~5%,则基于web产品常见的80-50原则,即80%的用户访问集中在12个小时内,则每秒钟大概有15个人访问主会场。

2.3 大促活动场景设计

性能测试场景设计是否合理直接关系到测试结果是否准确,是否能发现潜在的性能BUG。一般我们在设计一个场景时,需要考虑以下问题:

  • 是否需要铺底数据?需要铺底多少数据量?按照什么样的规则铺底数据?
  • 需要多大的并发压力?
  • 需要什么样的测试手段?
  • 如何验证测试结果的正确性?

下面我们以秒杀场景为例,简单描述下该场景的设计方案:

  • 测试数据:本次秒杀同一时刻进行秒杀的商品只有一个,所以,我们只需要准备一个商品即可,库存量设置和线上一样,配置为50个,但是参与秒杀的商品是特卖商品,所以需要给商品设置特卖属性;
  • 并发量:基于前面的数据分析,参与秒杀的人数约为3w左右,我们以大于1.5~2倍的要求进行压测,并发用户设置为5w;
  • 测试手段:秒杀场景特殊在大量的用户在同一时刻发出下单请求,所以我们需要利用集合点的概念进行测试,具体实现方法参见后面的介绍;
  • 正确性验证:
    1. 验证有50个人购买成功;
    2. 验证购买失败的原因:只能为抢购人数过多,或者已经抢购完成,无其他异常信息;
    3. 系统整体访问正常,不会影响其他业务。

2.4 混合场景测试

上面介绍的大促活动场景只是指针对这次大促的新增活动进行单场景测试,防止新增活动出现性能问题。但是针对整个大促来说,仅仅这些测试场景是不够的,我们还需要在混合场景下进行整体性能回归。

混合场景的设计原则是需要覆盖所有的核心业务以及高频业务,尽可能地保障整个系统无性能问题,所以混合场景包含:背景压力场景和活动场景两大类。

所谓背景压力即常规压力,和大促无关,是日常用户访问的请求,这些请求的提取原则同样为:

  • 高频访问请求:活动页、首页、商品详情页等;
  • 核心业务请求:下单、支付等。

提取方式基于对业务的了解以及线上方位日志的统计,因此我们背景压力场景设计如下:

  • 基于线上Nginx日志分析得的高频请求,一般取top40~top50;
  • 普通商品的下单支付(2%的比例),包含:单个商品下单、购物车下单等。

活动场景的设计原则是需要包含这次促销中涉及到的各种活动,例如包含:

  • 活动类型的商品下单:包含直降、特卖、N元任选、手机端特卖等;
  • 其他促销活动场景:一元秒杀、省钱榜等。

2.5 大促性能测试方法

常规情况下,我们使用性能测试平台即可以完成普通场景的测试工作,但是对于特殊的场景来说,需要特殊的手段进行测试:

(1) 秒杀场景的测试过程

秒杀场景具有一定的特殊性,参与秒杀的用户都要等待秒杀开始那一刻发送下单请求,这种场景,我们需要利用集合点的概念进行模拟。

所谓集合点即并发用户等待同一时刻发送请求。Grinder支持集合点的实现。

测试脚本简单实现如下:

  from net.grinder.script.Grinder import grinder

  class TestRunner:
    def __init__(self):
       # Each worker thread joins the barrier.
       self.phase1CompleteBarrier = grinder.barrier("Phase 1")

    def __call__(self):
       # ... Phase 1 actions.
       # Wait for all worker threads to reach this point before proceeding.
       self.phase1CompleteBarrier.await()
       # ... Further actions.

(2) HttpAsyncClient进行洪水压力的测试

常用的测试工具Grinder、Jmeter等都是同步测试工具,下一个请求的处理是在等待上一个请求结束后才发出的。但有些时候,我们需要模拟洪水压力,不会等待上一个请求结束才发起下一个请求。这个时候:我们需要异步压测工具,这里给大家推荐HttpAsyncClient。HttpAsyncClient是在HttpClient进化到4.x后,官方提供的基于NIO的异步版本。

Java利用httpasyncclient进行异步HTTP请求的部分代码实现如下:

public class AsyncClientHttpExchange {  
    public static void main(final String[] args) throws Exception {  
        CloseableHttpAsyncClient httpclient = HttpAsyncClients.createDefault();// 默认的配置  
        try {  
            httpclient.start();  
            HttpGet request = new HttpGet("http://www.kaola.com/");  
            Future<HttpResponse> future = httpclient.execute(request, null);  
            HttpResponse response = future.get();// 获取结果  
            System.out.println("Response: " + response.getStatusLine());  
            System.out.println("Shutting down");  
        } finally {  
            httpclient.close();  
        }  
        System.out.println("Done");  
    }  
}

参考文档:http://hc.apache.org/httpcomponents-asyncclient-dev/examples.html

3 从开发角度讲应对措施

线下测试只是保障手段的一种,对于这种促销活动做好线上保护同样至关重要。目前遇到过的保护措施主要有以下几个方面:

(1) 尽可能降低秒杀对后端服务的压力

对于秒杀这种特殊场景,瞬间会有大量的用户执行下单等操作,为了减少数据库等后端服务的压力,我们需要在压力达到数据库之前做好限流保护。

保护策略1:隔离大部分请求在下单服务外:用户可以先去秒杀等服务中获取资格,拥有资格的用户才能进行下一步下单请求;

保护策略2:通过反垃圾手段过滤非常规请求,同一个IP地址、用户名、DeviceID等请求在一秒内不允许多次访问;

保护策略3:通过验证码等手段降低到后端数据库的压力;

保护策略4:通过信号量等控制服务器端同时执行下单请求的个数,从而降低数据库压力。

(2) varnish静态化减少服务压力

页面静态化是搭建高性能网站常用的方式之一,通过页面静态化可以有效的提升系统响应速度。varnish是一种常见的内存缓存服务,具备三种功能:反向代理、高速缓存以及静态页面和动态内容在服务器端的整合。

配置策略:

  • 需要缓存的页面url规则改写;
  • Nginx针对所有改写的url都转发到varnish服务上;
  • varnish使用默认的cache-control控制缓存时间;
  • 缓存过期后,varnish会发送请求信息到tomcat服务器上获取页面。

参考手册:https://www.varnish-cache.org/docs/4.1/users-guide/index.html

(3) Nginx层做限流保护

Nginx自身有请求限制模块ngx_http_limit_req_module、流量限制模块ngx_stream_limit_conn_module。基于令牌桶算法,可以方便的控制令牌速率,自定义调节限流,实现基本的限流控制。

主要实现方式如下:

limit_req_zone $uri zone=limit_site:64m rate=2000r/s;
#针对uri进行限制,显示请求频率为 2000/s 
location /activity/page.html {
     limit_req zone=limit_site burst=1000 nodelay;
#burst表示缓存住的请求数目
     proxy_pass http://upstreamsite;
}

参考手册:http://nginx.org/en/docs/http/ngx_http_limit_req_module.html

作者介绍

侯本文

2012年2月入职网易,先后对Lofter、云课堂、网易宝、跨境电商、云信等多个产
品进行过性能测试,有较为丰富的Web产品性能测试经验,致力于建立Web产品
性能测试体系,为更多的产品服务。

更多内容请咨询作者泡泡:hzhoubenwen@corp.netease.com


网易云新用户大礼包:https://www.163yun.com/gift

本文来自网易实践者社区,经作者侯本文授权发布。