HTTP引流神器Goreplay详解【精译】

 

0.背景

校验系统的正确性和可靠性时,仅靠用例场景无法覆盖全生产环境下的所有场景,需要一套引流工具,在系统正式上线前,用线上的请求测试待上线系统,在正常请求下,是否有报错;在数倍请求下,系统的性能瓶颈。引流工具有goreplay, tcpcopy等,下面介绍goreplay,原名叫gor,因为其易上手,且功能比较全。

关于

GoReplay是在投入生产之前使用真实流量测试您的应用的最简单和最安全的方式。

随着应用程序的增长,测试所需的工作量也呈指数增长。GoReplay为您提供了重复使用现有流量进行测试的简单想法,这使得它非常强大。我们的先进技术可让您分析和记录您的应用程序流量,而不会对其造成影响。这消除了将第三方组件置于关键路径中带来的风险。

GoReplay增加了您对代码部署,配置更改和基础设施更改的信心。我们有没有提到不需要编码?

这里是基本的工作流程:侦听器服务器捕获http流量并将其发送到重放服务器或保存到文件。重播服务器将流量转发给给定的地址。

图

检查最新的文档

安装

https://github.com/buger/goreplay/releases下载最新的二进制文件自行编译

入门

最基本的设置将是sudo ./gor --input-raw :8000 --output-stdouttcpdump。如果你已经有测试环境,你可以开始重播:sudo ./gor --input-raw :8000 --output-http http://staging.env:80。如果要保留domain/host,请用: 

./goreplay --input-raw :80 --output-http  x.x.x.x:port --http-original-host

有关更多信息,请参阅我们的文档入门页面。

通讯

订阅我们的通讯,随时了解Gor项目的最新功能和变化。

想要升级?

我们创建了一个GoReplay PRO扩展,它提供了其他功能,例如支持Thrift或ProtocolBuffers等二进制协议,从云存储中进行保存和重放,TCP会话复制等.PRO版本还包括适用于商业的许可证,专用支持和它也可以让你支持高质量的开源开发。

问题?

如果您遇到问题,请查看FAQ故障排除 wiki页面。问题搜索问题也是一个好主意。

所有的错误报告和建议应该通过Github问题或我们的Google小组(您可以发送电子邮件到gor-users@googlegroups.com)。如果您有私人问题,请随时发送电子邮件至support@gortool.com

特约

  1. 把它叉起来
  2. 创建你的功能分支(git checkout -b my-new-feature)
  3. 提交您的更改(git commit -am'添加了一些功能')
  4. 推到分支(git push origin my-new-feature)
  5. 创建新的请求

 

依赖

要开始使用Gor,您需要在您的机器上运行Web服务器,并且需要终端来运行命令。如果您只是在四处漫游,您可以通过调用快速启动服务器gor file-server :8000,这将启动当前目录在端口上的简单文件服务器8000

安装Gor

https://github.com/buger/gor/releases下载最新的Gor二进制文件(我们为Windows,Linux x64和Mac OS提供预编译的二进制文件),或者您可以自己编译编译

一旦档案被下载并解压缩,您可以从当前目录运行Gor,或者您可能想要将二进制文件复制到您的PATH(可用于Linux和Mac OS /usr/local/bin)。

捕获网络流量

现在在终端中运行这个命令: sudo ./gor --input-raw :8000 --output-stdout

该命令表示监听端口8000上发生的所有网络活动并将其记录到stdout。如果您熟悉tcpdump,我们将实施类似的功能。

您可能会注意到它使用sudo并要求输入密码:要分析网络,Gor需要只有超级用户才能使用的权限。但是,可以将Gor配置为针对非root用户运行

通过http://localhost:8000在浏览器中打开或通过在终端中调用curl来发出一些请求curl http://localhost:8000您应该看到将gor所有HTTP请求输出到正在运行的终端窗口。请注意,默认GoReplay不会跟踪回复,您可以使用--output-http-track-response选项启用它们

Gor不是代理人:你不需要将第三方工具放到关键路径上。相反,Gor只是默默地分析你的应用程序的流量,并不影响它。

重播

现在是时候将您的原始流量重放到其他环境。让我们开始使用同一个文件Web服务器,但是在不同的端口上:gor file-server :8001

