Skip to content

Nginx 是什么?Nginx高并发架构拆解指南

你是一个程序员,你在电脑上编辑了一段文本,将它保存为 txt 文件。将它拖到浏览器打开,就能看到文件里的内容。

但这看起来太过单调,为了让画面更丰富,我们定个规则,在文本边上加个两个h1符号,文本就以标题形式展示。

加入ul和li就能变成列表,加入img还能让url文本直接变成对应的图片

这些带尖括号的特殊符号,我们叫它标签。只要浏览器识别到这些标签,就展示对应的样式。

为了将这个自带标签的文本跟 txt 纯文本区分开来,我们给了它新的后缀名, html

浏览器只要识别到文件是 html,就会解析里面的标签,这样我们就有了标题、输入框等各种丰富的内容了。这其实就是我们平时在浏览器中看到的网页

但不同的是,这个 html 文件是浏览器从我们本地电脑文件中打开的。

本地浏览器打开html

而我们平时访问的网页,则是从某台远端服务器,将文件传到我们电脑的浏览器后打开的。

从远端服务器得到html打开

那么问题就来了,我们是怎么获得这个远端服务器上的 html 文件的

没有什么是加一层中间层不能解决的,如果有,那就再加一层,这次我们要加的中间层是 Nginx.

nginx中间层

假设我们完全不了解 nginx,来看下它是怎么设计出来的。

HTTP 服务器是什么?

想要让本地的浏览器,获取到放在远端服务器上的 html 文件。

那很简单,我们可以在远端服务器启动一个进程,这个进程对外提供 http 服务,说白了就是提供了个 url

用户在浏览器中输入这个 url, 回车,浏览器就会向 这个进程发起 http 请求

进程收到浏览器的请求后,就将 html 文件发给浏览器,浏览器完成解析和展示,完美。

而像这种根据浏览器请求,返回 html 文件的服务进程,其实就叫 http 服务器

有了它,前端开发老哥写的各种 html 文件就能部署到远端服务器上,对外提供网页服务了。

http服务器是什么

反向代理是什么?

但一个完整产品往往不止有前端页面,还有后端服务,比如某宝,前端商城页面需要从后端服务那获取最新的商品数据。

前后端分离

假设现在前端页面已经被加载到浏览器中,浏览器会按页面里写好的代码逻辑,向后端商品服务发起请求,获取数据,流量小的时候没什么问题,流量变大后,后端服务器扛不住的话,就需要增加商品服务的个数,服务变多后,每个都有对应的 ip 和端口,浏览器就不知道该访问哪个服务了。

所以我们还需要在这几个后端服务前面加一个进程,对外提供一个 url 域名,请求来了,由这个进程均匀转发给背后的几个服务,让每个服务都能处理上请求,也就实现了所谓的负载均衡

像这种,屏蔽掉背后具体有哪些服务器的代理方式,就是我们常说的反向代理

反向代理

有了反向代理,我们对外就可以只提供一个url域名,背后根据需要, 随时扩缩容服务

这个反向代理的功能,正好可以加到前面放 html 文件的进程上。

那现在这个进程就很灵性了,既可以为 前端 html 文件提供 http 服务器的功能,当 html 文件被加载到浏览器,并向后端发起请求的时候,这个进程还能为后端服务器提供反向代理的功能。

http服务器+反向代理

模块化网关能力

既然是中间层,所有网络流量都要经过进程,那它高低也算个网关了。

网关

于是我们就可以顺理成章的在它上面加入一些通用网关能力,比如加个日志,记录每次调用的结果,方便后续排查问题,又比如加个对输入输出的内容进行压缩的功能,减小网络带宽消耗,又或者是对某个 IP 进行限流或封禁,甚至还可以修改输入输出的内容。能实现的功能实在太多,想象空间很大,于是将这部分功能设计为开放接口,让用户通过自定义模块来实现特定功能。

这还不够,现在这个网关只支持http,我们其实还能扩展下,让它支持tcp,udp,http2和websocket,你能想到的我都要支持,我本来不支持的,自会有人通过自定义模块帮我支持。

支持多种通用能力和协议

配置能力

前面提到那么多种能力,用户肯定不会全用上,所以需要有个地方让人选择用哪些能力,于是我们可以加个配置文件,也就是nginx.conf,用户想用什么能力,就在配置文件上声明清楚就行,非常方便。

nginx.conf配置

单线程

现在这个网关进程的主要任务就是跟上下游建立网络连接,顺便内部做下处理。多个客户端请求通过网络进入到一个进程,如果用多线程并发处理,那就需要考虑并发问题,同时影响性能。怎么办呢?

多线程

很简单!外部不管有多少有个网络连接,网关进程收到客户端请求后,都统一塞到一个线程上,在一个线程上处理客户端请求,什么并发问题线程切换开销,完全不存在!

单线程

多 worker 进程

