ngx_event_core_module模块属于事件模块,它是其他事件类模块的基础。它主要完毕下面任务:

  • 创建连接池
  • 决定使用哪些事件驱动机制
  • 初始化将要使用的事件模块

以下分析该模块的代码。

ngx_event_core_module的ngx_command_t数组定义例如以下:
  1. /* ngx_event_core_module对7个配置项感兴趣 */
  2. static ngx_command_t ngx_event_core_commands[] = {
  3. /* 一个worker进程的最大TCP连接数 */
  4. {
  5. ngx_string("worker_connections"),
  6. NGX_EVENT_CONF|NGX_CONF_TAKE1,
  7. ngx_event_connections,
  8. 0,
  9. 0,
  10. NULL
  11. },
  12. /* 同上 */
  13. {
  14. ngx_string("connections"),
  15. NGX_EVENT_CONF|NGX_CONF_TAKE1,
  16. ngx_event_connections,
  17. 0,
  18. 0,
  19. NULL
  20. },
  21. /* 确定选择哪一个事件模块作为事件驱动机制 */
  22. {
  23. ngx_string("use"),
  24. NGX_EVENT_CONF|NGX_CONF_TAKE1,
  25. ngx_event_use,
  26. 0,
  27. 0,
  28. NULL
  29. },
  30. /* 当有连接事件时,尽可能多地建立连接 */
  31. {
  32. ngx_string("multi_accept"),
  33. NGX_EVENT_CONF|NGX_CONF_FLAG,
  34. ngx_conf_set_flag_slot,
  35. 0,
  36. offsetof(ngx_event_conf_t, multi_accept),
  37. NULL
  38. },
  39. /* 确定是否使用负载均衡锁 */
  40. {
  41. ngx_string("accept_mutex"),
  42. NGX_EVENT_CONF|NGX_CONF_FLAG,
  43. ngx_conf_set_flag_slot,
  44. 0,
  45. offsetof(ngx_event_conf_t, accept_mutex),
  46. NULL
  47. },
  48. /* 启用负载均衡锁后,延迟accept_mutex_delay毫秒再处理新连接事件 */
  49. {
  50. ngx_string("accept_mutex_delay"),
  51. NGX_EVENT_CONF|NGX_CONF_TAKE1,
  52. ngx_conf_set_msec_slot,
  53. 0,
  54. offsetof(ngx_event_conf_t, accept_mutex_delay),
  55. NULL
  56. },
  57. /* 对指定IP的TCP连接打印debug级别的调试日志 */
  58. {
  59. ngx_string("debug_connection"),
  60. NGX_EVENT_CONF|NGX_CONF_TAKE1,
  61. ngx_event_debug_connection,
  62. 0,
  63. 0,
  64. NULL
  65. },
  66. ngx_null_command
  67. };

有几个配置项的解析使用的是Nginx预设的方法,解析出来的參数存放在ngx_event_conf_t结构体中。该结构体定义例如以下:
  1. /* 相应ngx_event_core_commands数组中解析配置项的7个方法 */
  2. typedef struct {
  3. ngx_uint_t connections; /* 连接池大小 */
  4. ngx_uint_t use; /* 该模块在事件模块中的编号。也就是ngx_module_s.ctx_index */
  5. ngx_flag_t multi_accept; /* 1表示一次建立尽可能多的连接 */
  6. ngx_flag_t accept_mutex; /* 1表示启用负载均衡锁 */
  7. ngx_msec_t accept_mutex_delay; /* 拿不到负载均衡锁时延迟建立连接的时间 */
  8. u_char *name; /* 所选用事件模块的名字 */
  9. #if (NGX_DEBUG)
  10. ngx_array_t debug_connection; /* 调试用 */
  11. #endif
  12. } ngx_event_conf_t; // 存储事件类配置项的结构体

以下再看看事件模块的通用接口ngx_event_module_t结构体的定义:
  1. ngx_event_module_t ngx_event_core_module_ctx = {
  2. &event_core_name,
  3. ngx_event_core_create_conf, /* create configuration */
  4. ngx_event_core_init_conf, /* init configuration */
  5. /* 定义事件驱动模块的核心方法
  6. * ngx_event_core_module不负责TCP网络事件的驱动,所以无须定义这些方法
  7. */
  8. { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }
  9. };

从上面的通用接口能够看到。ngx_event_core_module模块并未定义10个抽象方法。

由于事件驱动模块是诸如epoll、select这样具有事件驱动机制的模块来担当的,这些模块才须要提供函数接口,以便将事件加入或删除。而ngx_event_core_module模块的作用仅仅是管理更下层的事件驱动模块,比如ngx_epoll_module、ngx_kqueue_module、ngx_poll_module等模块。


