利用NGINX内置模块mirror进行流量复制等操作
在日常工作中,会有这样的场景,为了便于测试,可能希望线上的请求能够同步到测试一部分,以便于验证某些功能,或者是在多套测试环境的情况下,希望能够将某些请求在几个环境同步,比如在 1 环境测试的时候生成了某个图片或者视频,这个生成依赖于一个请求的回调,而如果没有特别配置,则这个请求就只在当前环境中生效,这对测试工作有相当大的不便。
版本说明
本文写于 2019-10。
未在更高版本上重新验证,请以对应版本的官方文档为准。
于是,我们需要引入流量复制这一概念,流量复制有不少工具可以实现,有 Gor、tcpreplay、tcpcopy 等,而今天将要使用的,是配置简单,使用方便的 NGINX 的一个模块:ngx_http_mirror_module。
mirror: 中文为镜像的意思,这里指流量复制的目的地。
# 1,特性。
- nginx 1.13.4 及后续版本内置 ngx_http_mirror_module 模块,提供流量镜像 (复制) 的功能。
- 支持流量放大,做法为:配置多份相同镜像。
- 相比 tcp-copy 的优势:无需录制流量,实时可用;配置相当简单。
- 源站请求,直接原路返回;正常配置下,mirror 请求不影响源站请求及响应,源站 nginx-server 将流量复制到 mirror 站后,两者不再有任何交集。
mirror 模块在 Nginx 1.13.4 以后的版本中默认是启用的,只需看一下版本即可,不必重新编译。
# 2,简单配置。
先看下当前使用的 NGINX 版本:
$ nginx -V
nginx version: nginx/1.14.0
built by gcc 4.8.5 20150623 (Red Hat 4.8.5-39) (GCC)
built with OpenSSL 1.0.2k-fips 26 Jan 2017
TLS SNI support enabled
configure arguments: --prefix=/usr/local/nginx --with-http_stub_status_module --with-http_ssl_module --with-http_v2_module --with-http_realip_module
2
3
4
5
6
接着添加如下配置:
worker_processes 1;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
server {
listen 8181;
access_log /var/log/nginx/test.log;
root html/test;
}
server {
listen 8282;
access_log /var/log/nginx/mir1.log;
root html/mir1;
}
server {
listen 8383;
access_log /var/log/nginx/mir2.log;
root html/mir2;
}
upstream backend {
server 127.0.0.1:8181;
}
upstream test_backend1 {
server 127.0.0.1:8282;
}
upstream test_backend2 {
server 127.0.0.1:8383;
}
server {
listen 80;
server_name localhost;
location / {
mirror /mirror1;
mirror /mirror2;
proxy_pass http://backend;
}
location = /mirror1 {
internal;
proxy_pass http://test_backend1$request_uri;
}
location = /mirror2 {
internal;
proxy_pass http://test_backend2$request_uri;
}
}
}
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
说明:
location / { # location /指定了源uri为/,也可以定义为其他指定接口
mirror /mirror1; # mirror /mirror指定镜像uri为/mirror
mirror /mirror2; # 有多个需要复制流量的,可以配置多条
mirror /mirror2; # 配置多条情况下,将会起到流量放大的作用,即主配置请求一次,镜像端会有两次
# mirror_request_body on; # 指定是否镜像请求body部分,请求自动缓存;
proxy_pass http://backend; # 指定处理主流量的后端Server
}
location = /mirror1 {
internal; # 指定此location只能被“内部的”请求调用,外部的调用请求会返回”Not found” (404)
proxy_pass http://test_backend1$request_uri; # 指定将要复制流量的Server1
}
location = /mirror2 {
internal;
proxy_pass http://test_backend2$request_uri;
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 3,验证。
此时验证也非常简单,检测配置无误,然后启动 NGINX,使用 tail 同时监听三个日志,然后请求 127.0.0.1/index.html,会发现这一请求同时在日志中出现了。
创建一下访问内容:
$ cd /usr/local/nginx/html/
$ mkdir test mir1 mir2
$ echo test > test/index.html
$ echo mir1 > mir1/index.html
$ echo mir2 > mir2/index.html
$ curl 127.0.0.1/index.html
2
3
4
5
6
请求看效果:

参考:
- https://dwz.cn/T1rLisdA
- https://dwz.cn/8atYbyNk
- https://dwz.cn/UpMMbdiC
# 4. 坑与边界
常见问题一:mirror 请求失败不影响主请求
mirror 请求是异步发送的,即使 mirror 目标服务器不可用,也不会影响主请求的响应。生产环境需要监控 mirror 请求的错误日志。
常见问题二:mirror 请求无响应体
默认情况下,mirror 请求只会复制请求体,不会返回响应体。如果需要对响应也做镜像,需要配合其他模块使用。
常见问题三:大文件场景性能
如果主请求传输大文件,mirror 也会复制同样的数据,可能导致出口带宽翻倍。需要评估服务器网络资源。
# 5. mirror 模块的原理
ngx_http_mirror_module 模块的工作原理:
- 主请求正常处理,按正常流程返回响应
- 同时创建一个"影子"请求,复制主请求的请求头和请求体
- 影子请求发送到 mirror 指定的 location 或 upstream
- 影子请求的响应被丢弃,不影响主请求
关键配置参数:
mirror:指定镜像目标mirror_request_body:是否镜像请求体(默认 on)
# 6. 高级应用场景
场景一:实时数据同步
将生产环境的写请求(POST/PUT/DELETE)镜像到数据分析系统,实现准实时数据同步:
location /api/ {
# 正常处理请求
proxy_pass http://backend;
# 镜像到数据同步系统
mirror /mirror;
mirror_request_body on;
}
location = /mirror {
internal;
proxy_pass http://data-sync-server;
proxy_set_header X-Mirror-From $host;
proxy_set_header X-Request-ID $request_id;
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
场景二:压力测试
将生产流量镜像到测试环境,验证新版本的稳定性:
location / {
proxy_pass http://production_backend;
mirror /mirror_test;
mirror_request_body on;
}
location = /mirror_test {
internal;
# 指向测试环境
proxy_pass http://test_backend;
# 可选:添加测试标记 header
proxy_set_header X-Test-Environment "true";
}
2
3
4
5
6
7
8
9
10
11
12
13
场景三:多环境同时生效
一个请求同时写入多个后端,实现跨环境数据一致性验证:
location /webhook {
# 主处理
proxy_pass http://primary_backend;
# 镜像到多个环境
mirror /mirror_staging;
mirror /mirror_test;
}
location = /mirror_staging {
internal;
proxy_pass http://staging_backend;
}
location = /mirror_test {
internal;
proxy_pass http://test_backend;
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 7. 性能优化建议
建议一:限制镜像请求的 scope
尽量只镜像必要的请求,不要对静态资源(CSS/JS/图片)做镜像:
location / {
# 只镜像 API 请求
location ~ ^/api/ {
mirror /mirror;
proxy_pass http://backend;
}
# 静态资源不镜像
proxy_pass http://static_backend;
}
2
3
4
5
6
7
8
9
建议二:使用专用 upstream
为 mirror 请求配置独立的 upstream,避免影响主请求的性能:
upstream mirror_backend {
server 192.0.2.50:8080;
}
location / {
mirror /mirror;
proxy_pass http://main_backend;
}
location = /mirror {
internal;
proxy_pass http://mirror_backend;
}
2
3
4
5
6
7
8
9
10
11
12
13
建议三:异步处理
mirror 请求默认是异步的,确保不会阻塞主请求。如果需要更极致的性能,可以考虑使用 Nginx 的 subrequest 机制。
# 8. 监控与日志
需要关注 mirror 模块的以下指标:
- mirror 请求成功率:监控 mirror 相关的请求状态码
- 响应时间:mirror 请求不应显著增加主请求的延迟
- 带宽占用:评估镜像带来的额外网络开销
配置专用的日志格式:
log_format mirror_log - []
rt= uct=
mrt=;
access_log /var/log/nginx/mirror.log mirror_log;
2
3
4
5
6
# 9. 参考
# 10. 与其他流量复制工具的对比
| 工具 | 类型 | 优点 | 缺点 |
|---|---|---|---|
| Nginx mirror 模块 | 嵌入式 | 配置简单,性能高,无需额外组件 | 需要 Nginx 编译支持 |
| Gor | 旁路式 | 支持抓包方式,对原系统无侵入 | 需要额外的 Gor 进程 |
| tcpreplay | 旁路式 | 支持重放历史流量 | 不支持实时流量 |
| tcpcopy | 旁路式 | 支持在线流量复制 | 配置相对复杂 |
Nginx mirror 模块的优势在于:
- 无需额外安装组件
- 配置在 Nginx 配置文件中统一管理
- 性能开销小(嵌入式)
- 实时性好(同步处理)
# 11. 生产环境检查清单
部署 Nginx mirror 模块前,需要确认:
模块是否可用
nginx -V 2>&1 | grep -o http_mirror_module1权限配置
- mirror 目标服务需要有正确的访问权限
- 建议使用内网 IP,避免暴露到公网
容量规划
- 评估镜像流量对网络带宽的影响
- 确保目标服务能处理镜像请求的负载
监控告警
- 添加 mirror 相关指标到监控系统
- 设置错误率阈值告警
# 12. 故障排查案例
案例:镜像请求返回 502
排查发现 mirror 目标服务不可用。解决方案:添加 backup upstream:
location = /mirror {
internal;
proxy_pass http://mirror_backend backup;
}
2
3
4
案例:内存占用过高
生产环境发现 Nginx 内存使用异常增长,排查发现 mirror_request_body未关闭,大文件上传时请求体被完整复制。解决方案:
location / {
mirror /mirror;
mirror_request_body off; # 关闭请求体镜像
proxy_pass http://backend;
}
2
3
4
5
# 13. 安全注意事项
注意事项一:数据敏感
镜像的请求可能包含敏感信息(用户名、密码、Token 等),确保 mirror 目标服务有同等的安全防护级别。
注意事项二:防止循环镜像
避免出现 A 镜像到 B,B 又镜像回 A 的情况,会导致死循环。配置 mirror 时使用 internal 指令确保 mirror 目标不接收外部请求。
注意事项三:合规要求
在某些行业(金融、医疗),镜像生产流量可能涉及合规要求,需要评估是否允许。
# 14. 总结
Nginx mirror 模块是一个强大的流量复制工具,特别适合以下场景:
- 功能测试:将生产流量复制到测试环境,验证新功能
- 数据同步:实时同步数据到数据仓库或分析系统
- 灰度发布:多版本并行验证
- 问题排查:在不影响主业务的情况下分析请求
配置示例回顾:
location / {
proxy_pass http://backend;
mirror /mirror;
mirror_request_body on;
}
location = /mirror {
internal;
proxy_pass http://mirror_backend;
}
2
3
4
5
6
7
8
9
10
核心要点:
- 使用
internal保护 mirror 端点 - 根据需要选择是否镜像请求体
- 监控 mirror 请求的健康状态
- 合理规划网络带宽