zl程序教程

您现在的位置是:首页 >  前端

当前栏目

Nginx http_mirror_module 实现流量复制

NginxHTTP 实现 复制 module 流量 Mirror
2023-09-14 09:01:46 时间

 

需求


将生产环境的流量拷贝到预上线环境或测试环境,这样做有很多好处,比如:

  • 可以验证功能是否正常,以及服务的性能;

  • 用真实有效的流量请求去验证,又不用造数据,不影响线上正常访问;

  • 这跟灰度发布还不太一样,镜像流量不会影响真实流量;

  • 可以用来排查线上问题;

  • 重构,假如服务做了重构,这也是一种测试方式;

为了实现流量拷贝,Nginx提供了ngx_http_mirror_module模块

The ngx_http_mirror_module module (1.13.4) implements mirroring of an original request by creating background mirror subrequests. Responses to mirror subrequests are ignored.

Example Configuration

location / {
    mirror /mirror;
    proxy_pass http://backend;
}

location = /mirror {
    internal;
    proxy_pass http://test_backend$request_uri;
}

Directives

Syntax:mirror uri | off; url是指需要将同步复制的请求访问到另外一个url上面去,即指向反向代理
Default:
mirror off;
Context:httpserverlocation

Sets the URI to which an original request will be mirrored. Several mirrors can be specified on the same level.

Syntax:mirror_request_body on | off; 是否需要将请求中的body转发到上游服务当中,默认是要复制http body的,指明off就不需要复制body了
Default:
mirror_request_body on; 
Context:httpserverlocation

Indicates whether the client request body is mirrored. When enabled, the client request body will be read prior to creating mirror subrequests. In this case, unbuffered client request body proxying set by the proxy_request_bufferingfastcgi_request_bufferingscgi_request_buffering, and uwsgi_request_buffering directives will be disabled.

location / {
    mirror /mirror;
    mirror_request_body off;
    proxy_pass http://backend;
}

location = /mirror {
    internal;
    proxy_pass http://log_backend;
    proxy_pass_request_body off;
    proxy_set_header Content-Length "";
    proxy_set_header X-Original-URI $request_uri;
}

 

http_mirror_module功能和特性


mirror模块可以帮助我们创建一份镜像流量,比如在生产环境下处理一些请求,这些请求可能要同步的copy一份到我的测试环境当中或者开发环境当中做处理,mirror模块就可以实现。

每当我们的请求到了nginx之后,可以生成子请求。这个子请求可以通过反向代理去访问我们其他的环境,比如我们的测试环境。而对测试环境和其他环境返回的内容我们是不做处理的,因为只做镜像的。

利用mirror模块,业务可以将线上实时访问流量拷贝至其他环境,基于这些流量可以做版本发布前的预先验证,进行流量放大后的压测等等。(复制线上真实流量,在不影响真实业务前提下,利用复制流量来做故障分析、性能定位、迁移评估等功能。)

我是这样理解的,这里,mirror本意是镜子、镜像,这里可以理解就像一个镜像站点一样,将所有的请求都收集起来,这个镜像就代表了所有真实有效的原始请求。有了这个镜像,后续我们才可能用这个镜像去做一些事情,比如重现一下所有的请求,这就实现了把线上的流程复制到别的地方。 

  • nginx 1.13.4及后续版本内置ngx_http_mirror_module模块,提供流量镜像(复制)的功能。
  • 支持流量放大,做法为:配置多份相同镜像。
  • 相比tcp-copy的优势:无需录制流量,实时可用,配置相当简单。
  • 源站请求,直接原路返回;正常配置下,mirror请求不影响源站请求及响应,源站nginx-server将流量复制到mirror站后,两者不再有任何交集。

 

 

配置流量复制


192.168.179.99流量镜像复制到上游服务192.168.179.100,配置如下:

192.168.179.99源站配置配置如下
[root@www ~]# echo "mirror.txt" > /usr/local/nginx/html/mirror.txt

