流量回放实战:基于开源 Conan 用 nginx 日志实现录制、回放与结果对比
导读:这篇文章介绍如何基于腾讯开源的流量录制回放平台 Conan,用 nginx 日志实现"录制—回放—结果对比"的完整链路,可省去部分接口测试与造数工作,用于回归与压力测试。文中给出了从 ELK、Kafka、Redis 到平台各模块的本地搭建与启动顺序,以及鉴权配置、grok 过滤表达式等落地细节,并总结了 nginx 默认不存 POST body(需在 log_format 加 $request_body)、相同参数下返回结果波动可用 json schema 匹配等踩坑经验与暂时无法解决的问题。适合想低成本落地流量回放做回归测试的测试工程师与后端开发者阅读。
分类:测试 | 标签:流量回放、conan、测试平台
1、流量回放是什么
1.1 项目介绍
Conan 是腾讯开源的一款流量录制回放平台(公共开源项目),更多使用说明可参考项目 README。简单来说,它做的事情是:
- web 系统被访问后,服务器上的 nginx 日志目录会产生一条访问记录;
- 平台解析该记录中的 url、接口、请求方式等信息并记录下来;
- 之后按记录重新发起调用,达到「回放」的目的。
1.2 基本原理
- 日志采集:使用 ELK(elasticsearch、logstash、kibana、filebeat)采集数据,通过 filter 筛选;
- 数据传输:Kafka;
- 数据转存:Redis 保存录制/回放的流量;
- 接口调用:对 http 接口进行调用;
- 数据对比:将回放结果使用 diff 工具做对比。
1.3 应用场景
- 省去部分接口测试工作,可用于回归测试、压力测试;
- 如果用线上流量做一次回归测试,可以进一步减少 bug 的风险;
- 大大节省构造测试数据、或编写造数脚本的时间,提高效率。
2、本地环境搭建
2.1 环境准备
- 编辑器:idea、vscode;
- 运行环境:java;
- 日志系统:elk(elasticsearch、logstash、kibana、filebeat)、elasticsearch-head;
- 中间件:kafka;
- 数据库:mysql、redis;
- 项目源码:conan。
2.2 本地调试启动顺序
- 找到 kafka 目录
kafka_2.12-2.8.1\bin\windows,打开 cmd 运行zookeeper-server-start.bat ../../config/zookeeper.properties; - 再开一个 cmd,运行
kafka-server-start.bat ../../config/server.properties; - 用 idea 打开 conan 项目,运行 conan-admin 模块的
ConanAdminApplication.class。注意:- 项目运行前需要将 sql 表及数据导入本地 mysql;
- 需要确保 application.yml 中的 mysql、redis 配置正确,并指定运行环境,如
spring.profiles.active: dev;
- 继续运行 conan-agent 模块的
ConanAgentApplication.class,同样注意 yml 配置; - 用 vscode 启动 conan-UI 的 vue 项目(也可以用 cmd 命令启动),启动后访问
http://localhost:8080/,使用系统默认账号登录(首次登录后请及时修改默认密码); - 找到 elasticsearch 目录
elasticsearch-7.16.3\bin,运行elasticsearch.bat; - 找到 elasticsearch-head 工程,用 vue 方式启动,启动后访问
http://localhost:9100,这个工程主要用来看 es 里的数据,也可以用 kibana 查看; - 找到 logstash 目录,运行
logstash.bat -f ../config/logstash-sample.conf。注意需要配置logstash-sample.conf,主要是加 filter 去过滤 nginx 日志,我的 filter 如下:
filter {
grok {
match => {
"message" => "%{HOSTNAME:domain} %{IP:remote_addr} - (?:%{WORD:remote_user}|-) \[%{HTTPDATE:time_local}\] %{WORD:scheme} \"%{WORD:method} %{NOTSPACE:request} HTTP/%{NUMBER:http_version}\" %{NUMBER:status} %{NUMBER:bytes_sent} \"%{DATA:rawrequest}\" \"%{DATA:http_referer}\" \"%{DATA:http_user_agent}\" %{QS:xforward} "
}
}
}
grok 表达式的验证可以使用在线工具 grok debug,例如
http://grokdebug.herokuapp.com/,如果失效可以自行搜索「grok debug 在线」。
- 找到 filebeat 目录,运行
filebeat.exe -e -c filebeat.yml,注意该 yml 配置需要修改你要监听的日志路径,并注销 elasticsearch output、改用 logstash output; - 打开你监测日志所在的目录,在 cmd 中输入
echo "xxx" >> 1.log(xxx 代表一条 nginx 日志内容,一条一条输入),目的是模拟 nginx 把日志写入本地,样例如下(域名、IP、业务路径已做脱敏与泛化处理):
example.com 203.0.113.10 - - [17/Feb/2022:14:09:58 +0800] https "POST /api/category/list HTTP/2.0" 200 1114 "" "https://example.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Safari/537.36" "-" "-" 0.142 127.0.0.1:30952 200 0.142
example.com 203.0.113.10 - - [17/Feb/2022:14:09:58 +0800] https "POST /api/order/list HTTP/2.0" 200 3132 "pageNumber=1&pageSize=30" "https://example.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Safari/537.36" "-" "-" 0.493 127.0.0.1:30952 200 0.493
example.com 203.0.113.10 - - [17/Feb/2022:14:10:14 +0800] https "POST /api/order/detail HTTP/2.0" 200 1115 "id=123" "https://example.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Safari/537.36" "-" "-" 0.140 127.0.0.1:30952 200 0.140
日志中各字段含义:域名、客户端 IP、时间、协议与 scheme、请求方法 + 请求路径 + HTTP 版本、状态码、响应大小、请求参数(body)、referer、user-agent,以及转发头、响应耗时、upstream 地址、upstream 状态等,与上面 grok 表达式的字段一一对应。
3、使用 conan 系统进行流量回放
以上准备工作做完后,就可以使用 conan 系统进行流量回放了。
3.1 配置
- 配置 es 数据源:注意 filebeat 的 index 每天都会变,配置时选择对应日期的 index;
- 配置域名:在平台中录入被测系统的域名;
- 配置域名下的 es 设置;
- 鉴权配置:需要登录态的接口要配置鉴权信息。我这边自己写了一个接口返回对应的 cookie,把 cookie 接口地址与参数配置到平台中即可(示例配置中的地址与账号密码已删除,请按自己的环境填写);
- 配置接口:把要回放的接口在平台中配置好。
3.2 录制
- 新建任务;
- 任务关联接口;
- 执行录制。注意:我修改了部分源码以方便录制成功(原始项目在一些采集链路上需要按自己的环境微调);
- 录制成功,可以在任务详情看到录到的流量数据。
3.3 回放
- 执行回放;
- 回放成功后查看回放结果列表。
3.4 对比
- 至少要回放 2 次才能做对比,对比时需要设置一次回放为基准;
- 设置基准后即可查看对比结果,平台会把回放结果与基准的差异(diff)展示出来。
4、问题与踩坑
4.1 nginx 日志默认不存 POST body
一般 nginx 日志不存 post body,想回放 post 请求怎么办?答案是让日志记录请求体,也就是修改 nginx 配置,在 log_format main 里添加 $request_body:
# nginx log format.
log_format main '$http_host $remote_addr - $remote_user [$time_local] '
'$scheme "$request" $status $bytes_sent "$request_body" "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for" "$gzip_ratio" $request_time '
'$upstream_addr $upstream_status $upstream_response_time ';
4.2 相同参数下接口返回结果波动
有些接口每次相同参数请求、返回结果也不一样,怎么处理?答案是给接口设置 json schema,返回结果符合规则就能匹配上。
4.3 暂时无法解决的问题
- 主流程测试,接口间相关联;
- 流量身份如何对应回放账号身份;
- 如何维护数据生命周期。
5、一些建议
- 尽量动手操作一遍系统才能更好理解整体流程;
- 这个项目有些源码需要更改,坑比较多,可以先用改过的版本把链路跑通,节省部分时间。
6、部署相关
中间件地址(已脱敏,请替换为自己的环境地址):
| 组件 | 地址 |
|---|---|
| kafka | <中间件服务器IP>:9092 |
| redis | <中间件服务器IP>:6379 |
| mysql | <数据库地址>:3306/<库名> |
| es | http://<es服务地址>:9200/ |
中间件以 daemon 方式启动的命令示例:
nohup sh zookeeper-server-start.sh -daemon ../config/zookeeper.properties > ../logs/zookeeper.log 2>&1 &
nohup sh kafka-server-start.sh -daemon ../config/server.properties > ../logs/kafka.log 2>&1 &
es 和 logstash 已部署在中间件机器上。想要采集日志,只需要在对应的被测服务器上安装一个 filebeat 即可,filebeat 中的配置需要改 path,即采集的日志目录。
项目编译:
mvn clean package -Dmaven.test.skip=true
项目运行:
nohup java -jar conan-admin.jar >/dev/null 2>&1 &
# 如果要输出日志
nohup java -jar conan-admin.jar >log.out &
7、业务接入
环境部署好后,访问平台首页即可进行业务接入,按「接入业务指南」配置域名、es 数据源、接口与鉴权信息,随后就可以开始录制回放。