Nginx以及如何拿到发送给mirror的request和response,并且将request和response打包发送给另一个新的服务?

新手上路,请多包涵

Nginx以及如何拿到发送给mirror的request和response,并且将request和response打包发送给另一个新的服务?

现在想要在Nginx实现一个流量复制的功能,同时需要将发送给mirror的request和response记录下来,并且将request和response全部再发送给另一个新服务. 应该如何配置Nginx?

配置文件如下:

user  nginx;
worker_processes  auto;

error_log  /var/log/nginx/error.log  notice;
pid        /var/run/nginx.pid;

events {
    worker_connections  1024;
}

http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    log_format main '$remote_addr - $remote_user [$time_local] "$request" '
        '"$status" $body_bytes_sent "$http_referer" '
        '"$http_user_agent" "$http_x_forwarded_for" '
        '"$gzip_ratio" $request_time $bytes_sent $request_length';

    open_log_file_cache max=1000 inactive=60s;

    access_log  /var/log/nginx/access.log  main;

    sendfile        on;
    #tcp_nopush     on;

    keepalive_timeout  65;
    upstream backends {
        server localhost:9099;
    }
    upstream mirror1_backend {
        server localhost:9099 weight=10;
        server testshadow-shad-36587-default.seldon.svc.cluster.local:8000 weight=90;
    }
    upstream mirror2_backend {
        server localhost:9099 weight=80;
        server testshadow-shad-d1c85-default.seldon.svc.cluster.local:8000 weight=20;
    }
    server {
        listen 9099;
        location / {
            return 200;
        }
    }

    #gzip  on;
    server {
        listen       8000-8050;
        listen       9000-9050;
        server_name  _;

        location / {
            mirror /mirror1;
            mirror /mirror2;
            proxy_pass  http://backends;

            proxy_method $request_method;

            mirror_request_body on;
            proxy_pass_request_body on;

            proxy_set_header Host $host:$server_port;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Real-PORT $remote_port;
            proxy_set_header X-Forwarded-Proto $scheme;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        }

        location = /mirror1 {
            internal;
            resolver 127.0.0.11 valid=10s;
            proxy_pass http://mirror1_backend$request_uri;

            proxy_method $request_method;

            mirror_request_body on;
            proxy_pass_request_body on;

            proxy_set_header Host $host:$server_port;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Real-PORT $remote_port;
            proxy_set_header X-Forwarded-Proto $scheme;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        }
        location = /mirror2 {
            internal;
            resolver 127.0.0.11 valid=10s;
            proxy_pass http://mirror2_backend$request_uri;

            proxy_method $request_method;

            mirror_request_body on;
            proxy_pass_request_body on;

            proxy_set_header Host $host:$server_port;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Real-PORT $remote_port;
            proxy_set_header X-Forwarded-Proto $scheme;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        }
}

现在已经将请求转发给了mirror1和mirror2,并且分配了比例到相关的服务。
testshadow-shad-36587-default.seldon.svc.cluster.local:8000 和 testshadow-shad-d1c85-default.seldon.svc.cluster.local:8000 是我的测试服务,分别为testS1和testS2。
testS1和testS2接收完全相同的输入,但是输出不一样。
现在的目的是把流量发给testS1和testS2的request和response都记录下来;
我看网上有办法记录到access_log。但是我是要把request和response合计发送给另一个服务,叫做bizlog服务。

现在的问题是,如何收集testS1和testS2的request和response,并且发送给bizlog服务?

阅读 1.5k
avatarAI BotBETA

在Nginx中,直接捕获和转发HTTP响应给另一个服务(如bizlog服务)通常不是Nginx核心功能的一部分,因为Nginx主要设计用于处理请求并代理或转发这些请求到后端服务器。然而,你可以通过几种方法来实现这一需求:

方法1: 使用第三方模块

Nginx的第三方模块如nginx-module-vts(主要用于监控和统计)可能不完全满足需求,但类似的功能模块可能存在于其他第三方库中,如nginx-http-lua-module。Lua模块可以让你在Nginx中执行Lua脚本,从而更灵活地处理请求和响应。

方法2: 使用Lua模块

如果你选择使用Lua模块(如OpenResty),你可以编写Lua脚本来拦截请求和响应,并将它们发送到bizlog服务。以下是一个基本的示例框架:

  1. 安装OpenResty:OpenResty是一个基于Nginx和Lua的Web平台。
  2. 配置Lua脚本:在Nginx配置中使用Lua脚本来拦截请求和响应。
