概述
本文基于 NGINX 源码和架构图表,深入分析 NGINX 如何实现高并发 HTTP 请求处理。我们将从进程模型、事件驱动机制、连接管理、请求处理流程等多个维度,结合具体的源码实现,全面解析 NGINX 的高并发处理能力。

1. 高并发架构基础
1.1 Master-Worker 进程模型
NGINX 采用经典的 Master-Worker 多进程架构,这是其高并发处理能力的基础。
Master 进程职责
- 配置管理: 读取和解析配置文件
- 进程管理: 创建、监控和重启 Worker 进程
- 信号处理: 处理管理员发送的控制信号
- 平滑重启: 实现零停机配置重载
核心实现 (src/os/unix/ngx_process_cycle.c
):
scss
void ngx_master_process_cycle(ngx_cycle_t *cycle)
{
// 设置信号掩码,阻塞工作进程不需要处理的信号
sigemptyset(&set);
sigaddset(&set, SIGCHLD); // 子进程状态变化
sigaddset(&set, SIGALRM); // 定时器信号
sigaddset(&set, SIGIO); // 异步I/O信号
// ... 其他信号
if (sigprocmask(SIG_BLOCK, &set, NULL) == -1) {
ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
"sigprocmask() failed");
}
// 启动工作进程
ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module);
ngx_start_worker_processes(cycle, ccf->worker_processes, NGX_PROCESS_RESPAWN);
// 主循环:监听信号,管理工作进程
for ( ;; ) {
if (ngx_terminate || ngx_quit) {
// 处理终止信号
ngx_signal_worker_processes(cycle,
ngx_signal_value(NGX_SHUTDOWN_SIGNAL));
}
if (ngx_reconfigure) {
// 处理重载配置信号
cycle = ngx_init_cycle(cycle);
ngx_start_worker_processes(cycle, ccf->worker_processes,
NGX_PROCESS_JUST_RESPAWN);
}
// 等待信号
sigsuspend(&set);
}
}
Worker 进程职责
- 请求处理: 接受和处理客户端连接
- 事件循环: 运行事件驱动的主循环
- 资源管理: 管理连接池和内存池
核心实现 (src/os/unix/ngx_process_cycle.c
):
scss
static void ngx_worker_process_cycle(ngx_cycle_t *cycle, void *data)
{
ngx_int_t worker = (intptr_t) data;
// 初始化工作进程
ngx_worker_process_init(cycle, worker);
// 主事件循环
for ( ;; ) {
if (ngx_exiting) {
// 优雅退出:等待现有连接处理完成
if (ngx_event_no_timers_left() == NGX_OK) {
break;
}
}
// 处理事件和定时器
ngx_process_events_and_timers(cycle);
if (ngx_terminate || ngx_quit) {
break;
}
}
ngx_worker_process_exit(cycle);
}
1.2 事件驱动机制
NGINX 使用事件驱动的异步非阻塞 I/O 模型,这是其高并发能力的核心。
epoll 事件模型
在 Linux 系统上,NGINX 优先使用 epoll 事件通知机制:
初始化 (src/event/modules/ngx_epoll_module.c
):
ini
static ngx_int_t ngx_epoll_init(ngx_cycle_t *cycle, ngx_msec_t timer)
{
ngx_epoll_conf_t *epcf;
epcf = ngx_event_get_conf(cycle->conf_ctx, ngx_epoll_module);
if (ep == -1) {
// 创建 epoll 实例
ep = epoll_create(cycle->connection_n / 2);
if (ep == -1) {
ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
"epoll_create() failed");
return NGX_ERROR;
}
}
// 分配事件列表内存
if (nevents < epcf->events) {
if (event_list) {
ngx_free(event_list);
}
event_list = ngx_alloc(sizeof(struct epoll_event) * epcf->events,
cycle->log);
if (event_list == NULL) {
return NGX_ERROR;
}
}
nevents = epcf->events;
// 设置边缘触发模式
ngx_event_flags = NGX_USE_CLEAR_EVENT | NGX_USE_GREEDY_EVENT | NGX_USE_EPOLL_EVENT;
return NGX_OK;
}
事件处理循环
核心事件循环 (src/event/modules/ngx_epoll_module.c
):
ini
static ngx_int_t ngx_epoll_process_events(ngx_cycle_t *cycle, ngx_msec_t timer, ngx_uint_t flags)
{
int events;
ngx_int_t instance, i;
ngx_event_t *rev, *wev;
ngx_connection_t *c;
// 等待事件发生
events = epoll_wait(ep, event_list, (int) nevents, timer);
if (events == -1) {
err = ngx_errno;
if (err == NGX_EINTR) {
return NGX_OK; // 被信号中断,继续
}
ngx_log_error(NGX_LOG_ALERT, cycle->log, err, "epoll_wait() failed");
return NGX_ERROR;
}
// 处理就绪事件
for (i = 0; i < events; i++) {
c = event_list[i].data.ptr;
instance = (uintptr_t) c & 1;
c = (ngx_connection_t *) ((uintptr_t) c & (uintptr_t) ~1);
rev = c->read;
// 检查事件是否过期
if (c->fd == -1 || rev->instance != instance) {
continue;
}
revents = event_list[i].events;
// 处理读事件
if ((revents & EPOLLIN) && rev->active) {
rev->ready = 1;
rev->available = -1;
if (flags & NGX_POST_EVENTS) {
// 延迟处理事件
ngx_post_event(rev, &ngx_posted_accept_events);
} else {
// 立即处理事件
rev->handler(rev);
}
}
// 处理写事件
wev = c->write;
if ((revents & EPOLLOUT) && wev->active) {
wev->ready = 1;
if (flags & NGX_POST_EVENTS) {
ngx_post_event(wev, &ngx_posted_events);
} else {
wev->handler(wev);
}
}
}
return NGX_OK;
}
2. 连接管理机制
2.1 连接池管理
NGINX 使用预分配的连接池来管理客户端连接,避免频繁的内存分配和释放。
连接池初始化 (src/core/ngx_connection.c
):
ini
ngx_int_t ngx_init_cycle_connections(ngx_cycle_t *cycle)
{
ngx_uint_t i;
ngx_connection_t *c, *next;
// 分配连接数组
cycle->connections = ngx_alloc(sizeof(ngx_connection_t) * cycle->connection_n,
cycle->log);
if (cycle->connections == NULL) {
return NGX_ERROR;
}
c = cycle->connections;
// 分配读事件数组
cycle->read_events = ngx_alloc(sizeof(ngx_event_t) * cycle->connection_n,
cycle->log);
if (cycle->read_events == NULL) {
return NGX_ERROR;
}
// 分配写事件数组
cycle->write_events = ngx_alloc(sizeof(ngx_event_t) * cycle->connection_n,
cycle->log);
if (cycle->write_events == NULL) {
return NGX_ERROR;
}
// 初始化连接链表
i = cycle->connection_n;
next = NULL;
do {
i--;
c[i].data = next;
c[i].read = &cycle->read_events[i];
c[i].write = &cycle->write_events[i];
c[i].fd = (ngx_socket_t) -1;
next = &c[i];
} while (i);
cycle->free_connections = next;
cycle->free_connection_n = cycle->connection_n;
return NGX_OK;
}
2.2 Accept 互斥锁机制
为了避免多个 Worker 进程同时 accept 同一个连接(惊群问题),NGINX 使用 accept_mutex 机制。
Accept 互斥锁实现 (src/event/ngx_event_accept.c
):
ini
ngx_int_t ngx_trylock_accept_mutex(ngx_cycle_t *cycle)
{
if (ngx_shmtx_trylock(&ngx_accept_mutex)) {
if (ngx_accept_mutex_held && ngx_accept_events == 0) {
return NGX_OK;
}
// 启用监听事件
if (ngx_enable_accept_events(cycle) == NGX_ERROR) {
ngx_shmtx_unlock(&ngx_accept_mutex);
return NGX_ERROR;
}
ngx_accept_events = 0;
ngx_accept_mutex_held = 1;
return NGX_OK;
}
if (ngx_accept_mutex_held) {
// 禁用监听事件
if (ngx_disable_accept_events(cycle, 0) == NGX_ERROR) {
return NGX_ERROR;
}
ngx_accept_mutex_held = 0;
}
return NGX_OK;
}
2.3 负载均衡机制
NGINX 通过 ngx_accept_disabled
变量实现 Worker 进程间的负载均衡:
ini
// 在事件循环中
if (ngx_accept_disabled > 0) {
ngx_accept_disabled--;
} else {
if (ngx_trylock_accept_mutex(cycle) == NGX_ERROR) {
return;
}
if (ngx_accept_mutex_held) {
flags |= NGX_POST_EVENTS;
} else {
if (timer == NGX_TIMER_INFINITE || timer > ngx_accept_mutex_delay) {
timer = ngx_accept_mutex_delay;
}
}
}
// 计算 accept_disabled 值
ngx_accept_disabled = ngx_cycle->connection_n / 8 - ngx_cycle->free_connection_n;
当某个 Worker 进程的连接数过多时,它会暂时停止接受新连接,让其他 Worker 进程处理新请求。
3. HTTP 请求处理流程
3.1 连接建立
当客户端发起连接时,获得 accept_mutex 的 Worker 进程会处理新连接:
连接接受 (src/event/ngx_event_accept.c
):
ini
void ngx_event_accept(ngx_event_t *ev)
{
socklen_t socklen;
ngx_err_t err;
ngx_log_t *log;
ngx_uint_t level;
ngx_socket_t s;
ngx_event_t *rev, *wev;
ngx_connection_t *c, *lc;
ngx_listening_t *ls;
lc = ev->data;
ls = lc->listening;
ev->ready = 0;
do {
socklen = sizeof(ngx_sockaddr_t);
// 接受新连接
s = accept(lc->fd, &sa.sockaddr, &socklen);
if (s == (ngx_socket_t) -1) {
err = ngx_socket_errno;
if (err == NGX_EAGAIN) {
return; // 没有更多连接
}
if (err == NGX_ECONNABORTED) {
continue; // 连接被客户端中止
}
// 处理文件描述符耗尽
if (err == NGX_EMFILE || err == NGX_ENFILE) {
ngx_disable_accept_events(cycle, 1);
return;
}
ngx_log_error(level, ev->log, err, "accept() failed");
return;
}
// 获取连接对象
c = ngx_get_connection(s, ev->log);
if (c == NULL) {
if (ngx_close_socket(s) == -1) {
ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_socket_errno,
ngx_close_socket_n " failed");
}
return;
}
// 设置非阻塞模式
if (ngx_nonblocking(s) == -1) {
ngx_close_accepted_connection(c);
return;
}
// 初始化连接
c->pool = ngx_create_pool(ls->pool_size, ev->log);
if (c->pool == NULL) {
ngx_close_accepted_connection(c);
return;
}
// 调用监听器的处理函数(通常是 HTTP 初始化)
ls->handler(c);
} while (ev->available);
}
3.2 HTTP 连接初始化
HTTP 连接初始化 (src/http/ngx_http_request.c
):
ini
void ngx_http_init_connection(ngx_connection_t *c)
{
ngx_uint_t i;
ngx_event_t *rev;
struct sockaddr_in *sin;
ngx_http_port_t *port;
ngx_http_in_addr_t *addr;
ngx_http_log_ctx_t *ctx;
ngx_http_connection_t *hc;
hc = ngx_pcalloc(c->pool, sizeof(ngx_http_connection_t));
if (hc == NULL) {
ngx_http_close_connection(c);
return;
}
c->data = hc;
// 设置读事件处理函数
rev = c->read;
rev->handler = ngx_http_wait_request_handler;
c->write->handler = ngx_http_empty_handler;
// 设置读超时
if (rev->ready) {
// 如果已有数据可读,立即处理
ngx_post_event(rev, &ngx_posted_events);
} else {
// 添加读事件到 epoll,设置超时
ngx_add_timer(rev, c->listening->post_accept_timeout);
if (ngx_handle_read_event(rev, 0) != NGX_OK) {
ngx_http_close_connection(c);
return;
}
}
}
4. 高并发优化机制
4.1 边缘触发模式
NGINX 在支持的平台上使用边缘触发(ET)模式,这要求一次性读取所有可用数据:
ini
// 在读事件处理中
do {
n = c->recv(c, b->last, size);
if (n == NGX_AGAIN) {
break; // 已读取所有可用数据
}
if (n == NGX_ERROR) {
c->error = 1;
return NGX_ERROR;
}
if (n == 0) {
// 连接关闭
return NGX_ERROR;
}
b->last += n;
size -= n;
} while (size > 0);
4.2 内存池优化
NGINX 使用内存池来减少内存分配开销:
scss
// 为每个请求创建内存池
r->pool = ngx_create_pool(cscf->request_pool_size, c->log);
if (r->pool == NULL) {
ngx_http_close_connection(c);
return;
}
// 请求结束时自动释放整个内存池
ngx_destroy_pool(r->pool);
4.3 sendfile 零拷贝
对于静态文件服务,NGINX 使用 sendfile 系统调用实现零拷贝:
arduino
#if (NGX_HAVE_SENDFILE)
if (file->sendfile) {
return ngx_linux_sendfile_chain(c, in, limit);
}
#endif
// sendfile 实现
ssize_t ngx_linux_sendfile(ngx_connection_t *c, ngx_buf_t *file, size_t size)
{
ssize_t n;
ngx_err_t err;
n = sendfile(c->fd, file->file->fd, &file->file_pos, size);
if (n == -1) {
err = ngx_errno;
switch (err) {
case NGX_EAGAIN:
return NGX_AGAIN;
case NGX_EINTR:
return NGX_EINTR;
default:
c->error = 1;
return NGX_ERROR;
}
}
return n;
}
5. 性能监控和调优
5.1 连接状态监控
NGINX 提供了丰富的状态信息用于监控:
arduino
// 连接统计
ngx_atomic_t ngx_stat_accepted; // 接受的连接数
ngx_atomic_t ngx_stat_handled; // 处理的连接数
ngx_atomic_t ngx_stat_requests; // 处理的请求数
ngx_atomic_t ngx_stat_active; // 活跃连接数
ngx_atomic_t ngx_stat_reading; // 正在读取的连接数
ngx_atomic_t ngx_stat_writing; // 正在写入的连接数
ngx_atomic_t ngx_stat_waiting; // 等待的连接数
5.2 配置优化建议
基于源码分析,以下是一些关键的配置优化建议:
ini
# 工作进程数通常设置为 CPU 核心数
worker_processes auto;
# 每个工作进程的最大连接数
worker_connections 1024;
# 使用 epoll 事件模型(Linux)
events {
use epoll;
multi_accept on; # 一次接受多个连接
accept_mutex off; # 关闭 accept 互斥锁(适用于高负载)
}
# HTTP 优化
http {
sendfile on; # 启用 sendfile
tcp_nopush on; # 启用 TCP_CORK
tcp_nodelay on; # 启用 TCP_NODELAY
keepalive_timeout 65; # Keep-Alive 超时
keepalive_requests 100; # 每个连接的最大请求数
# 缓冲区优化
client_body_buffer_size 128k;
client_max_body_size 10m;
client_header_buffer_size 1k;
large_client_header_buffers 4 4k;
}
总结
NGINX 的高并发处理能力来源于其精心设计的架构:
- Master-Worker 进程模型:实现了进程隔离和负载分担
- 事件驱动机制:基于 epoll 的异步非阻塞 I/O
- 连接池管理:预分配连接对象,避免频繁内存操作
- Accept 互斥锁:解决惊群问题,实现负载均衡
- 内存池优化:减少内存分配开销
- 零拷贝技术:提高文件传输效率
这些机制协同工作,使 NGINX 能够在有限的系统资源下处理大量并发连接,成为现代高性能 Web 服务器的典型代表。
通过深入理解这些实现细节,我们可以更好地配置和优化 NGINX,充分发挥其高并发处理能力。
6. HTTP 请求处理阶段详解
6.1 请求解析阶段
NGINX 的 HTTP 请求处理分为多个阶段,每个阶段都有特定的功能:
请求行解析 (src/http/ngx_http_parse.c
):
ini
ngx_int_t ngx_http_parse_request_line(ngx_http_request_t *r, ngx_buf_t *b)
{
u_char c, ch, *p, *m;
enum {
sw_start = 0,
sw_method,
sw_spaces_before_uri,
sw_schema,
sw_schema_slash,
sw_schema_slash_slash,
sw_host_start,
sw_host,
sw_host_end,
sw_host_ip_literal,
sw_port,
sw_after_slash_in_uri,
sw_check_uri,
sw_uri,
sw_http_09,
sw_http_H,
sw_http_HT,
sw_http_HTT,
sw_http_HTTP,
sw_first_major_digit,
sw_major_digit,
sw_first_minor_digit,
sw_minor_digit,
sw_spaces_after_digit,
sw_almost_done
} state;
state = r->state;
for (p = b->pos; p < b->last; p++) {
ch = *p;
switch (state) {
/* HTTP methods: GET, HEAD, POST */
case sw_start:
r->request_start = p;
if (ch == CR || ch == LF) {
break;
}
if ((ch < 'A' || ch > 'Z') && ch != '_' && ch != '-') {
return NGX_HTTP_PARSE_INVALID_METHOD;
}
state = sw_method;
break;
case sw_method:
if (ch == ' ') {
r->method_end = p - 1;
m = r->request_start;
switch (p - m) {
case 3:
if (ngx_str3_cmp(m, 'G', 'E', 'T', ' ')) {
r->method = NGX_HTTP_GET;
break;
}
if (ngx_str3_cmp(m, 'P', 'U', 'T', ' ')) {
r->method = NGX_HTTP_PUT;
break;
}
break;
case 4:
if (m[1] == 'O') {
if (ngx_str3Ocmp(m, 'P', 'O', 'S', 'T')) {
r->method = NGX_HTTP_POST;
break;
}
if (ngx_str3Ocmp(m, 'C', 'O', 'P', 'Y')) {
r->method = NGX_HTTP_COPY;
break;
}
if (ngx_str3Ocmp(m, 'M', 'O', 'V', 'E')) {
r->method = NGX_HTTP_MOVE;
break;
}
if (ngx_str3Ocmp(m, 'L', 'O', 'C', 'K')) {
r->method = NGX_HTTP_LOCK;
break;
}
} else {
if (ngx_str4cmp(m, 'H', 'E', 'A', 'D')) {
r->method = NGX_HTTP_HEAD;
break;
}
}
break;
}
state = sw_spaces_before_uri;
break;
}
if ((ch < 'A' || ch > 'Z') && ch != '_' && ch != '-') {
return NGX_HTTP_PARSE_INVALID_METHOD;
}
break;
/* URI parsing continues... */
}
}
b->pos = p;
r->state = state;
return NGX_AGAIN;
}
6.2 HTTP 处理阶段
NGINX 将 HTTP 请求处理分为 11 个阶段,每个阶段可以注册多个处理器:
阶段定义 (src/http/ngx_http_core_module.h
):
arduino
typedef enum {
NGX_HTTP_POST_READ_PHASE = 0, // 读取请求内容阶段
NGX_HTTP_SERVER_REWRITE_PHASE, // Server级别的重写阶段
NGX_HTTP_FIND_CONFIG_PHASE, // 配置查找阶段
NGX_HTTP_REWRITE_PHASE, // Location级别的重写阶段
NGX_HTTP_POST_REWRITE_PHASE, // 重写后处理阶段
NGX_HTTP_PREACCESS_PHASE, // 访问权限检查预处理阶段
NGX_HTTP_ACCESS_PHASE, // 访问权限检查阶段
NGX_HTTP_POST_ACCESS_PHASE, // 访问权限检查后处理阶段
NGX_HTTP_PRECONTENT_PHASE, // 生成内容前处理阶段
NGX_HTTP_CONTENT_PHASE, // 内容产生阶段
NGX_HTTP_LOG_PHASE // 日志记录阶段
} ngx_http_phases;
阶段处理器执行 (src/http/ngx_http_core_module.c
):
ini
void ngx_http_core_run_phases(ngx_http_request_t *r)
{
ngx_int_t rc;
ngx_http_phase_handler_t *ph;
ngx_http_core_main_conf_t *cmcf;
cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);
ph = cmcf->phase_engine.handlers;
while (ph[r->phase_handler].checker) {
rc = ph[r->phase_handler].checker(r, &ph[r->phase_handler]);
if (rc == NGX_OK) {
return;
}
}
}
6.3 内容生成和过滤
内容处理器 (src/http/ngx_http_core_module.c
):
rust
ngx_int_t ngx_http_core_content_phase(ngx_http_request_t *r,
ngx_http_phase_handler_t *ph)
{
size_t root;
ngx_int_t rc;
ngx_str_t path;
if (r->content_handler) {
r->write_event_handler = ngx_http_request_empty_handler;
ngx_http_finalize_request(r, r->content_handler(r));
return NGX_OK;
}
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"content phase: %ui", r->phase_handler);
rc = ph->handler(r);
if (rc != NGX_DECLINED) {
ngx_http_finalize_request(r, rc);
return NGX_OK;
}
/* rc == NGX_DECLINED */
ph++;
r->phase_handler++;
if (ph->checker) {
r->content_handler = ph->handler;
return NGX_AGAIN;
}
/* no content handler was found */
if (r->uri.data[r->uri.len - 1] == '/') {
if (ngx_http_map_uri_to_path(r, &path, &root, 0) != NULL) {
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"directory index of "%s" is forbidden", path.data);
}
ngx_http_finalize_request(r, NGX_HTTP_FORBIDDEN);
return NGX_OK;
}
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "no handler found");
ngx_http_finalize_request(r, NGX_HTTP_NOT_FOUND);
return NGX_OK;
}
7. 内存管理优化
7.1 内存池实现
NGINX 的内存池是其高性能的重要保障:
内存池结构 (src/core/ngx_palloc.h
):
arduino
typedef struct ngx_pool_s ngx_pool_t;
struct ngx_pool_large_s {
ngx_pool_large_t *next;
void *alloc;
};
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;
};
typedef struct {
u_char *last;
u_char *end;
ngx_pool_t *next;
ngx_uint_t failed;
} ngx_pool_data_t;
内存分配 (src/core/ngx_palloc.c
):
arduino
void *ngx_palloc(ngx_pool_t *pool, size_t size)
{
if (size <= pool->max) {
return ngx_palloc_small(pool, size, 1);
}
return ngx_palloc_large(pool, size);
}
static ngx_inline void *ngx_palloc_small(ngx_pool_t *pool, size_t size, ngx_uint_t align)
{
u_char *m;
ngx_pool_t *p;
p = pool->current;
do {
m = p->d.last;
if (align) {
m = ngx_align_ptr(m, NGX_ALIGNMENT);
}
if ((size_t) (p->d.end - m) >= size) {
p->d.last = m + size;
return m;
}
p = p->d.next;
} while (p);
return ngx_palloc_block(pool, size);
}
7.2 缓冲区管理
缓冲区结构 (src/core/ngx_buf.h
):
arduino
typedef struct ngx_buf_s ngx_buf_t;
struct ngx_buf_s {
u_char *pos; // 缓冲区数据开始位置
u_char *last; // 缓冲区数据结束位置
off_t file_pos; // 文件读取位置
off_t file_last; // 文件读取结束位置
u_char *start; // 缓冲区开始位置
u_char *end; // 缓冲区结束位置
ngx_buf_tag_t tag; // 缓冲区标记
ngx_file_t *file; // 关联的文件
ngx_buf_t *shadow; // 影子缓冲区
/* the buf's content could be changed */
unsigned temporary:1;
/*
* the buf's content is in a memory cache or in a read only memory
* and must not be changed
*/
unsigned memory:1;
/* the buf's content is mmap()ed and must not be changed */
unsigned mmap:1;
unsigned recycled:1;
unsigned in_file:1;
unsigned flush:1;
unsigned sync:1;
unsigned last_buf:1;
unsigned last_in_chain:1;
unsigned last_shadow:1;
unsigned temp_file:1;
/* STUB */ int num;
};
8. 错误处理和恢复机制
8.1 连接错误处理
文件描述符耗尽处理 (src/event/ngx_event_accept.c
):
ini
void ngx_event_accept(ngx_event_t *ev)
{
// ... 前面的代码
do {
s = accept(lc->fd, &sa.sockaddr, &socklen);
if (s == (ngx_socket_t) -1) {
err = ngx_socket_errno;
if (err == NGX_EAGAIN) {
return;
}
level = NGX_LOG_ALERT;
if (err == NGX_ECONNABORTED) {
level = NGX_LOG_ERR;
} else if (err == NGX_EMFILE || err == NGX_ENFILE) {
level = NGX_LOG_CRIT;
if (ngx_disable_accept_events((ngx_cycle_t *) ngx_cycle, 1)
!= NGX_OK)
{
return;
}
if (ngx_use_accept_mutex) {
if (ngx_accept_mutex_held) {
ngx_shmtx_unlock(&ngx_accept_mutex);
ngx_accept_mutex_held = 0;
}
ngx_accept_disabled = 1;
} else {
ngx_add_timer(ev, ecf->accept_mutex_delay);
}
}
ngx_log_error(level, ev->log, err,
"accept() failed (%d: %s)", err, ngx_strerror(err));
if (err == NGX_ECONNABORTED) {
if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) {
ev->available--;
}
if (ev->available) {
continue;
}
}
if (err == NGX_EMFILE || err == NGX_ENFILE) {
return;
}
if (ev->available) {
continue;
}
}
// ... 处理成功的连接
} while (ev->available);
}
8.2 请求超时处理
读超时处理 (src/http/ngx_http_request.c
):
ini
static void ngx_http_read_request_handler(ngx_event_t *rev)
{
ngx_connection_t *c;
ngx_http_request_t *r;
c = rev->data;
r = c->data;
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, rev->log, 0,
"http read request handler");
if (rev->timedout) {
ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "client timed out");
c->timedout = 1;
ngx_http_close_request(r, NGX_HTTP_REQUEST_TIME_OUT);
return;
}
if (ngx_http_read_request_header(r) != NGX_OK) {
return;
}
if (ngx_http_process_request_header(r) != NGX_OK) {
return;
}
ngx_http_process_request(r);
}
9. 性能测试和基准
9.1 性能指标
基于源码分析,NGINX 的关键性能指标包括:
- 并发连接数 : 受
worker_connections
和系统文件描述符限制 - 请求处理速度: 受事件循环效率和处理器性能影响
- 内存使用: 受连接池大小和请求缓冲区配置影响
- CPU 使用率: 受 Worker 进程数和负载均衡效果影响
9.2 性能调优实践
系统级调优:
bash
# 增加文件描述符限制
echo "* soft nofile 65535" >> /etc/security/limits.conf
echo "* hard nofile 65535" >> /etc/security/limits.conf
# 调整内核参数
echo "net.core.somaxconn = 65535" >> /etc/sysctl.conf
echo "net.ipv4.tcp_max_syn_backlog = 65535" >> /etc/sysctl.conf
echo "net.core.netdev_max_backlog = 32768" >> /etc/sysctl.conf
# 应用配置
sysctl -p
NGINX 配置调优:
ini
# 基于 CPU 核心数设置 Worker 进程
worker_processes auto;
worker_cpu_affinity auto;
# 优化事件处理
events {
worker_connections 65535;
use epoll;
multi_accept on;
accept_mutex off;
}
# HTTP 优化
http {
# 启用高效传输
sendfile on;
tcp_nopush on;
tcp_nodelay on;
# 优化缓冲区
client_body_buffer_size 128k;
client_max_body_size 10m;
client_header_buffer_size 1k;
large_client_header_buffers 4 4k;
output_buffers 1 32k;
postpone_output 1460;
# 连接优化
keepalive_timeout 65;
keepalive_requests 100;
reset_timedout_connection on;
client_body_timeout 10;
send_timeout 2;
# 压缩优化
gzip on;
gzip_vary on;
gzip_min_length 10240;
gzip_proxied expired no-cache no-store private must-revalidate;
gzip_types text/plain text/css text/xml text/javascript
application/x-javascript application/xml+rss;
gzip_disable "MSIE [1-6].";
}
10. 总结
NGINX 的高并发 HTTP 处理能力是多种技术的综合体现:
- 架构设计: Master-Worker 模型提供了稳定性和可扩展性
- 事件驱动: 基于 epoll 的异步 I/O 实现了高效的并发处理
- 内存管理: 内存池和缓冲区优化减少了系统开销
- 负载均衡: Accept 互斥锁和连接数控制实现了进程间负载均衡
- 错误恢复: 完善的错误处理机制保证了系统稳定性