Nginx 源码分析:从模块到配置(下)

发布于 2025-05-07 05:56:50 字数 7397 浏览 8 评论 0

关于模块

Nginx 的架构高度模块化。每个模块各司其职,组合在一起完成特定的功能。

Nginx 通过 configure 决定哪些模块被安装。所有安装的模块在编译阶段静态生成,其指针被统一放入 ngx_modules 数组中,供全局使用。

每个模块由以下几部分构成:

  1. ngx_module_t 结构体:代表模块本身,其指针被放入 ngx_modules 数组中。
  2. ngx_<module name>_conf_t 结构体:用来表示模块的配置内容,其中部分成员可以通过配置文件进行配置。
  3. ngx_<module name>_module_t 结构体:模块上下文,保存了一组操作, Nginx 初始化阶段调用这些操作,初始化 ngx_<module name>_conf_t 中的成员。
  4. ngx_command_t 结构体 数组 :该数组中每一项 ngx_command_t 对应配置文件中一条指令。

Nginx 的模块虽然有很多。但是基本类型只有 5 种: CORF、CONF、EVNT、HTTP、MAIL

#define NGX_CORE_MODULE      0x45524F43  /* "CORE" */
#define NGX_CONF_MODULE      0x464E4F43  /* "CONF" */
#define NGX_EVENT_MODULE     0x544E5645  /* "EVNT" */
#define NGX_HTTP_MODULE      0x50545448  /* "HTTP" */
#define NGX_MAIL_MODULE      0x4C49414D  /* "MAIL" */

每种类型对应一种 ngx_<module name>_module_t 上下文结构体。 Nginx 在初始化(主要在 ngx_init_cycle 函数中)时根据不同的模块类型,调用不同的上下文中的操作,完成其配置内容的初始化。

虽然模块类型只有 5 种,但是模块数量可以有很多,每个模块都针对自身有特定的配置内容, 这些配置内容中,可以被放到配置文件 nginx.conf 中的,被包装成了一条条 ngx_command_t 指令 。这些指令的内容决定了 nginx.conf 中可以写入的操作指令。

Nginx 初始化时解析 nginx.conf 配置文件,找到对应的 ngx_command_t 。调用该 ngx_command_t 中的函数,该函数最终初始化模块对应的 ngx_<module name>_conf_t 结构体,完成配置。

这就是模块和配置之间的关系。

配置文件、指令

谈到 Nginx 的配置,首先想到的肯定是配置文件 nginx.conf

众所周知, nginx.conf 配置文件的结构由一条条 Nginx 配置指令构成( 官方文档 )。
Nginx 配置指令可以分为两种:简单指令和块指令。

例如:

  • worker_processes 1; 就是一条简单指令
  • events { ... } 就是一条块指令

如果,一个块指令中含有其他指令,那么称这个块指令为 上下文 (注意区别模块中的上下文概念)。
例如:

 events {
      use epoll;
      worker_connections  1024;
 }

events 是块指令,由于 events 中包含有指令(简单指令或块指令)。因此称 eventsevents 上下文

常见的上下文还有: http 上下文、server 上下文、location 上下文整个 nginx.conf 文件称为 main 上下文

源码中的配置指令

前面提到过: Nginx 配置文件中的一条指令对应一个 ngx_command_t 结构体。因此,分析源码中的配置指令,就是分析 ngx_command_t 结构体。

ngx_command_t 结构体定义:

struct ngx_command_s {
    ngx_str_t             name;
    ngx_uint_t            type;
    char               *(*set)(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
    ngx_uint_t            conf;
    ngx_uint_t            offset;
    void                 *post;
};

各成员含义如下:

name :本条指令的名字,例如 worker_processes 1; 对应的 ngx_command_s.name 就是 worker_processes

set :函数指针,所以 set 用来表示,当 Nginx 解析配置文件,碰到指令时,该执行怎样的操作。而该操作本身,自然是用来设置本模块所对应的 ngx_<module name>_conf_t 结构体。

conf :这个变量只在 NGX_HTTP_MODULE 类型的模块的 ngx_command_t 使用。这个变量和今天讨论的话题关系不大。暂不讨论。

offset :这个变量用来标记 ngx_<module name>_conf_t 中某成员变量的偏移量,纯粹是为使用方便。

type :配置指令属性的集合。例如, worker_processes 这条指令对应的 type 定义为:

NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE1

其中,各个宏定义如下:

#define NGX_MAIN_CONF        0x01000000
#define NGX_DIRECT_CONF      0x00010000
#define NGX_CONF_TAKE1       0x00000002
  • NGX_MAIN_CONF 是指,该指令用于 main 上下文
  • NGX_DIRECT_CONF 是指,该指令是用于 main 上下文的简单指令
  • NGX_CONF_TAKE1 是指,该指令后跟一个参数,例如 worker_processes 1;1 就是指后面跟一个参数,这个参数的数目由 NGX_CONF_TAKE1 指定。

类似用来定义指令类型的宏还有很多,具体可以参考源码中各个模块中 ngx_command_t 的设置。

几个典型的配置指令

daemon 指令

Nginx 默认是以后台的形式运行的,这种运行形式被称为 daemon ,当然,在调试的时候,为了方便,一般是关掉 daemon 这种运行形式。

在配置文件中通过 daemon 指令来打开或关闭。官方文档对 daemon 指令说明如下:

Syntax:     daemon on | off;
Default:    daemon on;
Context:    main

在源码中( core\nginx.c ), daemon 指令对应的 ngx_command_t 结构体如下:

     {ngx_string("daemon"),                              // 指令的名字 daemon
      NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_FLAG,       // 指令的类型
      ngx_conf_set_flag_slot,                            // 指令对应的操作
      0,
      offsetof(ngx_core_conf_t, daemon),
      NULL }

其中, NGX_MAIN_CONF 指, daemon 指令的上下文为 main 上下文
NGX_DIRECT_CONF 指, daemon 指令是一条可以直接写在 main 上下文的 简单指令。
NGX_CONF_FLAG 指, daemon 指令是一个开关指令,接收 on | off 作为指令参数。

user 指令

Nginx 可以在配置文件中通过 user 指令指定运行时所在的用户及用户组。官方文档对 user 指令的说明如下:

Syntax:     user user [group];
Default:    user nobody nobody;
Context:    main

在源码中( core\nginx.c ), user 对应的 ngx_command_t 结构体定义如下:

    { ngx_string("user"),
      NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE12,
      ngx_set_user,
      0,
      0,
      NULL },

其中 NGX_MAIN_CONFNGX_DIRECT_CONF 的含义与 daemon 指令的含义相同。
NGX_CONF_TAKE12 是指该指令接收 1 个或两个参数 ,即 Syntax: user user [group];

events 指令

Nginx 中可以指定采用的事件监听机制类型,比如 select、poll、epoll 等。
这个指定操作在 events 指令中完成。这里 events 指令为 块指令

官方文档对 events 指令的定义如下:

Syntax:     events { ... }
Default:    —
Context:    main

在源码中( event\ngx_event.c ), events 指令对应的 ngx_command_t 结构体定义如下:

    { ngx_string("events"),
      NGX_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_NOARGS,
      ngx_events_block,
      0,
      0,
      NULL }

其中, NGX_MAIN_CONF 的含义与 daemon 指令相同。
NGX_CONF_BLOCK 是指,这是一条 块指令
NGX_CONF_NOARGS 是指,该指令不接受参数。

总结

以上三条指令能够很清楚的说明,在 Nginx 源码中是如何组织和管理配置文件中使用的配置指令的。
对于其他指令,可以直接阅读源码中该指令的定义。源码就是最好的文档。

关于模块和配置的总结

由于 Nginx 是高度模块化的,因而, Nginx 的配置一定是对模块的配置

Nginx 的每条配置指令对应某模块中的一条 ngx_command_t 定义。

每条 ngx_command_t 一定操作了其所在模块的 ngx_<module name>_conf_t 结构体中某些项。

Nginx 初始化时,首先解析配置文件,然后执行对应指令的 ngx_command_t 中的操作函数,设置 ngx_<module name>_conf_t 中的某些项,完成配置工作。

然后, Nginx 根据这些配置,执行启动流程,进而开始工作。

到此为止。本篇结束。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。