以下是整个ngx_module_t结构体的定义:
  1. ngx_module_t ngx_event_core_module = {
  2. NGX_MODULE_V1,
  3. &ngx_event_core_module_ctx, /* module context */
  4. ngx_event_core_commands, /* module directives */
  5. NGX_EVENT_MODULE, /* module type */
  6. NULL, /* init master */
  7. ngx_event_module_init, /* init module */
  8. ngx_event_process_init, /* init process */
  9. NULL, /* init thread */
  10. NULL, /* exit thread */
  11. NULL, /* exit process */
  12. NULL, /* exit master */
  13. NGX_MODULE_V1_PADDING
  14. };

能够看到,该模块定义了两个函数:ngx_event_module_init和ngx_event_process_init。Nginx启动过程中。在fork出worker进程之前调用ngx_event_module_init。这个函数做一些变量的初始化;在fork出worker进程之后调用ngx_event_process_init。该函数做了较多工作。流程图例如以下:

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbmVzdGxlcg==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">


此函数的代码在下方,凝视中的标号和流程图中的标号相相应:
  1. /* Nginx启动时在fork出worker子进程后调用 */
  2. static ngx_int_t
  3. ngx_event_process_init(ngx_cycle_t *cycle)
  4. {
  5. ngx_uint_t m, i;
  6. ngx_event_t *rev, *wev;
  7. ngx_listening_t *ls;
  8. ngx_connection_t *c, *next, *old;
  9. ngx_core_conf_t *ccf;
  10. ngx_event_conf_t *ecf;
  11. ngx_event_module_t *module;
  12. ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module);
  13. ecf = ngx_event_get_conf(cycle->conf_ctx, ngx_event_core_module); // 获得存储配置项的结构体
  14. /* 1、确定使用负载均衡锁的条件
  15. * 1.1 工作在master模式
  16. * 1.2 配置文件里打开了负载均衡锁
  17. * 1.3 worker进程数量大于1
  18. */
  19. if (ccf->master && ccf->worker_processes > 1 && ecf->accept_mutex) {
  20. ngx_use_accept_mutex = 1; /* 打开负载均衡锁 */
  21. ngx_accept_mutex_held = 0;
  22. ngx_accept_mutex_delay = ecf->accept_mutex_delay; /* 拿不到锁时的延迟时间 */
  23. } else {
  24. /* 2、关闭负载均衡锁 */
  25. ngx_use_accept_mutex = 0;
  26. }
  27. /* 3、初始化红黑树实现的定时器 */
  28. if (ngx_event_timer_init(cycle->log) == NGX_ERROR) {
  29. return NGX_ERROR;
  30. }
  31. for (m = 0; ngx_modules[m]; m++) {
  32. if (ngx_modules[m]->type != NGX_EVENT_MODULE) {
  33. continue;
  34. }
  35. /* ecf->use中保存了所使用的事件驱动模块的索引號 */
  36. if (ngx_modules[m]->ctx_index != ecf->use) {
  37. continue;
  38. }
  39. module = ngx_modules[m]->ctx; /* 获得选中模块的通用接口 */
  40. /* 4、初始化事件驱动模块模块 */
  41. if (module->actions.init(cycle, ngx_timer_resolution) != NGX_OK) {
  42. /* fatal */
  43. exit(2);
  44. }
  45. break;
  46. }
  47. /* 当配置文件里设置了timer_resolution配置项,进入这个块来控制时间精度 */
  48. if (ngx_timer_resolution && !(ngx_event_flags & NGX_USE_TIMER_EVENT)) {
  49. struct sigaction sa;
  50. struct itimerval itv;
  51. ngx_memzero(&sa, sizeof(struct sigaction));
  52. sa.sa_handler = ngx_timer_signal_handler; /* 信号处理函数 */
  53. sigemptyset(&sa.sa_mask);
  54. if (sigaction(SIGALRM, &sa, NULL) == -1) { /* 安装信号处理程序 */
  55. ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
  56. "sigaction(SIGALRM) failed");
  57. return NGX_ERROR;
  58. }
  59. itv.it_interval.tv_sec = ngx_timer_resolution / 1000;
  60. itv.it_interval.tv_usec = (ngx_timer_resolution % 1000) * 1000;
  61. itv.it_value.tv_sec = ngx_timer_resolution / 1000;
  62. itv.it_value.tv_usec = (ngx_timer_resolution % 1000 ) * 1000;
  63. /* 5、设置时间间隔。依据配置项timer_resolution的值,
  64. * 每隔这么多毫秒回调ngx_timer_signal_handler方法。
  65. * 该方法置位ngx_event_timer_alarm标志,表示须要更新时间
  66. */
  67. if (setitimer(ITIMER_REAL, &itv, NULL) == -1) {
  68. ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
  69. "setitimer() failed");
  70. }
  71. }
  72. if (ngx_event_flags & NGX_USE_FD_EVENT) {
  73. struct rlimit rlmt;
  74. if (getrlimit(RLIMIT_NOFILE, &rlmt) == -1) {
  75. ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
  76. "getrlimit(RLIMIT_NOFILE) failed");
  77. return NGX_ERROR;
  78. }
  79. cycle->files_n = (ngx_uint_t) rlmt.rlim_cur;
  80. /* 6、预先分配句柄 */
  81. cycle->files = ngx_calloc(sizeof(ngx_connection_t *) * cycle->files_n,
  82. cycle->log);
  83. if (cycle->files == NULL) {
  84. return NGX_ERROR;
  85. }
  86. }
  87. /* 7、预先分配连接池 */
  88. cycle->connections = ngx_alloc(sizeof(ngx_connection_t) * cycle->connection_n, cycle->log);
  89. if (cycle->connections == NULL) {
  90. return NGX_ERROR;
  91. }
  92. c = cycle->connections; // c指向连接池中的一个连接
  93. /* 8、预先分配读事件。事件个数等于分配的连接个数 */
  94. cycle->read_events = ngx_alloc(sizeof(ngx_event_t) * cycle->connection_n, cycle->log);
  95. if (cycle->read_events == NULL) {
  96. return NGX_ERROR;
  97. }
  98. rev = cycle->read_events;
  99. for (i = 0; i < cycle->connection_n; i++) {
  100. rev[i].closed = 1;
  101. rev[i].instance = 1;
  102. #if (NGX_THREADS)
  103. rev[i].lock = &c[i].lock;
  104. rev[i].own_lock = &c[i].lock;
  105. #endif
  106. }
  107. /* 9、预先分配写事件,事件个数等于分配的连接个数 */
  108. cycle->write_events = ngx_alloc(sizeof(ngx_event_t) * cycle->connection_n, cycle->log);
  109. if (cycle->write_events == NULL) {
  110. return NGX_ERROR;
  111. }
  112. wev = cycle->write_events;
  113. for (i = 0; i < cycle->connection_n; i++) {
  114. wev[i].closed = 1;
  115. #if (NGX_THREADS)
  116. wev[i].lock = &c[i].lock;
  117. wev[i].own_lock = &c[i].lock;
  118. #endif
  119. }
  120. i = cycle->connection_n;
  121. next = NULL;
  122. do {
  123. i--;
  124. /* 10、ngx_cycle_t所包括的连接池中,c指向连接池,
  125. * 一个连接相应一个读事件和一个写事件
  126. */
  127. c[i].data = next; /* 以data作为next指针将连接池中的连接串起来 */
  128. c[i].read = &cycle->read_events[i];
  129. c[i].write = &cycle->write_events[i];
  130. c[i].fd = (ngx_socket_t) -1;
  131. next = &c[i];
  132. #if (NGX_THREADS)
  133. c[i].lock = 0;
  134. #endif
  135. } while (i);
  136. /* 11、让free_connections指向空暇链表首部 */
  137. cycle->free_connections = next;
  138. cycle->free_connection_n = cycle->connection_n;
  139. /* for each listening socket */
  140. ls = cycle->listening.elts;
  141. for (i = 0; i < cycle->listening.nelts; i++) {
  142. /* 从空暇连接链表获得ngx_connection_t连接 */
  143. c = ngx_get_connection(ls[i].fd, cycle->log);
  144. if (c == NULL) {
  145. return NGX_ERROR;
  146. }
  147. c->log = &ls[i].log;
  148. c->listening = &ls[i];
  149. ls[i].connection = c;
  150. rev = c->read; /* 连接相应的读事件 */
  151. rev->log = c->log;
  152. rev->accept = 1;
  153. /* 12、定义读事件消费方法,有连接请求事件时调用此方法建立新连接 */
  154. rev->handler = ngx_event_accept;
  155. if (ngx_use_accept_mutex) {
  156. continue;
  157. }
  158. /* 13、将监听连接的读事件加入到epoll模块 */
  159. if (ngx_add_event(rev, NGX_READ_EVENT, 0) == NGX_ERROR) {
  160. return NGX_ERROR;
  161. }
  162. }
  163. return NGX_OK;
  164. }

