性能测试

性能测试是通过自动化的测试工具模拟多种正常、峰值以及异常负载条件来对系统的各项性能指标进行评估和优化的测试活动。服务端性能测试,即针对后台服务的性能测试。

性能测试的意义

故障事件回顾:

2012年11月11日零点,阿里各种系统报错、立刻下单报错、购物车支付报错、支付系统报错、购物车的东西丢失,系统显示交易成功率不到50%,产生了大量超卖,给阿里带来很大的损失。那一年的双11后,库存、商品、退款和相应数据库的同学,为了处理超卖导致的问题,没日没夜加了两周的班,同时给了用户不少糟糕购物体验。

故障的原因:
压测没有做到位,对整个全交易链路上的各个子系统的承受能力不清楚,并且错误预估了可能会达到的流量,也没有完善的预案。

负载测试和压力测试

负载测试和压力测试都属于性能测试,两者可以结合进行。

  • 负载测试:测试当负载逐渐增加时,获得系统各项性能指标的变化情况(关注点在系统性能指标)。
  • 压力测试:测试以确定系统瓶颈或者无法继续服务的负载点,来确定系统能提供的最大服务量(关注点在确定服务拐点)。

    单系统压测与全链路压测

    单系统压测:针对单个服务系统进行压力,评估单个系统的性能情况。
    全链路压测:完全模拟真实场景来压测,评估整个业务系统链路的性能情况。
    在流量洪峰来的瞬间,各系统都面临自身服务的巨大的压力,而系统之间是有互相依赖关系的,单机压测没有考虑到依赖环节压力都比较大的情况。一个系统出现故障,故障会在链路流转过程中层层累加,最终会造成无法评估的影响。所以最可靠的方式是完全模拟真实场景来压测,通过全链路压测提前发现问题。

    常见压测性能指标

  • QPS:Query Per Second,每秒处理的请求个数

  • TPS:Transactions Per Second,每秒处理的事务数,TPS <= QPS
  • RT: Response Time,响应时间,等价于Latency
    RT分平均延时,Pct延时(Percentile分位数)。平均值不能反映服务真实响应延时,实际压测中一般参考Pct90,Pct99等指标。
  • CPU使用率:出于节点宕机后负载均衡的考虑,一般 CPU使用率 < 75% 比较合适
  • 内存使用率:内存占用情况,一般观察内存是否有尖刺或泄露。
  • Load指标:CPU的负载,不是指CPU的使用率,而是在一段时间内CPU正在处理以及等待CPU处理的进程数之和的统计信息,表示CPU的负载情况,一般情况下 Load < CPU的核数*2
  • 缓存命中率:多少流量能命中缓存层(redis、memcached等)
  • 数据库耗时:慢查询、等待数据库连接耗时
  • 网络带宽:带宽是否瓶颈
  • 接口响应错误率
  • 错误日志量

    压测的流程

    完整的压测流程一般包含下面几个步骤:
  1. 压测目标的制定
  2. 压测链路的梳理
  3. 压测环境的准备
  4. 压测数据的构造
  5. 发压测试
  6. 瓶颈定位和调优
  7. 容量水位测试
  8. 压测总结

    压测目标的制定

    压测需求背景

    由于新公司业务快速发展带来的流量突增以及技术负债各方面,性能的问题就开始席卷而来,常见于以下情况:
  • 线上服务由于流量过高应用挂了
  • 运营做了拉新和新的渠道拓展
  • 系统架构由集群技改为微服务
  • 引入了限流和降级策略,需要故障演练

    测试的目的

    针对需求背景,可以知道性能测试的目的如下:

  • 定位瓶颈、分析调优验证

  • 评估系统性能是否满足新的线上业务
  • 验证稳定性、可用性、单实例容量,为线上服务扩容提供容量规划数据
  • 故障演练,验证预研可行性

    测试的目标

    较为科学的评估目标方法应该将指标-成功率-流量三者挂钩在一起
  1. 在响应时间的限制下,系统最高的吞吐量
  2. 在成功率100%的前提下,不考虑响应时间长短,系统能承受的吞吐量
  3. 容忍一定的失败率和慢响应,系统最高能承受的吞吐量(95%成功率,前95%的请求响应时间为xx毫秒时的最大QPS)
  4. 在上面的场景下还要考虑时间和资源,比如最高吞吐量持续10分钟和持续1小时是不一样的,不同的时间持续长度下,机器资源(cpu、内存、负载、句柄、线程数、IO、带宽)的占用是否合理(稳定性和长时间疲劳测试)

    准入准出条件

    准入条件:性能测试开始时需要具备的条件
  • 压测环境搭建完成
  • 功能测试通过
  • 测试数据构造完成
  • 压测集群搭建完成
  • 压测脚本编写完成
  • 监控指标验证通过

