【Nginx】Nginx基础架构

调用HTTP模块的流程:

Worker进程会在一个for循环语句中反复调用事件模块检测网络事件。当事件模块检测到某个客户端发起的TCP请求时(接收到SYN包),将会为它建立TCP连接,成功建立连接后根据nginx.conf文件中的配置会交由HTTP框架处理。HTTP框架会试图接收完整的HTTP头部,并在接受到完整的HTTP头部后将请求分发到具体的HTTP模块中处理。这种分发策略是多样化的,最常见的是根据请求的URI和nginx.conf里location配置项的匹配度来决定如何分发。HTTP模块在处理请求的结束时,大多会向客户端发送响应,此时会自动地依次调用所有的HTTP过滤模块,每个过滤模块可以根据配置文件决定自己的行为。

事件类型的模块主要处理I/O事件相关的功能,HTTP类型的模块主要处理HTTP应用层的功能。

Nginx在解析配置文件中的一个配置项时首先会遍历所有的模块,对于每一个模块而言,即通过遍历commands数组进行,另外,在数组中检查到ngx_null_command时,会停止使用当前模块解析该配置项。=>我的理解:如果在某模块中找到该配置项名称,则调用该模块中commands数组的set方法来解析该配置项。Set方法中会调用ngx_http_mytest_handler函数

一、Nginx的架构设计

1)优秀的模块化设计

1)高度抽象的模块接口

所有的模块都遵循着同样的ngx_module_t接口设计规范,ngx_module_t是所有模块的通用接口

2)模块接口非常简单,具有很高的灵活性

模块的基本接口ngx_module_t足够简单,只涉及模块的初始化、退出以及对配置项的处理

3)配置模块的设计

配置模块的类型是NGX_CONF_MODULE,它仅有的模块为ngx_conf_module,这是Nginx最底层的模块,它指导着所有模块以配置项为核心来提供功能

4)核心模块接口的简单化

基础类型的模块:核心模块,它的模块类型为NGX_CORE_MODULE,目前官方的核心类型模块中共有6个具体模块,分别是ngx_core_module,ngx_errlog_module,ngx_events_module,ngx_openssl_module,ngx_http_module,ngx_mail_module模块。定义核心模块是为了让非模块化的框架代码只关注于如何调用6个核心模块

核心模块的接口如下,它将ctx上下文进一步实例化为ngx_core_module_t结构体:

typedef struct{

//核心模块名称

ngx_str_t name;

void *(*create_conf)(ngx_cycle_t *cycle);

char *(*init_conf)(ngx_cycle_t *cycle,void *conf);

}ngx_core_module_t;

ngx_core_module_t上下文是以配置项的解析作为基础的,它提供了create_conf回调方法来创建存储配置项的数据结构,在读取nginx.conf配置文件时,会根据模块中的ngx_command_t把解析出的配置项存放在这个数据结构中;它还提供了init_conf回调方法,用于在解析完配置文件后,使用解析出的配置项初始化核心模块功能。

上述设计使得每个核心模块都可以自由地定义全新的模块类型,新定义的模块由核心模块管理。

5)多层次、多类别的模块设计

官方Nginx共有五大类型的模块:核心模块、配置模块、事件模块、HTTP模块、mail模块。

配置模块和核心模块由Nginx的框架代码定义,其他3种模块都不会和框架产生直接关系。

事件模块、HTTP模块、mail模块这三种模块在核心模块中各有一个模块作为自己的代言人,并在同类模块中有一个作为核心业务与管理功能的模块

在这5中模块中,配置模块与核心模块都是与Nginx框架密切相关的,是其他模块的基础。而事件模块则是HTTP模块和mail模块的基础。在事件模块中,ngx_event_core_module事件模块是其他所有事件模块的基础;在http模块中,ngx_http_core_module模块是其他所有HTTP模块的基础;在mail模块中,ngx_mail_core_module模块是其他所有mail模块的基础。

2)事件驱动架构

事件驱动架构是指由一些事件发生源来产生事件,由一个或多个事件收集器来收集、分发事件,然后许多事件处理器会注册自己感兴趣的事件,同时会消费这些事件。

