Ngnix 流量拷贝

在需要真实的流量做旁路测试的时候,我们就可以使用 nginx 来做流量的拷贝

1 Nginx Mirror 模块

nginx 自1.13.4 版本开始,自带一个 ngx_http_mirror_module,使用起来非常简单,只要在需要 mirror 的 location 处添加 mirror 关键字就行

Copy

1
2
3
4
5
6
7
8
9
location / {
    mirror /mirror;
    proxy_pass http://backend;
}
 
location = /mirror {
    internal;
    proxy_pass http://test_backend$request_uri;
}

 

一个简单的 nginx 配置如下:

Copy

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
33
http {
 
    upstream webserver1 {
        server  127.0.0.1:8881;
    }
 
    upstream webserver2 {
        server  127.0.0.1:8882;
    }
 
    server {
        listen       8080;
        server_name  localhost;
 
        location / {
            root   html;
            index  index.html index.htm;
        }
 
 
    location /test {
            mirror /mirror;
            proxy_pass http://webserver1/index;
        }
 
        location /mirror {
            internal;
            proxy_pass http://webserver2/index;
        }
 
    }
 
}

 

2 lua 脚本分发请求

但是 nginx 版本过低时,该如何做呢?
我们可以使用集成来 lua 的 OpenResty,使用 lua 脚本处理 web 请求完成流量的拷贝
我们直接看例子:
nginx.conf

Copy

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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
user root;
worker_processes  1;
error_log logs/error.log;
events {
    worker_connections 1024;
}
http {
 
    upstream product {
            server  127.0.0.1:8881;
    }
    upstream test {
            server  127.0.0.1:8882;
    }
    server {
            listen      8080;
            server_name 172.27.133.28;
            #lua_code_cache off;
 
            # 外部应用的请求地址,通过 lua 脚本分发到新的 product 和 test 地址
            location /predict/fake {
                    client_body_buffer_size 2m;
                    set $switch    "on";              #开启或关闭copy功能
                    content_by_lua_file /tmp/copy_req.lua;
            }
             
            # lua 脚本分发到 product,并且对 url 重写后,反向代理到 product 的 server
            location ~* ^/product {
                    log_subrequest on;
                    rewrite ^/product(.*)$ /predict break;
                    proxy_set_header Host $host;
                    proxy_set_header X-Real-IP $remote_addr;
                    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                    proxy_pass http://product;
                    access_log logs/product-upstream.log;
            }
 
            # lua 脚本分发到 test,并且对 url 重写后,反向代理到 test 的 server
            location ~* ^/test {
                    log_subrequest on;
                    rewrite ^/test(.*)$ /predict break;
                    proxy_set_header Host $host;
                    proxy_set_header X-Real-IP $remote_addr;
                    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                    proxy_pass http://test;
                    access_log logs/test-upstream.log;
            }
 
 
    }
 
}

 

copy_req.lua

Copy

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
local res1, res2, action
action = ngx.var.request_method
if action == "POST" then
        arry = {method = ngx.HTTP_POST, body = ngx.req.read_body()}
else
        arry = {method = ngx.HTTP_GET}
end
 
if ngx.var.switch == "on" then
        res1, res2 = ngx.location.capture_multi {    -- 分发请求的核心函数
                { "/product" .. ngx.var.request_uri , arry},
                { "/test" .. ngx.var.request_uri , arry},
        }
else
        res1, res2 = ngx.location.capture_multi {
                { "/product" .. ngx.var.request_uri , arry},
        }
end
 
if res1.status == ngx.HTTP_OK then
        local header_list = {"Content-Length", "Content-Type", "Content-Encoding", "Accept-Ranges"}
        for _, i in ipairs(header_list) do
                if res1.header[i] then
                        ngx.header[i] = res1.header[i]
                end
        end
        ngx.say(res1.body)
else
        ngx.status = ngx.HTTP_NOT_FOUND
end

 

我们来捋一捋这个流程:
背景:首先我们向外部注册的地址的是 /predict/fake,我们实际 web server 的地址是 /predict,然后一个生产的 upstream (product)一个测试用的 upstream(test),ok,这时候一个 /predict/fake 请求过来了发生了什么呢

  1. 首先 /predict/fake 匹配到了 location,然后经过 lua 脚本分发请求,产生了两个子请求 /product/predict/fake 和 /test/predict/fake
  2. /product/predict/fake 匹配到新的 location,并且对这个 url 进行了 rewrite,变成了真实的后端请求地址 /predict,并且反向代理到 product 这个 upstream 下的 server,同理对 /test/predict/fake 也是一样的
  3. 两个子请求都有返回,但是在 lua 脚本中,只有 product 对应的请求被最终返回给了前端

需要注意的点:
反向代理时 rewrite 后的 url 会覆盖 proxy_pass 的 url

参考:

nginx 之 proxy_pass 接口转发的规则

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值