但单个进程要单线程处理那么多流量,哪怕再快,压力也不小,万一这里面有美羊羊发的流量,你觊觎那么久?怎么忍心让她久等?沸羊羊你说话!

怎么办呢?既然多线程不行,那我们就上多进程

于是可以将单个进程改成多个进程,我们管它们叫 worker 进程。进程之间互相独立,一个 worker 跪了不影响另外一个 worker 进程。

多worker进程

让多个 worker 进程同时监听一个 ip 地址+端口。只要一有流量进来,操作系统就会随机给到其中一个进程处理。将进程数量设置为跟操作系统cpu核数一致,那每个进程都能得到一个核,开足马力猛猛干。

worker数与核数一致

看到这里,问题就来了,为什么多个进程同时监听一个端口不会出现端口冲突(port is already in use),评论区告诉我答案。

共享内存

但多 worker 进程的情况下,同一个客户端的多个请求会随机打到某个 worker ,对于限流这种需要计数的场景,就会被分散到多个 worker 上单独计数,那还怎么限流,所以还需要给这些 worker 进程 分配一个共享内存区域,方便多个进程之间共用同一份数据做逻辑,确保系统数据一致性。

共享内存

proxy cache

作为网关,它在收到前端网页请求后,会转发给后端,并将后端处理结果中转给前端。如果它能将响应结果缓存起来,这样下次收到同样的请求,直接将缓存里的数据返回给前端,从而减少响应时间和网络负载

那这个数据是放在共享内存里吗?内存贵,不合适,我们可以维护些磁盘文件,用于在前端请求后端的过程中,暂存后端响应的结果,后面再有相同请求,就可以将磁盘里的数据返回。

这又是经典的空间换时间,用廉价的磁盘空间换取网络传输和cpu计算耗时。对于后端响应较慢或重复请求较多的场景,读写磁盘总归比直接将请求打到后端来得快。这些用于缓存响应数据的磁盘文件,就是 所谓的proxy cache

proxy cache

加入 master 进程

但这还不够,现在每个 worker 都会分走一部分流量,如果功能更新,所有 worker 同时一起重启,上面的网络连接就会全部断掉。更好的方式是创建 worker 和关闭 worker 挨个陆续执行,这样前端网页连接断开后还能去连另外一个worker,保证任意时间一直有worker在工作。也就是所谓的滚动升级。因此还需要一个新的进程协调各个 worker 谁先谁后,这个协调进程,就是所谓的 master 进程。让master读取前面提到的nginx.conf配置,统一管理多个worker。

master进程

nginx 是什么

好啦,到这里,当初那个简陋的单进程网关服务,就变成了一个支持动态配置多种通用网关能力和多种网络协议,单 master 多 worker 架构、多个worker进程之间共享内存和proxy cache,对外提供一个IP+端口,支持 http 服务器和反向代理的高性能网关服务。

它就是所谓的 nginx

nginx是什么

它不仅支持日志、限流等各种通用能力、还支持自定义网关能力,只要你写好配置,就能让它给你当牛做马。性能上 5w qps 非常轻松,应付你那只有几十 qps 的服务更是绰绰有余了。

现在大家通了吗?好啦,如果你觉得这个视频对你有帮助,记得点赞并转发给你那不成器的兄弟,文字版的笔记见评论区。

最后遗留一个问题,想必大家也发现了,聊到现在它其实也只是某台服务器上的多个进程,一旦服务器跪了,nginx 也就跪了,存在单点问题

nginx单点问题

怎么解决 nginx 的单点问题呢?nginx 有集群模式吗?评论区告诉我答案。

最后的最后再遗留一个问题,你听说过大数据吗?你知道大家是怎么解决大数据问题的吗?

点赞超过 1w,下期聊聊这个话题,如果你感兴趣,记得关注。我们下期见!

Nginx 面试题

Nginx 是如何实现高并发的?

如果一个 server 采用一个进程(或者线程)负责一个 request 的方式,那么进 程数就是并发数。那么显而易见的,就是会有很多进程在等待中。等什么?最 多的应该是等待网络传输。其缺点胖友应该也感觉到了,此处不述。

而 Nginx 的异步非阻塞工作方式正是利用了这点等待的时间。在需要等待的 时候,这些进程就空闲出来待命了。因此表现为少数几个进程就解决了大量的 并发问题。

Nginx 是如何利用的呢,简单来说:同样的 4 个进程,如果采用一个进程负 责一个 request 的方式,那么,同时进来 4 个 request 之后,每个进程就 负责其中一个,直至会话关闭。期间,如果有第 5 个 request 进来了。就无 法及时反应了,因为 4 个进程都没干完活呢,因此,一般有个调度进程,每当 新进来了一个 request ,就新开个进程来处理。