对于Nginx而言,一般会由网卡、磁盘产生事件,事件模块将负责事件的收集、分发操作,而所有的模块都可能是事件消费者。

Nginx采用完全的事件驱动架构来处理业务。对于传统web服务器而言,事件驱动往往局限在TCP链接建立、关闭事件上,一个连接建立以后,在其关闭之前的所有操作逗不再是事件驱动,这时会退化成按序执行每个操作的批处理模式,这样每个请求在链接建立后都将始终占用着系统资源,知道连接关闭才会释放资源。传统web服务器往往把进程或线程作为事件消费者,当一个请求产生的事件被该进程处理时,知道这个请求处理结束时进程资源都将被这个请求所占用。

Nginx只有事件收集、分发器才有资格占用进程资源,它们会在分发某个事件时调用事件消费模块使用当前占用的进程资源。

3)请求的多阶段异步处理

即把一个请求的处理过程按照事件的触发方式分为多个阶段,每个阶段都可以由事件收集、分发器来触发。

关键在于划分请求的阶段,一般是找到请求处理流程中的阻塞方法(或者造成阻塞的代码段),在阻塞代码段上按照下面4种方式来划分阶段:

1.将阻塞进程的方法按照相关的触发事件分解为两个阶段

大部分情况下,一个阻塞进程的方法调用时可以划分为两个阶段:阻塞方法改为非阻塞方法调用,这个调用非阻塞方法并将进程归还给事件分发器的阶段就是第一阶段;增加新的处理阶段用于处理非阻塞方法最终返回的结果,这里的结果返回事件就是第二阶段的触发事件

2.将阻塞方法调用按照时间分解为多个阶段的方法调用

系统中的事件收集、分发者并非可以处理任何事件,如果按照前一种方式试图划分某个方法时,那么可能会发现找出的触发事件不能够被事件收集、分发器所处理,这时只能按照执行时间来拆分这个方法。

例如读取10MB的文件(ngx_epoll_module模块主要是针对网络事件),可以这样来分解读取文件调用:每次只读取10kb,这样该事件接收器占用进程的时间不会太久,整个进程可以及时地处理其他请求。

在读取0-10kb后,为了进入10kb-20kb阶段,可以用能被事件收集器处理的事件来触发,或者设置一个定时器。

3.在无所事事且必须等待系统的响应,从而导致进程空转时,使用定时器划分阶段

当定时器事件发生时就会检查标志,如果标志位不满足,就立刻归还进程控制权,同时继续加入期望的下一个定时器事件

4.如果阻塞方法完全无法继续划分,则必须使用独立的进程执行这个阻塞方法

4)管理进程、多工作进程设计

Nginx采用一个master管理进程、多个worker工作进程的设计方式。

优点:

1.利用多核系统的并发处理能力。

Nginx中所有的worker工作进程都是完全平等的。

2.负载均衡

多个worker工作进程间通过进程间通信来实现负载均衡,当一个请求到来时更容易被分配到负载较轻的worker工作进程中处理。

3.管理进程会负责监控工作进程的状态,并负责管理其行为。

5)内存池的设计

优点:把多次向系统申请内存的操作整合成一次,大大减少了cpu资源的消耗,同时减少了内存碎片,提高了内存的有效利用率和系统可处理的并发连接数。

二、Nginx框架中的核心结构体ngx_cycle_t

ngx_listening_t结构体

ngx_cycle_t对象中有一个动态数组成员叫做listening,它的每个数组元素都是ngx_listening_t结构体,而每个ngx_listening_t结构体代表着Nginx服务器监听的一个端口。

ngx_cycle_t结构体

Nginx框架是围绕着ngx_cycle_t结构体来控制进程运行的。ngx_cycle_t结构体的prefix,conf_prefix,conf_file等字符串类型成员保存着Nginx配置文件的路径。

三、Nginx启动时框架的处理流程

四、worker进程工作流程

五、master进程工作流程

参考:

http://blog.csdn.net/xifeijian/article/details/17385831