# 【NO.379】Nginx高效的原因，你都了解了吗

**导读**

研发朋友们对应用过载就扩容这个动作已是非常的熟悉，但大家有听说过业务流量突增，nginx也随之需要扩容嘛？我相信很少听过，为什么呢？主要是nginx高效工作起作用，那接下来我们来讲讲我们nginx为何高效。

## 1.Nginx 为何神物

Nginx 是一种异步框架的web服务器，它可以用作反向代理、负载均衡器和 HTTP 缓存或邮件服务器。Nginx 是免费且开源的，根据类 BSD 许可证的条款发布，意味任何人都可以下载甚至修改源码。Nginx 软件由伊戈尔·赛索耶夫创建并于 2004 年首次公开发布。2011 年成立同名公司以提供支持，现大部分互联网公司都在使用。

## 2.Nginx 为何高效

一个高性能web服务器典型特点是处理速度快且消耗资源少.尤其在上万连接同时在线的时候.若要做到处理速度快,并发模型的设计尤其关键.服务器并发量取决于两个因素:一是服务器连接的进程数量, 二是每个进程可同时处理的并发请求数量,因而web服务器并发模型由两部分构成,服务的提供方式和连接处理机制, 这两种别具一格的方式使得Nginx在同类型的web服务器中表现优秀。

### 2.1. 服务提供方式

一般Web服务器并发处理请求有以下三种方式：多进程方式、多线程方式、异步方式。

**多进程** 需要内存复制等额外开销,客户端较多时候，服务器性能会降低，典型应用如Apache的prefork模块；

**多线程** 使用进程中多个线程提供服务，多线程开销较小,典型应用如Apache的worker模块；

**异步** 则采用非阻塞的方式与每个客户通信，服务器用一个进程进行轮询，典型应用如Nginx的work process进程；

其中效率最高是异步，最稳定是多进程、占用资源少是多线程。

|    类型    |                             优点                             |                             缺点                             |
| :--------: | :----------------------------------------------------------: | :----------------------------------------------------------: |
| 多进程方式 | 稳定性高：由于采用独立进程处理独立请求，而进程之间是独立的，单个进程问题不会影响其他进程，因此稳定性最好 | 资源占用率高：当请求过大时，需要大量的进程处理请求，进程生成、切换开销很大，而且进程间资源是独立的，造成内存重复利用。 |
| 多线程方式 | 开销较小：线程间部分数据是共享的，且线程生成与线程间的切换所需资源开销比进程间切换小得多 | 线程切换过快可能造成线程抖动，且线程过多会造成服务器不稳定。 |
|  异步方式  | 性能最好：一个进程或线程处理多个请求，不需要额外开销，性能最好，资源占用最低。 | 某个进程或线程出错，可能导致大量请求无法处理，甚至导致整个服务宕机。 |

Nginx基于事件模型（异步方式）提供服务，更适合每秒连接数和请求数同时非线性增长的情况。即使负载增加了，内存和CPU使用事件数量始终保持可预期。Nginx使用普通的硬件就能在一个服务器上处理数万的并发连接。这就是Nginx高性能的第一个原因。

### 2.2.连接处理机制

谈到连接处理机制，关键是LINUX的I/O模型，同步阻塞io，同步非阻塞io，异步阻塞io（io复用），异步非阻塞io（信号驱动或者异步io）

**阻塞和非阻塞：**

那什么是阻塞和非阻塞呢,这里用点菜传菜举例来说明阻塞和非阻塞：
第一种：就在出菜窗口等待，直到厨师炒完菜后将菜送到窗口，然后服务员再将菜送到用户手中；
第二种：等一会再到窗口来问厨师，某个菜好了没？如果没有先处理其他事情，等会再去问一次；

第一种为阻塞方式，第二种为非阻塞的。从上面看，明显第二种非阻塞的效率更高；

**同步和异步：**

那什么是同步和异步呢，这里用传菜来举例下同步和异步 ：

同步：客户点菜，服务员直接跟厨师打交道，菜出来没出来，服务员直接指导，但只有当厨师将菜送到服务员手上，这个过程才算正常完成，这就是同步的事件。
异步：同样是点菜，有些餐馆有专门的传菜人员，当厨师炒好菜后，传菜员将菜送到传菜窗口，并通知服务员，这就变成异步的了。

对于同步的事件，你只能以阻塞的方式去做。而对于异步的事件，阻塞和非阻塞都是可以的，

