1、goreplay流量回放
- 目的
在实际项目中,会有大量的回归测试工作,通常会使用自动化代码的手段来实现回归,但是对于一个庞大的系统来说,通过自动化脚本的方式来实现回归测试,又显得很费时费力。并且如果有定期将线上数据同步到测试环境的需求的话,流量回放就显得很必要了。当然,流量回放并不能替代自动化,对于存在上下文关联的接口,流量回放的处理上就显得很复杂。
- 流量回放
其实流量回放主要是对某个端口的流量进行转发和存储,这边用的是goreplay,mitmproxy也可以做到流量的抓取和回放。
流量回放有三种使用方式:
- 服务->to->服务,即端到端
- 服务->to->文件,即流量存储
- 文件->to->服务,即流量文件回放到服务
- 常用配置示例
- service_to_file.yml
bin:
- "/opt/crawl/project/flow_replay/gor"
input:
- "--input-raw :18080"
- "--input-raw-track-response"
- "--prettify-http"
middle:
-
output:
- "--output-file ./data/requests-%Y-%m-%d-%H.gor"
- "--output-file-size-limit 100kb"
- "--output-file-queue-limit 60" - file_to_service.yml
bin:
- "/opt/crawl/project/flow_replay/gor"
input:
- "--input-file ./data/'requests-2024-03-18-14_7.gor'"
middle:
- "--middleware /opt/crawl/project/flow_replay/middle/main.js"
output:
- "--output-http='http://localhost:18080'"
- "--output-http-track-response"
- "--prettify-http" - 释义
gorplay的配置主要分为三个部分,分别是input、output和middleware
- input:定义需要捕获请求的一些必要条件
# 定义监听端口
--input-raw :18080
# 定义是否要捕获请求响应,只有添加了这个配置,回放时才会触发response事件
--input-raw-track-response
# 定义是否要美化响应,这个配置是作者修复bug新加的配置,必须要有,
# 如果没有会造成乱码
--prettify-http
# 定义存储请求的文件位置
# 可以使用*模糊匹配,批量回放相关文件,如requests-2024-03-18-*.gor
--input-file ./data/'requests-2024-03-18-14_7.gor'
# 定义缓冲区大小,单位为b
--input-raw-buffer-size 10485760 注:不论是从端口读取请求或者从文件读取请求,则必然会触发request事件
- output:定义输出请求的一些必要参数
# 定义存储请求文件的位置、格式及命名
--output-file ./data/requests-%Y-%m-%d-%H.gor
# 追踪流量回放响应,只有存在这个配置,回放成功后才会触发replay事件
--output-http-track-response
# 定义存储请求文件的最大size
--output-file-size-limit 100kb
# 定义单个存储文件中存储请求的数量
--output-file-queue-limit 20
# 同input
--prettify-http
# 定义请求丢弃比例,分别为绝对值和百分比
# 每秒请求超过绝对值的数字,则丢弃
# 只回放百分比的请求数量提升速度
--output-http='http://localhost:18080|10'
--output-http='http://localhost:18080|10%' - 中间件
- 中间件流程示意图

