情人节又来了,这一天的 IT 程序员常常成为被调侃的对象。事实上,性格内向的他们在向心仪的对象告白时,也确实会因为不善言辞,被搞得心里七上八下。
俗话说得好,术(po)业(guan)有(po)专(shuai)攻(ba),告白成不成功心里没数儿,系统扛不扛得住,你心里怎么还能没点儿 Balance !
常言道,「没过十五都是年」。在 2 月 14 日这一天,我们来想象一下中国的传统节日——春节。
你所在的业务线要上线一个活动:过年七天,用户每天签到、邀请好友、完成设定任务都可以得到红包。这个红包系统的建设由你来负责,包括所有与红包相关的功能,比如发红包、抢红包、拆红包等。需求方告诉你活动上线后,对红包系统调用的 QPS 是 5000。
- 面对每秒 5000 次的请求,你的系统是否可以稳定运行?
- 如果现在要同时上线 10 个活动都需要调用红包系统,你设计的系统又是否能扛住这 10 个活动的流量?
- 如果宕掉一台服务器会怎么样?
- 多长时间能够恢复?
- 如果扛不住,加多少资源合理?
面对这一连串的问题,你心里有数吗?
为什么需要关注性能测试?
对于用户来说,稳定、平稳的使用体验非常重要。在系统架构阶段,对于部分关键功能进行性能、容量、安全、可扩展性和稳定性等的评估非常必要。但我们常常缺少这个阶段的性能测试实践,等系统开发结束后才进行,常常为时已晚。
这好比是选拔长跑运动员,在选拔运动员前我们就要知道需要考察哪些素质,比如身体协调性、耐力、冲刺爆发力等等,综合评估能否应对大赛的考验。对系统的考察也是如此,在线运行时是否稳定,没有内存泄漏、线程安全等问题,应对突发大流量系统是否可以平稳度过,系统各类资源参数设置是否合理,该如何设置,参考的标准是什么。
概括来说,性能测试就是验证系统的爆发力、耐力、协调性,帮助定位问题,为性能不断优化指导方向。
完整的性能测试该如何进行
之前和其他公司的测试同学讨论时,问到他们的性能测试方案,有人说我们用 Loadrunner,有人说我们用 Jmeter。我的感觉是,测试工具一定是必要的,但性能测试一定不能和 Loadrunner、JMeter 划「=」,而是需要一个完整的测试流程。
下面,我结合马蜂窝大交通火车票抢票压测流程,来说说在我看来,整个性能测试应该包括哪些内容。我自己也处于性能测试的摸索阶段,如果有不妥之处,还请各位不吝赐教。
图1:大交通火车票压测项目流程图
一、准备阶段
1. 什么情况下需要进行性能测试
生产环境下可能出现各种场景,哪些场景下我们需要考进行性能测试?
服务的例行迭代
你所负责系统增加新功能需求,增加了新的业务代码,新增加代码有没有引入性能问题,以上次性能测试结果为参考对本次迭代版本进行压测,检查性能是否下降。
服务重构
核心搜索、交易线服务架构进行了重构或者调整,要与重构前服务性能状况进行对比检查服务的处理能力是否达到重构目标。
容量规划
生产环境需要进行容量规划以支撑更大流量或者新服务上线明确需要多少资源,比如几台服务器,Redis 容量是多少。举个例子,有一个服务 A 的 QPS 是 100,服务 A 每次请求都要对 Redis 进行一次读和写,Redis 的 QPS 是 700,原来服务 A 有 3 台服务器,高峰期流量是 300,生产环境没有出现资源不够用的情况。现在上线了一个活动,高峰期流量增长到 600,需要增加多少台服务器合适呢?上面的例子中根据单机 QPS 在增加 4 台服务器,可以应对高峰期流量吗?
有经验的同学会回答只是增加服务器个数还不够,因为每个请求对 Redis 有两次操作,高峰期 600 QPS 映射到 Redis 是 1200,按照 Redis 处理能力 700 QPS,显然增加机器后虽然服务 A 此时不是瓶颈,但是 Redis 的处理能力仍是瓶颈。
所以,容量规划的资源是否合理,进行容量规划时给各类资源的参考值是多少,都需要通过性能测试来给出。
服务支持上层多方业务交易应用
越是支撑各类业务的底层服务,对稳定性、系统吞吐要求越高,就像我们在开篇举例的红包系统,这样的服务在架构设计时需要充分的考虑并发处理能力,是否可以方便的进行系统的容量和性能扩展。
当然,需要性能测试的场景不仅局限于以上列举的部分,我只列举出一些,供大家参考和发散思维。
2. 组建测试团队
虽然在图 1 的角色中没有体现运维和 DBA 以及跨部门人员,很多时候,尤其是在生产环境做压测,都需要这些人员的参与,开发准备好软件版本由运维同学进行部署,同时需要提前知会其他上下游依赖部门,关注服务,共同配合。
3. 预先分析
为了对系统性能建立直观上的认识和分析,应对系统较重要和常用的业务场景模块有针对性地进行分析,以对接下来的测试方案设计进行准备。
二、设计测试方案
在整个性能测试过程中,制定合理有效的性能测试方案很重要。压测方案中需要明确的内容,我的总结如下图:
图2:压测方案设计思维
1. 性能指标
性能指标是进行压测的目标,一般这个指标由业务需求方产品经理或项目经理给出,如果产品经理或项目经理不能提供具体数值,如何估算出一个能够支持业务流量 QPS 值呢?提供几个参考思考方式:
1)对于活动促销类的方案,可以参考去年同期活动高峰流量上升百分比,今年同期峰值也上升相同的百分比或者在这个基础上在增加一定的余量;
2)利用「二八原则」,根据预期到达的 PV 值进行推算,80% 的请求集中在 20% 的时间,那么峰值时间每秒请求数 (QPS)=(总 PV 数 * 80% ) / (每天秒数 * 20% )
3)参考同类型业务最近一个季度甚至一年高峰期QPS 值;
2. 测试准备
测试内容
这里主要分为两部分,一部分是模拟请求的接口参数,另外是模拟商品(如果产品是外部供应商提供可能需求进行 mock)或者外部依赖服务产生的数据。
压测数据
- 数据类型:一是接口请求所需数据,如 10w 用户账号、100w 订单;二是压测所需产品数据准备;
- 代码上增加针对压测数据过滤的逻辑,主要为了方便的进行数据隔离和压测结束环境恢复;
- 有一些外部依赖不能参与压测(可能会产生费用或影响其他业务方),需要添加模拟的请求返回
压测资源
比如服务器,用到的中间件、数据库等。
这里,我想重点说一下为什么要进行数据隔离:
1)区分压测流量与真实流量,方便压测结束后进行数据清洗。压测结束后产生的交易、支付都要进行撤销,以免产生资损,落到数据库中数据也要删除。所以,将压测流量产生的数据落到影子库,可以方便进行这些操作,如果没有影子库,也可以通过对压测数据打标签,来进行分区。
2)压测数据隐藏,如果测试环境压测可以不考虑这个问题,生产环境压测产生的交易对客户不可见,包括为了进行压测准备的商品,对客户也要隐藏。
3)防止压测产生请求数据进入报表统计。
以在火车票抢票压测为例,处理的方式是对 UID 进行路由,压测 UID 产生的请求数据路由到影子库中,真实请求的 UID 数据存在测试环境数据库(压测是在线下压测环境进行的)。
综上,结合火车票抢票压测示例来看,我们在压测前了做了如下准备:
- 火车票抢票服务依赖其他服务,创建订单时,对依赖部分做 mock;
- 创单数据同步订单中心也是做了 mock;
- 准备用与创单的用户 uid;
- 将从cookie中获取登陆状态的代码剥离,脱离对登录的依赖,接口本身支持传 uid 就可以创建订单
图3: 火车票抢票压测服务拓扑
3. 构建压测模型
压测模型是模拟用户行为压测场景,每个接口请求参数有什么特殊要求,一个场景中会同时有多个接口,这些接口的流量如何配比,后面压测执行时都按照这样的场景进行。那如何分析用户的行为模式获取到接口的流量配比,下面给出 2 种参考方法:
1)对于已经上线的系统,采用系统日志或辅助的监控系统获得这些信息。大交通每个业务都接入了 CAT 系统,通过在 CAT 上查看每个 URL 的请求量,
得出压测场景中涉及到不同接口流量配比。
2)对于未上线的全新系系统,可以参考行业类似系统做分析,或公司类似业务做分析。
4. 编写压测脚本
按照用例描述,选择工具进行编写。对压测脚本的编写,现在有很多成熟的工具,比如 JMeter、nGrinder。火车票抢票压测工具选用了 JMeter。
三、压测执行
压测过程需要开发、运维同学参与,整个压测执行过程分两部分:一个部分是启动压测脚本对服务器产生请求压力;一部分是监控服务表现是否符合要求。压测过程中通常关注的内容有:
- CPU 使用率,通常要求 CPU 使用率<70%;
- 内存使用情况,是否存在内容泄漏;
- 系统业务完整性,返回结果是否正确;
- 系统响应时间是否满足业务要求;
- 系统处理能力是否稳定,QPS 的大小在固定很小范围内抖动比如,如果有规律的出现 QPS 值跌落,则链路上可能存在某个服务处理比较慢;
- 观察服务是否存在 ERROR/WARN 级别的报错;
- 观察服务 GC 的频率;
- 压测结束后占用的资源是否正常释放;
- 调整服务器数量看系统性能是否具备横向扩展的能力;
此外还有磁盘 IO、网络带宽等……
四、问题优化
压测目的是就是找出系统潜在的问题及系统各类资源参数设置,压测问题调优不同业务系统有不同解决方案,开发可能更有发言权,此处不赘述。列举一些常见的方法:
- 数据库进行读写分离,单条写改成批量写;
- 不属于关键链路上的服务不做重试或改为异步方式;
- 压测过程中报 connect: cannot assign requested address
原因:客户端端口不够,修改 sysctl.conf 文件配置
sysctl -w net.ipv4.tcp_tw_reuse=1
sysctl -w net.ipv4.tcp_timestamps=1
net.ipv4.ip_local_port_range = 1024 65535
- 通信的短链接改成长连接;
五、记录压测报告,分析结果
压测结束输出压测报告,分析不同压测情况下测试结果找到拐点,得出系统处理能力,得出各类资源参数设置参考值。
一些建议
除了加机器,你还能做什么?
生产环境下,我们会遇到各种各样的问题。有时,即使进行了充分的性能测试,还是会出现问题。那么对于提高系统稳定性,除了加机器,我们还有哪些方案呢?这里,给大家一些建议:
1)上线提前设计好限流方案,如:
- 活动入口的时候增加游戏环节进行消峰操作,还有秒杀前的倒计时也可以起到流量削峰;
- 在接口层面拒绝多余的访问, 或者让多余的访问排队等待服务;
2)降级服务,下线一些辅助功能,减少资源的竞争;
3)引入缓冲机制;
4)实时监控访问量,一旦 QPS 超过预设的阈值,则可以考虑进行扩容以避免出现访问量过大宕机。
路漫漫其修远兮,系统的稳定性也是如此,通过不断的解决问题积累经验,以应对日益增长的业务需求。
本文作者:董敏,马蜂窝大交通研发团队测试工程师,目前主要负责火车票相关业务的测试工作。
【本文是51CTO专栏作者马蜂窝技术的原创文章,作者微信公众号马蜂窝技术(ID:mfwtech)】