2021年中旬就计划着搭建一套压测系统,大约9月份已经搭建完成,使用至今还是比较稳定了,分享一下搭建思路及过程:

为什么选择Locust呢,因为Locust可以仅需要执行命令就可以完成压测任务,并且集群压测也很简单,只需压测机安装locust并把压测脚本推送到服务器即可。

Locust QQ群:

画了一个大致的思路图:

我们说的全链路其实有几层意思:

1.多接口多场景,而非单接口或单url

2.按照用户访问场景及频率,用户访问的路径是有先后的,访问的接口频率也是不一样的。怎么理解这个呢,很简单,比如获取列表的接口(get_list)和获取内容的接口(get_content),用户访问任何页面有可能都会访问

get_list,但用户可能都不会点击详情,所以调用get_list的频率会更多。

怎么真实的获取到用户访问的链路场景呢?

1.通过用户访问的日志,分析用户的行为,然后编写压测场景用例

2.模拟用户场景,导出用户记录
  A.浏览器直接导出记录生成.har文件

  B.app通过抓包工具获取用户记录导出生成.har文件

当然有的人说har文件解析生成接口后,后续压测能一直有效么,比如token等校验通不过,解决这个问题很简单,和研发商量一下,请求参数里加每个值或对特定设备或标识放开就行,后续一路畅通无阻。

压测脚本来源有了,第二步就是解析har文件,模块库里有解析har的,但发现不满足自己使用,自己写吧,项目结构仅供参考:

解析Har文件:

 1 # -*- coding = utf-8 -*-
2 # ------------------------------
3 # @time: 2021/3/22 14:53
4 # @Author: drew_gg
5 # @File: disassemble_har.py
6 # @Software: cover_app_platform
7 # ------------------------------
8
9 import json
10 from app.locust.anasiysis_har import judgment_exist as jud
11 from app.locust.anasiysis_har import deal_headers as dh
12 from app.locust.anasiysis_har import deal_request_data as dr
13 from app.config.har_to_api import api_filter as af
14
15
16 key_words = af.key_words
17
18
19 def disassemble_har(har_file, api_only=0):
20 """
21 提取分解har文件
22 :param har_file: .har文件
23 :param api_only: 1:去重,其他:不去重
24 :return:
25 """
26
27 req_l = []
28 rdl = []
29 rdl_set = []
30 host = ''
31 count = 1
32 # url过滤非接口请求
33 with open(har_file, "r", encoding='utf-8') as f:
34 f = json.loads(f.read())
35 for i in f['log']['entries']:
36 if jud.judgment_exist(i['request']['url'], key_words) is False:
37 req_l.append(i)
38 for index, i in enumerate(req_l):
39 rd = {}
40 # 解析host
41 host = i['request']['url'].split('//')[0] + '//' + i['request']['url'].split('//')[1].split('/')[0]
42 # 解析子url
43 # son_url = i['request']['url'].split(host)[1].split('&')[0]
44 son_url = i['request']['url'].split(host)[1]
45 deal_url = son_url.split('?')[0]
46 if deal_url == '/':
47 if len(son_url.split('?'))> 1:
48 deal_url = son_url.split('?')[1]
49 else:
50 deal_url = '/'
51 deal_url = deal_url.replace('/', '_').replace('-', '_').replace('.', '_').strip('_').lstrip('_')
52 if api_only == 1:
53 method_name = 'api_' + deal_url.lower()
54 else:
55 method_name = 'api_' + deal_url.lower() + '_' + str(index)
56 # 解析处理header
57 headers = dh.deal_headers(i['request']['headers'])
58 method = i['request']['method']
59 # 解析处理请求参数
60 if method.upper() == "POST":
61 request_data = dr.deal_request_data(method, i['request']['postData'])
62 if method.upper() == "GET":
63 request_data = '\'' + i['request']['url'].split(son_url)[1] + '\''
64 host = '"' + host + '"'
65 son_url = '"' + son_url + '"'
66 rd['host'] = host
67 rd['url'] = son_url
68 rd['headers'] = headers
69 rd['method'] = method
70 rd['method_name'] = method_name
71 rd['request_data'] = request_data
72 if api_only == 1:
73 # 去重并计数判断
74 if index == 0:
75 rd['count'] = count
76 rdl_set.append(rd)
77 else:
78 for x in rdl_set:
79 if son_url == x['url']:
80 x['count'] += 1
81 count = x['count']
82 else:
83 if count == 1:
84 rd['count'] = count
85 rdl_set.append(rd)
86 count = 1
87 else:
88 rd['count'] = count
89 rdl.append(rd)
90 if api_only != 1:
91 rdl_set = rdl
92 return rdl_set, host
93
94
95 if __name__ == '__main__':
96 har_path = r'D:\thecover_project\cover_app_platform\app\file_upload\首页普通\20210803-113719\syptxq.har'
97 disassemble_har(har_path)

