ngixn mirror及子请求源码分析
字数 808 2025-08-15 21:32:49

Nginx Mirror及子请求源码深度解析

1. 核心数据结构

Nginx处理mirror和子请求时主要依赖两个核心数据结构:

1.1 postponed链表

struct ngx_http_postponed_request_s {
    ngx_http_request_t *request;  // 指向请求对象
    ngx_chain_t *out;             // 输出链
    ngx_http_postponed_request_t *next;  // 下一个节点
};
  • 每个请求都有一个postponed链表
  • 一般情况下每个链表节点保存了该请求的一个子请求
  • 用于控制请求处理的顺序和输出顺序

1.2 posted_requests链表

struct ngx_http_posted_request_s {
    ngx_http_request_t *request;  // 指向请求对象
    ngx_http_posted_request_t *next;  // 下一个节点
};
  • 挂载当前需要遍历的请求
  • 保存在主请求(根节点)的posted_requests字段
  • 用于异步处理请求队列

2. Mirror模块配置

典型mirror配置示例:

server {
    listen 10.10.10.10:8080;
    
    location / {
        mirror /mirror;  # 指定mirror路径
        proxy_pass http://vedio_play_support;
        session_sticky_hide_cookie upstream=vedio_play_support;
    }
    
    location = /mirror {
        internal;  # 内部location
        proxy_pass http://backend$request_uri;
    }
}

3. Mirror处理流程

3.1 处理入口

mirror handler处于precontent阶段:

static ngx_int_t ngx_http_mirror_handler(ngx_http_request_t *r)
{
    mlcf = ngx_http_get_module_loc_conf(r, ngx_http_mirror_module);
    
    // 如果需要接收请求体
    if (mlcf->request_body) {
        rc = ngx_http_read_client_request_body(r, ngx_http_mirror_body_handler);
    }
    
    return ngx_http_mirror_handler_internal(r);
}

3.2 请求体处理回调

当请求体接收完成后调用的回调函数:

static void ngx_http_mirror_body_handler(ngx_http_request_t *r)
{
    ngx_http_mirror_ctx_t *ctx;
    ctx = ngx_http_get_module_ctx(r, ngx_http_mirror_module);
    
    // 创建子请求并与主请求关联
    ctx->status = ngx_http_mirror_handler_internal(r);
    
    r->preserve_body = 1;
    
    // 主请求继续执行处理阶段
    r->write_event_handler = ngx_http_core_run_phases;
    ngx_http_core_run_phases(r);
}

3.3 创建子请求

static ngx_int_t ngx_http_mirror_handler_internal(ngx_http_request_t *r)
{
    // 遍历mirror数组,生成subrequest
    for (i = 0; i < mlcf->mirror->nelts; i++) {
        if (ngx_http_subrequest(r, &name[i], &r->args, &sr, NULL, 
                               NGX_HTTP_SUBREQUEST_BACKGROUND) != NGX_OK) {
            return NGX_HTTP_INTERNAL_SERVER_ERROR;
        }
        
        sr->header_only = 1;
        sr->method = r->method;
        sr->method_name = r->method_name;
    }
    
    return NGX_DECLINED;
}

4. 子请求处理机制

4.1 创建子请求

ngx_int_t ngx_http_subrequest(ngx_http_request_t *r, ngx_str_t *uri, 
                             ngx_str_t *args, ngx_http_request_t **psr, 
                             ngx_http_post_subrequest_t *ps, ngx_uint_t flags)
{
    // 申请新的request结构
    sr = ngx_pcalloc(r->pool, sizeof(ngx_http_request_t));
    
    // 如果不是background模式(mirror默认使用background模式)
    if (!sr->background) {
        if (c->data == r && r->postponed == NULL) {
            c->data = sr;
        }
        
        // 申请postponed_request结构体包装子请求
        pr = ngx_palloc(r->pool, sizeof(ngx_http_postponed_request_t));
        pr->request = sr;
        pr->out = NULL;
        pr->next = NULL;
        
        // 将pr挂到r->postponed链表里
        if (r->postponed) {
            for (p = r->postponed; p->next; p = p->next) { /* void */ }
            p->next = pr;
        } else {
            r->postponed = pr;
        }
    }
    
    sr->internal = 1;
    sr->method = NGX_HTTP_GET;
    sr->read_event_handler = ngx_http_request_empty_handler;
    sr->write_event_handler = ngx_http_handler;
    
    r->main->count++;
    *psr = sr;
    
    // 将子请求挂到main request的posted_requests中
    return ngx_http_post_request(sr, NULL);
}