而不是--output-stdout我们将使用--output-http并提供第二台服务器的URL:sudo ./gor --input-raw :8000 --output-http="http://localhost:8001"

向第一台服务器发出少量请求。你应该看到他们复制到第二个,瞧!

将请求保存到文件并稍后重播

有时候不可能实时重放请求; Gor允许您保存对文件的请求并稍后重播。

首先用它--output-file来保存它们:sudo ./gor --input-raw :8000 --output-file=requests.gor这将创建新文件并不断向其写入所有捕获的请求。

让我们重新运行Gor,但现在重播来自文件的请求:./gor --input-file requests.gor --output-http="http://localhost:8001"您应该看到所有记录到第二台服务器的请求,并且它们将以相同的顺序重播,并且与录制的时间完全相同。

基础

概观

Gor架构试图遵循UNIX哲学:所有东西都由管道组成,各种输入将数据复用到输出。

您可以[速率限制](速率限制),[过滤器](请求过滤),[重写](请求重写)请求,甚至使用您自己的中间件来实现定制逻辑。此外,还可以以较高的速率重播请求,以进行[负载测试](保存和从文件中重放)。

可用的输入和输出插件

可用输入:

  • --input-raw - 用于捕获HTTP流量,您应该指定IP地址或接口和应用程序端口。有关捕获和重放流量的更多信息
  • --input-file- 接受之前使用的文件--output-file更多关于保存和从文件重播
  • --input-tcp - 如果您决定将来自多个转发器Gor实例的流量转发给它,则由Gor聚合实例使用。阅读关于使用Aggregator-forwarder设置

可用输出:

  • --output-http - 重放HTTP流量到给定的端点,接受基础URL。阅读[关于它的更多信息](重播HTTP流量)
  • --output-file - 记录传入的流量到文件。更多关于保存和从文件重播
  • --output-tcp- 将传入数据转发给另一个Gor实例,并与其一起使用--input-tcp阅读关于Aggregator-forwarder设置的更多信息
  • --output-stdout - 用于调试,输出所有数据到stdout。

 

捕获和重放流量

 

想想Gor更像网络分析器或tcpdump类固醇,它不是代理,不会影响你的应用程序。您指定应用程序端口,它将捕获并重放传入数据。

最简单的设置将是:

在您想要捕获流量的服务器上运行。你可以在每台“网络”机器上运行它。
sudo gor --input-raw:80 --output-http http://staging.com

它将记录和重放来自同一台机器的流量。但是,当您的Web计算机上的Gor将流量转发到在单独的服务器上运行的Gor聚合器实例时,可以使用Aggregator-forwarder设置

您可能会注意到它需要sudo:分析仅适用于root用户的网络Gor需求权限。但是,可以配置Gor [为非root用户运行beign](以非root用户身份运行)。

转发到多个地址

您可以将流量转发到多个端点。

gor --input-tcp :28020 --output-http "http://staging.com"  --output-http "http://dev.com"

分割交通

默认情况下,它会将相同的流量发送到所有输出,但您可以使用选项来平分它(循环) --split-output

gor --input-raw :80 --output-http "http://staging.com"  --output-http "http://dev.com" --split-output true

跟踪回复

默认情况下input-raw不拦截回复,只是请求。您可以使用--input-raw-track-response选项打开回复跟踪启用时,您将能够访问中间件和中间件中的响应信息output-file

交通拦截引擎

默认情况下,Gor将libpcap用于拦截流量,它应该在大多数情况下工作。如果你有任何问题,你可以尝试替代引擎:raw_socket

sudo gor --input-raw :80 --input-raw-engine "raw_socket" --output-http "http://staging.com"

您可以阅读关于重播HTTP流量的更多信息

跟踪原始IP地址

您可以使用--input-raw-realip-header选项指定标题名称:如果不是空白,则将具有给定名称和真实IP值的标题注入请求有效内容。通常,这个标题应该被命名为:X-Real-IP,但是你可以指定任何名字。

gor --input-raw :80 --input-raw-realip-header "X-Real-IP" ...

 

重播HTTP流量

Gor可以使用--output-http选项重播HTTP流量

sudo ./gor --input-raw:8000 --output-http =  http://staging.env 

您可以即时[过滤](请求过滤),[速率限制](速率限制)和[重写](请求重写)请求。