解析har文件,处理header、获取接口必要参数,然后对请求做分析,如果要去重,则统计相同请求的数量,压测时生成压测权重,如果不去重,后续生成压测脚本时则需要对处理方法名称。

解析好har文件后,需要生成调试脚本和压测脚本:

我处理方式实直接生成py文件,事先创建好模板,如:

生成调试脚本比较简单,只需要一个模板就行,生成locust压测脚本则稍微负责点,我是分拆成多个模板,然后整合到一个模板。

生成的脚本都规范放在目录里:

生成脚本目录结构:

生成压测脚本示例:

 1 # -*- coding = utf-8 -*-
2 # ------------------------------
3 # @time: 2021-04-19 13:43:10.380837
4 # @Author: drew_gg
5 # @File: liao_bao.py
6 # @Software: api_locust
7 # ------------------------------
8
9
10 from locust import SequentialTaskSet, task, constant, tag, TaskSet
11 from locust.contrib.fasthttp import FastHttpUser
12
13
14 class LiaoBao20210419(TaskSet):
15
16 @task(1)
17 @tag('api_getlist')
18 def api_getlist(self):
19 headers = {'Content-Type': 'application/x-www-form-urlencoded; charset=utf-8', 'tenantId': '7'}
20 # 请求参数组装 ## r_url:固定参数
21 r_url = "/getList?vno=6.4.0"
22 requests_data = {'account': 'E2247B94-51E2-4952-BC06-24752911C060', 'client': 'iOS', 'data': '{"operation_type":0,"news_id":0,xxxxxxxxxxxxxxxxxxx'}
23 # 发起请求
24 with self.client.post(r_url, data=requests_data, catch_response=True, name=r_url) as r:
25 if r.content == b"":
26 r.failure("No data")
27 if r.status_code != 200:
28 em = "request error --" + str(r.status_code)
29 r.failure(em)
30
31 @task(4)
32 @tag('api_getsysnotice')
33 def api_getsysnotice(self):
34 headers = {'Content-Type': 'application/x-www-form-urlencoded; charset=utf-8', 'tenantId': '7'}
35 # 请求参数组装 ## r_url:固定参数
36 r_url = "/getSysnotice?vno=6.4.0"
37 requests_data = {'account': 'E251179A-6309-4326-9827-73C892131605', 'client': 'iOS', 'data': '{"page_size":15,"page":1}', xxxxxxxxxxxxxxxxxxxxxxxx}
38 # 发起请求
39 with self.client.post(r_url, data=requests_data, catch_response=True, name=r_url) as r:
40 if r.content == b"":
41 r.failure("No data")
42 if r.status_code != 200:
43 em = "request error --" + str(r.status_code)
44 r.failure(em)
45
46 @task(4)
47 @tag('api_user_preparecancelaccount')
48 def api_user_preparecancelaccount(self):
49 headers = {'Content-Type': 'application/x-www-form-urlencoded; charset=utf-8', 'tenantId': '7'}
50 # 请求参数组装 ## r_url:固定参数
51 r_url = "/user/prepareCancelAccount?vno=6.4.0"
52 requests_data = {'account': '2FF3D47C-995B-4D7E-93CD-58B4F1E94B74', 'client': 'iOS', 'data': '{}', xxxxxxxxxxxxxxxxxxxxxxx}
53 # 发起请求
54 with self.client.post(r_url, data=requests_data, catch_response=True, name=r_url) as r:
55 if r.content == b"":
56 r.failure("No data")
57 if r.status_code != 200:
58 em = "request error --" + str(r.status_code)
59 r.failure(em)
60
61
62 class liao_bao_locust(FastHttpUser):
63 host = "https://xxxxxx.xxxxx.com"
64 wait_time = constant(0)
65 tasks = {LiaoBao20210419: 1}

生成好脚本后,需要生成执行命令:

 1 # -*- coding = utf-8 -*-
