是什么?
nginx是一个开源的,高性能的HTTP和反向代理web服务器,同时也提供了IMAP/POP3/SMTP服务。
什么是服务器
服务器的英文叫 Server , 顾名思义就是为其他人服务 的。我们可以把所有为其他用户提供服务的机器或者软件都叫做服务器。
- 服务器可以指硬件,比如对用户提供服务的主机
- 服务器也可以指软件。
- 比如nginx就是一个对用户提供HTTP服务的server;又比如网易邮箱服务器,是专门为用户提供邮箱服务的。
- 这些软件都运行在一个物理机器上面,专门对外提供服务
什么是web服务器
一个典型的web请求流程,如上图:
- 浏览器本身作为一个客户端,当你输入 www.weibo.com 的时候,向 DNS 服务器发出域名请求服务;
- DNS 服务器将域名将对应的 IP 地址返回给浏览器;
- 浏览器使用 IP 地址找到对应的服务器后,建立 TCP 连接,向服务器发送 HTTP 请求;
- 服务器接收到请求之后才开始处理,返回 HTTP 响应;
- 浏览器收到来自服务器的响应后开始渲染页面,最后断开与该服务器之间的 TCP 连接。
我们所介绍的 Web 服务器就是在第 3 和 4 步骤中发挥作用的。它的作用很简单,概括地讲,主要完成三个工作:
- 接收请求
- 处理请求,生成响应
- 发送响应
可以看到虽然 Web 服务器这个名字听起来很高大上,其实它的原理非常的简单,我们也可以自己写一个服务器。下面以 go 语言为例 DIY 一个自己的服务器
package main
import (
"fmt"
"log"
"net/http"
)
func sayHelloName(w http.ResponseWriter, r *http.Request) {
r.ParseForm()
fmt.Fprintf(w, "当前请求的地址为:"+r.URL.Path)
}
func main() {
http.HandleFunc("/", sayHelloName)
err := http.ListenAndServe(":8888", nil)
if err != nil {
log.Fatal("ListenAndServe: ", err)
}
}
这就是一个很简单的 web 服务器,它监控本机的 8888 端口。当我们访问 localhost:8888 的时候,浏览器上会输出我们当前的访问路径:
WEB服务器的分类
现在的市面上面有很多类似于 Nginx 的 Web 服务器,如下图:
- Apache 是一款历史悠久的开源 Web 服务器软件。拥有很多的第三方模块,你想使用的功能基本上都可以找到,避免自己重复造轮子。采用多进程方式处理请求,每个请求都对应于一个进程。在高并发的情况下,多进程处理方式特别的消耗资源,所以天然不适合高并发场景;
- Nginx 是年轻(相比 Apache )的开源 Web 服务器软件。它也采用 C 语言编写,代码运行效率很高。它采用了 epoll (以 Linux为例) 事件处理机制作为模型,能够保证非常高的并发量;
- IIS 是微软的 Web 服务器软件,收费
目前Nginx 开发者数量已经明显的超过了其他 Web Server 开发者数量,独占鳌头。
特点
- 占用内存小。这得益于Nginx使用C语言编写,能够高效的使用CPU、内存等系统资源。并且自己实现了内存管理机制等。Nginx 作者对内存的使用控制简直到了丧心病狂的地步,所以非常的节省系统资源,特别是内存;
- 高并发,高性能。
- Nginx出现的初衷就是为了解决C10K问题。和传统的web server不一样,它使用了异步事件引擎处理机制架构(epoll机制)。这种架构可以轻松高效的处理大量的请求,并且非常节省内存
- 理论上,Nginx可以同时处理的最大连接数取决于你的机器的物理内存,上不封顶
- 高可靠性。
- Nginx 使用了
Master-Worker
机制,真正处理请求的是 Worker 进程。 Master 进程可以监控 Worker 进程的运行状况,当某个 Worker 进程因意外原因退出的时候, Master 会重新启动 Worker 进程; - Nginx 的内部框架非常优秀。它的各个模块都非常简单,所以也非常的稳定。
- Nginx 使用了
- 模块化架构使得它的扩展性非常好
- 异步非阻塞的事件驱动模型
- 相对于其它服务器来说它可以连续几个月甚至更长而不需要重启服务器使得它具有高可靠性;
- 热部署、平滑升级;
- 完全开源,生态繁荣;
能做什么?
- HTTP服务器
- 负载均衡:Nginx 提供了多种负载均衡策略,实现了7层负载均衡。针对不同的情形,我们可以选择合适的策略。另外我们也可以自己实现特殊需求的负载均衡策略;
- 可以作为反向代理,还可以正向代理来进行上网等功能。
工作原理
进程池
nginx是个“轻量级”的web服务器,那么这个所谓的“轻量级”是什么意思呢?
“轻量级”是相对于“重量级”而言的,“重量级”就是指服务器进程很“重”,占用很多资源,当处理HTTP请求的时候会消耗大量的CPU和内存,受到这些资源的限制很难提高性能。
而nginx作为“轻量级”服务器,它的CPU、内存占用都非常少,同样的资源配置下就能够为更多的用户提供服务,原因就在于它独特的工作模式:
在nginx之前,web服务器的工作模式大都是“pre-process”和“per-thread”,对每一个请求使用单独的进程和线程处理。这就存在创建进程或者线程的成本,还会有进程、线程“上下文切换”的额外开销。如果请求数目很多,CPU就会在多个进程、线程之间切换,平白浪费了计算时间
nginx则完全不同,没有使用多线程,而是使用了进程池+单线程的工作模式。
- nginx在启动的时候会预先创建固定数量的worker进程,在之后的运行过程中不会再fork出新进程,这就是进程池,而且可以自动把进程“绑定”到独立的CPU上,这样就完全消除了进程创建和切换的成本,能够充分利用多核CPU的计算能力。
- 在进程池之上,还有一个叫做“master”进程,专门用来管理进程池,监控进程,自动恢复发生异常的worker,保存进程池的稳定和服务能力
为什么要单线程呢?
- 使用多线程能够很容易的实现并发处理,但是多线程也有它的缺点,比如“上下文切换”成本、编程模型复杂、数据竞争、同步等问题。
- 因此nginx就选择了单线程的方式,带来的好处是开发简单、没有互斥锁的成本,减少了系统消耗
那么为什么单线程的nginx,处理能够却能够超越其他多线程的服务器呢?
- 这就要归功于nginx利用了Linux内核里的一件“神兵利器”,IO多路复用接口
- web服务器从根本上来说是IO密集型而不是CPU密集型的,处理能力的关键在于网络收发而不是CPU计算,而网络IO会因为各种各样的原因不得不等待,比如数据还没有到达,对端没有响应,缓冲区满发不出去等等
- 这种情况有点像HTTP里的“队头阻塞”。对于一般的单线程来说CPU会“停下来”,造成浪费。而多线程的解决思路类似“并发连接”,虽然有的线程可能阻塞,但由于多个线程并行,总体上看阻塞的情况就不会太严重了
- nginx里使用epoll,就好像HTTP/2里的“多路复用”技术,它把多个HTTP请求处理打算成碎片,都“复用”到一个单线程里面,不按照先来后到的顺序处理,而是只当连接上真正可读、可写的时候才处理,如果可能发生阻塞就立即切换出去,处理其他请求。
- 通过这种方式,nginx就完全消除了IO阻塞,把CPU利用得“满满当当”,又因为网络收发并不会消耗太多的CPU计算能力,也不需要切换进程、线程,所以整体的CPU负载是相当低的
- 如下图,nginx中每个请求处理单独来看是分散、阻塞的,但因为都复用到了一个线程里,所以资源的利用率是非常高的
epoll还有一个特点,大量的连接管理工作都是在操作系统内核里做的,这就减轻了应用程序的负担,所以nginx可以为每个连接只分配很小的内存维护状态,即使有几万、几十万的并发连接也只会消耗几百M内存。
- nginx自1.7.11开始引入了“多线程”,但只是作为辅助手段,卸载阻塞的磁盘IO操作,主要的HTTP请求处理使用的还是单线程里的epoll
- 如何让web服务器能够高效的处理10K以上的并发(concurrent 10k)请求,这就是著名的"C10K问题",当然它早就被epoll/kqueu等解决了,现在的问题是C10M
多阶段处理
有了“进程池”和“IO多路复用”,nginx是如何处理HTTP请求呢?
nginx在内部也采用的是“化整为零”的思路,把整个web服务器分解成了多个“功能模块”,就好像是乐高积木,可以在配置文件里任意拼接搭建,从而实现了高度的灵活性和扩展性。
nginx的HTTP处理有四大类模块:
- handler模块:直接处理HTTP请求
- filter模块:不直接处理请求,而是加工过滤响应报文
- upstream模块:实现反向代理功能,转发请求到其他服务器
- balance模块:实现反向代理时的负载均衡算法
设计模式中有一个模式叫做职责链,它就好像是工程里的流水线,原料从一头里面流入,线上会有很多工人会进行各种加工处理,最后从另一头出来的就是完整的产品
nginx里面的handler模块和filter模块就是按照“职责链”模式设计和组织的,HTTP请求报文就是“原材料”,各种模块就是工厂里的工人,走完模块构成的“流水线”,出来的就是处理完成的响应报文。
下图就是nginx的“流水线”,在nginx里的术语叫做“阶段性处理”,一共有11个阶段,每个阶段里又有很多各司其职的模块,比如:
- charset模块:实现字符集编码转换
- chunked模块:实现响应数据的分块传输
- range模块:实现了范围请求,只返回数据的一部分
- rewrite模块:实现了重定向和跳转,还可以使用内置变量自定义跳转的URI
- not_modified模块:检查头字段
If-Modified-Since
和If-None-Match
,处理条件请求 - realip模块:处理X-Real-IP、
X-Forwarded-For
等字段,获取客户端的真实IP地址 - ssl模块:实现了SSL/TLS协议的支持,读取磁盘上的证书和私钥,实现了TLS握手和SNI、ALPN等扩展功能
- http_v2模块:实现了完整的HTTP/2协议
- limit_conn、limit_req:限流限速
- access:访问控制
- log:日志
小结
- nginx是一个高性能的web服务器,它非常的轻量级,消耗的CPU、内存确很少
- nginx采用
master/workers
进程池架构,不使用多线程,消除了进程、线程切换的成本 - nginx基于epoll实现了IO多路复用,不会阻塞,所以性能很高
- nginx使用了职责链模式,多个模块分工合作,自由组合,以流水线的方式处理HTTP请求