http {
    lua_package_path "/path/to/lua-resty-modules/?.lua;;";

    server {
        listen 80;

        location / {
            # 使用Lua脚本处理请求和响应
            access_by_lua_block {
                # 处理请求
                local req_body = ngx.var.request_body;  # 注意:对于POST请求,这可能需要特别处理
                # 发送请求到bizlog服务
                # 注意:这里只是一个示意,实际发送需要使用HTTP客户端库,如resty.http
            }

            proxy_pass http://backends;

            header_filter_by_lua_block {
                # 处理响应头
                # 这里可以读取响应头并发送到bizlog服务
            }

            body_filter_by_lua_block {
                # 逐步处理响应体
                # 可以在这里将响应体内容逐步发送到bizlog服务
            }

            log_by_lua_block {
                # 响应结束后处理
                # 如果需要发送整个响应体,可以在这里完成
            }
        }
    }
}

注意:上面的示例中ngx.var.request_body通常不直接包含POST请求体,因为Nginx在默认情况下不会存储整个请求体到变量中。你可能需要使用ngx_http_lua_module提供的ngx.req.read_body或类似的函数来读取请求体。

  1. 发送数据到bizlog服务:在Lua脚本中,你可以使用resty.http等库来向bizlog服务发送HTTP请求。

方法3: 自定义Nginx模块

如果你对Nginx的内部工作机制非常熟悉,你可以考虑编写自定义的Nginx模块来处理这一需求。这种方法需要较深的C语言知识和对Nginx源码的深入理解。

结论

对于大多数用户来说,使用Lua模块(如OpenResty)是最灵活和强大的解决方案。这允许你几乎以任何方式处理HTTP请求和响应,包括将它们发送到另一个服务。如果你不熟悉Lua或OpenResty,你可能需要花一些时间来学习这些技术。

2 个回答
http {
    user  nginx;
    worker_processes  auto;

    error_log  /var/log/nginx/error.log  notice;
    pid        /var/run/nginx.pid;

    events {
        worker_connections  1024;
    }

    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    log_format main '$remote_addr - $remote_user [$time_local] "$request" '
        '"$status" $body_bytes_sent "$http_referer" '
        '"$http_user_agent" "$http_x_forwarded_for" '
        '"$gzip_ratio" $request_time $bytes_sent $request_length';

    open_log_file_cache max=1000 inactive=60s;

    access_log  /var/log/nginx/access.log  main;

    sendfile        on;
    keepalive_timeout  65;

    upstream backends {
        server localhost:9099;
    }
    
    upstream mirror1_backend {
        server localhost:9099 weight=10;
        server testshadow-shad-36587-default.seldon.svc.cluster.local:8000 weight=90;
    }
    
    upstream mirror2_backend {
        server localhost:9099 weight=80;
        server testshadow-shad-d1c85-default.seldon.svc.cluster.local:8000 weight=20;
    }

    server {
        listen 9099;
        location / {
            return 200;
        }
    }

    server {
        listen 8000-8050;
        listen 9000-9050;
        server_name _;

        location / {
            mirror /mirror1;
            mirror /mirror2;
            proxy_pass http://backends;

            mirror_request_body on;
            proxy_pass_request_body on;

            proxy_set_header Host $host:$server_port;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Real-PORT $remote_port;
            proxy_set_header X-Forwarded-Proto $scheme;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        }

        location = /mirror1 {
            internal;
            resolver 127.0.0.11 valid=10s;
            proxy_pass http://mirror1_backend$request_uri;

            log_subrequest on; 
            proxy_pass_request_body on;

            proxy_set_header Content-Type application/json; 
            proxy_pass http://bizlog_service; 
        }

        location = /mirror2 {
            internal;
            resolver 127.0.0.11 valid=10s;
            proxy_pass http://mirror2_backend$request_uri;

            log_subrequest on; 
            proxy_pass_request_body on;

            proxy_set_header Content-Type application/json; 
            proxy_pass http://bizlog_service; 
        }
    }
}

使用mirror指令将请求复制到/mirror1/mirror2
/mirror1/mirror2的位置中,设置internal;使其仅能被内部调用。
使用proxy_pass将请求转发到目标服务(如testS1testS2)。
使用log_subrequest on;启用子请求日志,这样可以记录镜像的请求。
将镜像的请求体和响应体发送到bizlog_service。确保将Content-Type设置为JSON,以便于后端解析。
最后,确保bizlog_service可以接收并处理来自NginxPOST请求。

新手上路,请多包涵

看了AI的回复,我已经使用Lua脚本去记录response,并且成功拿到了结果。

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
宣传栏