进程结构
- 需要首先关注多进程和多线程的一个区别
- Nginx采用的是一种多进程,这样一种进程结构, 为何不采用多线程这样一种进程结构
- Nginx 设计之初就是为了高可能性和高可靠性而设计的
- Nginx 通常是运行在边缘节点上,通常是用来接受用户的第一个请求的时候,所需要的一个服务器
- 对于服务器本身就有了更高的要求,要求服务器本身的应用程序有足够的健壮性
- 如果要采用一种多线程的一种线程结构的时候,会遇到一个最大的问题是
- 如果有一个线程,因为代码写的不够多健壮,导致了某一段地址,空间越界出现了错误
- 可能会导致我们整个线程的不可用,多线程是采用共享同一个地址空间来实现的
- 所以说Nginx采用的是一种多进程的这样一种进程结构
- 上端有一个 Master Process,而下面有
- CM, CL 和 4个 worker process
- 对于Master Process来说,它并不真正的处理用户请求,而真正处理用户请求是worker process
- worker process 在实际的生态环境也不一定是4个
- Nginx 是模块化设计的, 有了这样一个master,还有很多的第三方模块
- Nginx 推行的一个原则就是,开发自己的第三方模块的时候,应该尽可能的减少修改 Master Process这样一个主程序模块
- 如果 Master Process 要挂的话,肯定整个服务就不可用了
- Nginx 在设计之初的时候,也是尽量的建议自己的开源生态,开发者开发自己的第三方模块的时候,尽可能的不要去修改 Master Process这样一个模块,而是只需要在你的第三方模块中进行修改
- 即使是你的第三方模块出了问题,那也不会导致我们整个Nginx的一个宕机
- 对Nginx本身来说,它是允许去修改它的 Master Process 这样一个主模块的, 但是通常来说没有人会去这样做
- Master Process: 本身并不真正用来处理用户请求,而只是用来管理下面的缓存模块啊,或子进程
- Worker Process: 本身是需要真正去处理用户请求的, Master Process 只是是来监控 Worker Process 子进程,比如重启子进程来维持正常运行,一个子进程宕了, 在 linux 中子进程会自动发送信号给主进程,自动启动一个新的来维持原有的数量
- 当某一个配置文件修改了,更改了Nginx的一个特性,比如增加配置,静态资源或调整URL, 主进程在监测到了之后,它也会通知子进程去拿新的配置文件生效,对于这样一种场景来说,就是热部署
- 热部署就是更改了我们的程序代码,需要影响原有的这个请求处理的过程而平滑升级
- Master Process 下面还管理的两个子进程,一个是 CM,还有一个是 CL,是和缓存有关的进程,在反向代理场景中,它会把动态请求代理给后端的一个应用程序服务器,在代理应用程序到达应用程序服务器之后,应用程序服务器在经过计算之后,把动态内容返回给Nginx的过程中,也可以直接用这样一个 cache loader 去缓存起来, 其实真正的缓存功能并不是CM 和 CL提供的
- 真正用来响应用户请求的是 worker process 子进程, 真正需要去缓存哪些内容,怎么样去接收应用程序发过来的,这些内容都是由我们的worker process来进行的,CL 是用来加载缓存,CM是用来管理缓存的,这些子进程之间的通信都是使用共享内存的形式来进行通信的
- Nginx 设计的初衷本身就是为高可能性和高可靠性而设计的
信号量管理
1 )Linux 的信号量管理
-
在Linux 操作系统中,对于进程管理是通过信号量来进行管理的, 比如说我们通常使用的q命令
-
通过 kill 命令,可以给某个进程PID发送很多的信号量,通常,直接使用 kill pid 的时候
-
相当于给linux发送一个 kill - 15 这样一个命令(代号)
-
$
kill -l
可查看所有 -
以上可以看到,现在大概是有 64 种信号量
-
可见, kill -9 可以发送一个 SIGKILL 的信号,它不管当前进程处于什么状态,无条件终止
-
常用信号量, 参数含义
代号 命令 SIGCHLD kill -17 $PID SIGQUIT kill- 3 $PID SIGTERM kill -15 $PID SIGKILL kill - 9 $PID SIGHUP kill -1 $PID SIGUSR1 kill -10 $PID SIGUSR2 kill -12 $PID SIGWINCH kill -28 $PID - SIGCHLD
- linux的一个父子进程之间进行通信的一个信号量
- 在 linux操系系统可以对子父进程 forker 出来很多的子进程
- 如果,其中某一个子进程 宕掉了,或者是由于其他因终止之后
- 它会自动的发送一个 SIGCHLD 这样一个信号量给父进程
- 让父进程可以收到子进程已经宕掉了的一个信号量
- 从而让父进程采取一些其他的措施,比如说重新启动一个新的子进程
- SIGQUIT
- SIGQUIT 在使用的时候就相当于是它的信号量的一个代码 kill -3
- 其实在发送这样一个信号量的时候,就相当于在键盘上使用了
ctrl + |
- 就比如说一个脚本正在输出很多的数据, 使用
ctrl + |
的话,它是会对进程发出一个 SIGQUIT 信号
- SIGTERM
- 日常用的最多, -15 可以省略,kill + pid,相当于发送进程终止的信号
- 但是允许进程处理完现有的数据,最后优雅的关闭进程,由进程决定何时关闭
- SIGKILL
- 日常用的最多,-9 表示立即终止
- SIGHUP
- 让进程重新读取配置文件,它会去迫使这样一个进程,重新读取配置文件
- 比如说,更改的配置文件,需要生效新的配置的时候,就可以给这个管理进程发送
- 这样一个信号,迫使我们当前的进程去重读配置文件,生效配置
- SIGUSR1
- SIGUSR2
- 以上两个都是 linux 提供给用户自定义的信号量
- 不满足需求,可以通过此自定义
- SIGWINCH
- 和上面两个一样,都用于平滑升级
- SIGCHLD
2 )使用信号量管理 Nginx
2.1 使用信号量管理 master 和 worker
- 看下 Nginx 有哪些子进程是可以使用信号量对它进行管理的,Nginx 进程结构就是由一个 master 主进程和若干 worker 子进程来组成的
2.1.1 Master 进程
- 很明显, master进程就是一个管理进程,管理进程, 可以给它发送信号量
- 由它来对整个 Nginx 进行这个管理
- Master 进程有如下任务
- 监控 worker 进程
- 在linux中worker 子进程宕掉之后,它会主动给Master进程发送一个CHILD这样一个信号
- 通知Master进程去采取进一步措施
- 管理 worker 进程,接收信号
- TERM, INT: 终止进程
- QUIT:会等待当前用户请求处理完之后才平滑关闭终止
- HUP:重读配置文件,改变Nginx行为,kill 之前的进程,重启后读取
- USER1
- USER2
- WINCH
- 监控 worker 进程
2.1.2 worker 进程
- worker 进程,并不推荐直接给它发送信号量,对它进行管理, 因为它们是由 master进程来进行管理和维护的,比如说某一个work进程宕掉了,master进程会自动监控到并且重新启动一个新的worker进程,从而来维持固定数量的一个worker进程这样一个进程结构
- 通常会推荐直接向 master 进程发送一个信号量,由master进程对worker进程进行管理
- Worker 进程
- 接收信号
- TERM, INT
- QUIT
- USR1
- WINCH
- 接收信号
2.1.3 命令行
- 还可以通过命令行:直接通过Nginx的二进制程序,加一些参数来对其进行行理
- 命令行
- reload: HUP 也是重读配置文件
- reopen: USR1 重新打开日志文件
- stop: TERM 停止 Nginx
- quit: QUIT 停止 Nginx
- 背后也是给 Master 进程发送信号,提供命令行管理形式而已
2.2 实际管理
- $
ps -ef | grep nginx
查看 nginx 进程细节root 26695 1 0 02:09 ? 00:00:00 nginx:master process /opt/nginx/sbin/nginx nginx 26703 26695 0 02:10 ? 00:00:00 nginx:worker process nginx 26704 26695 0 02:10 ? 00:00:00 nginx:worker process nginx 26705 26695 0 02:10 ? 00:00:00 nginx:worker process nginx 26710 26695 0 02:10 ? 00:00:00 nginx:worker process root 26716 26549 0 02:18 pts/0 00:00:00 grep --color=auto nginx
- 接下来, 就来实际的看一下怎么样对这些进行管理的
- 2.2.1 ) 现在已经启动了一个Nginx ,这里有一个master主进程
- 这个master主进程的PID号是 26695,同时它也生成了4个worker子进程
- work子进程,每一个都是有一个单独的PID, 但是父进程都是 26695
- 但是他们的副进程大家看都是这个二六六九五,对吧?
- Nginx 采用的是事件驱动模型事件处理机制,对于这样一个事件处理机制来说
- 它就尽可能的要求Nginx从始至终的一个worker进程都要跟一个CPU绑定在一块
- 从而尽可能的去减少CPU的这种切换,从而提高这个CPU缓存的一个命中效率
- 通常的一个 Nginx 服务器都会跟 CPU进行绑定,CPU有多少颗,通常就会启动几个worker子进程
- 现在看下 Nginx 的配置文件
worker_processes auto; # 这样配置,Nginx 会自行检测CPU核心个数,自行启动对应个数
- 我们可以把这个 auto 修改成 2个
- 现在我们 kill 26695 当前的 nginx,再重新启动 $
/opt/nginx/sbin/nginx
- 这时候 $
ps -ef | grep nginx
发现,只有2个子进程了, 所以,默认是 auto,这样省事省心 - 同时,我们可以通过
lscpu
的命令,可查看对应的服务器cpu核心数量 - 现在对 master 进程进行管理测试:$
kill -s SIGTERM 26733
- 再次 $
ps -ef | grep nginx
发现 Nginx 进程已经消失了
- 再次 $
- 测试重读配置文件,$
kill -s SIGHUP 26747
这个 26747 是新启动的nginx的主进程- 当执行这个命令时,子进程的pid变化了,也就是其实他重启了子进程来进行重读的
- 其他类似信号,可以同等测试
- 2.2.2 ) 这里,也可以对 worker 子进程进程信号量管理,虽然不推荐,操作同上,将pid换成子进程即可
- 注意,如果操作杀死子进程,那么主进程会立即重启一个新的
- 2.2.3 ) 现在尝试对命令行进行管理
- 可以通过 $
/opt/nginx/sbin/nginx -h
查看有哪些命令可以使用nginx version: nginx/1.16.1 Usage: nginx [-?hvVtTq] [-s signal] [-c filename] [-p prefix] [-g directives] Options: -?,-h : this help -v : show version and exit -V : show version and configure options then exit -t : test configuration and exit -T : test configuration, dump it and exit -q : suppress non-error messages during configuration testing -s signal : send signal to a master process: stop, quit, reopen, reload -p prefix : set prefix path (default: /opt/nginx/) -c filename : setconfigurationfile(default:/opt/nginx/conf/nginx.conf) -g directives : set global directives out of configuration file
- $
/opt/nginx/sbin/nginx -s stop
停止 - $
/opt/nginx/sbin/nginx -s reload
重启,重读和HUP类似
- 可以通过 $