关于mirror:Nginx-Mirror-流量复制的心路历程

9次阅读

共计 2571 个字符,预计需要花费 7 分钟才能阅读完成。

原文地址:Nginx Mirror 流量复制的心路历程

背景

上篇文章写到 Lua OpenResty 的容器化,我的项目实现了上云,然而有面临了几个新的问题:

  1. 旧业务跑了这么多年,如何保障上云后的稳定性呢?
  2. 如何确保接口都能失常拜访呢?
  3. 如何确保两边 api 申请的幂等呢?

为了保障服务的品质,咱们决定借助 nginx mirror(流量复制)来统计服务的幂等状况,作为判断服务是否达到上线规范的一个重要指标。

nginx mirror 是什么?

ngx_http_mirror_module 模块(1.13.4)通过创立后盾镜像子申请来实现原始申请的镜像。镜像子申请的响应将被疏忽。

利用 mirror 模块,业务能够将线上实时拜访流量拷贝至其余环境,基于这些流量能够做版本公布前的事后验证,进行流量放大后的压测。

官网案例:

upstream mirror_backend {server mirrorHost:mirrorPort;}

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

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

如何判断 mirror 后的后果是否幂等?

mirror 后,能够通过剖析两边的 access.log,来判断幂等状况:

170.21.40.147 [20/Apr/2021:14:02:02 +0000] "POST /test/query?client_name=test&client_version=2148205812&client_sequence=1&r=1618327396996&isvip=0&release_version=1.1.0

然而要判断同一个申请在两边的后果是否幂等,单目前的信息还是不够的,比方:

  1. 如何判断两边是同一个申请?
  2. 如何判断申请返回的后果是统一的?
  3. 如何对所有申请的幂等性进行统计?

如何判断两边是同一个申请?

要判断两边申请是否同一个,咱们须要一个 Unique Tracing ID,并且贯通两边的 access.log。

Nginx 在 1.11.0 版本中就提供了内置变量 $request_id,其原理就是生成 32 位的随机字符串,虽不能比较 UUID 的概率,但 32 位的随机字符串的反复概率也是微不足道了,所以个别可视为 UUID 来应用即可。

so,咱们能够在生产机器的 nginx 的 access.log 减少 $request_id:

log_format  access_log_format
           ''$remote_addr $request_time $request $request_id';

并将 $request_id 通过 header 和申请一起转发到 mirror 的服务器上:

location = /mirror {
    internal;
      proxy_set_header X-Request-Id $request_id; # $request_id
    proxy_pass http://test_backend$request_uri;
}

最初在 mirror 服务器的 nginx access 日志格局减少:

$http_request_id,就能够失去:

170.21.40.147 [20/Apr/2021:14:02:02 +0000] "POST /test/query?client_name=test&client_version=2148205812&client_sequence=1&r=1618327396996&isvip=0&release_version=1.1.0 nqrbyg9l50jwu3ezmvtfc6hx487i2kpo

两个通过 nqrbyg9l50jwu3ezmvtfc6hx487i2kpo 就能够将申请关联上了。

如何判断申请返回的后果是统一的?

$request_id曾经有了,那么如何判断后果是否统一呢?这里能够将两边服务器的返回后果(resp_body)进行 md5,而后进行比拟。

在两边的 nginx 定义变量:

set $resp_body "";
body_filter_by_lua '
    local resp_body = string.sub(ngx.arg[1], 1, 1000)
    ngx.ctx.buffered = (ngx.ctx.buffered or "") .. resp_body
    if ngx.arg[2] then
       ngx.var.resp_body = ngx.md5(ngx.ctx.buffered)
    end
';

而后在 log_format access_log_format 减少$resp_body,即:

log_format  access_log_format
           ''$remote_addr $request_time $request $request_id $resp_body';

得出日志:

170.21.40.147 [20/Apr/2021:14:02:02 +0000] "POST /test/query?client_name=test&client_version=2148205812&client_sequence=1&r=1618327396996&isvip=0&release_version=1.1.0 nqrbyg9l50jwu3ezmvtfc6hx487i2kpo 0vy27c35aqrsxgzflk4inwtjd1omu96p

ps:nqrbyg9l50jwu3ezmvtfc6hx487i2kporequest_id0vy27c35aqrsxgzflk4inwtjd1omu96presp_bodymd5 后的后果。

如何对所有申请的幂等性进行统计?

至此,咱们曾经失去了咱们想要的日志格局了,通过 request_idresp_body能够对两个申请的信息幂等判断。

然而又有一个新的问题,一台机器采集到的 access_log 就靠近 3000W,因为$request_id 是字符随机串,所以须要对两边 access log 进行排序,能力做统计,然而要怎么做呢?

  1. 因为日志太大,所以依据 request_id 第一个字符进行 mod 10,将文件切割成 10 份。
  2. 对 10 份 log 依据 request_id 进行排序。
  3. 合并文件
  4. 最初通过比拟的形式,对两个文件进行统计。
正文完
 0