📝 面试求职: 「面试试题小程序」 ,内容涵盖 测试基础、Linux操作系统、MySQL数据库、Web功能测试、接口测试、APPium移动端测试、Python知识、Selenium自动化测试相关、性能测试、性能测试、计算机网络知识、Jmeter、HR面试,命中率杠杠的。(大家刷起来…)
📝 职场经验干货:
一、背景与挑战
在过去的几年里,货拉拉的用户和货运订单数量都实现了快速增长,现已发展成为全球最大的闭环物流交易平台。随着订单业务的飞速发展,系统稳定性的保障变得越来越重要,全链路压测在保证系统稳定性的过程中发挥了关键的验证作用,其目标是检验系统的稳定性和容量。然而,在业务快速迭代和高速增长的背景下,全链路压测也面临着更高的需求和挑战。
及时验证峰值容量: 随着业务的高速发展,订单量常常会突破历史峰值,甚至曾在半个月内多次打破记录。因此,我们必须确保压测能够及时验证服务的总体容量以及单个服务扩容后相关链路的稳定性。
提升压测效率: 传统的全链路压测是一项较为繁重的测试活动,它不仅涉及多个部门和人员,还需要核心服务的开发人员进行值班。此外,还包含了较多的脚本维护,复杂的造数,以及较长的压测流程。若要求能够实现及时、高效的全链路压测,我们必须提升测试工作的效率,同时减少对值守人员的依赖。
保障压测安全性: 全链路压测通常是在生产环境中进行,压测所产生的大流量可能导致某些服务的响应变得不稳定,甚至可能引发连锁反应,影响到更多服务并导致线上真实故障的发生。因此,在压测过程中要具备熔断机制,在服务被压崩溃前及时停止压测流量,保障系统稳定运行。
二、方案与目标
在构思初始方案时,我们在行业内寻找并比对类似的解决方案,但是发现相关资料较少。由于全链路压测和压测自动化都需要与公司业务和内部平台频繁交互,我们在考虑改造全链路压测自动化时,决定结合公司业务特点和现有全链路压测流程以及内部平台特性进行改造。
为实现全链路压测的自动化,主要目标是把人工操作的重复工作自动化。在确定整体方案后,我们详细梳理了全链路压测前、中、后的常见工作场景,并确认了对应的需求以及平台服务支撑。以下是我们的整体改造思路图。
梳理出改造场景中的重点和难点问题,我们需要着重完成以下功能:
模型建模与模型效果对比: 无论是在压测场景和流量的配比,还是在压测后的效果对比中,都需要我们找到一个适合的模型算法,以确认压测场景的模型以及对比压测效果。
压测任务编排: 在压测任务中,一些任务有固定的时间顺序或因果关系顺序。这就要求我们需要有一个灵活的任务编排系统,方便自由地编排相关压测任务。
压测任务调度: 以货拉拉货运全链路压测为例,每次涉及到超 70 个脚本,300 余台压测机,以及数百万订单的压测目标流量。因此,如何对测试场景、脚本和测试数据以及压测流量进行有效的管理、分发和收集显得尤为重要。
健全的熔断机制: 既要检测出系统瓶颈,又要在出现异常时及时停止压测流量,以避免引发更大的生产问题,因此需要一个健全的熔断机制。
三、能力建设
全链路压测自动化的整体能力建设内容繁多,我们将以重点改造为例,列出相关的思考和部分实现原理。
3.1 高峰流量与压测流量建模
压测模型,简而言之,就是设定被压测的各个服务及其相关接口的具体目标 QPS 比例,压测流量模型应尽可能接近线上真实流量。模型自动化在全链路压测的整个过程中有各种应用场景,其中包括在压测前建立压测模型,在压测过程中调整压测场景,以及在压测后对比流量模型。
3.1.1 高峰流量建模
当服务数量有限时,常通过手动观察各服务接口的请求量并配置对应压测流量比例来建立模型。但在大型项目全链路压测中,接口数量和脚本量的增长使这成为了压测人员最繁重的任务之一。且在人工配置过程中可能出现疏忽,导致流量比例失真。
对于压测模型的构建,我们首先从公司监控平台获取主要相关数据,然后进行关联和模型转换,最终定时生成各服务不同指标的峰值流量模型。
/**简化代码,只保留主要流程信息,
*从监控平台获取相关服务数据,并转化为压测模型保存在压测平台
*/
public PressureModel getAndSaveOneDayMonitorData(String appId, String env, String name, String batchId, long start, long end, long step, MonitorData orderMonitorData) {
PressureModel model = new PressureModel();
String timeScope = StrUtil.isEmpty(orderMonitorData.getTimeScope()) ? MonitorData.TIME_ALL_DAY : MonitorData.TIME_CUSTOM;
//soa监控数据获取并转换模型
HashMap<String, MetricIntegratorData> monitorQpsSoaData = getMonitorQpsSoaData(env, appId, false, start, end, step);
List<MonitorData> monitorQpsSoaDataFromMetricDates = getMonitorDataFromMetricDates(appId, env, name, batchId, MonitorData.TYPE_QPS_SOA, MonitorData.TYPE_QPS_SOA, timeScope, monitorQpsSoaData);
if (!monitorQpsSoaDataFromMetricDates.isEmpty()) {
monitorDataRepository.saveAll(monitorQpsSoaDataFromMetricDates);
model = M