Nginx源码研究二:NGINX的事件处理概论
NGINX作为服务端的应用程序,在客户端发出数据后,服务端在做着这样一些处理,数据先会经过网卡,网卡会和操作系统做交互,经过操作系统的协议栈处理,再和不同的应用程序交互。
在这里面涉及两个概念,一个是用户态,一个是内核态。应用程序通过系统调用函数进入内核空间,内核运行进行数据准备和数据拷贝等工作。对于NGINX来说,他是作为应用程序和操作系统交互,即是用户态和内核态的之间的交互,NGINX和内核交互方式有很多,例如open(),read() 等都是在和内核交互,而对于网络IO来说,我们知道linux下的网络IO主要有五种:
一是阻塞IO,应用程序调用内核函数,阻塞到内核完成数据准备和数据拷贝的全过程。
二是非阻塞IO,应用程序调用内核函数,不断的查问内核数据是否准备好,直到内核数据准备好,再阻塞到内核完成数据拷贝。
第三种是I/O复用,应用程序调用内核参数,告知内核关心的事件,内核在收到该事件准备好的数据后,通知应用程序,应用程序再阻塞到内核的数据拷贝完成,一般web服务器都采用这样的IO模型,例如Apache采用的select/poll,当然nginx也支持select/poll,但是在linux2.6后,NGINX一般选择epoll。
第四种是信号,应用程序安置一个信号处理函数,运行过程不阻塞,操作系统在将数据准备好后,会发送一个信号给应用程序,应用程序的信号处理函数可以做IO处理。
第五种的异步,应用程序在调用操作系统提供的异步IO函数,例如aio_read。
告知操作系统发出的请求无需立即返回,待操作系统做完数据准备和数据拷贝后,再通知应用程序通过系统调用函数指定的信号。
实际上网络I/O模型中,前四种都是同步模型,第五种是异步模型。
我们先看一下NGINX的module里面支持的IO模型。
|-- event
| |-- modules
| | |-- ngx_aio_module.c
| | |-- ngx_devpoll_module.c
| | |-- ngx_epoll_module.c
| | |-- ngx_eventport_module.c
| | |-- ngx_kqueue_module.c
| | |-- ngx_poll_module.c
| | |-- ngx_rtsig_module.c
| | |-- ngx_select_module.c
| | `-- ngx_win32_select_module.c
在本章,将重点研究NGINX使用epoll做网络IO。
NGINX做网络IO,涉及到三个module:
module名称 |
类型 |
所在文件 |
ngx_events_module |
NGX_CORE_MODULE |
ngx_event.c |
ngx_event_core_module |
NGX_EVENT_MODULE |
ngx_event.c |
ngx_epoll_module |
NGX_EVENT_MODULE |
module/ngx_epoll_module.c |
在上一章,提到了module的启动过程,在init_cycle函数,对ngx_events_module的配置信息做了生成,通过分析配置文件,调用ngx_events_commands去对NGX_EVENT_MODULE做了配置信息的生成,分析,初始化。
一、master-work工作模式的处理过程
在解决配置信息的处理后,我们来看看进程的处理过程
1、 我们选择master-work工作模式
ngx_master_process_cycle(ngx_cycle_t *cycle)
{
...... ngx_start_worker_processes(cycle, ccf->worker_processes,
NGX_PROCESS_RESPAWN);
ngx_start_cache_manager_processes(cycle, ); ......
}
2、
static void
ngx_start_worker_processes(ngx_cycle_t *cycle, ngx_int_t n, ngx_int_t type)
{
ngx_int_t i;
ngx_channel_t ch; ngx_log_error(NGX_LOG_NOTICE, cycle->log, , "start worker processes"); ch.command = NGX_CMD_OPEN_CHANNEL; for (i = ; i < n; i++) { ngx_spawn_process(cycle, ngx_worker_process_cycle,
(void *) (intptr_t) i, "worker process", type); ch.pid = ngx_processes[ngx_process_slot].pid; //主进程的情况
ch.slot = ngx_process_slot;
ch.fd = ngx_processes[ngx_process_slot].channel[]; ngx_pass_open_channel(cycle, &ch);
}
}
3、
//进程生成
ngx_pid_t
ngx_spawn_process(ngx_cycle_t *cycle, ngx_spawn_proc_pt proc, void *data,
char *name, ngx_int_t respawn)
{
…… pid = fork(); switch (pid) { case -:
ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
"fork() failed while spawning \"%s\"", name);
ngx_close_channel(ngx_processes[s].channel, cycle->log);
return NGX_INVALID_PID; case : //子进程进入到proc
ngx_pid = ngx_getpid();
proc(cycle, data);
break; default: //父进程继续
break;
} …… return pid;
}
4、
static void
ngx_worker_process_cycle(ngx_cycle_t *cycle, void *data)
{
…… ngx_worker_process_init(cycle, worker); ngx_setproctitle("worker process"); …… for ( ;; ) {
……
ngx_process_events_and_timers(cycle);
……
}
}
5、
static void
ngx_worker_process_init(ngx_cycle_t *cycle, ngx_int_t worker)
{
…… for (i = ; ngx_modules[i]; i++) {
if (ngx_modules[i]->init_process) {
if (ngx_modules[i]->init_process(cycle) == NGX_ERROR) {
/* fatal */
exit();
}
}
} …… if (ngx_add_channel_event(cycle, ngx_channel, NGX_READ_EVENT,
ngx_channel_handler)
== NGX_ERROR)
{
/* fatal */
exit();
}
}
6、
static ngx_int_t
ngx_event_process_init(ngx_cycle_t *cycle)
{
...... //初始化module的action ......
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;
} rev = cycle->read_events;
for (i = ; i < cycle->connection_n; i++) {
rev[i].closed = ;
rev[i].instance = ;
#if (NGX_THREADS)
rev[i].lock = &c[i].lock;
rev[i].own_lock = &c[i].lock;
#endif
} cycle->write_events = ngx_alloc(sizeof(ngx_event_t) * cycle->connection_n,
cycle->log);
if (cycle->write_events == NULL) {
return NGX_ERROR;
} wev = cycle->write_events;
for (i = ; i < cycle->connection_n; i++) {
wev[i].closed = ;
#if (NGX_THREADS)
wev[i].lock = &c[i].lock;
wev[i].own_lock = &c[i].lock;
#endif
} 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) -; next = &c[i]; #if (NGX_THREADS)
c[i].lock = ;
#endif
} while (i); cycle->free_connections = next;
cycle->free_connection_n = cycle->connection_n; /* for each listening socket */ ls = cycle->listening.elts;
for (i = ; i < cycle->listening.nelts; i++) { ...... rev->handler = ngx_event_accept; if (ngx_use_accept_mutex) {
continue;
} if (ngx_event_flags & NGX_USE_RTSIG_EVENT) {
if (ngx_add_conn(c) == NGX_ERROR) {
return NGX_ERROR;
} } else {
if (ngx_add_event(rev, NGX_READ_EVENT, ) == NGX_ERROR) {
return NGX_ERROR;
}
} #endif } return NGX_OK;
}
Nginx源码研究二:NGINX的事件处理概论的更多相关文章
- Nginx源码研究一:NGINX模块启动
Nginx 是一个轻量级,但是高性能的 HTTP 和 代理 服务器,也是一个 IMAP/POP3/SMTP代理服务器. 它的第一个版本0.1.0是由俄罗斯的工程师Igor Sysoev与2004年10 ...
- Chrome自带恐龙小游戏的源码研究(二)
在上一篇<Chrome自带恐龙小游戏的源码研究(一)>中实现了地面的绘制和运动,这一篇主要研究云朵的绘制. 云朵的绘制通过Cloud构造函数完成.Cloud实现代码如下: Cloud.co ...
- Nginx源码研究七:nginx的location指令分析
在nginx的配置文件nginx.conf中,我们在配置server的时候,会配置一下location指令,这个location指令是提供给用户来配置对于符合指令的http请求,采用该指令内部的处理方 ...
- Nginx源码研究六:NGINX的配置文件分析
上一篇写到nginx的各个模块的配置信息的存储结构,大体描述了对配置信息的配置项生成,定制,初始化过程.这里重点研究实现定制的过程,所谓实现定制,这里指的是,nginx系统提供使用者定义nginx的配 ...
- Nginx (一)Windows下编译Nginx源码以及安装 nginx for windows方法步骤
转载自: http://apps.hi.baidu.com/share/detail/11192699#content Nginx介绍: Nginx ("engine x")是一个 ...
- Nginx源码研究五:NGINX的配置信息管理
配置信息是nginx系统重要的组成部分,配置信息的使用,实际上包含两层,一层是用户针对参数定义了值,例如下面nginx参数文件中的 keepalive_timeout 65,还有一部分是用户没有定义值 ...
- Nginx源码研究八:nginx监听socket实现流程
前面描述了nginx系统分析nginx的配置文件,初始化模块相关参数的过程,这里利用nginx监听socket的实现过程,做一次完整的回顾 1.首先,nginx启动的main函数中,会先初始化cycl ...
- Nginx源码研究四:NGINX的内存管理
关于nginx的内存使用,我们先看代码,下面是nginx_cycle.c中对全局数据结构cycle的初始化过程 pool = ngx_create_pool(NGX_CYCLE_POOL_SIZE, ...
- Nginx源码研究三:Epoll在NGINX中的使用
Web服务器在面对高并发的情况下,网络的IO一般选择IO复用,像apache选择的Select/poll.Nginx在linux 2.6后选择Epoll做网路IO,提高了WEB服务的并发能力. 在本章 ...
随机推荐
- 设计模式(四):SIMPLE FACTORY简单工厂模式 -- 创建型模式
1.定义 简单工厂模式又称静态工厂方法模式.重命名上就可以看出这个模式一定很简单.它存在的目的很简单:定义一个用于创建对象的接口. 2.适用场景 如果一个客户要一款宝马车,一般的做法是客户去创建一款宝 ...
- HDU 献给杭电五十周年校庆的礼物 1290 递推
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=1290 题目大意: n刀最多可以把一块蛋糕切多少块 题目分析: 假如我们按照立体考虑的话,这题就非常不 ...
- kindle paperwhite 使用说明
calibre,eink必备转换软件. easypub,lucida制作的软件,支持txt to epub:txt to mobi,可以实现目录. 售后电话:400 817 0100 正常的设计格式转 ...
- SQL中Merge的用法
SQL中Merge的用法 Merge的用法 Merge可以完成以下功能: 1. 两个表之间数据的更新 2. 进行进销存更新库存 3. 进行表之间数据的复制 语法说明: 1. 在语句结束后一定要 ...
- ulimit开启coredump时核心转储
[root@localhost ~]# ulimit -c [root@localhost ~]# ulimit -a core data seg size (kbytes, -d) unlimite ...
- Hibernate 关于load和get方法区别
load和个体方法都可以充分利用内部缓存和二级缓存中的现有数据. ******************************************************************* ...
- JAVA - 回调机制
参考例子:android的Button OnClickListener接口.<第一行代码>中的回调例子 定义接口 public interface HttpCallbackListen ...
- yii图片上传
http://wuhai.blog.51cto.com/2023916/953300 首先感谢这里的博主,提供了思路,不过在调用 $model->b_image->extensionNam ...
- 【转】iOS实时卡顿监控
转自http://www.tanhao.me/code/151113.html/ 在移动设备上开发软件,性能一直是我们最为关心的话题之一,我们作为程序员除了需要努力提高代码质量之外,及时发现和监控软件 ...
- 小学生之使用Mybatis反向生成dao,entity,xml
本小学生刚进公司的时候,就一顿装逼,不管别人问我啥我都会说:"会"!毕竟在公司吗,什么都要装,不要别人看出你的底细.不过有一天,听说用Mybatis可以反向生成dao(第一次听说) ...