1 Nginx进程模型
nginx共有两种进程模型,即master和worker进程。master主进程管理worker进程。管理包含:
- 接收来自外界的信号,向各worker进程发送信号;
- 监控worker进程的运行状态,当worker进程退出后(异常情况下),会自动重新fork新worker进程。Work进程主要去处理用户请求。
worker进程可以在核心配置文件中配置成多个。
## ./conf/nginx.conf
worker_processes 6;
查看nginx进程
# ps -ef|grep nginx
管理员发送指令(stop/reload等)到master进程,master再将指令分发给每个woker进程执行。
- woker进程竞争来自客户端的请求。woker收到关闭请求,在处理结束、连接释放后才能关闭。
- worker进程间相互独立,相对线程更安全。
- 一个请求,只可能在一个worker进程中处理,一个worker进程,不可能处理其它进程的请求。尽量保持worker进程数与机器cpu核数一致,减少进程上下文切换、CPU资源竞争、cache失效等问题。
2 Worker抢占机制
当客户端请求进来,worker进程竞争该连接的accept_mutex锁。
accept_mutex的意义:当一个新连接到达时,如果激活了accept_mutex,那么多个Worker将以串行方式来处理,其中有一个Worker会被唤醒,其他的Worker继续保持休眠状态;如果没有激活accept_mutex,那么所有的Worker都会被唤醒,不过只有一个Worker能获取新连接,其它的Worker会重新进入休眠状态,这就是「惊群问题」
对Nginx而言,一般来说,worker_processes会设置成CPU个数,所以最多也就几十个,即便发生惊群问题的话,影响相对也较小。
Nginx缺省(默认)激活了accept_mutex,是一种保守的选择。如果关闭了它,可能会引起一定程度的惊群问题,表现为上下文切换增多(sar -w)或者负载上升,但是如果你的网站访问量比较大,为了系统的吞吐量,我还是建议大家关闭它。
3 Nginx事件处理机制
传统服务器事件处理采用同步阻塞AIO机制(例如Apache),当客户端请求进来后,worker1处理请求,此时worker1会阻塞,无法处理其他请求。针对于高并发的场景,则需要生产大量的worker。
Nginx采用了Linux的epoll模型,异步非阻塞。单个worker可以同时处理几万个请求的,具体取决于CPU和内存。当多个client请求worker1,假设client1的请求阻塞,由于异步非阻塞机制,worker1仍可以去处理其他客户端请求。
events {
# Linux默认使用epoll模型
use epoll;
# 设置每个worker允许最大客户端连接数
worker_connections 1024;
}
为什么要尽量保持worker进程数与CPU核心数一致?
一个worker进程可以同时处理的请求数只受限于内存大小,而且在架构设计上,不同的worker进程之间处理并发请求时几乎没有同步锁的限制,worker进程通常不会进入睡眠状态,因此,当Nginx上的进程数与CPU核心数相等时(最好每一个worker进程都绑定特定的CPU核心),尽可能减少进程上下文切换,避免多个worker进程抢占CPU,以及缓存失效等问题。
当worker_processes的值为auto时,nginx会自动检测当前主机的cpu核心数,并启动对应数量的worker进程。
work进程绑定某个CPU核心使用worker_cpu_affinity指令。