- 中间件常用Api
init - 初始化
httpPath - 获取请求URL,不包含请求的域名: gor.httpPath(req.http)
httpMethod - 获取请求方法:gor.httpMethod(req.http).
setHttpPath - 更新URL: req.http = gor.setHttpPath(req.http, newPath)
httpPathParam - 获取URL上的参数: gor.httpPathParam(req.http, queryParam)
setHttpPathParam - 设置URL参数: req.http = gor.setHttpPathParam(req.http, queryParam, value)
httpStatus - 响应状态码:gor.httpStatus(rep.http)
httpHeaders - 获取所有请求头: gor.httpHeaders(req.http)
httpHeader - 获取指定请求头: gor.httpHeader(req.http, "Content-Length")
setHttpHeader - 设置请求头, returns modified payload: req.http = gor.setHttpHeader(req.http, "X-Replayed", "1")
httpBody - 获取请求体: gor.httpBody(req.http)
setHttpBody - 设置请求体,需要注意Content-Length的大小: req.http = gor.setHttpBody(req.http, Buffer.from('hello!')).
httpBodyParam - 获取post请求param: gor.httpBodyParam(req.http, param)
setHttpBodyParam - 设置post请求的param: req.http = gor.setHttpBodyParam(req.http, param, value)
httpCookie - 获取cookie: gor.httpCookie(req.http, "SESSSION_ID")
setHttpCookie - 设置cookie, returns modified payload: req.http = gor.setHttpCookie(req.http, "iam", "cuckoo")
deleteHttpCookie - 删除cookie, returns modified payload: req.http = gor.deleteHttpCookie(req.http, "iam") - 事件
事件只存在于中间件中,goreplay接收到某个端口的请求后,会把request和response压缩成gzip,通过data.http字段转发给中间件,这样会触发request事件和response事件,当回放完成后,会触发replay事件
- 中间件代码示例
#!/usr/bin/node
const gor = require("goreplay_middleware");
const NodeRSA = require('node-rsa');
const axios = require('axios')
const {user, baseUrl, publicKey} = require('./defalut')
const https = require('https');
const jsonpath = require('jsonpath');/**
* @description 对公钥进行加密
* @param publicKey
* @param {string} data 需要加密的数据
* @returns {string} 加密后的数据
*/
function encrypt(publicKey, data) {let buffer = Buffer.from(data);let key = new NodeRSA(publicKey);
key.setOptions({encryptionScheme: 'pkcs1'});return key.encrypt(buffer, 'base64', 'base64');
}/**
*
* @param str
* @param color:string, red, green, yellow, blue, and white if the color is the other value
* @return {string}
*/
function addStringColor(str, color) {switch (color) {case "red":
color = "31";break;case "green":
color = "32";break;case "yellow":
color = "33";break;case "blue":
color = "34";break;case "pink":
color = "35";break;default:
color = "37";break;}return "\x1b[" + color + "m" + str + "\x1b[0m";
}/**
* @description send login request and extract sessionId
* @param baseUrl{string} request url
* @returns {string} return sessionId
*/async function getCookie(baseUrl) {const data = {
userName: user["username"],
password: encrypt(publicKey, user["password"])};const url = baseUrl.concat('api/auth/doLogin');try {const response = await axios.post(url, data, {
httpsAgent: new https.Agent({rejectUnauthorized: false}),
headers: {'Content-Type': 'application/json; charset=utf-8'}});return response.headers['set-cookie'][0].match('(?<=JSESSIONID=)[a-f0-9-]+')[0];} catch (error) {
console.error(error);}
}(async () => {let cookie = await getCookie(baseUrl);
gor.init();
gor.on('request', function (request) {//request.http = gor.deleteHttpCookie(request.http, 'JSESSIONID')
request.http = gor.setHttpCookie(request.http, 'JSESSIONID', cookie)
gor.on("replay", request.ID, function (replay) {try {let obj = JSON.parse(gor.httpBody(replay.http).toString('utf8'))if (jsonpath.query(obj, '$..code')[0] === '0000') {
console.error(addStringColor(`√\t${gor.httpMethod(request.http)}\t${gor.httpPath(request.http)}`, 'green'))} else {
console.error(addStringColor(`x\t${gor.httpMethod(request.http)}\t${gor.httpPath(request.http)}\n ${gor.httpBody(replay.http)} `, 'red'))}} catch (e) {
console.error(addStringColor(`\t${gor.httpMethod(request.http)}\t${gor.httpPath(request.http)}\n ${e}`, 'red'))}return replay;})return request})
})() - 效果展示

