Nginx基础教程(32)Nginx HTTP框架综述之处理引擎:Nginx HTTP框架深度解剖:从入门到精通的处理引擎指南

Nginx HTTP处理引擎详解

如果你曾被Nginx的强大性能所吸引,却又对它的内部工作机制感到困惑,那么你来对地方了。

1. Nginx简介:不只是Web服务器

Nginx(发音为“engine x”)最初由Igor Sysoev开发,是一个HTTP Web服务器、反向代理、内容缓存、负载均衡器、TCP/UDP代理服务器和邮件代理服务器。

它以其灵活性和高性能以及低资源利用率而闻名,如今已经成为世界上最流行的Web服务器之一。

Nginx由内核和模块组成。内核的设计非常微小和简洁,完成的工作也非常简单,仅仅通过查找配置文件将客户端请求映射到一个location block(location是Nginx配置中的一个指令,用于URL匹配)。

而在这个location中所配置的每个指令将会启动不同的模块去完成相应的工作。

2. Nginx模块化架构:乐高积木式的设计哲学

Nginx采用模块化设计,从结构上可以分为核心模块、基础模块和第三方模块。

HTTP模块、EVENT模块和MAIL模块等属于核心模块,HTTP Access模块、HTTP FastCGI模块、HTTP Proxy模块和HTTP Rewrite模块属于基础模块。

而用户根据自己的需要开发的模块都属于第三方模块。

从功能角度,Nginx的模块可以分为三类:

  • Handlers(处理器模块):直接处理请求,并进行输出内容和修改headers信息等操作。Handlers处理器模块一般只能有一个。
  • Filters(过滤器模块):主要对其他处理器模块输出的内容进行修改操作,最后由Nginx输出。
  • Proxies(代理类模块):Nginx的HTTP Upstream之类的模块,这些模块主要与后端一些服务比如FastCGI等进行交互,实现服务代理和负载均衡等功能。

这种模块化架构使得Nginx具备了极强的扩展性,开发者可以根据自己的需要开发自定义模块,嵌入到Nginx的整个工作流程中,实现更加便捷的个性化功能定制与开发。

3. Nginx处理引擎:HTTP请求的11个阶段之旅

为什么Nginx要把HTTP请求的处理过程分为多个阶段呢?这就像工厂的流水线一样,通过分工提高效率。

Nginx的模块化设计使得每一个HTTP模块可以仅专注于完成一个独立的、简单的功能,而一个请求的完整处理过程可以由无数个HTTP模块共同合作完成。

当多个HTTP模块流水式地处理同一个请求时,单一的处理顺序是无法满足灵活性需求的。因此,HTTP框架依据常见的处理流程将处理阶段划分为11个阶段。

3.1 11个处理阶段的详细解析

虽然搜索结果中没有完整列出11个阶段的具体名称,但我们可以了解到Nginx处理请求的基本流程和阶段划分的重要性。

这种阶段划分的设计让每一个正在处理请求的HTTP模块能够灵活、有效地指定下一个HTTP处理模块是哪一个,同时让每一个HTTP模块能正确地将自己插入到完整流程的合适位置中。

对于TCP/UDP会话,Nginx也采用了类似的阶段处理方式,会话会按顺序经过多个称为阶段的步骤进行处理:

  • Post-accept(接受后):接受客户端连接后的第一个阶段
  • Pre-access(访问前):初步的访问检查
  • Access(访问):在实际数据处理之前限制客户端访问
  • SSL:TLS/SSL终止
  • Preread(预读):将初始数据字节读取到预读缓冲区中
  • Content(内容):实际处理数据,通常将数据代理到上游服务器或返回指定值给客户端
  • Log(日志):记录客户端会话处理的结果

3.2 请求处理的完整流程

Nginx处理HTTP请求的完整过程,对应到底层,就是读写socket事件。它包括:

  • 建立连接
  • 读取请求:解析请求
  • 处理请求
  • 响应请求

具体来说,接收请求时,Nginx会逐行读取请求行和请求头,判断有请求体后读取请求体;然后处理请求;最后根据处理结果返回响应,生成相应的HTTP请求(响应行、响应头、响应体)。

4. Nginx的进程模型:高效并发的秘密

Nginx之所以能实现高性能和高并发,与其精巧的进程模型密不可分。Nginx服务器正常运行过程中采用多进程架构:

  • Master进程:管理Worker进程,对外接口接收外部操作(信号),对内转发根据外部操作的不同通过信号管理Worker,并监控worker进程的运行状态,worker进程异常终止后自动重启worker进程。
  • Worker进程:所有Worker进程都是平等的,实际处理网络请求由Worker进程处理。Worker进程数量在nginx.conf中配置,一般设置为核心数,充分利用CPU资源,同时避免进程数量过多导致进程竞争CPU资源,增加上下文切换的损耗。

Nginx采用多进程+异步非阻塞方式(IO多路复用epoll)处理请求。这种设计使得Nginx能够高效处理大量并发连接,每个工作进程可以处理数千个并发连接,而不会产生严重的性能开销。

启动时,Master进程加载配置文件,初始化监听的socket,然后fork出多个Worker进程。Worker进程竞争新的连接,获胜方通过三次握手建立Socket连接,并处理请求。

5. Nginx配置与模块开发:实战入门

5.1 开发一个简单的HTTP模块