HTTP输出工作者

默认情况下,Gor创建一个动态工作池:它从10开始,并在HTTP输出队列长度大于10时创建更多的HTTP输出工作者。创建的工人数量(N)等于该工作时间的队列长度检查并发现其长度大于10.每次将消息写入HTTP输出队列时都检查队列长度。在产生N名工人的请求得到满足之前,不会再有工人产卵。如果动态工作人员当时不能处理消息,它将睡眠100毫秒。如果动态工作人员无法处理消息2秒钟,则会死亡。您可以使用--output-http-workers=20选项指定固定数量的工人 

重定向之后

默认情况下,Gor会忽略所有重定向,因为它们是由使用您的应用的客户端处理的,但在重播环境引入新重定向的情况下,您可以像这样启用它们:

gor --input-tcp replay.local:28020 --output-http http://staging.com --output-http-redirects 2

给出的示例将跟随每个请求最多2个重定向。

HTTP超时

默认情况下,http请求和响应的超时时间为5秒。你可以像这样覆盖它:

gor --input-tcp replay.local:28020 --output-http http://staging.com --output-http-timeout 30s

响应缓冲区

默认情况下,为了减少内存消耗,内部HTTP客户端将获取响应主体的最大200kb(在使用中间件时使用),通过使用--output-http-response-buffer选项可增加限制(接受字节数)。

基本身份验证

如果您的开发或登台环境受基本身份验证保护,那么可以在重放期间注入这些凭据:

gor --input-raw :80 --output-http "http://user:pass@staging.com"

注意:这将覆盖原始请求中的任何授权标头。

多域支持

如果你的应用程序接受来自多个域的流量,并且你想保留原始头文件,具体--http-original-host告诉Gor不要触摸Host头文件。

 

保存并从文件中重放

 

您可以将请求保存到文件,并在稍后重播。重播时将保留请求之间的原始时间差异。如果您在两个请求之间应用[基于百分比的限制](速率限制)时间点,则会适当减少或增加:此方法可开启负载测试等可能性,请参见下文。

写入文件
gor --input-raw:80 --output-file requests.log

从文件读取 
gor --input-file requests.gor --output-http http://staging.com 

默认情况下,Gor以块的形式写入文件。这个可配置的使用--output-file-append选项:刷新的块被附加到存在文件或不附加。默认值是false默认情况下,--output-file将每个块刷新到不同的路径。

gor ... --output-file%Y%m%d.log
  append false
20140608_0.log
20140608_1.log
20140609_0.log
20140609_1.log

这使并行文件处理变得容易。但是如果你想禁用这种行为,你可以通过添加--output-file-append选项来禁用它

gor ... --output-file%Y%m%d.log --output-file-append
  append true
20140608.log
20140609.log

如果您多次运行gor并找到现有文件,它将从最后一个已知索引继续。

块大小

您可以使用--output-file-size-limit--output-file-queue-limit选项设置块限制块队列的长度和每个块的大小。默认值分别是256和32mb。可以使用后缀“k”(KB),“m”(MB)和“g”(GB)output-file-size-limit如果你只想要大小限制,你可以设置--output-file-queue-limit为0,反之亦然。

gor --input-raw:80 --output-file%Y-%m-%d.gz --output-file-size-limit 256m --output-file-queue-limit 0

在文件名中使用日期变量

例如,您可以告诉每小时创建一个新文件:--output-file /mnt/logs/requests-%Y-%m-%d-%H.log 它将为每个小时创建一个新文件:requests-2016-06-01-12.log,requests-2016-06-01-13.log,...

用作文件名称一部分的时间格式。创建文件时,以下字符将替换为实际值:

  • %Y:包括世纪在内的年份(至少4位数字)
  • %m:一年中的月份(01..12)
  • %d:月中的某天(01..31)
  • %H:一天中的小时,24小时制(00..23)
  • %M:小时(00..59)
  • %S:二分钟(00..60)

默认格式是%Y%m%d%H,每小时创建一个文件。

GZIP压缩

要读取或写入GZIP压缩文件,请确保文件扩展名以“.gz”结尾: --output-file log.gz

从多个文件重播

