master进程

Nginx采用的模型是master-worker模型,即:

  • 由master进程负责创建worker进程,以及监控worker进程的情况,如需要更新配置的情况下发消息给worker进程重新加载配置等。
  • master进程负责具体网络事件。

将里面核心的流程和函数抽取出来,如下图所示:

master-worker

  • master进程的主循环在函数ngx_master_process_cycle中,主要负责:
    • 调用ngx_start_worker_processes函数创建worker子进程。
    • 监控各种信号量的变化做处理,比如需要停止进程、重新加载配置等。
  • master进程最终会调用函数ngx_spawn_process函数来创建出worker子进程:
    • 使用共享内存创建出用于master-worker进程之间通信的channel。
    • fork出子进程之后,进入worker进程的主函数ngx_worker_process_cycle。

以下列举出几个相关的信号量:

信号 对应全局变量 处理
QUIT ngx_quit 优雅关闭整个Nginx服务
TERM或者INT ngx_terminate 强制关闭Nginx服务
USR1 ngx_reopen 重新打开文件
WINCH ngx_noaccept 所有worker进程不再接受新的连接,相当于给子进程发送QUIT信号
USR2 ngx_change_binary 平滑升级到新的Nginx二进制文件
HUP ng_reconfigure 重新加载配置文件
CHLD ngx_reap 需要监控所有子进程

worker进程

worker进程的函数入口在ngx_worker_process_cycle中,其主要做的工作分为两部分:

  • 调用ngx_process_events_and_timers处理IO事件以及定时器事件。
  • 判断ngx_terminate、ngx_quit、ngx_reopen这几个变量是否被置位来做相应的处理。

下面主要谈网络IO事件的处理,即ngx_process_events_and_timers函数。

先来介绍几个与接收连接相关的全局变量:

  • ngx_use_accept_mutex:由配置项accept_mutex配置,表示是否需要使用accept锁,只有抢到该锁的worker才允许接收新的连接。
  • ngx_accept_mutex_delay:由配置项accept_mutex_delay配置,在开启accept_mutex的情况下,一个worker进程在抢不到accept锁的情况下,最长多少时间才重新接收新的连接。
  • ngx_accept_disabled:值为ngx_cycle->connection_n / 8 - ngx_cycle->free_connection_n,可以看到当链接数量到nginx.conf中配置的worker_connections的7/8以上时,这个变量ngx_accept_disabled为正数,此时不会接收新的连接,直到该值小于等于0为止。
  • ngx_accept_mutex_held:表示是否抢到了accept锁,只有抢到的才能接收新连接。

具体来看看ngx_process_events_and_timers函数中与接收连接相关的逻辑,伪代码如下:

如果开启了accept_mutex配置:
  如果当前ngx_accept_disabled大于0,表示不能接收新的连接,直接返回。
  否则尝试获取accept mutex。
  如果获取accept mutex锁成功:
    将调用事件轮询函数的标志位加上NGX_POST_EVENTS标志
  如果获取失败:
    调用事件轮询函数的事件参数不得超过ngx_accept_mutex_delay值。

  调用ngx_process_events函数处理轮询事件

  调用ngx_event_process_posted(cycle, &ngx_posted_accept_events)函数处理accept事件

  如果前面拿到了accept mutex锁,则释放这个锁,好让其他worker也有机会接收新的连接

  调用ngx_event_expire_timers处理定时器事件

  调用ngx_event_process_posted(cycle, &ngx_posted_events);函数处理除了accept事件以外的其他post事件

在ngx_process_events处理函数中,当传入的flags有NGX_POST_EVENTS标志时,意味着并不马上在这个函数中调用事件的回调函数进行处理,而是放在一个队列中,回头在后面的ngx_event_process_posted函数中再进行处理。

而这里的队列分为两类:

  • ngx_posted_accept_events用于存放接收新连接事件。
  • ngx_posted_events用于存放除了accept之外的其他事件。

这样的做法,是为了将接收新连接的事件优先级放在其他IO事件以及定时器事件之前。

在下一篇文章,再详细展开事件模块的分析。