​ 传统的压力测试都是模拟流量,而不是真实流量,模拟流量有时并不能涵盖所有的线上请求,很可能在线下压测正常的服务在线上面对各种各样的问题,而故障频发。下面我们介绍两个引流工具,可以直接将线上的真实流量复制到测试机,可以用于仿真测试。

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

  1. 登录目标测试机(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。

  2. 登录辅助机(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
    
  1. 登录线上机(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 查看。

测试:

$ 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重画)

​ 在这个例子中,数据包的流转如上图所示

  1. 正常的用户请求和响应。

  2. tcpcopy 数据链路层拦截数据并复制(如果是非 pcap 模式,会从IP层拦截数据)。

  3. 报文经过改写之后(主要是目标地址),将数据发送给目标主机。

  4. 目标数据主机将 tcpcopy 的请求当做正常的用户请求处理

  5. 数据转发给辅助主机。

  6. 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 消息的转发。感兴趣的读者可以参考官方文档。

https://goreplay.org/

https://github.com/buger/goreplay

results matching ""

    No results matching ""