goreplay 使用经验

简介:

测试 HTTP 服务,为了覆盖更多的场景,可以考虑录制线上流量,在测试环境进行重放。之前用 tcpcopy 比较多,最近遇到一些需求,需要在 HTTP 层做一些过滤,例如只录制指定 URL 的请求。

经过调研,发现 goreplay,其前称是 gor,很适合这个场景,有以下优点。

  1. 支持 HTTP 请求的录制和重放,可以在线上录制请求,在测试环境进行重放。
  2. 支持 HTTP 层面的流量过滤,可以只挑选我们感兴趣的流量。
  3. 支持请求放大,用于性能测试。

1. 用法

免 root 运行,抓包并不需要 root 权限,同样的方法适用于 tcpdump,其实 goreplay 和 tcpdump 一样,都用 libpcap 来抓包。

$ sudo setcap "cap_net_raw,cap_net_admin+eip" ./goreplay

抓取 80 端口的 HTTP 请求,只抓请求 URL 是 /api/v1 的,并输出到终端。这个比 tcpdump 更直观,打印到终端的是我们熟悉的 HTTP 协议。

第一行是 goreplay 自定义的 header,平常使用可以不必理会,不是实际抓到的包,从第二行开始才是实际抓到的包。

$ ./goreplay --input-raw :80 --http-allow-url '/api/v1' --output-stdout

抓取 80 端口的所有请求,并保存到文件。实际会分批保存为 request_0.gor,request_1.gor 这种文件名。

$ ./goreplay --input-raw :80 --output-file 'request.gor'

重放请求,例如 host2.com 是我们的新机房域名。这种重放,会根据请求的时间戳,按照抓取时的请求顺序重放。

例如抓取的时候,第一秒 10 个请求,第二秒 20 个请求,那么重放的时候,也会按照这个顺序。并且读完 request.gor 文件,就会停止。

上面我们看到了 goreplay 自定义的 header,其第三个字段,是一个纳秒级的时间戳,根据这个来保证重放的顺序和速率。

$ ./goreplay --input-file 'request.gor' --output-http 'http://host2.com'

如果是性能测试,可以不考虑请求的顺序和速率,并且要求无限循环。

# --input-file 从文件中获取请求数据,重放的时候 100x 倍速
# --input-file-loop 无限循环,而不是读完这个文件就停止
# --output-http 发送请求到 http://host2.com
# --output-http-workers 并发 100 发请求
# --stats --output-http-stats 每 5 秒输出一次 TPS 数据
$ ./goreplay --input-file 'request.gor|10000%' --input-file-loop --output-http 'http://host2.com' --output-http-workers 100 --stats --output-http-stats

更多的命令行参数及用法,可以查看 goreplay 源码的 settings.go 文件。

其输出的 stats 含义,可以看看 这个帖子 的解释。

2. 坑

使用过程中遇到的坑。

  1. 如果 HTTP 请求不符合规范,可能会抓不到包。遇到过 HTTP 请求头里面的 Content-Length 不等于实际的 Body 大小,goreplay 认为其请求未结束。
  2. input-file 是单 goroutine 在跑,会有性能瓶颈。测试的时候,读取的 RPS 在 1.7w - 1.8w 左右,如果压测需求大于这个,需要开多个进程同时跑。

3. 深入

goreplay 是用 golang 编写的,抓包的时候调用 gopacket,后者通过 cgo 来调用 libpcap。从编译开始,从源码层面学习一下其实现。

TL;DR

3.1 编译

由于 goreplay 使用了第三方 C 代码,不能使用 Go 的交叉编译功能来跨平台编译。只能在 Linux 下编译 Linux 使用的可执行文件。

在 Redhat 系发型版下,可以使用 yum 来安装依赖。

$ sudo yum install libpcap libpcap-devel

或者从源码编译 libpcap。

# 安装依赖
$ sudo yum install gcc flex byacc bison
$ wget http://www.tcpdump.org/release/libpcap-1.8.1.tar.gz && tar xzf libpcap-1.8.1.tar.gz
$ cd libpcap-1.8.1
$ ./configure
$ sudo make install

cd 到 goreplay 的源码目录,执行命令。

# 纯静态编译
$ go build -ldflags '-extldflags "-static"'

如果编译成功,在当前目录会生成一个 goreplay 文件,试运行一下。

[vagrant@localhost goreplay]$ ./goreplay
Version:
2018/06/08 08:06:22 Required at least 1 input and 1 output