2 # ------------------------------
3 # @time: 2021/3/3 11:08
4 # @Author: drew_gg
5 # @File: locust_create_cmd.py
6 # @Software: cover_app_platform
7 # ------------------------------
8
9
10 def create_master_cmd(locust_pra):
11 """
12 生成master命令
13 :param locust_pra:
14 :return:
15 """
16 # locust master 命令样式:
17 """
18 locust -f /work/locust/api_locust/locust_view/fm_api/locust_api/locust_fm_640.py
19 --master
20 --master-bind-port 9800
21 --headless
22 -u 600
23 -r 200
24 --expect-worker 16
25 -t 10m
26 -s 10
27 --csv /work/locust/locust_report/fm/locust_get_dynamic.py0223145309
28 --html /work/locust/api_locust/resource/html/new_html/locust_get_operation_parm.html
29 """
30 run_port = '9800'
31 master_cmd = "locust -f %s --master --master-bind-port %s --headless " % (locust_pra['to_file'], run_port)
32 master_pra = "-u %s -r %s --expect-worker %s -t %ss -s 10 --csv %s --html %s > %s" % \
33 (locust_pra['user'], locust_pra['rate'], locust_pra['thread'], locust_pra['time'], locust_pra['csv'],
34 locust_pra['html'], locust_pra['master_log'])
35 master_cmd = master_cmd + master_pra
36 return master_cmd
37
38
39 def create_slave_cmd(locust_pra):
40 """
41 生成slave命令
42 :return:
43 """
44 run_port = '9800'
45 if len(locust_pra['api']) == 1 and locust_pra['api'][0] == '':
46 slave_cmd = "locust -f %s --master-host %s --master-port %s --headless --worker > %s" % \
47 (locust_pra['to_file'], locust_pra['master'].split('-')[0], run_port, locust_pra['slave_log'])
48 else:
49 tags = ''
50 for i in locust_pra['api']:
51 tags += i.split(".py")[0] + ' '
52 slave_cmd = "locust -f %s --master-host %s --master-port %s --headless --worker -T %s > %s" % \
53 (locust_pra['to_file'], locust_pra['master'].split('-')[0], run_port, tags, locust_pra['slave_log'])
54 return slave_cmd

然后把文件推送到服务器上,服务器也需要有规定的目录:

每台压测机上建立三个目录:

master上存储压测生成的报告、csv文件,然后写个定时程序拉去报告到项目服务器,压测完后可直接查询报告。

平台主要界面:

1.首页

2.上传并解析har文件页面

3.压测脚本在线编辑执行页面

4.接口调试页面

5.调试结果页

6.压测配置页面

7.压测执行及记录页面

8.压测报告页面

9.服务器管理页面

大致包含这些功能,当然,项目搭建过程中遇到各种坑,要尝试才知道,后续打算优化一下代码,再升级几个版本,也算彻底搞定。

欢迎感兴趣的一起研究讨论。

