利用ngx_http_mirror_module模块实现nginx流量复制


模块介绍

  • 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 "";


文章作者: NesTeaLin
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 NesTeaLin !
  目录