不依赖任何库。

[vagrant@localhost goreplay]$ ldd goreplay
    not a dynamic executable

一个合法的可执行文件。

[vagrant@localhost goreplay]$ file goreplay
goreplay: ELF 64-bit LSB executable, x86-64, version 1 (GNU/Linux), statically linked, for GNU/Linux 2.6.32, BuildID[sha1]=e334de401c00057ca56a33c0136dc5c86debee61, not stripped

如果遇到以下编译错误。

[vagrant@localhost goreplay]$ go build -ldflags '-extldflags "-static"'
# github.com/buger/goreplay
/home/vagrant/local/go/pkg/tool/linux_amd64/link: running gcc failed: exit status 1
/usr/bin/ld: cannot find -lpthread
/usr/bin/ld: cannot find -lc
collect2: error: ld returned 1 exit status

需要安装 glibc 的静态库。

$ sudo yum install glibc-static.x86_64

如果不是通过 go get 来获取 goreplay,而是通过 git clone 下来的,那么会缺少一些第三方库的依赖,通过 go get 命令补充就好。

$ go get github.com/Shopify/sarama

3.2 input 和 output

input 和 output 是 goreplay 对数据流的抽象,在源码目录有很多 input_xxx.go 和 output_xxx.go,实现了 goreplay 的核心功能。

在启动的时候,会解析命令行参数中指定的 input 和 output,接着启动 emitter,从 input 中读数据,写到 output 中。

emitter.go 中核心代码如下:

for _, in := range Plugins.Inputs {
    go CopyMulty(in, Plugins.Outputs...)
}

多个 input 之间是并行的,但单个 input 到多个 output,是串行的。所有 input 都实现了 io.Reader 接口,output 都实现了 io.Writer 接口。所以阅读代码时,input 的入口是 Read() 方法,output 的入口是 Write() 方法。

3.3 UDP 抓包

抓包是核心功能,也算是一种 input 的类型。不过 goreplay 的实现中,实现上和 HTTP 协议绑定的很死。我参考 goreplay 的代码,实现了 goreplay-udp,用法上和 goreplay 保持一致。

目录
相关文章
|
5月前
|
JSON 前端开发 数据格式
经验大分享:TheGeneofBitizens
经验大分享:TheGeneofBitizens
32 3
|
5月前
经验大分享:OpenFOAM中的边界条件(一)
经验大分享:OpenFOAM中的边界条件(一)
192 0
经验大分享:OpenFOAM中的边界条件(一)
|
5月前
|
JSON 网络协议 Linux
经验大分享:serval
经验大分享:serval
23 0
|
5月前
经验大分享:sdfdsf
经验大分享:sdfdsf
24 0
|
5月前
|
机器学习/深度学习
经验大分享:Sicily1153
经验大分享:Sicily1153
26 0
|
6月前
|
安全 前端开发 开发者
干货!6个方面,32条总结教你提升职场经验
本文提出了职场成长的建议,包括不要依赖“新人”身份,撰写技术博客促进成长,阅读《金字塔原理》和《高效能人士的七个习惯》等书籍,积极解决问题,不沉迷于忙碌,长远看待得失,拓宽知识领域,保持好奇和热爱。日常工作要注重质量,主动规划,良好沟通,避免传播负面情绪,理解和尊重上级,学会被管理。培养定义问题的能力,以价值、结果和问题为导向思考,控制情绪,以及成为他人的追随者而非仅仅管理者。
|
小程序 程序员 Windows
学习经验
写写自己的学习经验
|
存储 算法 Ubuntu
学习 C++ 的一点浅薄经验
工作所需,需要学习下 C++,今天就谈一下自己是怎么快速学习 C++,并且在工作中实际上手开发的,希望能够给大家一些启发。
160 0
|
机器学习/深度学习 存储 Cloud Native
如何在工作中快速成长?致工程师的 10 个简单技巧
精英人数的增长速度持续加快后,很多人开始焦虑,我也焦虑,深知要走出焦虑不容易,我想把走出焦虑快速成长的认知和方法写成文章分享给更多人,做成【技术人成长系列】文章给更多人面对面分享,该系列总共三篇,分别是《完成自己的认知升级》、《自我成长的方法》、《学会自我培养或培养他人》。本文是快速成长第一篇:“完成自己的认知升级”,内容偏长但值得仔细阅读。
如何在工作中快速成长?致工程师的 10 个简单技巧