模块介绍
- ngx_http_mirror_module模块特性:
- nginx 1.13.4及后续版本内置ngx_http_mirror_module模块,提供流量镜像(复制)的功能。
- 支持流量放大,做法为:配置多份相同镜像。
- 相比tcp-copy的优势:无需录制流量,实时可用;配置相当简单。
- 源站请求,直接原路返回;正常配置下,mirror请求不影响源站请求及响应,源站nginx-server将流量复制到mirror站后,两者不再有任何交集。
实验流程
- 具体配置:
# 源后端 upstream dtest-server { server 172.17.20.23:5454; } # 镜像目标后端 upstream dtest-mirror1 { server 172.17.10.13:5555; } # 流量分流 split_clients $remote_addr $mirror_backend { 30% dtest-mirror1; * ""; } server { listen 80; listen 8443; server_name abc.nestealin.com; charset utf-8; access_log logs/$http_host.access.main.log main; error_log logs/abc.nestealin.com.error.crit.log crit; location /mirror-test/ { #allow 14.28.151.69; #include firewall.conf; # 复制请求体 mirror_request_body on; # 流量复制到/mirror1的location mirror /mirror1; proxy_redirect off; 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_set_header X-Real-Port $remote_port; proxy_pass http://dtest-server; } # 镜像站点1 location = /mirror1 { # 内部路径,禁止直接请求,外部访问该路径直接提示404 internal; if ($mirror_backend = "") { return 400; } #使用真实的url重置url proxy_set_header X-Original-URI $request_uri; # 原始请求正文传递 proxy_pass_request_body on; #allow 1.2.3.4; #include firewall.conf; proxy_redirect off; 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_set_header X-Real-Port $remote_port; proxy_pass http://$mirror_backend$request_uri; } }
$mirror_backend
变量由 split_clients 配置块定义,split_clients 会将左边的变量 $remote_addr
(requests remote address)经过 MurmurHash2 算法进行哈希,得出的值如果在前 30% ,那么 $mirror_backend
的值为 dtdns-mirror1;
如果不在前 30%,那么 $mirror_backend
的值为空字符 “”。
从以上事例,做到了 30% 流量到镜像后端,如果 $mirror_backend
变量的值为空字符串,就不复制流量;其他情况就会将流量到镜像后端。
因为镜像请求的错误响应并不会影响原始请求,所以丢弃镜像请求并返回错误响应是很安全的。
在 mirror1 的 location 中,请求会被转发到 $mirror_backend
变量定义的后端。
请求日志分析
客户端请求日志
- 先是响应 302 状态码跳转,再返回 200 状态码
nestealin >> ~ # curl http://abc.nestealin.com/mirror-test/ -IL HTTP/1.1 302 Moved Temporarily Server: nginx Date: Fri, 06 Aug 2021 14:53:29 GMT Content-Type: text/html Content-Length: 138 Connection: keep-alive Keep-Alive: timeout=120 Location: http://abc.nestealin.com/login HTTP/1.1 200 OK Server: nginx Date: Fri, 06 Aug 2021 14:53:29 GMT Content-Type: application/json Content-Length: 11 Connection: keep-alive Keep-Alive: timeout=120
nginx日志
- upstream_server 字段中只有 172.17.20.23:5454 后端进行响应
192.168.1.13:53130 80 - [06/Aug/2021:22:37:57 +0800] "GET /mirror-test/ HTTP/1.1" 302 138 93 "-" "curl/7.64.1" - 172.17.20.23:5454 302 0.001 0.001 abc.nestealin.com "- - -" "192.168.1.13" 192.168.1.13:53130 80 - [06/Aug/2021:22:37:57 +0800] "GET /login HTTP/1.1" 200 11 86 "-" "curl/7.64.1" - 172.17.20.23:5454 200 0.000 0.000 abc.nestealin.com "- - -" "192.168.1.13"
源后端 ( dtest-server ) 日志
- 与客户端响应一致
192.168.1.13: 12345 - [06/Aug/2021:22:37:57 +0800] "GET /mirror-test/ HTTP/1.0" 302 138 188 "-" "curl/7.64.1" 192.168.1.13 - - - 0.000 abc.nestealin.com "- - -" "192.168.1.13" 192.168.1.13: 12345 - [06/Aug/2021:22:37:57 +0800] "GET /login HTTP/1.0" 200 11 206 "-" "curl/7.64.1" 192.168.1.13 - - - 0.000 abc.nestealin.com "- - -" "192.168.1.13"
镜像后端日志 ( dtest-mirror1 )
- 镜像后端响应 201 状态码,与客户端最终响应不一致,没有参与客户端响应返回
192.168.1.13: 12346 - [06/Aug/2021:22:37:57 +0800] "GET /mirror-test/ HTTP/1.0" 201 36 219 "-" "curl/7.64.1" 192.168.1.13 - - - 0.000 abc.nestealin.com "- - -" "192.168.1.13"
小结及注意点
镜像后端不参与客户端请求响应,最终只以原始 proxy_pass 响应为准;
后端即使报错、返回异常状态码、直接不通 ( 502 ) 或其他异常处理,也不会影响真实流量;
但后端不可响应缓慢,这种情况会阻塞原始请求;
如果需要不传递请求 body ,需要置空正文长度
proxy_pass_request_body off; proxy_set_header Content-Length "";