Nginx 原理
Nginx 以其高性能,稳定性,丰富的功能,简单的配置和低资源消耗而闻名。
Nginx进程模型
Nginx 是一个多进程的模型,主要分为一个 Master 进程、多个 Worker 进程。
-
Master 进程: 管理 Worker 进程。
-
对外接口:接收外部的操作(信号);
-
对内转发:根据外部的操作的不同,通过信号管理 Worker;
-
监控:监控 Worker 进程的运行状态,Worker 进程异常终止后,自动重启 Worker 进程。
-
-
Worker 进程: 所有 Worker 进程都是平等的。
-
实际处理:网络请求,由 Worker 进程处理。
-
Worker 进程数量:在 nginx.conf 中配置,一般设置为核心数,充分利用 CPU 资源,同时,避免进程数量过多,避免进程竞争 CPU 资源,增加上下文切换的损耗。
-
HTTP 连接建立和请求处理过程
-
Nginx 启动时,Master 进程,加载配置文件。
-
Master 进程,初始化监听的 Socket。
-
Master 进程,Fork 出多个 Worker 进程。
-
Worker 进程,竞争新的连接,获胜方通过三次握手,建立 Socket 连接,并处理请求。
Nginx 高性能、高并发
Nginx 为什么拥有高性能并且能够支撑高并发?
-
Nginx 采用多进程 + 异步非阻塞方式(IO 多路复用 Epoll)。
-
请求的完整过程:建立连接→读取请求→解析请求→处理请求→响应请求。
-
请求的完整过程对应到底层就是:读写 Socket 事件。
Nginx 的事件处理模型
Request:Nginx 中 HTTP 请求。
基本的 HTTP Web Server 工作模式:
-
接收请求: 逐行读取请求行和请求头,判断段有请求体后,读取请求体。
-
处理请求。
-
返回响应: 根据处理结果,生成相应的 HTTP 请求(响应行、响应头、响应体)。
模块化体系结构
nginx的模块根据其功能基本上可以分为以下几种类型:
- event module: 搭建了独立于操作系统的事件处理机制的框架,及提供了各具体事件的处理。包括ngx_events_module, ngx_event_core_module和ngx_epoll_module等。nginx具体使用何种事件处理模块,这依赖于具体的操作系统和编译选项。
- phase handler: 此类型的模块也被直接称为handler模块。主要负责处理客户端请求并产生待响应内容,比如ngx_http_static_module模块,负责客户端的静态页面请求处理并将对应的磁盘文件准备为响应内容输出。
- output filter: 也称为filter模块,主要是负责对输出的内容进行处理,可以对输出进行修改。例如,可以实现对输出的所有html页面增加预定义的footbar一类的工作,或者对输出的图片的URL进行替换之类的工作。
- upstream: upstream模块实现反向代理的功能,将真正的请求转发到后端服务器上,并从后端服务器上读取响应,发回客户端。upstream模块是一种特殊的handler,只不过响应内容不是真正由自己产生的,而是从后端服务器上读取的。
- load-balancer: 负载均衡模块,实现特定的算法,在众多的后端服务器中,选择一个服务器出来作为某个请求的转发服务器。
基础背景:
- Nginx 是多进程模型,Worker 进程用于处理请求;
- 单个进程的连接数(文件描述符 fd),有上限(
nofile
):ulimit -n
- Nginx 上配置单个 worker 进程的最大连接数:
worker_connections
上限为nofile
- Nginx 上配置 worker 进程的数量:
worker_processes
因此,Nginx 的最大连接数:
- Nginx 的最大连接数:
Worker 进程数量
x单个 Worker 进程的最大连接数
- 上面是 Nginx 作为通用服务器时,最大的连接数
- Nginx 作为
反向代理
服务器时,能够服务的最大连接数:(Worker 进程数量
x单个 Worker 进程的最大连接数
)/ 2。 - Nginx 反向代理时,会建立
Client 的连接
和后端 Web Server 的连接
,占用 2 个连接
Nginx vs. Apache
以下内容来源于:http://www.oschina.net/translate/nginx-vs-apache
what's the Apache
Apache 服务器从 1995 年就开始使用了。相比其他产品,Apache 服务器是使用最多的,其次是微软的 IIS 服务器。
由于开源的 Apache 服务器已经被使用多年,并且有众多的用户,人们开发出了很多的模块来扩展它的功能,其中的大多数模块也是开源的。举例来说,一个比较常见的配置是使用 Apache 来为静态页面提供服务,并使用 mod_jk 模块来运行 Tomcat 上的 Java 和 JSP 代码,以便使程序具有交互功能。另一个例子是使用 mod_php 模块来执行 php 代码,而不用去使用 cgi。
但是,Apache 在高负载的情况下表现的差强人意,原因是它需要去运行新的进程,因此要消耗更多的内存。同时,他还要产生新的线程来与其他的线程竞争内存和 CPU。当进程的流量达到了管理员设置的上限时,Apache 会拒绝新的连接。
what's the Nginx
Nginx 是一个开源的服务器,用来解决一些 Apache 在性能和扩展性方面的问题的。Nginx 是开源并且免费的,但是如果你购买了它的 Nginx Plus 版本的话是可以享受到服务支持的。
Nginx 声称它的服务器是用来解决 C10K 问题(出自Daniel Kegel发表的一篇关于如何使一个服务器处理10000个连接——假设的操作系统的上限的论文)的。在他的论文中,他引用了另一篇由 Dean Gaudet 写的论文,其中写到“你们为什么不使用一个像 Zeus 那样的选择/事件(select/event)为基础的模型呢?很明显那是最快的”。
Nginx 确实是以事件为基础的(event-based)。他们把他们的架构称为“事件驱动且异步”(event-driven and asynchronous)。Apache 依赖于进程和线程。那么,区别是什么呢?
Apache 的工作方式
Apache 通过创建进程和线程来处理其他的连接。管理员可以通过设置来控制服务器所能允许的最大进程数量。这个配置因机器的可用内存而异。过多的进程会耗尽内存从而使得机器使用磁盘上的交换内存,这严重的降低了性能。而且,当达到进程的上限之后,Apache 会拒绝新的连接。
Apache 可以通过设置来运行在 pre-forked 模式或 worker multi-process 模式(MPM)。当其他的用户连接时,两种方式都会创建新的进程。区别在于,pre-forked 模式为每一个进程创建一个线程,用来处理一个用户的请求。worker 模式也创建新的进程,但是每一个进程至少有一个线程,每一个线程用来处理单个用户的单个请求。所以,一个 worker mode 的进程处理至少一个连接,而一个 per-fork 模式的进程只处理一个连接。
相比于 forked 模式,worker 模式使用更少的内存,原因是进程比线程消耗更多的内存,线程只是运行在进程中的代码。
此外,worker 模式不是线程安全的。这意味着如果你使用像 mod_php 这样的非线程安全的模块来服务 php 页面时,你需要使用 pre-forked 模式,因此要消耗更多的内存。所以,当选择模块和配置服务器时,你必须要面对是线程还是进程更优的问题以及一些约束的问题。
在调整 Apache 时的一个限制因素是内存以及当争夺同一个CPU和内存时潜在的线程死锁问题。如果一个线程停止了,用户会一直处于等待页面出现的状态,直到进程将该线程回收,以便可以发回页面。如果一个线程发生了死锁,它不知道如何重启,因此会一直处于卡住状态。
Nginx 的工作方式
和 Apache 相比,Nginx 的工作方式有很大不同,主要是在于它如何处理线程。
Nginx 并不会为每一个的 web 请求创建新的进程,相反,管理员可以配置 Nginx 主进程的工作进程的数量(一个常见的做法是为每一个 CPU 配置一个工作进程)。所有这些进程都是单线程的。每一个工作进程可以处理数千个并发的请求。它通过一个线程来异步的完成了这些工作,而没有使用多线程的编程模型。
Nginx 还拆分了缓存加载器(cache loader)和缓存管理器(cache manager)进程用来从磁盘中读取数据并将其加载到缓存中,当缓存直接读取的时候缓存过期。
Nginx 有一系列的模块组成,这些模块在编译的时候就被包含进去了。这意味着,用户下载源码并选择他们要编译的模块。这些模块中包括连接后端应用服务器,负载均衡,代理服务器以及其他。并没有 PHP 的模块,因为 Nginx可 以自己编译 PHP 代码。
下图为 Nginx 的架构
从这个图表中我们可以看出,Nginx 使用 FastCGI 进程来执行 Python,Ruby 以及其他代码,使用 Memcached 对象缓存系统。工作进程为 HTTP 请求加载 ht_core Nginx 进程。我们还可以看到,Nginx 和 Windows 以及 Linux 内核的功能紧密的集成在了一起,以便提升性能。这些内核功能已经经过长时间的改良,而 Nginx 正是利用了这一点。
Nginx 声称是事件驱动,异步且无阻塞的。“事件(Event)”指的是一个用户的连接。“异步(Asynchronous)”指的是它一次处理多个用户连接的用户交互。“无阻塞(Non-blocking)”指的是它不会由于 CPU 处于忙状态而停止磁盘的 I/O,在这种情况下,它会处理其他事件,直到 I/O 资源得到释放。
网络 IO 模型:
- nginx:IO 多路复用,epoll(freebsd 上是 kqueue )
- 高性能
- 高并发
- 占用系统资源少
- apache:阻塞 + 多进程/多线程
- 更稳定,bug 少
- 模块更丰富
参考:https://www.zhihu.com/question/19571087
IO 多路复用
:单个连接的请求处理速度没有优势,适合 IO 密集型 场景,事件驱动- 大并发量:只使用一个线程,处理大量的并发请求,降低上下文环境切换损耗,也不需要考虑并发问题,相对可以处理更多的请求;
- 消耗更少的系统资源(不需要
线程调度开销
) - 适用于
长连接
的情况(多线程模式长连接
容易造成线程过多
,造成频繁调度
)
阻塞IO
+多线程
:实现简单,可以不依赖系统调用,适合 CPU 密集型 场景- 每个线程,都需要时间和空间;
- 线程数量增长时,线程调度开销指数增长
其他链接