传统的压力测试都是模拟流量,而不是真实流量,模拟流量有时并不能涵盖所有的线上请求,很可能在线下压测正常的服务在线上面对各种各样的问题,而故障频发。下面我们介绍两个引流工具,可以直接将线上的真实流量复制到测试机,可以用于仿真测试。
Tcpcopy
TCPCopy 是一款针对TCP流量的重放工具,他可以复制报文,并通过修改报文头信息将请求复制到目标主机上。它基于BSD许可,是一款国人开发的优秀开源软件,github 网址为 https://github.com/session-replay-tools/tcpcopy,其原理架构图如下:
(https://github.com/session-replay-tools/tcpcopy)
(TODO,重新画,印刷没有颜色)
在 TCPCopy 的发展过程中,架构经过多次调整, 在最新版中,其使用场景中包含三服务器角色:
- 线上服务器(Online Server),真实流量发生的主机,用于用户请求。
- 目标服务器(Target Server),用于接受TCPCopy副本请求的服务器,通常是我们的测试服务器。
- 辅助服务器(Asisstant Server),TODO,
TCPCopy 包含两个应用程序 tcpcopy 和 intercept. tcpcopy 运行在线上服务器上,用于捕获真实流量报文并进行转发,intercept 运行在辅助服务器上。
tcpcopy 默认情况下使用 raw socket 拦截数据包(也可以通过 pcap 库抓包,编译时需要指定 --pcap-capture 和 --pcap-send 选项 ),着这里会做一些基本的网络控制操作(比如 对TCP层和上层链路交互操作的模拟,网络控制等),并将报文转发给目标主机,如图中粉色箭头所示。在默认情况下,tcpcopy 在网络层抓包,在系统繁繁忙时,容易造成丢包,如果使用 pcap,会从数据链路层转抓包并转发,会减少丢包率并带来更好的性能,所以推荐使用 pcap 的方式。
对于测试服务器需要设置路由配置,将对报文的响应发送给辅助服务器。如图中的绿色箭头所示。
intercept 捕获到响应报文之后,提取响应头信息,使用一个特殊通道将响应头发回给tcpcopy,如图中的紫色箭头所示。在这里服务服务器充当副本流量响应的黑洞,测试服务器处理的响应信息并不会发会给真实用户,否则一个用户会造成多个返回。
我们举例来说明 Tcpcopy 的用法,定义三台主机,角色分配如下:
服务器 | 角色 |
---|---|
192.168.56.101 | Online server |
192.168.56.102 | Assistant Server |
192.168.56.103 | Target Server |
登录 192.168.56.102 安装 intercept。
$ sudo yum install -y libpcap libpcap-devel
$ wget https://github.com/session-replay-tools/intercept/archive/1.0.0.tar.gz
$ tar zxvf ./1.0.0.tar.gz
$ cd intercept-1.0.0/
$ sudo ./configure --prefix=/user/local/intercept/ --pcap-capture --pcap-send
$ sudo make
$ sudo make install
编译 intercept 之前,需要先安装 libpcap库,是一个网络转包的函数库,Linux 下的tcpdump 工具就是基于它开发的。
登录 192.168.56.101 安装 tcpcopy
$ wget https://github.com/session-replay-tools/tcpcopy/archive/v1.1.0.tar.gz
$ tar -zxvf ./v1.1.0.tar.gz
$ cd tcpcopy-1.1.0/
$ sudo ./configure --prefix=/user/local/tcpcopy
$ sudo make
$ sudo make install
启动并测试 TCPCopy
登录目标测试机(192.168.56.103)配置路径
$ sudo route add -net 192.168.200.0 netmask 255.255.255.0 gw 192.168.56.102 $ sudo route -n Kernel IP routing table Destination Gateway Genmask Flags Metric Ref Use Iface ... 192.168.200.0 192.168.56.106 255.255.255.0 UG 0 0 0 enp0s8
将所有来自 192.168.200.* IP端的网关设置为 192.168.56.102,该IP段的多有响应会发送给 192.168.56.102。
登录辅助机(192.168.56.102)启动 intercept
$sudo ./intercept -i enp0s8 -F 'tcp and src port 80' -d
- -i 表示监控的网卡接口,这里 enp0s8 是 IP 192.168.56.102 对应的网卡接口。
- -F 设置过滤器规则,这里表示监控 80 端口的 TCP 报文,其格式和 pcap 过滤器的格式意向,可以通过
man pcap-filter
命令来查看。 - -d 表示按照守护进程方式运行。
如果以非 root 方式启动,需要获取 CAP_NET_RAW ,方式如下:
$ setcap CAP_NET_RAW=ep ./intercept $ getcap ./intercept ./intercept = cap_net_raw+ep
登录线上机(192.168.56.101)启动 tcpcopy
$ sudo ./tcpcopy -x 80-192.168.56.103:80 -s 192.168.56.101 -c 192.168.200.x -d
- -x,设置目标测试机地址和端口,其格式为
本地端口-目标机IP:目标端口
本例中80-192.168.56.103:80 表示捕获本机的80端口的报文,并将副本报文转到到 目标机器的 192.168.56.103 的 80 端口,这里可以也可以设置多个目标主机,用逗号分隔。 - -s,设置 intercept 主机地址,可以设置多个,用英文逗号分隔。
- -c ,是可选参数,用来设置一个虚拟IP段,为了避免和应用程序使用的IP段冲突,应用程序可能会调用其主机的服务,冲突会造成服务不可用。
- -d,表示以守护进程运行。
其他比较有用的参数还有:
- -r,设置转发流量的比例,如 -r 20,表示转发20%的流量。
- -n,设置流量放大几倍,如 -n 2,表示流量放大2倍,一个用户请求会变成两条tcpcopy请求。
- -k,设置 keepalived 时长。
更多参数可以通过 -h 查看。
- -x,设置目标测试机地址和端口,其格式为
测试:
$ curl http://192.168.56.101 -I
查看 192.168.56.101 的 nginx 日志
[192.168.56.101] $ tail -f /yourpath/nginx/logs/access.log
192.168.56.1 - - [18/Oct/2017:10:14:56 +0800] "HEAD / HTTP/1.1" 200 0 "-" "curl/7.54.0"
查看 192.168.56.103 的 nginx 日志
[192.168.56.103] $ tail -f /yourpath/nginx/logs/access.log
192.168.200.1 - - [18/Oct/2017:10:14:56 +0800] "HEAD / HTTP/1.1" 200 0 "-" "curl/7.54.0"
从测试结果来看,一个用户请求,分别在 192.168.56.101 和 192.168.56.103 变为两次请求。192.168.56.101 日志中额客户端IP是真实的用户IP,192.168.56.103 中的用户IP是配置 tcpcopy 虚拟处理的IP。
(http://www.cnblogs.com/zhengyun_ustc/p/tcpcopy.html)(TODO重画)
在这个例子中,数据包的流转如上图所示
正常的用户请求和响应。
tcpcopy 数据链路层拦截数据并复制(如果是非 pcap 模式,会从IP层拦截数据)。
报文经过改写之后(主要是目标地址),将数据发送给目标主机。
目标数据主机将 tcpcopy 的请求当做正常的用户请求处理
数据转发给辅助主机。
intercept 拦截到响应数据进行修改之后发回给线上主机。
参考资料:
https://github.com/session-replay-tools/tcpcopy
http://blog.csdn.net/wangbin579/article/details/8949315
http://blog.csdn.net/qq_21033663/article/details/53033621
http://www.cnblogs.com/zhengyun_ustc/p/tcpcopy.html
goreplay
goreplay 是另外一个款针对HTTP协议开源流量复制工具,使用LGPLv3 许可,官方网站为http://goreplay.org。在原理上和 tcpcopy 类似,也是使用 raw sockets 和 pacp(默认),差别在于,tcpcopy 可以转发tcp协议,goreplay 主要针对HTTP协议。
开源版本的 goreplay 只支持HTTP协议,付费的pro版本可以支持tcp协议。
目前的版本中 goreplay 还不支持将一台主机的流量复制到多台主机,器架构图如下。
goreplay 的安装,goreplay 基于 go 语言开发的,并且和tcpcopy一样,依赖 libpcap库,所以需要先安装环境。
$ sudo yum install -y golang libpcap libpcap-devel
源码安装:
# 下载源码
$ sudo go get -v github.com/buger/gor
# 查看安装目录
$ sudo go env | grep GOPATH
GOPATH="/root/go"
$ cd /root/go/src/github.com/buger/gor
# 编译安装
$ sudo go build -v
# 在当前目录中会出现编译好的可执行文件 gor
$ ./gor -h
如果不使用源码安装方式,也可以直接使用官方编译好的可执行文件,地址:https://github.com/buger/goreplay/releases,目前包含Linux和 MacOS两个平台的。
相比于 tcpcopy ,goreplay 的用法非常简单,只需要线上机器上安装使用即可。例如:
$ sudo ./gor --input-raw :80 --output-http="http://192.168.56.103:80"
改命令表示监控本机的80端口,并请请求复制到 192.168.56.103 的80端口。如果要复制到多台主机,可以添加多个 --output-http 参数,例如:
$ sudo gor --input-raw :80 --output-http="http://192.168.56.106:80" --output-http="http://192.168.107:80"
- --input-raw,指定在本机要捕获哪个端口,和tcpcopy的默认方式一样,使用 RAW sockets 相关接口来实现的。需要具有 root 权限,或者通过 setcap 命令打开 CAP_NET_RAW 权限。
- --output-http,以http方式输出复制流量,在这里执行 http 地址。
goreplay 还可以将请求录制到文件中,并进行离线重放,例如:
$ sudo gor --input-raw :80 --output-file requests.log
文件格式为:
tail -f ./requests_0.log
1 c52a3e633c68954c993abb05a2e32e012768f3e6 1508304649039186000
GET / HTTP/1.1
Host: 192.168.56.101
User-Agent: curl/7.54.0
Accept: */*
...
1 fb18157dd83ee3a58dbecd6143176f655ed9c518 1508304644764272000
HEAD / HTTP/1.1
Host: 192.168.56.101
User-Agent: curl/7.54.0
Accept: */*
...
离线重放:
$ sudo gor --input-file requests_0.log --output-http="http://192.168.56.103:80"
限流
# 每秒转发不超过100次
$ sudo gor --input-raw :80 --output-http="http://192.168.56.103:80|100"
# 只转发 20% 的流量。
$ sudo gor --input-raw :80 --output-http="http://192.168.56.103:80|20%"
根据正则过滤转发的url请求,针对特定URL进行测试的时候比较有用。
# 只转发匹配 /api 的 URL 请求
$ sudo gor --input-raw :80 --output-http="http://192.168.56.103:80" --http-allow-url /api
# 只转发不匹配 /api 的 URL 请求
$ sudo gor --input-raw :80 --output-http="http://192.168.56.103:80" --http-disallow-url /api
其他常用选项为:
- -http-allow-method,掉请求方法进行过滤,可以指定对条,如 --output-http staging.com --http-allow-method GET --http-allow-method HEAD。
- -http-allow-header/-http-disallow-header,针对HTTP请求头进行过滤。
- -http-rewrite-url,进行请求的重写,类似于 Nginx 的url重写机制,比如 --http-rewrite-url /v1/user/(\/+)/ping:/v2/user/$1/ping
- -http-set-header,转发请求时,添加额外的头信息,比如:--http-set-header 'User-Agent: Gor'
- -input-file-loop,循环遍历请求日志文件,通常用于压测。
- -input-raw-engine,设置拦截请求的方式,默认为 libpcap,还可以设置为 raw_socket。
- -input-raw-realip-header,设置用户请求的真实IP地址,比如
X-Real-IP
- -input-tcp ,从其他 gor 进行接收请求,该选项用于设置上游gor进行的端口,默认为 28020。
- -output-file-append,将请求追加到请求记录文件中。
- -output-file-flush-interval,gor 不是立即将请求记录到文件中,为了提高效率而是成批写入,该选项记录写入日志文件从周期,默认为1秒。
- -output-file-queue-limit,设置输出队列长度,用于写入文件时使用。默认为 256。
- -output-file-size-limit,设置输出文件的大小,超过这个值会自动创建一个新的文件,这是为了避免文件膨胀太大。默认为32MB。
- -output-http-redirects,设置跟踪几次HTTP跳转请求。
另外,goreplay 还支持对对 ElasticSearch 请求和 Kafka 消息的转发。感兴趣的读者可以参考官方文档。