Nginx 不这样,每进来一个 request ,会有一个 worker 进程去处理。但不 是全程的处理,处理到什么程度呢?处理到可能发生阻塞的地方,比如向上游 (后端)服务器转发 request ,并等待请求返回。那么,这个处理的 worker 不会这么傻等着,他会在发送完请求后,注册一个事件:“如果 upstream 返 回了,告诉我一声,我再接着干”。于是他就休息去了。此时,如果再有 request 进来,他就可以很快再按这种方式处理。而一旦上游服务器返回了, 就会触发这个事件,worker 才会来接手,这个 request 才会接着往下走。 这就是为什么说,Nginx 基于事件模型。

由于 web server 的工作性质决定了每个 request 的大部份生命都是在网络 传输中,实际上花费在 server 机器上的时间片不多。这是几个进程就解决高 并发的秘密所在。即:

webserver 刚好属于网络 IO 密集型应用,不算是计算密集型。异步,非阻 塞,使用 epol- ,和大量细节处的优化,也正是 Nginx 之所以然的技术基 石。

请解释 Nginx 如何处理 HTTP 请求。

Nginx 使用反应器模式。主事件循环等待操作系统发出准备事件的信号,这样 数据就可以从套接字读取,在该实例中读取到缓冲区并进行处理。单个线程可 以提供数万个并发连接。

为什么要做动、静分离?

在我们的软件开发中,有些请求是需要后台处理的(如:.jsp,.do 等等),有些 请求是不需要经过后台处理的(如:css、html、jpg、js 等等),这些不需要 经过后台处理的文件称为静态文件,否则动态文件。因此我们后台处理忽略静 态文件,但是如果直接忽略静态文件的话,后台的请求次数就明显增多了。在 我们对资源的响应速度有要求的时候,应该使用这种动静分离的策略去解决

动、静分离将网站静态资源(HTML,JavaScript,CSS 等)与后台应用分开 部署,提高用户访问静态代码的速度,降低对后台应用访问。这里将静态资源 放到 nginx 中,动态资源转发到 tomcat 服务器中,毕竟 Tomcat 的优势是处理 动态请求。

nginx 是如何实现高并发的?

一个主进程,多个工作进程,每个工作进程可以处理多个请求,每进来一个 request,会有一个 worker 进程去处理。但不是全程的处理,处理到可能发生 阻塞的地方,比如向上游(后端)服务器转发 request,并等待请求返回。那 么,这个处理的 worker 继续处理其他请求,而一旦上游服务器返回了,就会 触发这个事件,worker 才会来接手,这个 request 才会接着往下走。由于 web server 的工作性质决定了每个 request 的大部份生命都是在网络传输中, 实际上花费在 server 机器上的时间片不多。这是几个进程就解决高并发的秘密 所在。即 webserver 刚好属于网络 IO 密集型应用,不算是计算密集型。

Nginx 静态资源?

静态资源访问,就是存放在 nginx 的 html 页面,我们可以自己编写。

Nginx 配置高可用性怎么配置?

当上游服务器(真实访问服务器),一旦出现故障或者是没有及时相应的话,应

该直接轮训到下一台服务器,保证服务器的高可用。

Nginx 配置代码:

server { 

     listen 80; 

     server\_name www.lijie.com;cc  nginx 发送给上游服务器(真实访问的服 务器)超时时间 

         proxy\_send\_timeout 1s;###

         nginx 接受上游服务器(真实访问的服务器)超时时间 

         proxy\_read\_timeout 1s;

         index index.html index.htm;

     } 

}

502 错误可能原因

  • FastCGI 进程是否已经启动

  • FastCGI worker 进程数是否不够

  • FastCGI 执行时间过长

  • fastcgi_connect_timeout 300; - fastcgi_send_timeout 300;

  • fastcgi_read_timeout 300;

  • FastCGI Buffer 不够

  • nginx 和 apache 一样,有前端缓冲限制,可以调整缓冲参数 - fastcgi_buffer_size 32k;

  • fastcgi_buffers 8 32k;

  • Proxy Buffer 不够

  • 如果你用了 Proxying,调整

  • proxy_buffer_size 16k;

  • proxy_buffers 4 16k;

  • php 脚本执行时间过长

  • 将 php-fpm.conf 的 0s 的 0s 改成一个时间

在 Nginx 中,解释如何在 URL 中保留双斜线?

要在 URL 中保留双斜线,就必须使用 语法:merge_slashes [on/off] 默认值: merge_slashes on

环境: http,server

 merge_slashes_off;

Nginx 服务器上的 Master 和 Worker 进程分别是什么?

Master 进程:读取及评估配置和维持 ;Worker 进程:处理请求。

Nginx 的优缺点?

优点:

  • 占内存小,可实现高并发连接,处理响应快。

  • 可实现 HTTP 服务器、虚拟主机、方向代理、负载均衡。 - Nginx 配置简单。

  • 可以不暴露正式的服务器 IP 地址。

缺点:

动态处理差,nginx 处理静态文件好,耗费内存少,但是处理动态页面则很鸡 肋,现在一般前端用 nginx 作为反向代理抗住压力。

正在精进