server {
        listen       80;
        server_name  localhost;

      location / {
        mirror /mirror;
        mirror_request_body off;
      }

      location =/mirror{
         proxy_pass http://192.168.179.100$request_uri;  
         #原始uri不会镜像,可以通过#$request_uri变量取得原始请求的uri
         proxy_set_header Host $host;
         proxy_set_header X-Real-IP $remote_addr;

      }
}


192.168.179.100镜像站配置
server{
      listen  80;
      server_name localhost;
      charset utf-8;
      error_page 404 =200 /404.html;
      location /{
      return 200 'mirror respone';
     }
}


客户端192.168.179.102去请求192.168.179.99资源
[root@localhost ~]# curl 192.168.179.99/mirror.txt
mirror.txt

-----------------------------------------------------------------------------------------
192.168.179.99日志如下:
192.168.179.102 - - [29/Apr/2020:11:30:09 +0800] "GET /mirror.txt HTTP/1.1" 200 11 "-" "curl/7.29.0" "-"       --通过日志可以看到99收到了该请求

192.168.179.100日志如下:
192.168.179.99 - - [29/Apr/2020:11:30:09 +0800] "GET /mirror.txt HTTP/1.0" 200 14 "-" "curl/7.29.0" "192.168.179.102"   --上游服务也收到该请求,可以看到时间也是一样
可以看到上游服务和代理服务都拿到到了客户端相同的请求这样实现了流量的拷贝

 

 流量放大配置方法(配置多分mirror) 


server {
        listen       80;
        server_name  web1.www.com;
        # 源站配置
        location / {
                access_log  /data/nginx/1.14.1/logs/web1/access.log  accesslog;
                mirror /mirror;
                # 多加一份mirror,流量放大一倍
                mirror /mirror;
                mirror_request_body on;# Indicates whether the client request body is mirrored. default value is on.
                proxy_pass http://web1.upstream.name;
        }
        # 镜像站点配置
        location /mirror {
                internal; 
#internal 指定此location只能被“内部的”请求调用,外部的调用请求会返回”Not found” (404)
#跳转到下面的内部server
                proxy_pass http://mirror.web1.upstream.name$request_uri;
                proxy_pass_request_body on; 
# Indicates whether the original request body is passed to the proxied server. default #value is on
 
               proxy_set_header X-Original-URI $request_uri; # reset uri
        }
}

 

mirror日志


镜像配置不正确,导致复制操作没正常执行,此时nginx可能缺少错误日志,严重影响调试,所以非常建议配置镜像日志。mirror中不支持配置access_log,解决方法:mirror-location跳转到server,在server中配置accesslog。 

server {
        listen       80;
        server_name  web1.www.com;
 
        # 源站配置
        location / {
                access_log  /data/nginx/1.14.1/logs/web1/access.log  accesslog;
                mirror /mirror;
                mirror_request_body off;# Indicates whether the client request body is mirrored. default value is on.
                proxy_pass http://web1.upstream.name;
        }
 
        # 镜像站点配置
        location /mirror {
                internal; # 内部配置
                # 跳转到下面的内部server
                proxy_pass http://127.0.0.1:10901$request_uri;
                proxy_pass_request_body off; # Indicates whether the original request body is passed to the proxied server. default value is on
                # Content-Length必须配置在mirror中否则无效
                proxy_set_header Content-Length ""; 
# mirror_request_body/proxy_pass_request_body都设置为off,则Conten-length需要设置为"",否则有坑
                proxy_set_header X-Original-URI $request_uri; # 使用真实的url重置url
        }
}
 
server {
    # server没法设置为内部
    listen 127.0.0.1:10901;
    location / {
        # 判断放在server,使得post请求日志可以记录
        if ($request_method != GET) {
            return 403;
        }
        access_log /data/nginx/1.14.1/logs/web1/access.log  accesslog;
        proxy_pass http://mirror.web1.upstream.name;
    }
}