准出条件:性能测试完成时需要具备的条件

  • 测试场景均测试完成
  • 性能数据均记录完成
  • 调优后功能测试通过
  • 性能测试报告已输出

暂停条件:

  • 系统出现大量错误,暂停执行性能测试
  • 试压结果跟预期差很多,建议暂停优化再继续

    测试阶段制定

    从细粒度开始慢慢集成到整个大系统,就像单测->接口测试->集成测试,压测也是先从简单的开始,一步一步走向全资源全链路,可以参考过程:单接口单机->单接口1/4资源->场景化1/4资源->全量资源压测->拨测。

  • 单接口单机:在单核(或物理资源少)机器上部署单个服务,排除外部链路、网络等因素,得出自身服务的单核性能情况(单位QPS/core),后续根据此单核性能指标结合压测目标值进行扩容。另外由于是压的单接口单机,无其他接口请求影响,上下游在足够资源的情况下也不会造成瓶颈,所以能确保服务的性能真实值。

  • 单接口1/4资源:单接口单机压测环节,服务端已经完成了部分性能优化,接下来可以进入单接口1/4资源压测,这样是为了验证在单接口单机压测中得到的单核性能数据,在扩容1/4资源下性能是否会线性增长,是否存在性能损耗以及定位损耗源。
  • 场景化1/4资源:单接口压测局限很明显,场景化压测由于引入了上下游服务的其他接口的因素,可以发现单接口压测无法发现的问题,更接近线上用户场景。
  • 全量资源全链路:全部资源到位后,预估的线上压力是否能承受,这一步也是压测过程的最后一步。
  • 拨测:验证用户从客户端到服务端的整个带宽资源是否满足预期,内网压测已经确认了业务性能是否达标,因此拨测可以只选择了一个场景进行验证即可。(简单来说拨测相当于压测cdn,检查各地cdn节点资源是否充足)能

    压测策略

    压测过程也要提前规划好,加入一定的人工策略调整,如果有使用缓存,需要考虑是否需要预热。

  • 试压或者基准压测:在正式压测之前,先进行一次基准压测,类似于冒烟测试,通过小量压测来看看性能指标,如果基准都不符合预期,太差的话,那就应该先暂停了

  • 稳定性压测:基准压测完毕后如果指标达到要求,根据业务情况如果需要长时间的压测,那么就需要稳定性压测,有些问题需要长时间才会暴露,比如内存泄露
  • 峰值脉冲:直接上大量并发用户数,并运行一段时间,不考虑思考时间,完成时也是瞬间停止,瞬间发起瞬间结束,主要验证系统应对瞬时流量的可靠性
  • 系统摸高:关闭熔断降级限流等自救功能,提高压力观察系统性能拐点
  • 自救策略验证:开启熔断限流等自救功能,这些功能是否生效,系统是否还能扛得住
  • 破坏性测试:主要为了验证预案的有效性,类似于容灾演练时的预案执行演练,验证后手抢救方案
  • 容量测试:主要是为了评估不同的系统配置下,系统能承受的吞吐量,为后期运维部署扩容缩容做参考

    压测链路梳理

    系统架构梳理

    梳理出被测系统的架构拓扑图,包含被测服务、依赖服务、依赖组件、SLB、Nginx转发层等,另外如有熔断限流、降级、限流策略也需要梳理清楚,还要关注是否有第三方付费服务,例如短信服务。
    一般开发都会梳理出架构图和文字描述,团队评审。

    核心业务场景梳理

    梳理出以下场景:

  • 高频的业务场景(比如获取用户信息)

  • 关键业务场景(比如登录)
  • 性能高消耗场景(比如下单消费)
  • 历史出现过问题的场景