--input-file接受文件模式,例如:--input-file logs-2016-05-*GoReplay足够聪明,保持请求的原始顺序。它通过并行读取所有文件并通过时间戳在多个文件之间对请求进行排序来实现。它不会读取内存中的所有文件,而是根据需要在流媒体中读取它们。

缓冲的文件输出

Gor写入文件时拥有内存缓冲区,并持续刷新文件更改。如果缓冲区已满,则每隔1秒强制刷新一次,或者如果Gor关闭,则会发生冲突至文件。您可以使用--output-file-flush-interval选项更改它大多数情况下它不应该被触及。

文件格式

按原样存储HTTP请求,纯文本:标题和正文。请求按\n🐵🙈🙉\n分隔(使用此类序列以获得唯一性和乐趣)。在每个请求进行单线行包含有效负载类型(1 - 请求,2 - 响应,3 - 重播响应)的元信息时,请求发出时,唯一请求标识(请求和响应具有相同)和时间戳。2个请求的示例:

1 d7123dasd913jfd21312dasdhas31 127345969\n
GET / HTTP/1.1\r\n
\r\n
\n
🐵🙈🙉
\n
POST /upload HTTP/1.1\r\n
Content-Length: 7\r\n
Host: www.w3.org\r\n
\r\n
a=1&b=2

请注意,技术上\ r和\ n符号是不可见的,并指示新行。为了展示它在字节级别的外观,我在示例中使它们可见。

使其文本友好可以编写简单的解析器并使用控制台工具grep来进行分析。您甚至可以手动编辑它们,但请确保您的文件编辑器不会更改行尾。

性能测试

目前,input-file仅在使用基于百分比的限制器时才支持此功能与默认限制器不同input-file,它不会降低请求速度而会减慢速度或加速请求发射。请注意限制器应用于输入

# Replay from file on 2x speed 
gor --input-file "requests.gor|200%" --output-http "staging.com"

使用--stats --output-http-stats查看延迟统计。

循环播放文件以无限期重放

您可以循环同一组文件,因此当最后一个重放所有请求时,它不会停止,并且将从第一个重新开始。只有少量的请求可以进行广泛的性能测试。通过--input-file-loop让它工作。

 

 

限速

 

如果您只想转发部分传入流量,例如,不会超载您的测试环境,则速率限制可能很有用。有两种策略:根据标题或URL参数值丢弃随机请求或删除部分请求。

丢弃随机请求

每个输入和输出都支持随机速率限制。有两种限制算法:绝对或基于百分比。

绝对:如果在当前秒钟内达到了指定的请求限制 - 忽略其余,则在下一秒计数器重置时。

百分比:对于输入文件,它会减速或加速请求执行,其余的将使用随机生成器根据您指定的机会决定请求是否通过。

您可以使用“|”指定您想要的限制 服务器地址后的运算符,请参阅下面的示例。

限制重播使用绝对数量

# staging.server will not get more than ten requests per second
gor --input-tcp :28020 --output-http "http://staging.com|10"

使用基于百分比的限制器限制侦听器

# replay server will not get more than 10% of requests 
# useful for high-load environments
gor --input-raw :80 --output-tcp "replay.local:28020|10%"

基于Header或URL参数值的一致限制

如果您拥有存储在标头或URL中的唯一用户标识(如API密钥),则只能为该用户的一小部分转发指定的流量百分比。基本公式看起来像这样:FNV32-1A_hashing(value) % 100 >= chance例子:

# Limit based on header value
gor --input-raw :80 --output-tcp "replay.local:28020|10%" --http-header-limiter "X-API-KEY: 10%"

# Limit based on header value
gor --input-raw :80 --output-tcp "replay.local:28020|10%" --http-param-limiter "api_key: 10%"

 

请求过滤

 

当您只需要捕获特定部分的流量(如API请求)时,过滤非常有用。可以通过URL,HTTP标头或HTTP方法进行过滤。

允许URL正则表达式

# only forward requests being sent to the /api endpoint
gor --input-raw :8080 --output-http staging.com --http-allow-url /api

禁止URL正则表达式

# only forward requests NOT being sent to the /api... endpoint
gor --input-raw :8080 --output-http staging.com --http-disallow-url /api

基于标题的正则表达式筛选

# only forward requests with an api version of 1.0x
gor --input-raw :8080 --output-http staging.com --http-allow-header api-version:^1\.0\d