4.2 将请求加入posted队列

ngx_int_t ngx_http_post_request(ngx_http_request_t *r, 
                               ngx_http_posted_request_t *pr)
{
    if (pr == NULL) {
        pr = ngx_palloc(r->pool, sizeof(ngx_http_posted_request_t));
        pr->request = r;
        pr->next = NULL;
        
        // 找到main request的posted_requests,放到末尾
        for (p = &r->main->posted_requests; *p; p = &(*p)->next) { /* void */ }
        *p = pr;
    }
    // ...
}

4.3 运行posted请求

void ngx_http_run_posted_requests(ngx_connection_t *c)
{
    ngx_http_request_t *r;
    ngx_http_posted_request_t *pr;
    
    r = c->data;
    
    // 从main开始遍历所有子请求
    pr = r->main->posted_requests;
    if (pr == NULL) {
        return;
    }
    
    r->main->posted_requests = pr->next;
    r = pr->request;
    
    // 调用write event handler,mirror的handler是ngx_http_handler
    r->write_event_handler(r);
}

5. 请求处理阶段

5.1 请求处理器

void ngx_http_handler(ngx_http_request_t *r)
{
    if (!r->internal) {
        // 处理外部请求的连接类型
        switch (r->headers_in.connection_type) {
            // ...处理各种连接类型...
        }
        r->phase_handler = 0;  // 从第一个阶段开始
    } else {
        // 对于mirror等内部请求,从server_rewrite阶段开始
        cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);
        r->phase_handler = cmcf->phase_engine.server_rewrite_index;
    }
    
    // 执行处理阶段
    r->write_event_handler = ngx_http_core_run_phases;
    ngx_http_core_run_phases(r);
}

5.2 请求头处理

static void ngx_http_process_request_headers(ngx_event_t *rev)
{
    // 成功解析完整个header后
    rc = ngx_http_process_request_header(r);
    if (rc != NGX_OK) {
        break;
    }
    
    ngx_http_process_request(r);
    
    // 运行子请求
    ngx_http_run_posted_requests(c);
}

6. 请求终结处理

6.1 终结请求函数

void ngx_http_finalize_request(ngx_http_request_t *r, ngx_int_t rc)
{
    // 如果是子请求且有回调函数
    if (r != r->main && r->post_subrequest) {
        rc = r->post_subrequest->handler(r, r->post_subrequest->data, rc);
    }
    
    // 处理子请求
    if (r != r->main) {
        // background模式直接关闭request
        if (r->background) {
            r->done = 1;
            ngx_http_finalize_connection(r);
            return;
        }
        
        // 还有未处理完的数据或子请求
        if (r->buffered || r->postponed) {
            // 添加写事件以便下次继续处理
            if (ngx_http_set_write_handler(r) != NGX_OK) {
                ngx_http_terminate_request(r, 0);
            }
            return;
        }
        
        pr = r->parent;
        
        // 子请求处理完毕
        if (r == c->data) {
            r->main->count--;
            r->done = 1;
            
            // 从父请求的postponed链表中删除
            if (pr->postponed && pr->postponed->request == r) {
                pr->postponed = pr->postponed->next;
            }
            
            // 将c->data指向parent
            c->data = pr;
        } else {
            // 子请求提前完成且没有产生数据
            r->write_event_handler = ngx_http_request_finalizer;
            if (r->waited) {
                r->done = 1;
                
                // 将父请求加入posted_request队尾
                if (ngx_http_post_request(pr, NULL) != NGX_OK) {
                    r->main->count++;
                    ngx_http_terminate_request(r, 0);
                    return;
                }
            }
        }
    }
    
    // 处理主请求结束逻辑
    if (r->buffered || c->buffered || r->postponed || r->blocked) {
        // 添加写事件以便下次继续处理
        if (ngx_http_set_write_handler(r) != NGX_OK) {
            ngx_http_terminate_request(r, 0);
        }
        return;
    }
    // ...
}