开发一个完整的简单的HTTP模块需要几个步骤(以模块名为ngx_http_mytest_module为例):

  1. 编写config文件:为了让nginx在configure过程能找到编写的模块。
  2. 编写模块结构ngx_http_mytest_module:定义模块的上下文结构和命令结构。
  3. 编写模块上下文结构ngx_http_mytest_module_ctx:指定nginx在触发了模块运行的时候,如何处理已经在其他http、server、location定义过的上下文。
  4. 编写模块命令结构ngx_http_mytest_commands:指定nginx在配置文件中触发了哪些命令,包括触发命令的回调函数。
  5. 编写触发命令的回调函数ngx_http_mytest:设置对http请求的具体处理方法。
  6. 编写对http请求的具体处理方法ngx_http_mytest_handler:从参数中获取http请求结构,并设置http返回。

5.2 使用NJS脚本语言扩展Nginx

除了使用C语言开发模块外,Nginx还提供了NJS脚本语言,通过JavaScript脚本扩展服务器的功能。使用NJS可以:

  • 在请求到达上游服务器之前进行复杂的访问控制和安全检查
  • 操作响应头
  • 编写灵活的异步内容处理程序和过滤器

以下是一个基本的NJS示例:

创建一个NJS脚本文件,例如http.js

function hello(r) {
    r.return(200, "Hello world!");
}

export default {hello};

nginx.conf文件中,启用ngx_http_js_module模块并使用http.js脚本文件:

load_module modules/ngx_http_js_module.so;

events {}

http {
    js_import http.js;

    server {
        listen 8000;

        location / {
            js_content http.hello;
        }
    }
}

这种方式比开发完整的C模块要简单得多,适合实现一些自定义逻辑。

6. 性能优化:让Nginx飞起来

要最大化Nginx的性能,需要考虑多个方面的优化:

  • Worker进程数:一般设置为核心数,充分利用CPU资源。
  • 事件处理模型:使用epoll(Linux 2.6+)等高效的事件处理机制。
  • 文件AIO:在支持的系统上(FreeBSD 4.3+、Linux 2.6.22+)启用文件异步I/O。
  • 直接I/O:在适当情况下使用DIRECTIO(FreeBSD 4.4+、Linux 2.4+、Solaris 2.6+、macOS)。
  • 连接限制:限制来自单个地址的并发连接或请求数,防止某些客户端耗尽资源。
  • 响应速率限制:控制响应输出的速率。

7. 完整示例:构建一个自定义内容过滤器

让我们通过一个完整的示例,演示如何开发一个简单的HTTP模块,用于在响应中添加自定义页脚。

7.1 编写config文件

ngx_addon_name=ngx_http_mytest_module
HTTP_MODULES="$HTTP_MODULES ngx_http_mytest_module"
NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/ngx_http_mytest_module.c"

7.2 编写模块源代码

#include <ngx_config.h>
#include <ngx_core.h>
#include <ngx_http.h>

static ngx_int_t ngx_http_mytest_handler(ngx_http_request_t *r);
static char *ngx_http_mytest(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);

static ngx_command_t ngx_http_mytest_commands[] = {
    {
        ngx_string("mytest"),
        NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LMT_CONF|NGX_CONF_NOARGS,
        ngx_http_mytest,
        NGX_HTTP_LOC_CONF_OFFSET,
        0,
        NULL
    },
    ngx_null_command
};

static ngx_http_module_t ngx_http_mytest_module_ctx = {
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL
};

ngx_module_t ngx_http_mytest_module = {
    NGX_MODULE_V1,
    &ngx_http_mytest_module_ctx,
    ngx_http_mytest_commands,
    NGX_HTTP_MODULE,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NGX_MODULE_V1_PADDING
};

static char *ngx_http_mytest(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
    ngx_http_core_loc_conf_t *clcf;

    clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);
    clcf->handler = ngx_http_mytest_handler;

    return NGX_CONF_OK;
}

static ngx_int_t ngx_http_mytest_handler(ngx_http_request_t *r)
{
    ngx_int_t rc;
    ngx_buf_t *b;
    ngx_chain_t out;

    rc = ngx_http_discard_request_body(r);
    if (rc != NGX_OK) {
        return rc;
    }

    ngx_str_t response = ngx_string("Hello, this is my test module!");

    b = ngx_create_temp_buf(r->pool, response.len);
    if (b == NULL) {
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    ngx_memcpy(b->pos, response.data, response.len);
    b->last = b->pos + response.len;
    b->last_buf = 1;
    b->last_in_chain = 1;

    r->headers_out.status = NGX_HTTP_OK;
    r->headers_out.content_length_n = response.len;

    rc = ngx_http_send_header(r);
    if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) {
        return rc;
    }

    out.buf = b;
    out.next = NULL;

    return ngx_http_output_filter(r, &out);
}

7.3 编译和配置

将以上代码保存为ngx_http_mytest_module.c,然后在编译Nginx时添加该模块:

./configure --add-module=/path/to/module
make && make install

在Nginx配置中使用:

location /test {
    mytest;
}

8. 结语

Nginx的HTTP处理框架是一个精心设计的系统,它通过阶段划分、模块化设计和高效的事件处理机制,实现了极高的性能和可扩展性。

理解Nginx的HTTP处理引擎,不仅有助于我们更好地使用Nginx,更能为我们设计高性能系统提供宝贵的思路和启示。

无论是使用现有的Nginx功能,还是开发自定义模块,深入理解Nginx的HTTP框架都是非常有价值的。随着HTTP/3等新协议的支持,Nginx仍在不断进化,继续为构建高性能Web服务提供坚实的基础。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

值引力

持续创作,多谢支持!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值