From cd807e43aabe7d2ac3a9292180f943ece6e6f85a Mon Sep 17 00:00:00 2001 From: xfy Date: Thu, 16 Apr 2026 11:09:26 +0800 Subject: [PATCH] =?UTF-8?q?docs(nginx):=20=E6=B7=BB=E5=8A=A0=20nginx=20?= =?UTF-8?q?=E6=BA=90=E7=A0=81=E6=9E=B6=E6=9E=84=E5=88=86=E6=9E=90=E6=96=87?= =?UTF-8?q?=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Upstream 模块源码实现分析(负载均衡算法、故障转移) - Stream 模块架构分析(TCP/UDP 代理处理流程) - Mail 模块架构概述(IMAP/POP3/SMTP 协议支持) - 事件模块源码架构(定时器、epoll、QUIC) - 变量系统源码实现(索引变量、前缀变量机制) 基于 nginx 1.31.0 源码分析 Co-Authored-By: Claude Opus 4.6 --- docs/nginx/00-nginx-source-architecture.md | 894 +++++++++++++++++++++ docs/nginx/04-nginx-proxy-loadbalancing.md | 215 ++++- docs/nginx/10-nginx-stream-tcp-udp.md | 172 +++- docs/nginx/24-nginx-core-events.md | 217 +++++ docs/nginx/25-nginx-variables-reference.md | 104 ++- 5 files changed, 1598 insertions(+), 4 deletions(-) create mode 100644 docs/nginx/00-nginx-source-architecture.md diff --git a/docs/nginx/00-nginx-source-architecture.md b/docs/nginx/00-nginx-source-architecture.md new file mode 100644 index 0000000..6f5bd5e --- /dev/null +++ b/docs/nginx/00-nginx-source-architecture.md @@ -0,0 +1,894 @@ +# NGINX 源码架构深度分析 + +基于 nginx 1.31.0 源码(lib/nginx)的架构分析文档。 + +--- + +## 1. 目录结构概览 + +``` +lib/nginx/src/ +├── core/ # 核心模块(40+ 文件) +│ ├── nginx.c # 主程序入口 +│ ├── ngx_cycle.c # 配置周期管理 +│ ├── ngx_connection.c # 连接管理 +│ ├── ngx_module.c # 模块系统 +│ └── ... +├── event/ # 事件模块 +│ ├── ngx_event.c # 事件驱动核心 +│ ├── ngx_event_openssl.c # SSL(163KB) +│ ├── modules/ # IO 多路复用实现 +│ │ ├── ngx_epoll_module.c +│ │ ├── ngx_kqueue_module.c +│ │ └── ... +│ └── quic/ # QUIC/HTTP3 支持(33 文件) +├── http/ # HTTP 模块 +│ ├── ngx_http.c # HTTP 模块核心 +│ ├── ngx_http_core_module.c # HTTP 核心(149KB) +│ ├── ngx_http_request.c # 请求处理(105KB) +│ ├── ngx_http_upstream.c # 上游代理(187KB) +│ ├── ngx_http_variables.c # 变量系统(70KB) +│ ├── modules/ # HTTP 子模块(63 个) +│ ├── v2/ # HTTP/2 实现 +│ └── v3/ # HTTP/3 实现 +├── stream/ # TCP/UDP Stream 模块(32 文件) +├── mail/ # 邮件代理模块 +└── os/ # 操作系统适配 +``` + +**源码统计**:395 个 C/H 文件,HTTP 子模块 63 个,事件模块支持 epoll/kqueue/eventport/iocp 等。 + +--- + +## 2. 核心数据结构 + +### 2.1 ngx_cycle_t - 配置周期 + +nginx 运行时配置周期的核心结构,管理整个进程的生命周期状态。 + +```c +// src/core/ngx_cycle.h +struct ngx_cycle_s { + void ****conf_ctx; // 配置上下文层级 + ngx_pool_t *pool; // 内存池 + + ngx_log_t *log; // 日志对象 + ngx_log_t new_log; // 新日志(reload) + + ngx_connection_t **files; // 文件描述符->连接映射表 + ngx_connection_t *free_connections; // 空闲连接链表 + ngx_uint_t free_connection_n; // 空闲连接数 + + ngx_module_t **modules; // 模块数组 + ngx_uint_t modules_n; // 模块数量 + + ngx_queue_t reusable_connections_queue; // 可复用连接队列 + + ngx_array_t listening; // 监听端口数组 + ngx_array_t paths; // 路径数组 + + ngx_list_t open_files; // 打开的文件列表 + ngx_list_t shared_memory; // 共享内存区域列表 + + ngx_uint_t connection_n; // 总连接数 + ngx_connection_t *connections; // 连接数组 + ngx_event_t *read_events; // 读事件数组 + ngx_event_t *write_events; // 写事件数组 + + ngx_cycle_t *old_cycle; // 旧周期(用于 upgrade) + + ngx_str_t conf_file; // 配置文件路径 + ngx_str_t conf_prefix; // 配置前缀 + ngx_str_t prefix; // 安装前缀 + ngx_str_t error_log; // 错误日志路径 + ngx_str_t lock_file; // 锁文件 + ngx_str_t hostname; // 主机名 +}; +``` + +**生命周期阶段**: +1. `ngx_init_cycle()` - 初始化新周期(读取配置、创建监听、分配连接) +2. 配置 reload 时创建新 cycle,旧 cycle 被保留用于回滚 +3. 升级时新旧 cycle 共存(`ngx_old_cycles` 数组) + +### 2.2 ngx_connection_t - 连接结构 + +表示一个网络连接(客户端或上游)。 + +```c +// src/core/ngx_connection.h +struct ngx_connection_s { + void *data; // 模块私有数据(HTTP 请求等) + ngx_event_t *read; // 读事件 + ngx_event_t *write; // 写事件 + + ngx_socket_t fd; // 文件描述符 + + ngx_recv_pt recv; // 接收函数指针 + ngx_send_pt send; // 发送函数指针 + ngx_recv_chain_pt recv_chain; // 链式接收 + ngx_send_chain_pt send_chain; // 链式发送 + + ngx_listening_t *listening; // 关联的监听端口 + + off_t sent; // 已发送字节数 + + ngx_log_t *log; // 日志对象 + + ngx_pool_t *pool; // 内存池 + + int type; // 连接类型(SOCK_STREAM/SOCK_DGRAM) + + struct sockaddr *sockaddr; // 远端地址 + socklen_t socklen; // 地址长度 + ngx_str_t addr_text; // 地址文本 + + ngx_proxy_protocol_t *proxy_protocol; // PROXY 协议信息 + +#if (NGX_QUIC || NGX_COMPAT) + ngx_quic_stream_t *quic; // QUIC 流 +#endif + +#if (NGX_SSL || NGX_COMPAT) + ngx_ssl_connection_t *ssl; // SSL 连接 +#endif + + ngx_udp_connection_t *udp; // UDP 连接 + + struct sockaddr *local_sockaddr; // 本端地址 + socklen_t local_socklen; + + ngx_buf_t *buffer; // 缓冲区 + + ngx_queue_t queue; // 连接队列节点 + + ngx_atomic_uint_t number; // 连接序号(全局唯一) + ngx_msec_t start_time; // 连接开始时间 + ngx_uint_t requests; // 请求数(HTTP keepalive) + + unsigned buffered:8; // 缓冲状态位 + + unsigned log_error:3; // 错误日志级别 + + unsigned timedout:1; // 是否超时 + unsigned error:1; // 是否错误 + unsigned destroyed:1; // 是否已销毁 + unsigned pipeline:1; // 是否 pipeline 模式 + + unsigned idle:1; // 是否空闲(keepalive) + unsigned reusable:1; // 是否可复用 + unsigned close:1; // 是否需要关闭 + unsigned shared:1; // 是否共享 + + unsigned sendfile:1; // 是否启用 sendfile + unsigned tcp_nodelay:2; // TCP_NODELAY 状态 + unsigned tcp_nopush:2; // TCP_NOPUSH 状态 +}; +``` + +### 2.3 ngx_event_t - 事件结构 + +事件驱动模型的核心。 + +```c +// src/event/ngx_event.h +struct ngx_event_s { + void *data; // 关联的连接或其他数据 + + unsigned write:1; // 是否写事件 + unsigned accept:1; // 是否接受连接事件 + + unsigned instance:1; // 实例标记(防止 stale event) + + unsigned active:1; // 是否已添加到事件驱动 + unsigned disabled:1; // 是否禁用 + + unsigned ready:1; // 是否就绪(可读/可写) + unsigned oneshot:1; // 是否一次性事件 + + unsigned complete:1; // AIO 操作是否完成 + + unsigned eof:1; // 是否 EOF + unsigned error:1; // 是否错误 + + unsigned timedout:1; // 是否超时 + unsigned timer_set:1; // 是否设置了定时器 + + unsigned delayed:1; // 是否延迟 + + unsigned posted:1; // 是否已投递到 posted 队列 + + ngx_event_handler_pt handler; // 事件处理函数 + + ngx_rbtree_node_t timer; // 定时器红黑树节点 + + ngx_queue_t queue; // posted 队列节点 +}; +``` + +### 2.4 ngx_http_request_t - HTTP 请求结构 + +HTTP 请求处理的核心结构。 + +```c +// src/http/ngx_http_request.h +struct ngx_http_request_s { + uint32_t signature; /* "HTTP" */ + + ngx_connection_t *connection; // 底层连接 + + void **ctx; // 模块上下文数组 + void **main_conf; // main 配置 + void **srv_conf; // server 配置 + void **loc_conf; // location 配置 + + ngx_http_event_handler_pt read_event_handler; + ngx_http_event_handler_pt write_event_handler; + +#if (NGX_HTTP_CACHE) + ngx_http_cache_t *cache; // 缓存对象 +#endif + + ngx_http_upstream_t *upstream; // 上游对象 + ngx_array_t *upstream_states; // 上游状态记录 + + ngx_pool_t *pool; // 请求内存池 + ngx_buf_t *header_in; // 请求头缓冲 + + ngx_http_headers_in_t headers_in; // 请求头结构 + ngx_http_headers_out_t headers_out; // 响应头结构 + + ngx_http_request_body_t *request_body; // 请求体 + + time_t start_sec; // 请求开始时间 + ngx_msec_t start_msec; + + ngx_uint_t method; // HTTP 方法 + ngx_uint_t http_version; // HTTP 版本 + + ngx_str_t request_line; // 请求行 + ngx_str_t uri; // URI + ngx_str_t args; // 参数 + ngx_str_t exten; // 扩展名 + ngx_str_t unparsed_uri; // 原始 URI + + ngx_chain_t *out; // 输出链 + + ngx_http_request_t *main; // 主请求 + ngx_http_request_t *parent; // 父请求(子请求) + ngx_http_postponed_request_t *postponed; // 延迟请求队列 + ngx_http_posted_request_t *posted_requests; // 投递请求队列 + + ngx_int_t phase_handler; // 阶段处理位置 + ngx_http_handler_pt content_handler; // content 处理函数 + + ngx_http_variable_value_t *variables; // 变量值数组 + +#if (NGX_PCRE) + ngx_uint_t ncaptures; // 正则捕获数 + int *captures; // 捕获数组 +#endif + + size_t limit_rate; // 限速 + off_t request_length; // 请求长度 + + ngx_uint_t err_status; // 错误状态码 + + ngx_http_connection_t *http_connection; // HTTP 连接 + ngx_http_v2_stream_t *stream; // HTTP/2 流 + ngx_http_v3_parse_t *v3_parse; // HTTP/3 解析 + + unsigned count:16; // 引用计数 + unsigned subrequests:8; // 子请求限制 + unsigned blocked:8; // 阻塞计数 + + unsigned http_state:4; // HTTP 状态 + + unsigned pipeline:1; // pipeline 模式 + unsigned chunked:1; // chunked 编码 + unsigned header_only:1; // 只需头 + unsigned keepalive:1; // keepalive + unsigned internal:1; // 内部请求 + unsigned header_sent:1; // 头已发送 + unsigned response_sent:1; // 响应已发送 +}; +``` + +--- + +## 3. 启动流程 + +### 3.1 main() 函数流程 + +```c +// src/core/nginx.c +int main(int argc, char *const *argv) +{ + // 1. 解析命令行参数 + ngx_get_options(argc, argv); + + // 2. 初始化时间、日志、内存池 + ngx_time_init(); + ngx_log_init(); + + // 3. 初始化 cycle(核心) + cycle = ngx_init_cycle(&init_cycle); + + // 4. 根据运行模式启动 + if (ngx_process == NGX_PROCESS_SINGLE) { + // 单进程模式 + ngx_single_process_cycle(cycle); + } else { + // master-worker 模式 + ngx_master_process_cycle(cycle); + } +} +``` + +### 3.2 ngx_init_cycle() - 配置周期初始化 + +```c +// src/core/ngx_cycle.c +ngx_cycle_t *ngx_init_cycle(ngx_cycle_t *old_cycle) +{ + // 1. 创建内存池 + pool = ngx_create_pool(NGX_CYCLE_POOL_SIZE, log); + + // 2. 分配 cycle 结构 + cycle = ngx_pcalloc(pool, sizeof(ngx_cycle_t)); + + // 3. 保存命令行参数 + cycle->conf_file = old_cycle->conf_file; + + // 4. 解析配置文件 + conf.ctx = ngx_conf_create_context(cycle); + ngx_conf_parse(&conf, &cycle->conf_file); + + // 5. 打开监听端口 + ngx_open_listening_sockets(cycle); + + // 6. 配置监听 socket 参数 + ngx_configure_listening_sockets(cycle); + + // 7. 分配连接和事件数组 + cycle->connections = ngx_alloc(sizeof(ngx_connection_t) * n, log); + cycle->read_events = ngx_alloc(sizeof(ngx_event_t) * n, log); + cycle->write_events = ngx_alloc(sizeof(ngx_event_t) * n, log); + + // 8. 初始化模块 + for (i = 0; cycle->modules[i]; i++) { + if (cycle->modules[i]->init_module) { + cycle->modules[i]->init_module(cycle); + } + } + + // 9. 初始化共享内存 + ngx_init_zones(cycle, old_cycle); + + // 10. 创建 PID 文件 + ngx_create_pidfile(&cycle->pid, log); +} +``` + +--- + +## 4. 事件驱动模型 + +### 4.1 ngx_event_actions_t - 事件操作接口 + +```c +// src/event/ngx_event.h +typedef struct { + ngx_int_t (*add)(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags); + ngx_int_t (*del)(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags); + + ngx_int_t (*enable)(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags); + ngx_int_t (*disable)(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags); + + ngx_int_t (*add_conn)(ngx_connection_t *c); + ngx_int_t (*del_conn)(ngx_connection_t *c, ngx_uint_t flags); + + ngx_int_t (*notify)(ngx_event_handler_pt handler); + + ngx_int_t (*process_events)(ngx_cycle_t *cycle, ngx_msec_t timer, + ngx_uint_t flags); + + ngx_int_t (*init)(ngx_cycle_t *cycle, ngx_msec_t timer); + void (*done)(ngx_cycle_t *cycle); +} ngx_event_actions_t; +``` + +### 4.2 事件处理主循环 + +```c +// src/event/ngx_event.c +void ngx_process_events_and_timers(ngx_cycle_t *cycle) +{ + // 1. 计算定时器超时 + timer = ngx_event_find_timer(); + + // 2. 尝试获取 accept mutex(防止惊群) + if (ngx_trylock_accept_mutex(cycle) == NGX_OK) { + // 获得 mutex,设置 accept 事件 + flags |= NGX_POST_EVENTS; + } + + // 3. 处理事件(调用 epoll_wait 等) + ngx_process_events(cycle, timer, flags); + + // 4. 处理 posted 事件队列 + if (ngx_accept_mutex_held) { + ngx_unlock_accept_mutex(); + } + + ngx_event_process_posted(cycle, &ngx_posted_accept_events); + ngx_event_process_posted(cycle, &ngx_posted_events); + + // 5. 处理定时器 + ngx_event_expire_timers(); +} +``` + +### 4.3 epoll 实现(Linux) + +```c +// src/event/modules/ngx_epoll_module.c +static ngx_int_t ngx_epoll_process_events(ngx_cycle_t *cycle, + ngx_msec_t timer, ngx_uint_t flags) +{ + // 调用 epoll_wait + events = epoll_wait(ep, event_list, nevents, timer); + + for (i = 0; i < events; i++) { + c = event_list[i].data.ptr; + + // 判断事件类型 + if ((event_list[i].events & EPOLLIN) && rev->active) { + rev->ready = 1; + if (flags & NGX_POST_EVENTS) { + // 投递到队列 + ngx_post_event(rev, queue); + } else { + // 直接调用处理函数 + rev->handler(rev); + } + } + + if ((event_list[i].events & EPOLLOUT) && wev->active) { + wev->ready = 1; + // 同上处理... + } + } +} +``` + +### 4.4 定时器实现(红黑树) + +```c +// src/event/ngx_event_timer.c +void ngx_event_add_timer(ngx_event_t *ev, ngx_msec_t timer) +{ + key = ngx_current_msec + timer; + + // 插入红黑树 + ngx_rbtree_insert(&ngx_event_timer_rbtree, &ev->timer); +} + +ngx_msec_int_t ngx_event_find_timer(void) +{ + // 返回最小节点的超时时间 + node = ngx_rbtree_min(root, sentinel); + timer = (ngx_msec_int_t) (node->key - ngx_current_msec); + return timer > 0 ? timer : 0; +} +``` + +--- + +## 5. HTTP 请求处理 + +### 5.1 请求处理阶段 + +```c +// src/http/ngx_http_request.c +// HTTP 状态枚举 +typedef enum { + NGX_HTTP_INITING_REQUEST_STATE = 0, // 初始化 + NGX_HTTP_READING_REQUEST_STATE, // 读取请求 + NGX_HTTP_PROCESS_REQUEST_STATE, // 处理请求 + + NGX_HTTP_CONNECT_UPSTREAM_STATE, // 连接上游 + NGX_HTTP_WRITING_UPSTREAM_STATE, // 写入上游 + NGX_HTTP_READING_UPSTREAM_STATE, // 读取上游 + + NGX_HTTP_WRITING_REQUEST_STATE, // 写入响应 + NGX_HTTP_LINGERING_CLOSE_STATE, // lingering 关闭 + NGX_HTTP_KEEPALIVE_STATE // keepalive +} ngx_http_state_e; +``` + +### 5.2 HTTP 处理阶段(PHASE) + +nginx 的 HTTP 处理分为多个阶段,每个阶段可注册多个 handler: + +| 阶段 | 名称 | 说明 | +|------|------|------| +| 0 | NGX_HTTP_POST_READ_PHASE | 读取请求头后 | +| 1 | NGX_HTTP_SERVER_REWRITE_PHASE | server 级 rewrite | +| 2 | NGX_HTTP_FIND_CONFIG_PHASE | 查找 location(内部) | +| 3 | NGX_HTTP_REWRITE_PHASE | location 级 rewrite | +| 4 | NGX_HTTP_POST_REWRITE_PHASE | rewrite 后处理(内部) | +| 5 | NGX_HTTP_PREACCESS_PHASE | access 前处理 | +| 6 | NGX_HTTP_ACCESS_PHASE | 访问控制(allow/deny/auth) | +| 7 | NGX_HTTP_POST_ACCESS_PHASE | access 后处理(内部) | +| 8 | NGX_HTTP_PRECONTENT_PHASE | content 前处理 | +| 9 | NGX_HTTP_CONTENT_PHASE | 内容生成 | +| 10 | NGX_HTTP_LOG_PHASE | 日志记录 | + +### 5.3 location 匹配算法 + +```c +// src/http/ngx_http_core_module.c +ngx_http_core_find_location(ngx_http_request_t *r) +{ + // 使用 location tree(radix tree + 前缀匹配) + // 精确匹配 > 正则匹配 > 前缀匹配 +} +``` + +--- + +## 6. Upstream 负载均衡 + +### 6.1 ngx_http_upstream_t - 上游结构 + +```c +// src/http/ngx_http_upstream.h +struct ngx_http_upstream_s { + ngx_http_upstream_handler_pt read_event_handler; + ngx_http_upstream_handler_pt write_event_handler; + + ngx_peer_connection_t peer; // 对端连接 + + ngx_event_pipe_t *pipe; // 管道(流式传输) + + ngx_chain_t *request_bufs; // 请求缓冲 + + ngx_http_upstream_conf_t *conf; // upstream 配置 + ngx_http_upstream_srv_conf_t *upstream; // upstream 组配置 + + ngx_http_upstream_headers_in_t headers_in; // 上游响应头 + + ngx_buf_t buffer; // 响应缓冲 + + ngx_int_t (*create_request)(ngx_http_request_t *r); + ngx_int_t (*reinit_request)(ngx_http_request_t *r); + ngx_int_t (*process_header)(ngx_http_request_t *r); + void (*finalize_request)(ngx_http_request_t *r, + ngx_int_t rc); + + ngx_msec_t start_time; + + ngx_http_upstream_state_t *state; // 状态信息 + + unsigned store:1; + unsigned cacheable:1; + unsigned buffering:1; + unsigned keepalive:1; + unsigned upgrade:1; +}; +``` + +### 6.2 Round Robin 数据结构 + +```c +// src/http/ngx_http_upstream_round_robin.h +struct ngx_http_upstream_rr_peer_s { + ngx_str_t name; // 服务器名称 + ngx_addr_t *addrs; // 地址数组 + ngx_uint_t naddrs; // 地址数 + + ngx_uint_t weight; // 权重 + ngx_uint_t effective_weight; // 有效权重 + ngx_uint_t current_weight; // 当前权重 + + ngx_uint_t max_conns; // 最大连接数 + ngx_uint_t conns; // 当前连接数 + + ngx_uint_t max_fails; // 最大失败次数 + time_t fail_timeout; // 失败超时 + time_t accessed; // 最后访问时间 + time_t checked; // 最后检查时间 + + ngx_uint_t fails; // 失败次数 + + ngx_uint_t down; // 是否下线 + + unsigned backup:1; // 是否备份服务器 +}; + +struct ngx_http_upstream_rr_peers_s { + ngx_uint_t number; // 服务器数量 + + ngx_uint_t total_weight; // 总权重 + ngx_uint_t next_weight; // 下一个权重 + + ngx_http_upstream_rr_peer_t *peer; // 服务器数组 + + ngx_http_upstream_rr_peers_t *next; // 下一组(backup) + + ngx_uint_t weighted; // 是否加权 + + ngx_str_t *name; // 组名 + +#if (NGX_HTTP_UPSTREAM_ZONE) + ngx_shm_zone_t *shm_zone; // 共享内存区 + ngx_slab_pool_t *shpool; // slab 池 +#endif +}; +``` + +### 6.3 负载均衡算法实现 + +#### Weighted Round Robin(默认) + +```c +// src/http/ngx_http_upstream_round_robin.c +ngx_http_upstream_get_peer(ngx_peer_connection_t *pc, void *data) +{ + // 平滑加权轮询算法 + // 每次选择 current_weight 最大的服务器 + // 然后将其 current_weight 减去 total_weight + + for (p = peers->peer; p; p++) { + if (p->current_weight > best->current_weight) { + best = p; + } + } + + best->current_weight -= peers->total_weight; + + return best; +} +``` + +#### Least Connections + +```c +// src/http/modules/ngx_http_upstream_least_conn_module.c +ngx_http_upstream_get_least_conn_peer(ngx_peer_connection_t *pc, void *data) +{ + // 选择活动连接数最少的服务器 + // conns/effective_weight 作为比较因子 + + for (p = peers->peer; p; p++) { + if (p->conns * best->effective_weight + > best->conns * p->effective_weight) { + best = p; + } + } +} +``` + +#### Hash / Consistent Hash + +```c +// src/http/modules/ngx_http_upstream_hash_module.c +// 一致性哈希实现 +typedef struct { + uint32_t hash; + ngx_str_t *server; +} ngx_http_upstream_chash_point_t; + +typedef struct { + ngx_uint_t number; + ngx_http_upstream_chash_point_t point[1]; +} ngx_http_upstream_chash_points_t; + +// 虚拟节点分布在 0-2^32 的圆环上 +// 根据 key 的 hash 值查找最近的节点 +ngx_http_upstream_find_chash_point(points, hash); +``` + +--- + +## 7. SSL/TLS 实现 + +### 7.1 SSL 连接结构 + +```c +// src/event/ngx_event_openssl.h +typedef struct { + ngx_ssl_conn_t *connection; // SSL 连接 + + SSL_CTX *session_ctx; // 会话上下文 + + ngx_int_t last; // 最后操作结果 + + ngx_buf_t *buf; // 缓冲区 + + ngx_connection_handler_pt handler; // 处理函数 + + ngx_event_t *read; // 读事件 + ngx_event_t *write; // 写事件 + + ngx_uint_t buffer_size; // 缓冲区大小 + + ngx_str_t session; // 会话 ID + + unsigned handshaked:1; // 是否握手完成 + unsigned renegotiation:1; // 是否重协商 + unsigned buffer:1; // 是否缓冲 + unsigned no_wait_shutdown:1; + unsigned no_send_shutdown:1; +} ngx_ssl_connection_t; +``` + +### 7.2 SSL 握手流程 + +```c +// src/event/ngx_event_openssl.c +ngx_int_t ngx_ssl_handshake(ngx_connection_t *c) +{ + // 调用 SSL_do_handshake + n = SSL_do_handshake(c->ssl->connection); + + if (n == 1) { + // 握手完成 + c->ssl->handshaked = 1; + return NGX_OK; + } + + // 处理 WANT_READ/WANT_WRITE + sslerr = SSL_get_error(c->ssl->connection, n); +} +``` + +--- + +## 8. HTTP/2 与 HTTP/3 (QUIC) + +### 8.1 HTTP/2 模块结构 + +``` +src/http/v2/ +├── ngx_http_v2.c # HTTP/2 核心逻辑 +├── ngx_http_v2_filter_module.c # 响应过滤器 +├── ngx_http_v2_module.c # 配置指令处理 +├── ngx_http_v2_table.c # HPACK 动态表 +├── ngx_http_v2_encode.c # HPACK 编码 +└── ngx_http_v2.h # 数据结构定义 +``` + +### 8.2 HTTP/3 + QUIC 模块结构 + +``` +src/http/v3/ +├── ngx_http_v3.c # HTTP/3 核心 +├── ngx_http_v3_filter_module.c # 响应过滤器 +├── ngx_http_v3_parse.c # QPACK 解析 +├── ngx_http_v3_encode.c # QPACK 编码 +├── ngx_http_v3_table.c # QPACK 动态表 +├── ngx_http_v3_request.c # 请求处理 +├── ngx_http_v3_uni.c # 单向流处理 + +src/event/quic/ +├── ngx_event_quic.c # QUIC 连接核心 +├── ngx_event_quic_transport.c # QUIC 包传输 +├── ngx_event_quic_protection.c # 加密保护 +├── ngx_event_quic_frames.c # QUIC 帧 +├── ngx_event_quic_streams.c # QUIC 流 +├── ngx_event_quic_ssl.c # QUIC TLS 握手 +├── ngx_event_quic_output.c # 输出处理 +├── ngx_event_quic_ack.c # ACK 处理 +├── ngx_event_quic_migration.c # 连接迁移 +├── ngx_event_quic_connid.c # 连接 ID +└── ... # 其他模块 +``` + +--- + +## 9. Stream 模块(TCP/UDP) + +### 9.1 Stream 模块结构 + +``` +src/stream/ +├── ngx_stream.c # Stream 模块核心 +├── ngx_stream_core_module.c # 核心配置 +├── ngx_stream_handler.c # 连接处理 +├── ngx_stream_proxy_module.c # 代理模块 +├── ngx_stream_upstream.c # upstream 管理 +├── ngx_stream_upstream_round_robin.c # 负载均衡 +├── ngx_stream_ssl_module.c # SSL 模块 +├── ngx_stream_ssl_preread_module.c # SSL preread(SNI 路由) +└── modules/ # 其他子模块 +``` + +--- + +## 10. 模块系统架构 + +### 10.1 模块结构定义 + +```c +// src/core/ngx_module.h +struct ngx_module_s { + ngx_uint_t ctx_index; // 模块类别内索引 + ngx_uint_t index; // 全局索引 + + char *name; // 模块名称 + + ngx_uint_t version; // 版本(NGX_MODULE_V1) + + void *ctx; // 模块上下文 + + ngx_command_t *commands; // 配置指令数组 + + ngx_uint_t type; // 模块类型 + + ngx_int_t (*init_master)(ngx_log_t *log); + ngx_int_t (*init_module)(ngx_cycle_t *cycle); + ngx_int_t (*init_process)(ngx_cycle_t *cycle); + ngx_int_t (*init_thread)(ngx_cycle_t *cycle); + void (*exit_thread)(ngx_cycle_t *cycle); + void (*exit_process)(ngx_cycle_t *cycle); + void (*exit_master)(ngx_cycle_t *cycle); +}; +``` + +### 10.2 HTTP 模块上下文 + +```c +// src/http/ngx_http_config.h +typedef struct { + ngx_int_t (*preconfiguration)(ngx_conf_t *cf); + ngx_int_t (*postconfiguration)(ngx_conf_t *cf); + + void *(*create_main_conf)(ngx_conf_t *cf); + char *(*init_main_conf)(ngx_conf_t *cf, void *conf); + + void *(*create_srv_conf)(ngx_conf_t *cf); + char *(*merge_srv_conf)(ngx_conf_t *cf, void *prev, void *conf); + + void *(*create_loc_conf)(ngx_conf_t *cf); + char *(*merge_loc_conf)(ngx_conf_t *cf, void *prev, void *conf); +} ngx_http_module_t; +``` + +--- + +## 11. 内存管理 + +### 11.1 内存池结构 + +```c +// src/core/ngx_palloc.h +typedef struct { + u_char *last; // 已分配末尾 + u_char *end; // 块末尾 + ngx_pool_t *next; // 下一个块 + ngx_uint_t failed; // 分配失败次数 +} ngx_pool_data_t; + +struct ngx_pool_s { + ngx_pool_data_t d; // 数据区 + size_t max; // 最大分配大小 + ngx_pool_t *current; // 当前块 + ngx_chain_t *chain; // 缓冲链 + ngx_pool_large_t *large; // 大块内存链 + ngx_pool_cleanup_t *cleanup; // 清理函数链 + ngx_log_t *log; +}; +``` + +--- + +## 12. 参考资源 + +- nginx 源码目录:`lib/nginx/src/` +- nginx 版本:1.31.0(开发版) +- 源码文件数:395 个 C/H 文件 +- HTTP 子模块:63 个 +- 支持的事件机制:epoll、kqueue、eventport、iocp、poll、select +- 支持 HTTP 版本:HTTP/1.0、HTTP/1.1、HTTP/2、HTTP/3(QUIC) \ No newline at end of file diff --git a/docs/nginx/04-nginx-proxy-loadbalancing.md b/docs/nginx/04-nginx-proxy-loadbalancing.md index 49fea19..9409075 100644 --- a/docs/nginx/04-nginx-proxy-loadbalancing.md +++ b/docs/nginx/04-nginx-proxy-loadbalancing.md @@ -1483,4 +1483,217 @@ init_worker_by_lua_block { - 商业环境且有预算:**NGINX Plus**(完整支持,商业支持) - 开源替代且功能优先:**nginx_upstream_check_module** - 需要动态配置:**OpenResty + lua-resty-upstream-healthcheck** -- 新架构选型:**Traefik** 或 **Envoy**(原生支持服务发现) \ No newline at end of file +- 新架构选型:**Traefik** 或 **Envoy**(原生支持服务发现) + +--- + +## 19. Upstream 模块源码实现分析 + +基于 nginx 1.31.0 源码(`lib/nginx/src/http/`)。 + +### 19.1 核心数据结构 + +#### ngx_http_upstream_t - 上游请求结构 + +```c +// src/http/ngx_http_upstream.h:336-420 +struct ngx_http_upstream_s { + ngx_http_upstream_handler_pt read_event_handler; + ngx_http_upstream_handler_pt write_event_handler; + + ngx_peer_connection_t peer; // 对端连接 + + ngx_event_pipe_t *pipe; // 管道(流式传输) + + ngx_chain_t *request_bufs; // 请求缓冲 + + ngx_http_upstream_conf_t *conf; // upstream 配置 + ngx_http_upstream_srv_conf_t *upstream; // upstream 组配置 + + ngx_http_upstream_headers_in_t headers_in; // 上游响应头 + + ngx_buf_t buffer; // 响应缓冲 + + // 回调函数 + ngx_int_t (*create_request)(ngx_http_request_t *r); + ngx_int_t (*reinit_request)(ngx_http_request_t *r); + ngx_int_t (*process_header)(ngx_http_request_t *r); + void (*finalize_request)(ngx_http_request_t *r, ngx_int_t rc); + + ngx_msec_t start_time; + + ngx_http_upstream_state_t *state; // 状态信息 + + unsigned store:1; + unsigned cacheable:1; + unsigned buffering:1; + unsigned keepalive:1; + unsigned upgrade:1; // WebSocket 升级 +}; +``` + +#### ngx_http_upstream_rr_peer_t - 服务器节点 + +```c +// src/http/ngx_http_upstream_round_robin.h +struct ngx_http_upstream_rr_peer_s { + ngx_str_t name; // 服务器名称 + ngx_addr_t *addrs; // 地址数组 + ngx_uint_t naddrs; // 地址数 + + ngx_uint_t weight; // 配置权重 + ngx_uint_t effective_weight; // 有效权重(故障恢复) + ngx_uint_t current_weight; // 当前权重(轮询用) + + ngx_uint_t max_conns; // 最大连接数 + ngx_uint_t conns; // 当前连接数 + + ngx_uint_t max_fails; // 最大失败次数 + time_t fail_timeout; // 失败超时 + time_t accessed; // 最后访问时间 + time_t checked; // 最后检查时间 + + ngx_uint_t fails; // 失败次数 + + ngx_uint_t down; // 是否下线 + + unsigned backup:1; // 是否备份服务器 +}; +``` + +### 19.2 加权轮询算法(平滑分配) + +```c +// src/http/ngx_http_upstream_round_robin.c:810-895 +ngx_http_upstream_get_peer(ngx_peer_connection_t *pc, void *data) +{ + // 平滑加权轮询:避免突发集中分配 + for (p = peers->peer; p; p++) { + if (p 已尝试过 || p down || 超过 max_fails || 超过 max_conns) + continue; + + p->current_weight += p->effective_weight; // 累加有效权重 + total += p->effective_weight; + + // 慢恢复:失败后逐步恢复权重 + if (p->effective_weight < p->weight) + p->effective_weight++; + + // 选 current_weight 最高的 + if (best == NULL || p->current_weight > best->current_weight) + best = p; + } + + // 选中后扣减总权重 + best->current_weight -= total; + return best; +} +``` + +**算法特点**: +- 权重平滑分配,避免请求集中到某台服务器 +- 故障恢复时权重逐步回升,而不是直接恢复 +- 支持 backup 服务器组切换 + +### 19.3 一致性哈希实现 + +```c +// src/http/modules/ngx_http_upstream_hash_module.c +typedef struct { + uint32_t hash; + ngx_str_t *server; +} ngx_http_upstream_chash_point_t; + +typedef struct { + ngx_uint_t number; + ngx_http_upstream_chash_point_t point[1]; // 虚拟节点数组 +} ngx_http_upstream_chash_points_t; + +// 虚拟节点分布在 0-2^32 的圆环上 +// 根据 key 的 hash 值查找最近的节点(二分查找) +ngx_http_upstream_find_chash_point(points, hash); +``` + +### 19.4 Upstream 请求处理流程 + +``` +ngx_http_upstream_init(r) + | + v +ngx_http_upstream_init_request(r) + | + +-- 解析 upstream 名称 + +-- 创建 peer 连接 (peer.get = ngx_http_upstream_get_round_robin_peer) + | + v +ngx_http_upstream_connect(r, u) + | + +-- ngx_event_connect_peer() 连接到上游服务器 + | + v +ngx_http_upstream_send_request() --> 发送客户端请求到上游 + | + v +ngx_http_upstream_process_header(r, u) + | + +-- 解析上游响应头 + +-- ngx_http_upstream_process_headers() 处理 set-cookie 等 + | + v +分支: + +-- 缓冲模式: ngx_http_upstream_process_request() + | (读完整上游响应到临时文件/内存,再转发给客户端) + | + +-- 非缓冲模式: ngx_http_upstream_process_upgraded() + (双向透传,用于 WebSocket 等升级连接) + | + v +ngx_http_upstream_finalize_request(r, u, rc) + | + +-- peer.free() 记录失败/成功,更新权重 + +-- 清理资源 +``` + +### 19.5 故障转移机制 + +```c +// src/http/ngx_http_upstream.c +#define NGX_HTTP_UPSTREAM_FT_ERROR 0x00000002 +#define NGX_HTTP_UPSTREAM_FT_TIMEOUT 0x00000004 +#define NGX_HTTP_UPSTREAM_FT_INVALID_HEADER 0x00000008 +#define NGX_HTTP_UPSTREAM_FT_HTTP_500 0x00000010 +#define NGX_HTTP_UPSTREAM_FT_HTTP_502 0x00000020 +#define NGX_HTTP_UPSTREAM_FT_HTTP_503 0x00000040 +#define NGX_HTTP_UPSTREAM_FT_HTTP_504 0x00000080 + +ngx_http_upstream_next(r, u, ft_type) +{ + if (u->peer.tries > u->conf->next_upstream_tries) + return finalize; + + if (ft_type & u->conf->next_upstream) { + // 符合重试条件,选择下一台服务器 + ngx_http_upstream_connect(r, u); + } else { + // 不符合条件,直接结束请求 + ngx_http_upstream_finalize_request(r, u, status); + } +} +``` + +### 19.6 关键源码路径 + +| 功能 | 文件路径 | 大小 | +|------|----------|------| +| Upstream 核心 | `src/http/ngx_http_upstream.c` | 187KB | +| Upstream 头文件 | `src/http/ngx_http_upstream.h` | 16KB | +| Round Robin 负载均衡 | `src/http/ngx_http_upstream_round_robin.c` | 32KB | +| Least Connections | `src/http/modules/ngx_http_upstream_least_conn_module.c` | 4KB | +| Hash/一致性哈希 | `src/http/modules/ngx_http_upstream_hash_module.c` | 8KB | +| Random 负载均衡 | `src/http/modules/ngx_http_upstream_random_module.c` | 6KB | +| Proxy 模块 | `src/http/modules/ngx_http_proxy_module.c` | 80KB | + +--- + +*源码分析基于 nginx 1.31.0* +*源码目录:`lib/nginx/src/http/`* \ No newline at end of file diff --git a/docs/nginx/10-nginx-stream-tcp-udp.md b/docs/nginx/10-nginx-stream-tcp-udp.md index 1ed31ea..6eb31f5 100644 --- a/docs/nginx/10-nginx-stream-tcp-udp.md +++ b/docs/nginx/10-nginx-stream-tcp-udp.md @@ -1059,4 +1059,174 @@ stream { | `max` | 缓存的最大文件描述符数 | | `inactive` | 非活动文件保留时间 | | `valid` | 检查文件是否有效的时间间隔 | -| `min_uses` | 最小使用次数才缓存 | \ No newline at end of file +| `min_uses` | 最小使用次数才缓存 | + +--- + +## 20. Stream 模块源码架构分析 + +基于 nginx 1.31.0 源码(`lib/nginx/src/stream/`,24 个 .c 文件)。 + +### 20.1 模块文件结构 + +``` +src/stream/ +├── ngx_stream.c # 模块入口(252 行) +├── ngx_stream_core_module.c # 核心配置(1524 行) +├── ngx_stream_handler.c # 连接处理(390 行) +├── ngx_stream_proxy_module.c # 反向代理(2870 行) +├── ngx_stream_upstream.c # upstream 管理 +├── ngx_stream_upstream_round_robin.c # 负载均衡 +├── ngx_stream_ssl_module.c # SSL/TLS 支持 +├── ngx_stream_ssl_preread_module.c # SSL preread(SNI 路由) +├── ngx_stream_access_module.c # IP 访问控制 +├── ngx_stream_log_module.c # 访问日志 +├── ngx_stream_variables.c # 变量支持 +├── ngx_stream_return_module.c # 返回响应 +├── ngx_stream_map_module.c # 变量映射 +├── ngx_stream_split_clients_module.c # A/B 测试 +└── modules/ # 其他子模块 +``` + +### 20.2 处理阶段(7 Phase) + +```c +// src/stream/ngx_stream_core_module.h +typedef enum { + NGX_STREAM_POST_ACCEPT_PHASE = 0, // 接受后处理(proxy_protocol) + NGX_STREAM_PREACCESS_PHASE, // 预访问检查 + NGX_STREAM_ACCESS_PHASE, // 访问控制(allow/deny) + NGX_STREAM_SSL_PHASE, // SSL 握手 + NGX_STREAM_PREREAD_PHASE, // 协议识别预读(SNI 检测) + NGX_STREAM_CONTENT_PHASE, // 内容处理(调用 handler) + NGX_STREAM_LOG_PHASE // 日志记录 +} ngx_stream_phases; +``` + +### 20.3 TCP 代理处理流程 + +``` +client 连接 + | + v +ngx_stream_init_connection() + | + +-- 创建 ngx_stream_session_t + +-- 执行 phases (accept, access, ssl, preread, content) + | + v +ngx_stream_proxy_handler() + | + +-- ngx_stream_proxy_connect() 连接上游服务器 + +-- ngx_stream_proxy_process() 双向数据转发 + | + v +双向数据流: + client <---> ngx_stream_proxy_process <---> upstream +``` + +### 20.4 UDP 代理处理流程 + +``` +client 数据 + | + v +ngx_stream_core_udp_handler() + | + +-- 创建临时 UDP session + +-- ngx_stream_proxy_init_upstream() 获取上游地址 + +-- sendto() 直接发送数据 + | + v +通过 udp_connection_pool 复用连接 +``` + +### 20.5 SSL Preread 模块(SNI 路由) + +```c +// src/stream/ngx_stream_ssl_preread_module.c +// 在 PREREAD_PHASE 阶段解析 TLS ClientHello +// 提取 SNI(Server Name Indication)用于路由决策 + +typedef struct { + ngx_uint_t server_name_len; + u_char server_name[256]; +} ngx_stream_ssl_preread_ctx_t; + +// 根据 $ssl_preread_server_name 变量选择 upstream 组 +``` + +### 20.6 关键源码路径 + +| 功能 | 文件路径 | 行数 | +|------|----------|------| +| Stream 入口 | `src/stream/ngx_stream.c` | 252 | +| 核心配置 | `src/stream/ngx_stream_core_module.c` | 1524 | +| 连接处理 | `src/stream/ngx_stream_handler.c` | 390 | +| 反向代理 | `src/stream/ngx_stream_proxy_module.c` | 2870 | +| SSL 模块 | `src/stream/ngx_stream_ssl_module.c` | - | +| SSL Preread | `src/stream/ngx_stream_ssl_preread_module.c` | - | +| 变量系统 | `src/stream/ngx_stream_variables.c` | - | +| 负载均衡 | `src/stream/ngx_stream_upstream_round_robin.c` | - | + +--- + +## 21. Mail 模块架构概述 + +基于 nginx 1.31.0 源码(`lib/nginx/src/mail/`,14 个 .c 文件)。 + +### 21.1 协议支持 + +| 协议 | 端口 | SSL 端口 | +|------|------|----------| +| IMAP | 143 | 993 | +| POP3 | 110 | 995 | +| SMTP | 25/587 | 465 | + +### 21.2 模块文件结构 + +``` +src/mail/ +├── ngx_mail.c # 模块入口(486 行) +├── ngx_mail_core_module.c # 核心配置(534 行) +├── ngx_mail_handler.c # 连接处理(750 行) +├── ngx_mail_imap_module.c # IMAP 模块 +├── ngx_mail_imap_handler.c # IMAP 协议处理 +├── ngx_mail_pop3_module.c # POP3 模块 +├── ngx_mail_pop3_handler.c # POP3 协议处理 +├── ngx_mail_smtp_module.c # SMTP 模块 +├── ngx_mail_smtp_handler.c # SMTP 协议处理 +├── ngx_mail_proxy_module.c # 邮件代理 +├── ngx_mail_auth.c # 认证核心 +└── ngx_mail_variables.c # 变量支持 +``` + +### 21.3 认证机制支持 + +- PLAIN、LOGIN(基础认证) +- CRAM-MD5(挑战-响应认证) +- EXTERNAL(外部认证) +- APOP(POP3 专用) + +### 21.4 代理流程 + +``` +client 连接 + | + v +ngx_mail_init_connection() + | + +-- 根据端口识别协议(IMAP/POP3/SMTP) + +-- ngx_mail_auth() 执行认证 + | + v +ngx_mail_proxy_init() 连接上游邮件服务器 + | + v +协议转发: client <-> proxy <-> upstream +``` + +--- + +*源码分析基于 nginx 1.31.0* +*源码目录:`lib/nginx/src/stream/` 和 `lib/nginx/src/mail/`* \ No newline at end of file diff --git a/docs/nginx/24-nginx-core-events.md b/docs/nginx/24-nginx-core-events.md index 250aade..96b4be4 100644 --- a/docs/nginx/24-nginx-core-events.md +++ b/docs/nginx/24-nginx-core-events.md @@ -1537,3 +1537,220 @@ ls -la /var/run/nginx.pid # 手动指定 PID 路径 nginx -s reload -p /etc/nginx -c nginx.conf ``` + +--- + +## 10. 事件模块源码架构分析 + +基于 nginx 1.31.0 源码(`lib/nginx/src/event/`)。 + +### 10.1 核心数据结构 + +#### ngx_event_s - 事件结构 + +```c +// src/event/ngx_event.h:30-138 +struct ngx_event_s { + void *data; // 关联的连接或其他数据 + + unsigned write:1; // 是否写事件 + unsigned accept:1; // 是否接受连接事件 + unsigned instance:1; // 实例标记(防止 stale event) + + unsigned active:1; // 是否已添加到事件驱动 + unsigned disabled:1; // 是否禁用 + unsigned ready:1; // 是否就绪 + unsigned oneshot:1; // 是否一次性事件 + + unsigned eof:1; // 是否 EOF + unsigned error:1; // 是否错误 + unsigned timedout:1; // 是否超时 + unsigned timer_set:1; // 是否设置了定时器 + unsigned posted:1; // 是否已投递到队列 + + ngx_event_handler_pt handler; // 事件处理函数 + ngx_rbtree_node_t timer; // 定时器红黑树节点 + ngx_queue_t queue; // posted 队列节点 +}; +``` + +#### ngx_event_actions_t - 事件操作接口 + +```c +// src/event/ngx_event.h:166-183 +typedef struct { + ngx_int_t (*add)(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags); + ngx_int_t (*del)(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags); + ngx_int_t (*add_conn)(ngx_connection_t *c); + ngx_int_t (*del_conn)(ngx_connection_t *c, ngx_uint_t flags); + ngx_int_t (*notify)(ngx_event_handler_pt handler); + ngx_int_t (*process_events)(ngx_cycle_t *cycle, ngx_msec_t timer, ngx_uint_t flags); + ngx_int_t (*init)(ngx_cycle_t *cycle, ngx_msec_t timer); + void (*done)(ngx_cycle_t *cycle); +} ngx_event_actions_t; +``` + +### 10.2 Worker 主循环 + +```c +// src/event/ngx_event.c:195-264 +void ngx_process_events_and_timers(ngx_cycle_t *cycle) +{ + // 1. 计算定时器超时 + timer = ngx_event_find_timer(); + + // 2. 尝试获取 accept mutex(防止惊群) + if (ngx_trylock_accept_mutex(cycle) == NGX_OK) { + flags |= NGX_POST_EVENTS; + } + + // 3. 处理事件(调用 epoll_wait/kevent 等) + ngx_process_events(cycle, timer, flags); + + // 4. 处理 posted accept events(优先) + ngx_event_process_posted(cycle, &ngx_posted_accept_events); + + // 5. 释放 accept mutex + if (ngx_accept_mutex_held) { + ngx_unlock_accept_mutex(); + } + + // 6. 处理 posted events + ngx_event_process_posted(cycle, &ngx_posted_events); + + // 7. 处理超时定时器 + ngx_event_expire_timers(); +} +``` + +### 10.3 定时器红黑树实现 + +```c +// src/event/ngx_event_timer.c +// 全局红黑树 +ngx_rbtree_t ngx_event_timer_rbtree; +static ngx_rbtree_node_t ngx_event_timer_sentinel; + +// 添加定时器 +void ngx_event_add_timer(ngx_event_t *ev, ngx_msec_t timer) +{ + key = ngx_current_msec + timer; // 绝对时间 + ngx_rbtree_insert(&ngx_event_timer_rbtree, &ev->timer); +} + +// 查找最近超时 +ngx_msec_int_t ngx_event_find_timer(void) +{ + node = ngx_rbtree_min(root, sentinel); // O(log N) + timer = node->key - ngx_current_msec; + return timer > 0 ? timer : 0; +} +``` + +### 10.4 epoll 模块核心 + +```c +// src/event/modules/ngx_epoll_module.c:784-936 +static ngx_int_t ngx_epoll_process_events(...) +{ + // 调用 epoll_wait + events = epoll_wait(ep, event_list, nevents, timer); + + for (i = 0; i < events; i++) { + c = event_list[i].data.ptr; + + // 处理读事件 + if ((event_list[i].events & EPOLLIN) && rev->active) { + rev->ready = 1; + if (flags & NGX_POST_EVENTS) { + ngx_post_event(rev, queue); + } else { + rev->handler(rev); + } + } + + // 处理写事件 + if ((event_list[i].events & EPOLLOUT) && wev->active) { + wev->ready = 1; + // 同上... + } + } +} +``` + +### 10.5 Posted 事件队列 + +三级 posted 队列优先级: +```c +ngx_queue_t ngx_posted_accept_events; // accept 事件(最高优先级) +ngx_queue_t ngx_posted_next_events; // next 事件(次优先级) +ngx_queue_t ngx_posted_events; // 普通事件 +``` + +处理顺序:accept → next → regular → timers + +### 10.6 SSL 异步握手 + +```c +// src/event/ngx_event_openssl.c:2201 +ngx_int_t ngx_ssl_handshake(ngx_connection_t *c) +{ + n = SSL_do_handshake(c->ssl->connection); + + if (n == 1) { + c->ssl->handshaked = 1; + return NGX_OK; + } + + sslerr = SSL_get_error(c->ssl->connection, n); + // WANT_READ/WANT_WRITE -> 注册事件,等待回调后递归调用 +} +``` + +### 10.7 QUIC 模块架构 + +``` +src/event/quic/(25 个文件) +├── ngx_event_quic.c # 入口:包分发、连接生命周期 +├── ngx_event_quic_transport.c # 包解析/组装、帧解析 +├── ngx_event_quic_output.c # 发包、GSO +├── ngx_event_quic_protection.c # AEAD 加解密、HKDF +├── ngx_event_quic_ssl.c # QUIC-TLS 集成 +├── ngx_event_quic_streams.c # 流管理、流控 +├── ngx_event_quic_ack.c # ACK 生成、范围跟踪 +├── ngx_event_quic_migration.c # 连接迁移、路径验证 +└── ngx_event_quic_connid.c # 连接 ID 管理 +``` + +核心连接结构: +```c +// src/event/quic/ngx_event_quic_connection.h:222-309 +struct ngx_quic_connection_s { + ngx_quic_send_ctx_t send_ctx[3]; // Initial/Handshake/Application + ngx_quic_congestion_t congestion; // 拥塞控制 + ngx_quic_streams_t streams; // 流管理 + ngx_msec_t avg_rtt; // RTT 估计 + // ... +}; +``` + +--- + +## 11. 关键源码路径 + +| 功能 | 文件路径 | +|------|----------| +| 事件核心 | `src/event/ngx_event.c:195-264` | +| 定时器 | `src/event/ngx_event_timer.c` | +| epoll 模块 | `src/event/modules/ngx_epoll_module.c:784` | +| kqueue 模块 | `src/event/modules/ngx_kqueue_module.c:507` | +| SSL 实现 | `src/event/ngx_event_openssl.c:2201` | +| SSL 对象缓存 | `src/event/ngx_event_openssl_cache.c` | +| 连接接受 | `src/event/ngx_event_accept.c:21-341` | +| 连接建立 | `src/event/ngx_event_connect.c:20-331` | +| QUIC 核心 | `src/event/quic/ngx_event_quic.c` | + +--- + +*源码分析基于 nginx 1.31.0* +*源码目录:`lib/nginx/src/event/`* diff --git a/docs/nginx/25-nginx-variables-reference.md b/docs/nginx/25-nginx-variables-reference.md index 0d0909b..fc15b63 100644 --- a/docs/nginx/25-nginx-variables-reference.md +++ b/docs/nginx/25-nginx-variables-reference.md @@ -251,5 +251,105 @@ log_format security '$remote_addr $request_method $request_uri ' --- -*文档生成时间:2026-04-03* -*基于 nginx 1.24+ 版本* +## 12. 变量系统源码实现 + +基于 nginx 1.31.0 源码分析(`src/http/ngx_http_variables.c`)。 + +### 12.1 变量注册机制 + +```c +// src/http/ngx_http_variables.h +typedef struct { + ngx_str_t name; // 变量名 + ngx_http_get_variable_pt get_handler; // 获取函数 + ngx_http_set_variable_pt set_handler; // 设置函数(可选) + ngx_uint_t flags; // 标志位 + ngx_uint_t index; // 索引(索引变量) +} ngx_http_variable_t; +``` + +### 12.2 变量标志位 + +| 标志 | 值 | 说明 | +|------|-----|------| +| `NGX_HTTP_VAR_CHANGEABLE` | 1 | 可通过 set 指令修改 | +| `NGX_HTTP_VAR_NOCACHEABLE` | 2 | 每次请求重新计算 | +| `NGX_HTTP_VAR_INDEXED` | 4 | 索引变量(O(1) 查找) | +| `NGX_HTTP_VAR_NOHASH` | 8 | 不加入 hash 表 | +| `NGX_HTTP_VAR_PREFIX` | 16 | 前缀变量($http_, $cookie_, $arg_) | + +### 12.3 索引变量 vs 前缀变量 + +**索引变量**(配置期注册,运行期 O(1)): +- `$uri`, `$args`, `$host`, `$remote_addr` 等 +- 通过 `ngx_http_get_variable_index()` 注册 +- 存储在 `r->variables[index]` + +**前缀变量**(运行期动态匹配): +- `$http_XXX` → `ngx_http_variable_unknown_header_in` +- `$cookie_XXX` → `ngx_http_variable_cookie` +- `$arg_XXX` → `ngx_http_variable_argument` +- `$sent_http_XXX` → `ngx_http_variable_unknown_header_out` + +### 12.4 变量求值流程 + +``` +ngx_http_get_variable(r, name, key) + | + +-- 查找 hash 表 (cmcf->variables_hash) + | if found && index: return r->variables[index] + | if found && get_handler: return get_handler(r, data) + | + +-- 查找前缀变量表 (cmcf->prefix_variables) + | 检查 name 是否匹配前缀 + | 提取后缀部分作为参数 + | 调用 get_handler(r, data, suffix) + | + +-- 未找到:返回 NGX_HTTP_VAR_NOT_FOUND +``` + +### 12.5 可缓存变量 vs 不可缓存变量 + +**可缓存**(一次请求只计算一次): +- `$host`, `$server_name`, `$nginx_version` + +**不可缓存**(每次访问重新计算): +- `$uri`(可能被 rewrite 修改) +- `$args`(可能被 set 修改) +- `$request_time`(随时间变化) +- `$upstream_response_time`(请求结束时才确定) + +### 12.6 自定义变量 + +**set 指令**(ngx_http_rewrite_module): +```nginx +set $my_var "value"; +``` + +源码实现:将赋值编译为 `ngx_http_script_set_code` 指令,运行期执行。 + +**map 指令**(ngx_http_map_module): +```nginx +map $remote_addr $my_var { + default "unknown"; + 192.168.1.0/24 "internal"; +} +``` + +源码实现:创建 `ngx_http_map_t` 结构,运行期根据源变量值查表。 + +**geo 指令**(ngx_http_geo_module): +```nginx +geo $remote_addr $country { + default "XX"; + 127.0.0.0/8 "LOCAL"; +} +``` + +源码实现:使用 radix tree 存储 IP 范围映射。 + +--- + +*文档生成时间:2026-04-16* +*基于 nginx 1.31.0 源码分析* +*源码参考:`lib/nginx/src/http/ngx_http_variables.c`(70KB)*