7. 响应处理逻辑

7.1 upstream响应处理

static void ngx_http_upstream_process_header(ngx_http_request_t *r, 
                                           ngx_http_upstream_t *u)
{
    ngx_http_upstream_send_response(r, u);
}

static void ngx_http_upstream_send_response(ngx_http_request_t *r, 
                                          ngx_http_upstream_t *u)
{
    rc = ngx_http_send_header(r);
    p->output_filter = ngx_http_upstream_output_filter;
}

static ngx_int_t ngx_http_upstream_output_filter(void *data, ngx_chain_t *chain)
{
    rc = ngx_http_output_filter(r, chain);
}

7.2 输出过滤器链

ngx_int_t ngx_http_send_header(ngx_http_request_t *r)
{
    return ngx_http_top_header_filter(r);
}

ngx_int_t ngx_http_output_filter(ngx_http_request_t *r, ngx_chain_t *in)
{
    rc = ngx_http_top_body_filter(r, in);
}

7.3 延迟过滤器

static ngx_int_t ngx_http_postpone_filter(ngx_http_request_t *r, ngx_chain_t *in)
{
    ngx_connection_t *c;
    ngx_http_postponed_request_t *pr;
    
    c = r->connection;
    
    // 如果r不等于c->data,说明是需要保存数据的父request
    if (r != c->data) {
        if (in) {
            // 保存数据
            ngx_http_postpone_filter_add(r, in);
            return NGX_OK;
        }
        return NGX_OK;
    }
    
    // 如果r->postponed为空,说明是最后一个sub request
    if (r->postponed == NULL) {
        // 发送数据
        if (in || c->buffered) {
            return ngx_http_next_filter(r->main, in);
        }
        return NGX_OK;
    }
    // ...
}

8. 关键点总结

  1. 子请求特性

    • 子请求不存在响应头部的概念
    • 子请求读事件设置为空,不受前端控制
    • 默认从server_rewrite阶段开始处理
  2. 处理顺序控制

    • postponed链表控制子请求的处理顺序
    • posted_requests链表管理待处理请求队列
  3. Mirror模块特点

    • 使用background模式创建子请求
    • 主请求和mirror请求并行处理
    • mirror请求默认header_only=1
  4. 输出控制

    • 通过postpone_filter控制响应输出顺序
    • 子请求的输出会被缓存直到轮到它发送
  5. 请求生命周期

    • 通过finalize_request函数统一处理请求终结
    • 主请求和子请求有不同的终结路径
Nginx Mirror及子请求源码深度解析 1. 核心数据结构 Nginx处理mirror和子请求时主要依赖两个核心数据结构: 1.1 postponed链表 每个请求都有一个postponed链表 一般情况下每个链表节点保存了该请求的一个子请求 用于控制请求处理的顺序和输出顺序 1.2 posted_ requests链表 挂载当前需要遍历的请求 保存在主请求(根节点)的posted_ requests字段 用于异步处理请求队列 2. Mirror模块配置 典型mirror配置示例: 3. Mirror处理流程 3.1 处理入口 mirror handler处于precontent阶段: 3.2 请求体处理回调 当请求体接收完成后调用的回调函数: 3.3 创建子请求 4. 子请求处理机制 4.1 创建子请求 4.2 将请求加入posted队列 4.3 运行posted请求 5. 请求处理阶段 5.1 请求处理器 5.2 请求头处理 6. 请求终结处理 6.1 终结请求函数 7. 响应处理逻辑 7.1 upstream响应处理 7.2 输出过滤器链 7.3 延迟过滤器 8. 关键点总结 子请求特性 : 子请求不存在响应头部的概念 子请求读事件设置为空,不受前端控制 默认从server_ rewrite阶段开始处理 处理顺序控制 : postponed链表控制子请求的处理顺序 posted_ requests链表管理待处理请求队列 Mirror模块特点 : 使用background模式创建子请求 主请求和mirror请求并行处理 mirror请求默认header_ only=1 输出控制 : 通过postpone_ filter控制响应输出顺序 子请求的输出会被缓存直到轮到它发送 请求生命周期 : 通过finalize_ request函数统一处理请求终结 主请求和子请求有不同的终结路径