传统的服务器采用的就是同步阻塞的多进程模型，而Nginx服务器使用多进程机制能够保证不增长对系统资源的压力,同时使用异步非阻塞方式减少了工作进程在I/O调用上的阻塞延迟，保证了不降低对请求的处理能力，这就是高效原因之一。

**I/O多路复用：**

select 和 poll 一般所有的操作系统都会支持，但是每次等待都要设置需要等待的套接口，并且内部的实现不够高效，很难支持监听高并发量的套接口集。不同的操作系统使用了不同的高级轮询技术来支持高性能的监听，一般这些方式都不是可移植的，比如freebsd上实现了 kqueue，solaris实现了/dev/poll，linux实现了epoll等。我们使用的 Centos 6.x 系统的epoll库。这也就是Nginx高性能的第二大原因。

### 2.3. Tengine 丰富插件

Tengine 是 nginx衍生版本，性能和稳定性已经在大型的网站如淘宝网，天猫商城等得到了很好的体验，其一个重要特点就是非常多的丰富插件，以下就来介绍下我们乐信使用了哪些 Tengine 插件模块：

\- –with-http_concat_module \ ## 用于合并多个文件在一个响应报文中
\- –with-http_flv_module \ ## 供服务端伪流媒体支持
\- –with-http_stub_status_module \ ## nginx 性能监控
\- –with-http_gzip_static_module \ ## gzip 支持各类数据压缩传输，降低网络
\- –with-http_sysguard_module \ ## 过载保护模块
\- –with-http_lua_module \ ## lua 模块
\- –with-http_v2_module \ ## http2支持
\- –add-module=../nginx_upstream_check_module-master \ ## upstream 健康检测和自动剔除模块
\- –add-module=../nginx-upsync-module-1.8.x ## 实现配置动态更新等等；

正是以上tengine丰富的插件，给我们的业务带来了强稳定性，高并发性能噢；

### 2.4. tengine 其它特性

除了以上，内部有大量可见的细节优化，采用多进程单线程的工作方式，并且利用cpu和进程的亲缘性将进程和特定cpu绑定（tengine默认支持），避免了进程上下文切换的开销，从而减少了cpu占用。另外它实现了高效的内存池，将内存占用降到最低等，这个依靠于nginx.cong 主配置进行优化等等；

## 3. tengine 扩展 lua

ngx_lua 模块是 nginx 第三方模块,它能将lua语言嵌入到nginx配置中,从而使用lua 极大增强了nginx的能力，nginx以高并发而知名,lua脚本轻便,两者的搭配堪称完美。

我们使用的 tengine+lua 大致可以分为2类作用，第一类是核心接入服务器，第二类是业务承载服务器，可能在我们这里都统称在一个大集群里面：

核心接入服务器：
1.如动态负载均衡（后续我们需要做的，因为我们业务需更高级别隔离）；
2.根据请求特征将流量分配到不同分组不同set或者机房，我们叫它流量调度（已具备）；
3.防DDOS攻击限流：可以将请求日志推送到实时计算集群，然后将需要限流的IP推送到核心Nginx进行限流（我们利用TGW防DDOS攻击）；
4.缓存服务，使用Nginx Proxy Cache实现内容页面的缓存等等；
业务承载服务器：
1.缓存，直接把图片等资源链接存储在redis,通过lua+nginx+redis 进行第一层请求返回（如tab页缓存）；
2.AB测试/灰度发布：比如要上一个新的接口，可以通过在业务Nginx通过Lua写复杂的业务规则实现不同的人看到不同的版本。（已具备）；
3.服务质量监控：我们可以记录请求响应时间、缓存响应时间、反向代理服务响应时间等达到实时监控，另外记录非200状态码错误来了监控服务可用率（已具备）等功能；

## 4.总结

1. nginx 它是一个高性能web服务器，它能同时提供上万的连接请求，而且速度快，占用资源少，部署在普通服务器就ok；
2. nginx 高效是因为异步且采用非阻塞的方式与每个客户通信，通过使用了操作系统IO复用方式（select和poll、epoll）达到高性能；
3. tengine 丰富的插件可提供我们插拔式选择使用，并且在主配置文件也具有大量的优化性能参数，如内存池，cpu亲缘性绑定等等；
4. lua_ngx 现在在我们业务方面实践，比如有waf防火墙，流量调度，流量管控，页面缓存，质量监控，统一日志等多个模块应用业务上。

原文链接：https://zhuanlan.zhihu.com/p/406797738

作者：[Hu先生的Linux](https://www.zhihu.com/people/huhu520-10)