是什么

  • 流量镜像 (流量镜像/流量拷贝/流量复制)
  • 利用此模块可以将线上实时流量镜像至其他环境,而Nginx最终会丢弃mirror的响应,从而不影响源站请求的响应

目的:创建请求镜像

文档:https://nginx.org/en/docs/http/ngx_http_mirror_module.html

解决什么问题

  • 将生产的流量导入到测试环境排查线上问题
  • 通过预生产环境测试来观察新系统对生产环境流量的处理能力。
  • 记录和分析生产环境日志

怎么使用

指令:

  • mirror
    • 默认值:mirror off
  • mirror_request_body
    • 默认值:mirror_request_body on;

context:

  • http
  • server
  • location

实战

backend

// backend.go
package main

import (
	"net/http"

	"github.com/gin-gonic/gin"
)

func main() {
	r := gin.Default()
	r.GET("/", func(c *gin.Context) {
		c.String(http.StatusOK, "hello backend")
	})

	r.Run(":8080")
}

test-backend

// test_backend.go
package main

import (
	"net/http"

	"github.com/gin-gonic/gin"
)

func main() {
	r := gin.Default()
	r.GET("/", func(c *gin.Context) {
		c.String(http.StatusOK, "hello mirror")
	})

	r.Run(":8081")
}

nginx配置:

# default.conf
upstream backend {
    server 192.168.1.4:8080;
}

upstream test_backend {
    server 192.168.1.4:8081;
}

server {
    listen 80;
    listen [::]:80;
    server_name localhost;

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

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

或者复制50%的流量到test_backend

upstream backend {
    server 192.168.1.4:8080;
}

upstream test_backend {
    server 192.168.1.4:8081;
}

# split_clients $remote_addr $mirror_backend {
#     50% test_backend;
#     * "";
# }

split_clients $arg_apikey $mirror_backend {
    50% test_backend;
    * "";
}

server {
    listen 80;
    listen [::]:80;
    server_name localhost;

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

    location = /mirror {
        internal;
        if ($mirror_backend = "") {
            return 400;
        }
        proxy_pass http://$mirror_backend$request_uri;
    }
}

运行测试:

# run backend
go run backend.go

# run test_backend
go run test_backend.go

# 运行nginx
docker run \
    --name nginx \
    -p 80:80 \
    -d \
    -v ${PWD}/default.conf:/etc/nginx/conf.d/default.conf \
    nginx:mainline-alpine

# docker run \
#     --name nginx \
#     -p 80:80 \
#     -d \
#     -v ${PWD}/default_50_percent.conf:/etc/nginx/conf.d/default.conf \
#     nginx:mainline-alpine
# for i in {1..20};do curl -i "localhost/?apikey=${i}" ;done