基于locust全链路压测系统的更多相关文章

  1. 全链路压测平台(Quake)在美团中的实践

    背景 在美团的价值观中,以“客户为中心”被放在一个非常重要的位置,所以我们对服务出现故障越来越不能容忍.特别是目前公司业务正在高速增长阶段,每一次故障对公司来说都是一笔非常不小的损失.而整个IT基础设 ...

  2. 京东全链路压测军演系统(ForceBot)架构解密

    摘要:全链路压测是应对电商大促容量规划最有效的手段,如何有效进行容量规划是其中的架构关键问题.京东在全链路压测方面做过多年尝试,本文转载京东商城基础平台技术专家文章,介绍其最新的自动化压测 Force ...

  3. 高德全链路压测平台TestPG的架构与实践

    导读 2018年十一当天,高德DAU突破一个亿,不断增长的日活带来喜悦的同时,也给支撑高德业务的技术人带来了挑战.如何保障系统的稳定性,如何保证系统能持续的为用户提供可靠的服务?是所有高德技术人面临的 ...

  4. 【转】京东金融App端链路服务端全链路压测策略

    京东金融移动端全链路压测历时三个月,测试和服务端同学经过无数日日夜夜,通宵达旦,终于完成了移动端链路的测试任务.整个测试有部分涉及到公司敏感数据,本文只对策略部分进行论述. 1.系统架构与策略 在聊性 ...

  5. <转>二十问全链路压测干货汇总(上)

    本文转载自:微信公众号-数列科技<二十问全链路压测干货汇总(上)> 最近几年全链路压测无疑成为了一个热门话题,在各个技术峰会上都可以看到它的身影. 一些大型的互联网公司,比如阿里巴巴.京东 ...

  6. 生产环境全链路压测平台 Takin

    什么是Takin? Takin是基于Java的开源系统,可以在无业务代码侵入的情况下,嵌入到各个应用程序节点,实现生产环境的全链路性能测试,适用于复杂的微服务架构系统. Takin核心原理图 Taki ...

  7. 案例 | 荔枝微课基于 kubernetes 搭建分布式压测系统

    王诚强,荔枝微课基础架构负责人.热衷于基础技术研发推广,致力于提供稳定高效的基础架构,推进了荔枝微课集群化从0到1的发展,云原生架构持续演进的实践者. 本文根据2021年4月10日深圳站举办的[腾讯云 ...

  8. 让全链路压测变得更简单!Takin2.0重磅来袭!

    自Takin社区版1.0发布两个多月以来,有很多测试同学陆续在各自的工作中运用了起来,其中包括金融.电商.物流.出行服务等行业.这个过程中我们收到了很多同学的反馈建议,同时也了解到很多同学在落地全链路 ...

  9. 全链路压测SOP

    压测模型构建:人工 线上(大促)流量数据 (数据脱敏) 日常流量数据 业务方新的特性产生的变更数据 友商做过的事情 压测模型构建:自动 流程包括:录制-清洗-回放 (目前能做好的公司非常少) 压测标准 ...

  10. 美团--Quake全链路压测平台

    原文:连接: https://tech.meituan.com/2018/09/27/quake-introduction.html 开源分布式监控Cat: https://github.com/di ...

随机推荐

  1. Advanced .Net Debugging 3:基本调试任务(对象检查:内存、值类型、引用类型、数组和异常的转储)

    一.介绍 这是我的<Advanced .Net Debugging>这个系列的第四篇文章.今天这篇文章的标题虽然叫做"基本调试任务",但是这章的内容还是挺多的.由于内容 ...

  2. MySQL8.0与5.7版本的下载、安装与配置

    •软件下载 下载地址 [官网],点开该网址,点击  DOWNLOAD 来到如下页面: MySQL的版本介绍 MySQL Community Server  社区版本:开源免费,自由下载,但不提供官方技 ...

  3. modalError.vue 错误提示框 vue2 iview

    需求 一个错误提示框,后台需要有换行,默认没有换行,做一个支持换行的全局错误提示函数. 注意 代码只展示原理,直接不能使用,里面有getAc,有需要参考 https://www.cnblogs.com ...

  4. 基于python的密码生成器实例解析

    一 概念   密码生成不复杂,可是它却涉及到了string的常用技巧和一些概念 记得python中的random模块,这是所有随机数的藏身之处 记得python中的string模块,这个是字符操作的盛 ...

  5. esp8266 I2C 实例解析及源码分析

    一  前言 作为一个方案商兼芯片开发者,研究芯片和功能实现除了基本的工作需要,还有一层就是也变成了一种职业习惯.从芯片到方案,发现很多方案公司的人水平都比较堪忧,只会调用api,根本不会看底层的代码实 ...

  6. 性能优化:编译器优化选项 -O2/-O3 究竟有多强大?

    之前的"性能优化的一般策略及方法"一文中介绍了多种性能优化的方法.根据以往的项目经验,开启编译器优化选项可能是立竿见影.成本最低.效果最好的方式了. 这么说可能还不够直观,举个真实 ...

  7. 【专访蓝景科技】5G+实时云渲染赋能数字孪生,共建元宇宙

    ​ 2021年伊始,元宇宙 概念不断扩展探讨与深入,国内外科技巨头扎堆布局元宇宙. 元宇宙第一股------ROBLOX 上市.字节跳动 90亿收购国内TOP1VR厂商PICO.FACEBOOK改名为 ...

  8. python基础八(迭代器、生成器、生成式、递归、匿名函数、面向过程编程)

    一 迭代器 1.什么是迭代器 迭代器指的是迭代取值的工具,迭代是一个重复的过程,每次重复都是基于上一次的结果而 继续的,单纯的重复并不是迭代2.为何要有迭代器 迭代器是用来迭代取值的工具,而涉及到把多 ...

  9. 深入浅出Java多线程(十三):阻塞队列

    引言 大家好,我是你们的老伙计秀才!今天带来的是[深入浅出Java多线程]系列的第十三篇内容:阻塞队列.大家觉得有用请点赞,喜欢请关注!秀才在此谢过大家了!!! 在多线程编程的世界里,生产者-消费者问 ...

  10. 记录--纯CSS实现骚气红丝带

    这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助 在本文中,我们将探讨如何使用 CSS 以最少的代码创造出精美的 CSS 丝带形状,并最终实现下面这个效果: 下面我们使用html和css来 ...