# only forward requests NOT containing User-Agent header value "Replayed by Gor"
gor --input-raw :8080 --output-http staging.com --http-disallow-header "User-Agent: Replayed by Gor"

基于HTTP方法过滤

不匹配指定白名单的请求可以被过滤掉。例如,去除非零能力的请求:

gor --input-raw :80 --output-http "http://staging.server" \
    --http-allow-method GET \
    --http-allow-method OPTIONS

请求重写

 

Gor支持重写URL,URL参数和标题,见下文。

如果测试环境没有与您的产品相同的数据,并且您希望在test用户上下文中执行所有操作,则重写可能很有用:例如,将所有API令牌重写为某个测试值。其他可能的用例是使用自定义标题打开/关闭功能,或者如果在新环境中更改URL,则可以重写URL。

对于更复杂的逻辑,您可以使用中间件

根据映射重写URL

--http-rewrite-url预期“:”格式的值:“:”是一个稀释度。<replace>部分中,您可以使用捕获的正则表达式组值。这与replaceJavascript或gsubRuby中的方法类似

# Rewrites all `/v1/user/<user_id>/ping` requests to `/v2/user/<user_id>/ping`
gor --input-raw :8080 --output-http staging.com --http-rewrite-url /v1/user/([^\\/]+)/ping:/v2/user/$1/ping

设置网址参数

设置请求url参数,如果参数已经存在,它将被覆盖。

gor --input-raw :8080 --output-http staging.com --http-set-param api_key=1

设置标题

设置请求标题,如果标题已经存在,它将被覆盖。如果您需要确定由Gor生成的请求或在应用程序中启用功能标记的功能,可能会有用:

gor --input-raw :80 --output-http "http://staging.server" \
    --http-header "User-Agent: Replayed by Gor" \
    --http-header "Enable-Feature-X: true"

主机头

主机头获得特殊待遇。默认情况下,主机将被设置为--output-http中指定的值。如果您手动设置--http-header“Host:anonther.com”,则Gor不会覆盖主机值。

如果你的应用程序接受来自多个域的流量,并且你想保留原始头文件,具体--http-original-host告诉Gor不要触摸Host头文件。

 

中间件

 

概观

GoReplay提供了NodeJS语言的框架,它隐藏了协议实现,并为编写中间件提供了原语,请参阅文档https://github.com/buger/goreplay/tree/master/middleware但协议本身非常简单,您可以随意使用任何语言。

中间件是一个程序,它接受STDIN上的请求和响应负载,并在STDOUT处发出修改后的请求。您可以实现任何自定义逻辑,如剥离私人数据,高级重写,支持oAuth等。检查包含在我们的回购中的示例

                   Original request      +--------------+
+-------------+----------STDIN---------->+              |
|  Gor input  |                          |  Middleware  |
+-------------+----------STDIN---------->+              |
                   Original response (1) +------+---+---+
                                                |   ^
+-------------+    Modified request             v   |
| Gor output  +<---------STDOUT-----------------+   |
+-----+-------+                                     |
      |                                             |
      |            Replayed response                |
      +------------------STDIN----------------->----+

(1):如果--input-raw-track-response指定选项,则原始响应只会发送给中间件

中间件可以用任何语言编写,请参阅examples/middleware文件夹中的示例。中间件程序应该接受与Gor的所有通信都是异步的,不能保证原始请求和响应消息会一个接一个地出现。如果逻辑取决于原始响应或重播响应,则应用程序应该处理状态,请参阅examples/middleware/token_modifier.go示例。

简单的bash echo中间件(返回相同的请求)将如下所示:

while read line; do
  echo $line
end

--middleware通过指定可执行文件的路径,可以使用选项启用中间件

gor --input-raw :80 --middleware "/opt/middleware_executable" --output-http "http://staging.server"

分布式配置

 

有时候使用单独的Gor实例重播流量并执行负载测试等事情是有意义的,因此您的生产计算机不会花费宝贵的资源。可以在您的Web计算机上配置Gor,将流量转发到在单独的服务器上运行的Gor聚合器实例。

在您想要捕获流量的服务器上运行。你可以在每台`web`机器上运行它。
sudo gor --input-raw:80 --output-tcp replay.local:28020