至此,ngx_event_core_module模块的启动工作完毕,接下来的工作交由epoll事件驱动模块ngx_epoll_module负责。它负责收集、分发等事件。

參考:
《深入理解Nginx》 P305-P310.

【Nginx】ngx_event_core_module模块的更多相关文章

  1. Nginx事件管理之ngx_event_core_module模块

    1. 概述 ngx_event_core_module 模块是一个事件类型的模块,它在所有事件模块中的顺序是第一位.它主要完成以下两点任务: 创建连接池(包括读/写事件): 决定究竟使用哪些事件驱动机 ...

  2. Nginx:事件模块

    参考资料<深入理解Nginx> 根据不同的系统内核,Nginx会使用不同的事件驱动机制,本次描述的场景是使用epoll来驱动事件的处理. epoll的使用方法 1.int epoll_cr ...

  3. 【Nginx】Nginx事件模块

    一.事件处理框架概述 事件处理框架所要解决的问题是如何收集.管理.分发事件.事件以网络事件和定时器事件为主,而网络事件中以TCP网络事件为主.事件处理框架需要在不同的操作系统内核中选择一种事件驱动机制 ...

  4. 基于Nginx dyups模块的站点动态上下线并实现简单服务治理

    简介 今天主要讨论一下,对于分布式服务,站点如何平滑的上下线问题. 分布式服务 在分布式服务下,我们会用nginx做负载均衡, 业务站点访问某服务站点的时候, 统一走nginx, 然后nginx根据一 ...

  5. Nginx 切片模块、断点续传

    熟悉 CDN 行业主流技术的朋友应该都比较清楚,虽然 Nginx 近几年发展的如日中天,但是基本上没有直接使用它自带的 proxy_cache 模块来做缓存的,原因有很多,例如下面几个: 不支持多盘 ...

  6. nginx事件模块分析(一)

    nginx ngx_events_module模块分析 ngx_events_module模块是核心模块之一,它是其它所有事件模块的代理模块.nginx在启动时只与events模块打交道,而由even ...

  7. mac下Nginx+lua模块编译安装

    Nginx的nb之处就不说了,lua也是一个小巧的脚本语言,由标准C编写而成,几乎可以运行在所有的平台上,也非常强大,其他特性请自行度娘.nginx_lua_module是由淘宝的工程师清无(王晓哲) ...

  8. nginx添加模块 (非覆盖安装)

    nginx添加模块(非覆盖安装) 原已经安装好的nginx,现在需要添加一个未被编译安装的模块: 查看原来编译时都带了哪些参数# /usr/local/nginx/sbin/nginx -V ngin ...

  9. 一些好用的nginx第三方模块

    一些好用的nginx第三方模块 转自;http://macken.iteye.com/blog/1963301  1.Development Kit https://github.com/simpl/ ...

