最近发现了陶辉大佬的nginx教程,也在学习中,同时会将自己的感悟记录下来,如果有不正确的地方,也希望大家能多多指正。

1.nginx的进程结构

nginx以前台进程运行 nginx的进程结构_配置文件


nginx有一个主进程和多个子进程,子进程包括worker进程和缓存进程,多进程结构可以充分地发挥cpu的性能,比单进程效果好。

同时,nginx要保证自己的高可用性(保持其服务的高度可用性)和高可靠性,当采用多线程时,如果发生了某一第三方模块引发了某一地址空间导致的段错误时,会导致整个nginx崩溃,而多进程则不会发生这样的情况,所以nginx采用的是多进程。

我们一般将一个worker进程与一个cpu核绑定在一起,以提高cpu缓存的命中率。

主进程一开始会初始化及读取配置。并载入各模块的功能,然后fork()出N个子进程(即工作进程),具有同样的工作逻辑和功能。父进程负责监听信号(如HUP,QUIT等),通过socket pair把信号传递给子进程(子进程间一般不通信)。

子进程通过事件来处理父进程传递的信号。由于每一个子进程都共享服务监听port(如http 80),当用户发送请求时,会触发子进程的事件调用函数。因此在accept()请求的时候,须要用到mutex,保证仅仅有一个工作进程接受并处理请求。2.nginx请求处理流程

nginx以前台进程运行 nginx的进程结构_nginx以前台进程运行_02


处理三种流量请求:1.处理tcp/udp的传输层状态机

2.处理应用层的http状态机

3.处理邮件的mail状态机

之所以叫状态机是因为nginx中核心的绿色的框是用非阻塞的事件驱动处理引擎,一旦使用这种异步处理引擎后,通常要用状态机来把请求正确的识别和处理(即归类处理)。

基于这样的事件状态处理机,我们在解析出请求需要访问静态资源时,可以看到走左下方的箭头去找静态资源,做反向代理时,对反向代理的内容也可以做磁盘缓存,但是当内存不足以缓存静态资源信息时,会退化成阻塞的线程调用,所以要有线程池来进行处理。

更多的时候,nginx作为负载均衡和反向代理来使用,这时我们可以把请求通过协议传输到后面的服务器,也可以通过应用层的一些协议代理到响应的应用服务器。

对于每一个处理完成的请求,我们会记录access日志和error日志。

个人感想:现实生活中,往往大部分的事情,我们基本上都需要进行分类处理。当处理某一件事时,如果遇到更加紧急的事情,我们经常放下手中的事情来处理它。对于nginx来说,任何请求来了,其都将其进行非阻塞的处理,以提高响应效率。

3.进程管理的信号

nginx以前台进程运行 nginx的进程结构_子进程_03


当我们更新了nginx的配置文件都会使用-reload将配置文件进行重载。在使用这条命令的时候希望ngnix不能停止服务,始终还在处理新的请求的同时将nginx的旧的配置文件更新为新的配置文件。

这样一个功能对于nginx非常有必要,但是在高并发的场景下会发现使用-s reload之后worker进程的数量变多了,这其实是老的配置的worker进程长时间没有退出。

使用-s reload会把之前的worker进程优雅的退出然后再使用新的配置项去启动新的worker进程,我这里没有改变配置,但是可以看到,老的一个worker子进程将会退出还会生成新的worker子进程。
因为master 进程会启动worker进程,它管理worker进程的信号首先是监控woker 进程有没有发送CHLD信号。linux 操作系统中规定,当子进程终止的时候,会向父进程发送CHLD信号。

master进程管理 Worker 进程,发送信号,其接收信号如下:
TERM/INT,立刻停止进程;
QUIT,优雅的退出,等请求处理完才退出;
HUP,重载配置文件;
USR1,重新打开日志文件,做日志文件的切割;
USR2,热升级第一阶段,启动新进程。旧的 Nginx 主进程 Master 将会把自己的进程文件改名为 .oldbin,然后执行新版 Nginx。此时新旧 Nginx 进程会同时运行,共同处理请求;
WINCH,热升级第二阶段,停止老进程。逐步停止旧版 Nginx 的 Worker 进程就都会随着任务执行完毕而退出,新版的 Nginx 的 Worker 进程会逐渐取代旧版 Worker 进程。

worker进程:处理任务。
worker接收信号:TERM/INT、QUIT、USR1、WINCH。

nginx命令行:
reload: HUP;
reopen: USR1;
stop: TERM;
quit: QUIT。
进程间可以通过信号进行交流,用户也可以通过信号与进程进行交流。