重播服务器(replay.local)。
gor --input-tcp replay.local:28020 --output-http http://staging.com

如果您有多个重播机器,您可以使用--split-output选项将流量分割为多个:使用循环算法将所有传入流量均分为所有输出。

gor --input-raw :80 --split-output --output-tcp replay1.local:28020 --output-tcp replay2.local:28020

加密

之间的通信量--input-tcp--output-tcp可使用TLS协议进行加密。要使其生效,您需要生成SSL证书,指定路径以及用于生成证书的密钥,并启用安全模式。

证书和密钥应该是PEM编码的。例如:--input-tcp :28020 --input-tcp-secure --input-tcp-certificate ./cert.pem --input-certificate ./key.pem您可以使用以下命令生成自签名证书和密钥:

openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365 -subj "/CN=localhost"`

常问问题

 

什么操作系统支持?

Gor会在libpcap工作的地方运行,并且它可以在大多数平台上运行。但是,目前,我们在Linux和Mac上进行测试。查看更多关于汇编

为什么--input-raw需要sudo或root访问?

侦听器通过嗅探来自特定端口的流量来工作。它只能通过使用sudo或root访问来访问。但可以以非root用户身份运行

你如何处理用户会话以正确重放流量?

您可以重写会话相关的头文件/ params以匹配您的分段环境。如果您需要自定义逻辑(例如基于随机令牌的身份验证),请参阅此讨论:https//github.com/buger/gor/issues/154

我可以使用Gor拦截SSL流量吗?

基本思想是SSL是为了保护自己免受交通拦截。有2个选项:

  1. 将SSL处理移至代理,如Nginx或Amazon ELB。让Gor听听上游。
  2. 使用--input-http这样你可以直接从您的应用程序复制请求有效载荷到Gor,但它会需要您的应用程序修改。

更多可以在这里找到:https//github.com/buger/gor/issues/85

使用output-http时HTTP请求的大小是否有限制?

由于Gor无法保证截取所有数据包,因此对于大于200kb的有效载荷,有可能丢失一些数据包和腐败主体。将其视为一项功能,并有机会测试处理破碎的物体:)保证交付的唯一方法就是使用--input-http,但您会错过一些功能。

我得到'太多打开文件'的错误

典型的Linux shell在1024下有一个小的打开文件软限制。在开始gor重放过程之前,你可以很容易地提出这个问题:

ulimit -n 64000

关于ulimit的更多信息:http : //www.thecodingmachine.com/solving-the-too-many-open-files-exception-in-red5-or-any-other-application/

我的负载平衡目标的CPU平均值高于源

如果您正在将来自多个侦听器的流量重放到负载平衡目标并使用粘性会话,则可能会发现目标服务器的CPU负载高于侦听器服务器。这可能是因为原始负载均衡器的粘性会话cookie未被目标负载均衡器所尊敬,从而导致请求通常会碰到同一个目标服务器,从而降低了后端的不同服务器的负载,从而降低了通过负载平衡获得的一些缓存收益。尝试针对一个重播目标运行一个侦听器,并查看CPU利用率比较是否更准确。

另请参阅故障排除

不要忘记用您的域名或IP替换“localhost”。

在配置安全输入时,--output-tcp-secure为GoReplay客户端启用标志,并连接到它。


GoReplay PRO支持精确记录和重播tcp会话,并且当--recognize-tcp-sessions选项通过时,而不是循环,它将使用更智能的算法,确保同一会话将被发送到同一个重播实例。

如果您计划进行大型负载测试,则可以考虑使用单独的主控实例来控制实际重放流量的Gor从站。例如:

# This command will read multiple log files, replay them on 10x speed and loop them if needed for 30 seconds, and will distributed traffic (tcp session aware) among multiple workers
gor --input-file logs_from_multiple_machines.*|1000% --input-file-loop --exit-after 30s --recognize-tcp-sessions --split-output --output-tcp worker1.local --output-tcp worker2.local:27017 --output-tcp worker3.local:27017 ...  --output-tcp workerN.local:27017

# worker 
gor --input-tcp :27017 --ouput-http load_test.target



posted @ 2018-05-22 16:49  sunsky303  阅读(12026)  评论(1编辑  收藏  举报
显示搜索