一般由开发梳理出业务调用链路,画出时序图,团队评审。

压测环境的准备

压测环境

常见压测环境:

  • 脚本调试环境:用于调试脚本的环境,可以是测试环境,可前置准备压测脚本。在编写脚本时,需要对服务地址和数据进行参数化,之后切到正式压测环境时可以修改配置即可。
  • 独立压测环境:用于正式压测的环境,一般部署好之后,还需进行一次功能验证,确保正常。部分依赖服务会选择mock方式,此时需要验证mock是否正确、合理。
  • 对照调优环境:独立压测环境一致,可选,用于调优后进行对比验证。
  • 线上正式环境:在线上环境做压测,准备过程比较复杂,但是压测结果最准确。

    监控

    监控的作用

  • 事前及时预警和发现故障

  • 事后提供详实的数据用于追查定位问题

    常见的监控

    一般压测过程需要关注的监控有以下:

  • 压测数据监控:TPS、99%RT、错误率

  • 压测集群系统资源监控:CPU、内存、网络、IO、load、上下文切换等
  • API监控:QPS、错误率
  • 服务端系统资源监控:CPU、内存、网络、IO、load、上下文切换等
  • 服务端业务指标监控:在线用户数、活跃用户等
  • 服务中间件监控:缓存、消息队列、DB等
  • 链路监控:JVM、线程池、连接池、调用链路耗时等
  • 日志监控:错误日志、日志量

    压测数据的构造

    按照业务核心场景将场景所需要的数据都构造出来,一般有以下方式:
  1. 批量写库
  2. 复制数据库
  3. 批量调接口

    压测工具和脚本

    压测工具和脚本五花八门,不在此赘述了

    测试执行

    按压测场景进行发压测试,并记录过程中的性能数据和问题现象

    瓶颈定位和调优

    瓶颈定位

    常见的压测问题:
  • CPU高负载
  • 内存OOM
  • 网络带宽满
  • 磁盘满
  • 接口耗时长
  • 消息堆积
  • 数据库挂
  • Redis挂
  • Nginx挂
  • JVM频繁GC

    调优

    具体如何定位和调优,主题太大,不在此处赘述。

    容量水位测试

    目标值往往是比当前线上实际大很多的,为了降低成本,可以缩容测出不同容量的应用配置,供后续运维配置扩缩容策略。
    在压测到达目标,准备结束测试之前,可以进行容量水位测试:

    比如目标是300w,线上是100w,则可以分别缩容测出150w、200w、250w、300w所需要的配置情况,运维根据实际配置扩缩容策略。

压测结束

性能测试报告

一份性能测试报告,至少应该包含如下内容:

  1. 测试基本信息:包含测试目的、报告目标读者、术语定义、参考资料。
  2. 测试环境描述:包含服务器软/硬件环境、网络环境、测试工具、测试人员
  3. 性能测试案例执行分析:需要详细描述每个测试案例的执行情况,以及对应的测试结果分析。
  4. 测试结果综合分析及建议:对本次性能测试做综合分析,并给出测试结论和改进建议。
  5. 测试经验总结:对一些问题总结方法,根据情况输出。

    压测工作收尾

    数据清理

    如果是在线上进行压测,那需要在结束后清理掉压测标记的数据,避免给线上数据库带来不必要的负担。

    肉机镜像和脚本备份

    如果肉机环境搭建比较复杂,容易出错,而之后可能还会再次压测,那可以考虑让运维做一个镜像进行备份,下次进行复用,提高效率,脚本同理,需要做好备份。

    资源回收

    运维把压测用的相关资源回收。