随机推荐

  1. Git简明教程二、开始进行版本管理

    上一篇介绍了Git中的一些基本概念.本篇来实际看一看如何通过几个常用命令来快速上手Git,完成版本管理的日常操作(核心操作). 0. 准备工作 安装Git后,请先在你的电脑上新建或选择一个目录作为测试 ...

  2. Django配置https协议

    本博客来自https://blog.csdn.net/huplion/article/details/52892901 1.首先我们需要得到一张证书文件 参考:WINDOWS系统下创建自签名SSL证书 ...

  3. 学习python绘图

    学会python画图 # 使用清华的pip源进行安装sklearn # pip install -i https://pypi.tuna.tsinghua.edu.cn/simple -U sciki ...

  4. 《精通Python设计模式》学习结构型之适配器模式

    大名鼎鼎~~ 在兼容老系统和其它系统外调用时,用得着~ class Synthesizer: def __init__(self, name): self.name = name def __str_ ...

  5. AndroidStudio3.0到3.1遇到的坑

    原文:https://blog.csdn.net/qq_36676433/article/details/80361064 本以为3.0到3.1仅仅是界面的优化,万万没想到的是这个坑比起2.0到3.0 ...

  6. CSU训练分类

    √√第一部分 基础算法(#10023 除外) 第 1 章 贪心算法 √√#10000 「一本通 1.1 例 1」活动安排 √√#10001 「一本通 1.1 例 2」种树 √√#10002 「一本通 ...

  7. 浅谈 Java 中的枚举

    枚举也就是一一列举,常用来表示那些可以明确范围的集合,比方说性别,季节,星期,月份等. 在 JDK 1.5 才出现枚举类,在没有出现枚举类之前,我们要表示几个确定的值通常会使用常量来表示,形如 pub ...

  8. 批量ssh登录,获取操作系统、CPU、内存、硬盘信息<shell>

    说明:该脚本读取machine.txt文件中的机器名,然后批量ssh登录,获取每台机器的操作系统,CPU,内存,硬盘等信息. 使用方法:将文件保存为sh,chmod +x filename 为该sh文 ...

  9. 总结html

    1.初识html W3C : 万维网联盟!(World Wide Web Consortium )   创建于1994年,是web技术领域最权威最具有影响力的标准机构!           W3C规定 ...

  10. [ 原创 ] git使用技巧

    Git的使用--如何将本地项目上传到Github Git分支图介绍 https://www.cnblogs.com/cheneasternsun/p/5952830.html https://www. ...