mirror 模块是 Nginx 的一个非常强大且实用的功能,它主要用于复制传入的请求,并将其发送到另一个地方(镜像位置),而不会影响原始请求的处理。


1. 什么是 Mirror 模块?

  • 核心功能:流量镜像(或称流量影子)。
  • 工作方式:它会把客户端发来的原始请求创建一个“镜像副本”,然后异步地将这个副本请求发送到你指定的“镜像位置”。
  • 关键特性
  • 异步处理:镜像请求的处理与原始请求的处理是完全分离的。原始请求会按照正常流程被处理并返回给客户端,不会等待镜像请求的完成。
  • 无视镜像响应:无论镜像请求返回什么结果(成功、失败、超时),都不会影响原始请求的响应。客户端对镜像请求的存在是完全无感知的。
  • 低延迟影响:由于是异步的,它对原始请求的延迟影响极小。

2. 主要应用场景

mirror 模块是以下场景的理想选择:

  1. 线上流量压测
  • 将生产环境的真实流量复制一份到新的测试服务器或新版本的应用程序上,来观察其在真实负载下的表现,而不会对线上用户产生任何影响。
  1. Bug 复现与诊断
  • 当生产环境出现难以复现的 Bug 时,可以将流量镜像到一个用于调试的隔离环境中,以便捕获和分析请求,而不会干扰正常用户。
  1. 版本验证与金丝雀分析
  • 在发布新版本时,可以将一小部分流量镜像到新版本后端,通过日志或监控系统来分析新版本的错误率、性能等指标,为正式发布提供数据支持。
  1. 日志与审计
  • 将所有请求额外镜像到一个专门的日志收集系统,用于进行更详细的安全审计、数据分析或长期存储。

3. 配置语法

mirror 模块包含两个主要指令:

mirror
  • 语法mirror uri | off;
  • 默认值mirror off;
  • 上下文http, server, location
  • 说明: 指定要复制请求到的镜像 URI。可以配置多个 mirror 指令来将请求复制到多个地方。
mirror_request_body
  • 语法mirror_request_body on | off;
  • 默认值mirror_request_body on;
  • 上下文http, server, location
  • 说明: 指示是否将原始请求的请求体复制到镜像请求中。通常需要保持为 on

4. 配置示例

下面通过几个例子来展示如何配置。

示例 1:基础镜像配置

这个例子将所有发送到 /api/ 的请求镜像到 http://mirror_backend

http {
    # 定义原始请求的后端服务器
    upstream primary_backend {
        server 10.0.1.100:8080;
    }

    # 定义镜像请求的后端服务器
    upstream mirror_backend {
        server 10.0.2.200:8080;
    }

    server {
        listen 80;

        location /api/ {
            # 将请求代理到主后端
            proxy_pass http://primary_backend;

            # 启用镜像,并指定镜像位置的URI
            mirror /mirror;
            # 确保请求体被复制
            mirror_request_body on;
        }

        # 这个内部location用于处理镜像请求
        location = /mirror {
            # 设置为internal,意味着它不能被外部直接访问
            internal;
            # 将镜像请求代理到镜像后端
            proxy_pass http://mirror_backend$request_uri;

            # 为了让镜像后端能收到和原始请求一样的内容,需要重置一些头信息
            proxy_pass_request_body on;
            proxy_set_header X-Original-URI $request_uri;
            # 可以设置一个自定义头来标识这是一个镜像请求
            proxy_set_header X-Mirrored-For "yes";
        }
    }
}

工作流程

  1. 客户端请求 GET /api/user/1
  2. Nginx 将该请求代理到 http://primary_backend/api/user/1
  3. 同时,Nginx 会创建一个镜像请求 GET /mirror(但内部会转换为 http://mirror_backend/api/user/1)。
  4. 客户端从 primary_backend 收到响应,对镜像过程完全不知情。
示例 2:镜像部分流量(采样)

你可以使用 Nginx 的内置变量(如 $remote_addr)和 if 指令来实现流量采样,例如只镜像 50% 的请求。

注意:在 Nginx 中使用 if 需要小心,但它在这里是适用的。

location /api/ {
    proxy_pass http://primary_backend;

    # 使用$binary_remote_addr的最后一个比特来决定是否镜像(50%概率)
    if ( $binary_remote_addr ~* "1$" ) {
        mirror /mirror;
    }
    mirror_request_body on;
}

location = /mirror {
    internal;
    proxy_pass http://mirror_backend$request_uri;
    proxy_set_header X-Mirrored-For "sampled";
}

5. 注意事项与局限性

  1. 响应被忽略:再次强调,镜像上游的响应会被 Nginx 完全忽略。即使镜像服务返回 500 错误或超时,也不会影响客户端。
  2. 资源消耗
  • 网络带宽:镜像会使你的出口带宽消耗几乎翻倍。
  • 后端资源:你的镜像后端需要有足够的资源来处理复制的流量。
  1. 复杂请求:对于文件上传等包含大量请求体的请求,配置 mirror_request_body on; 是必须的,并且要确保镜像后端能够处理。
  2. 模块默认可用性mirror 模块是 Nginx 官方模块,通常包含在大多数标准发行版中(如 nginx.org 的官方包),但一些第三方打包版本(如某些旧的 Debian/Ubuntu 的 nginx-light)可能不包含它。你可以通过 nginx -V 命令查看是否包含 --with-http_mirror_module 来确认。

总结

Nginx 的 mirror 模块是一个极其有价值的运维和开发工具,它通过一种安全、非侵入式的方式实现了生产环境流量的复制。它为进行真实的性能测试、问题诊断和渐进式发布提供了坚实的数据基础,是构建高可靠性、高可观测性系统架构的重要组件之一。