相关文章:
1、goreplay流量回放
目的 在实际项目中,会有大量的回归测试工作,通常会使用自动化代码的手段来实现回归,但是对于一个庞大的系统来说,通过自动化脚本的方式来实现回归测试,又显得很费时费力。并且如果有定期将线上数据同步到测试环境的需求…...
Transformer的前世今生 day06(Self-Attention和RNN、LSTM的区别)
Self-Attention和RNN、LSTM的区别 RNN的缺点:无法做长序列,当输入很长时,最后面的输出很难参考前面的输入,即长序列会缺失上文信息,如下: 可能一段话超过50个字,输出效果就会很差了 LSTM通过忘…...
UDP send 出现大量“Resource temporarily unavailable”
背景 最近排查用户现场环境,查看日志出现大量的“send: Resource temporarily unavailable”错误,UDP设置NO_BLOCK模式,send又发生在进程上下文,并且还设置了SO_SNDBUF 为8M,在此情况下为什么还会出现发送队列满的情况…...
怎么拆解台式电脑风扇CPU风扇的拆卸步骤-怎么挑
今天我就跟大家分享一下如何选购电脑风扇的知识。 我也会解释一下机箱散热风扇一般用多少转。 如果它恰好解决了您现在面临的问题,请不要忘记关注本站并立即开始! 文章目录列表:大家一般机箱散热风扇都用多少转? 机箱散热风扇选择…...
Windows安装Odoo结合内网穿透实现公网访问本地企业管理系统
文章目录 前言1. 下载安装Odoo:2. 实现公网访问Odoo本地系统:3. 固定域名访问Odoo本地系统 前言 Odoo是全球流行的开源企业管理套件,是一个一站式全功能ERP及电商平台。 开源性质:Odoo是一个开源的ERP软件,这意味着企…...
Portainer的替代Dockge?又一个Docker Compose管理器?
Dockge:让Docker Compose管理触手可及,一图胜千言,轻松构建与管控您的容器服务栈!- 精选真开源,释放新价值。 概览 Docker,这一开放源代码的创新平台,旨在实现应用程序部署、扩展与运维的自动化…...
Midjourney AI绘图工具介绍及使用
介绍 Midjourney是一款目前被誉为最强的AI绘图工具。只要输入想到的文字,就能通过人工智能产出相对应的图片。 官网只是宣传和登录入口,提供个人主页、订阅管理等功能,Midjourney实际的绘画功能,是在另外一个叫discord的产品中实…...
clang-query 的编译安装与使用示例
1,clang query 概述 作用: 检查一个程序源码的抽象语法树,测试 AST 匹配器; 帮助检查哪些 AST 节点与指定的 AST 匹配器相匹配; 2,clang-query 安装 准备: git clone --recursive https://git…...
echarts数据下钻如何配置
官方范例:https://echarts.apache.org/examples/zh/editor.html?cbar-multi-drilldown 看了一眼范例直接晕了,你这,一堆数据直接写死,这怎么用啊! 一般来说,实现步骤是: 1)后台&a…...
git 提交空目录
git 提交空目录 1. git 无法感应空目录2. git 提交空目录References 1. git 无法感应空目录 Git FAQ https://archive.kernel.org/oldwiki/git.wiki.kernel.org/index.php/GitFaq.html Currently the design of the Git index (staging area) only permits files to be liste…...
【优化方案】Java 将字符串中的星号替换为0-9中的数字,并返回所有可能的替换结果
需求 将输入的字符串中的星号替换为0-9中的数字,并返回所有可能的替换结果,允许存在多个*号。 分析: 在每个星号位置,我们需要进行 0-9 的循环遍历,因此每个星号位置都有 10 种可能性。如果字符数组中有k个星号&#x…...
C语言复习-链表
链表: 特点: 通过 next 指针 把内存上不连续 的几段数据 联系起来 set nu -- 打印行号 概念: 一种数据结构 -- 数据存放的思想 比如 -- 数组 -- 内存连续的一段空间,存放相同类型的一堆数据 缺点 -- 增删元素很 难 -- 不灵活 --> 引入链表 next指针的初步认识…...
Redis面试题-缓存雪崩、缓存穿透、缓存击穿问题
1 穿透: 两边都不存在(皇帝的新装) (黑名单) (布隆过滤器) 2 击穿:一个热点的key失效了,这时大量的并发请求直接到达数据库. (提前预热) 3 雪崩:…...
【Node.js】npx
概述 npx 可以使用户在不安装全局包的情况下,运行已安装在本地项目中的包或者远程仓库中的包。 高版本npm会自带npx命令。 它可以直接运行 node_modules/.bin 下的 exe 可执行文件。而不像之前,我们需要在 scripts 里面配置,然后 npm run …...
hive授予指定用户特定权限及beeline使用
背景:因业务需要,需要使用beeline对hive数据进行查询,但是又不希望该用户可以查询所有的数据,希望有一个新用户bb给他指定的库表权限。 解决方案: 1.赋权语句,使用hive管理员用户在终端输入hive进入命令控…...
Vmware虚拟机无法用root直连说明
Vmware虚拟机无法用root直连说明 背景目的SSH服务介绍无法连接检查配置 背景 今天在VM上新装了一套Centos-stream-9系统,网络适配器的连接方式采用的是桥接,安装好虚拟机后,在本地用ssh工具进行远程连接,ip、用户、密码均是成功的…...
Visio中存在问题的解决方法
公式缩放 mathtype公式在visio缩放之后,出现了变形。 解决方法:每次输入公式都通过 插入->对象->mathType Equation 新建一个公式。可以避免 注:网上有的说在word中使用mathtype编写公式,之后复制到visio中。 插入波形 选择…...
taro之Swiper的使用
图样: 往往我们需要轮播图去显示我们想要的图片之类的 这是工作的代码 <View classNametop-title><SwiperclassNamebanner-swiperinterval{3000}circularautoplay>{homeBannerList.map((item) > {return (<SwiperItem key{item.id}><View…...
正大国际:金融行业发展趋势
2024金融科技趋势研究报告 大模型生态揭秘!金融行业迎来变革,中控成生态核心,大模型在金融行业的应用 随着大模型的不断发展,越来越多的金融机构开始尝试在一些业务场景中引入大模型和生成式A能力,预计2024年,领先的金…...
vue中实现超出一行 展开和收起的功能
html中: <divclass="txttype"ref="txttype"style="margin-bottom: 6px":class="hidetext == true ? hidetext : "><div style="width: 96%"><el-tagtype="info"style="margin-right: 10px&…...
浅谈 React Hooks
React Hooks 是 React 16.8 引入的一组 API,用于在函数组件中使用 state 和其他 React 特性(例如生命周期方法、context 等)。Hooks 通过简洁的函数接口,解决了状态与 UI 的高度解耦,通过函数式编程范式实现更灵活 Rea…...
conda相比python好处
Conda 作为 Python 的环境和包管理工具,相比原生 Python 生态(如 pip 虚拟环境)有许多独特优势,尤其在多项目管理、依赖处理和跨平台兼容性等方面表现更优。以下是 Conda 的核心好处: 一、一站式环境管理:…...
突破不可导策略的训练难题:零阶优化与强化学习的深度嵌合
强化学习(Reinforcement Learning, RL)是工业领域智能控制的重要方法。它的基本原理是将最优控制问题建模为马尔可夫决策过程,然后使用强化学习的Actor-Critic机制(中文译作“知行互动”机制),逐步迭代求解…...
HashMap中的put方法执行流程(流程图)
1 put操作整体流程 HashMap 的 put 操作是其最核心的功能之一。在 JDK 1.8 及以后版本中,其主要逻辑封装在 putVal 这个内部方法中。整个过程大致如下: 初始判断与哈希计算: 首先,putVal 方法会检查当前的 table(也就…...
SQL慢可能是触发了ring buffer
简介 最近在进行 postgresql 性能排查的时候,发现 PG 在某一个时间并行执行的 SQL 变得特别慢。最后通过监控监观察到并行发起得时间 buffers_alloc 就急速上升,且低水位伴随在整个慢 SQL,一直是 buferIO 的等待事件,此时也没有其他会话的争抢。SQL 虽然不是高效 SQL ,但…...
Kafka入门-生产者
生产者 生产者发送流程: 延迟时间为0ms时,也就意味着每当有数据就会直接发送 异步发送API 异步发送和同步发送的不同在于:异步发送不需要等待结果,同步发送必须等待结果才能进行下一步发送。 普通异步发送 首先导入所需的k…...
MFC 抛体运动模拟:常见问题解决与界面美化
在 MFC 中开发抛体运动模拟程序时,我们常遇到 轨迹残留、无效刷新、视觉单调、物理逻辑瑕疵 等问题。本文将针对这些痛点,详细解析原因并提供解决方案,同时兼顾界面美化,让模拟效果更专业、更高效。 问题一:历史轨迹与小球残影残留 现象 小球运动后,历史位置的 “残影”…...
C++课设:简易日历程序(支持传统节假日 + 二十四节气 + 个人纪念日管理)
名人说:路漫漫其修远兮,吾将上下而求索。—— 屈原《离骚》 创作者:Code_流苏(CSDN)(一个喜欢古诗词和编程的Coder😊) 专栏介绍:《编程项目实战》 目录 一、为什么要开发一个日历程序?1. 深入理解时间算法2. 练习面向对象设计3. 学习数据结构应用二、核心算法深度解析…...
C语言中提供的第三方库之哈希表实现
一. 简介 前面一篇文章简单学习了C语言中第三方库(uthash库)提供对哈希表的操作,文章如下: C语言中提供的第三方库uthash常用接口-CSDN博客 本文简单学习一下第三方库 uthash库对哈希表的操作。 二. uthash库哈希表操作示例 u…...
tomcat指定使用的jdk版本
说明 有时候需要对tomcat配置指定的jdk版本号,此时,我们可以通过以下方式进行配置 设置方式 找到tomcat的bin目录中的setclasspath.bat。如果是linux系统则是setclasspath.sh set JAVA_HOMEC:\Program Files\Java\jdk8 set JRE_HOMEC:\Program Files…...
