Nginx
Nginx 是一个免费的,开源的,高性能的 HTTP 服务器和反向代理,以及 IMAP / POP3 代理服务器;Nginx 以其高性能,稳定性,丰富的功能,简单的配置和低资源消耗而闻名。
简单来说,Nginx 具有以下几个优点:
- 1.高并发,高性能
- 2.可扩展性好
- 3.高可靠,一年之中停机时间可能只有几秒
- 4.热部署,可以不重启升级
- 5.灵活性高,采用BSD 许可证
BSD开源协议是一个给予使用者者很大自由的协议。基本上使用者可以”为所欲为”,可以自由的使用,修改源代码,也可以将修改后的代码作为开源或者专有软件再发布
背景
Nginx 出现的背景是由于互联网的快速普及导致数据量的快速增长,同时催生出了海量的连接。 传统的 Apache 等服务器采用的是单进程模型, 这意味着,每处理一个请求就会创建一个进程,这不但存在进程创建的开销, 而且进程之间相互切换产生的上下文开销也非常耗费 CPU 资源, 导致这种传统的服务器在面对成千上万的并发连接时,性能非常低下,而这是快速发展的互联网所不能够忍受的。
在这种背景下,Nginx 采用的是进程池和 epoll 处理模型,这二者加起来使得 Nginx 的性能非常优异,一台 32 核的机器上可以支撑数千万的并发连接。
Nginx - 整体架构
Nginx 里有一个 master 进程和多个 worker 进程。
- master 进程并不处理网络请求,主要负责调度工作进程:加载配置、启动工作进程及非停升级。
- worker 进程负责处理网络请求与响应。
master进程主要用来管理worker进程,具体包括如下4个主要功能:
- 1.接收来自外界的信号。
- 2.向各worker进程发送信号。
- 3.监控woker进程的运行状态。
- 4.当woker进程退出后(异常情况下),会自动重新启动新的woker进程。
woker进程主要用来处理基本的网络事件:
- 1.多个worker进程之间是对等且相互独立的,他们同等竞争来自客户端的请求。
- 2.一个请求,只可能在一个worker进程中处理,一个worker进程,不可能处理其它进程的请求。
- 3.worker进程的个数是可以设置的,一般我们会设置与机器cpu核数一致。 nginx为了更好的利用多核特性,具有cpu绑定选项,我们可以将某一个进程绑定在某一个核上,这样就不会因为进程的切换带来cache的失效。
Nginx - 模块化设计
高度模块化的设计是 Nginx 的架构基础。
Openresty 就是在 Nginx 上引入了 lua 等第三方模块,使得扩展更加方便了。
Nginx - 状态机
Nginx 对外提供服务时,主要有三种流量会到达 Nginx:WEB、EMAIL、TCP 流量。这三种流量到达 Nginx 后,会分别由传输层状态机、应用层状态机、MAIL 状态机来处理。当内存不足以缓存所有的静态资源时,会退化成阻塞的磁盘调用,这个时候需要一个线程池来处理,对于每一个处理完的请求记录访问日志和错误日志,日志也是记录到磁盘中的。
Nginx - 进程结构
Nginx 有四种进程:
- 1.Master 进程。Master 进程是父进程,其他进程都是子进程,Master 进程对 worker 进程进行管理
- 2.worker 进程。worker 进程有多个,是负责处理具体的请求的。Nginx 为什么采用多进程而不是多线程的进程结构呢?是因为 Nginx 要保证高可用性,多线程之间会共享地址空间,当某一个第三方模块引发了一个段错误时,就会导致整个 Nginx 进程挂掉。而采用多进程模型不会出现这个问题
- cache manager 和 cache loader 进程。缓存除了要被多个 worker 进程使用,也要被 cache 进程使用,cache loader 做缓存的载入,cache manager 做缓存的管理,实际上每一个请求所使用的缓存还是由 worker 进程来进行的。这些进程间的通信都是通过共享内存来进行的
为什么 worker 进程需要很多个?
这是因为,Nginx 采用了事件驱动的模型后,它期望 worker 进程可以从头到尾占满一颗 CPU,这样可以更加高效的利用整颗 CPU,提高 CPU 的缓存命中率,另外还可以将 worker 进程与某一个 CPU 核绑定在一起。
Nginx- 父子进程 使用信号管理
Nginx 的命令行指令,其实很多 Nginx 的信号都是通过向 master 进程发送信号来实现的。
Master 进程
master 进程会监控 worker 进程,而监控是通过 Linux 规定的当子进程退出时需要向父进程发送 CHLD 信号实现的。这样可以当出现 bug 时,立刻拉起 worker。
master 进程可以接收以下信号:
- TERM, INT
- QUIT
- HUP
- USR1
- USR2
- WINCH
Worker 进程
worker 进程可以接收以下信号:
- TERM, INT
- QUIT
- HUP
- USR1
- WINCH
命令行对应的信号
- reload:HUP
- reopen:USR1
- stop:TERM
- quit:QUIT
USR2 和 WINCH 没有对应的信号,只能通过 kill 发送。
stop 和 quit 的区别是,一个是立即退出,一个是优雅的停止。
Nginx - reload 重载配置文件
- 1.向 master 进程发送 HUP 信号
- 2.master 进程检查配置文件是否有语法问题
- 3.master 进程打开新的监听端口(如果配置了新的端口)
- 4.master 进程使用新的配置文件启动 worker 进程
- 5.master 进程向老的 worker 进程发送 QUIT 信号
- 6.老 worker 进程关闭监听句柄,处理完当前连接后结束进程
Nginx - 热部署
- 1.将旧的 Nginx 文件替换成新的 Nginx 文件(注意备份)
- 2.向 master 进程发送 USR2 信号
- 3.master 进程修改 pid 文件名,加后缀 .oldbin
- 4.master 进程用新 Nginx 文件启动新 master 进程
- 5.向老的 master 进程发送 quit 信号,关闭老的 master
- 6.回滚操作,向老的 master 进程发送 HUP 信号,向新的 master 发 QUIT
Nginx - 优雅的关闭 worker 进程
- 1.设置定时器 worker_shutdown_timeout
- 2.关闭监听句柄
- 3.关闭空闲连接
- 4.再循环等待全部连接关闭
- 5.退出进程
这里面,定时器的作用是,如果时间超时了,但是连接还没有处理完毕,就会强制退出进程。另外,Nginx 只能处理 HTTP 的优雅关闭,websocket 、TCP、UDP 的代理都做不到,worker 不解析数据。