目录

Goreplay-修改output-Http的url

背景

公司让调研流量回放工具goreplay,实现部分能力,其中包括要统计线上业务还在使用的api(代码陈旧,俗称屎山,无法从代码层面去做),我这里就使用goreplay来实现,先说说如何将线上环境接入goreplay。

接入

goreplay仓库地址

我这里采用类sidecar形式去做,这样不会影响原业务容器,goreplay本身也是这样的设计

制作容器

为什么要自己制作容器,不用官方已经做好的?因为后面使用的时候发现需求有出入,goreplay无法满足需求,需要对源码进行一点修改,然后自行编译二进制文件来制作容器

Dockerfile如下

1
2
3
4
5
FROM alpine:latest
ADD ./gor /gor
ENV INPUT :80
ENV OUTPUT https://example.com/api/goreplay
CMD ["sh", "-c", "/gor --input-raw $INPUT $OUTPUT"]

描述文件如下(精简后)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: service
  name: service
  namespace: service
spec:
  replicas: 1
  selector:
    matchLabels:
      app: service
  template:
    metadata:
      labels:
        app: service
    spec:
      containers:
      - env:
		...省略
        image: service:2024-01-15-17-58-26
        imagePullPolicy: IfNotPresent
        name: service
        ...省略
      - env:
        - name: INPUT
          value: ":80"
        - name: OUTPUT
          value: "https://example.com/api/goreplayHanddle"
        image: registry-vpc.cn-hangzhou.aliyuncs.com/zhangjinhui/gor:sidecar
        imagePullPolicy: IfNotPresent
        name: admin-service

启动后即可

实现URL转换

在使用官方的最新版1.3.0时(截至目前已停止更新),发现,在使用output-http回放流量时,request请求进来的PATH,是我配置的OUTPUT的PATH,根据上面描述文件,回放后,path变为了:/api/goreplayHanddle, 这样我无法根据回放流量获取原始的PATH路径了,在翻阅Issue后找到862, 内容跟我并没有什么关系,但是我发现可以根据该段代码自行修改发挥,从而可以实现我的需求。

思路

1
2
3
4
5
6
7
	// fix #862
	if c.config.url.Path == "" && c.config.url.RawQuery == "" {
		req.URL.Scheme = c.config.url.Scheme
		req.URL.Host = c.config.url.Host
	} else {
		req.URL = c.config.url
	}

源码中逻辑为,如果配置的output-http中包含path内容,则直接将配置URL全部作为回放URL,如果配置中没有PATH内容,则只采用Scheme和Host回放,Path则使用原始的req的path进行回放,此时就出现了问题,因为我既想要配置自定义的path用来方便我收集回放流量,又要原始path进行后续处理,于是将该段代码修改为:

1
2
3
4
5
6
7
8
9
	// fix #862
	if c.config.url.Path == "" && c.config.url.RawQuery == "" {
		req.URL.Scheme = c.config.url.Scheme
		req.URL.Host = c.config.url.Host
	} else {
		req.URL.Scheme = c.config.url.Scheme
		req.URL.Host = c.config.url.Host
        req.URL.Path = c.config.url.Path + req.URL.Path
	}

我将自己配置的path和req原始path拼接,获得了一个以"/api/goreplayHanddle"开头的path,这样我自己写一个接口就可以收集所有回放的流量,然后再进行其他处理,在我的处理逻辑中,我再将前缀去除:

1
url := strings.ReplaceAll(c.Ctx.Request.URL.String(), "/api/goreplayHanddle", "")

这样我就得到了原始的URL,以此实现我的需求。

下面是整个过程。

拉源码

1
git clone https://github.com/buger/goreplay.git

修改代码

就是修改上面部分

编译

编译前需要先制作环境容器,在仓库中有一个Dockerfile.dev文件,直接将他build出来,起名为gor-amd64:latest,因为makefile中使用的是这个名字

1
docker build -t gor-amd64:latest -f Dockerfile.dev .

随后开始编译

1
make release-linux-amd64

完成之后在当前目录下就会生成一个gor名字的文件,再经上文制作容器后即可进行使用。

效果

目前自己的api只是将部分request内容转存到mysql,还没有做去重、分类等等需求,后面慢慢做。

../images/goreplay-1.png