📚 文稿库

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

视频深入浅出地讲解了Nginx的核心概念,包括HTTP服务器、反向代理、负载均衡及高并发架构设计原理。

UP主: 小白debug · 时长: 8:21 · 🔗 B站原视频

标签: Nginx · 后端开发 · 服务器架构 · 负载均衡 · 反向代理

网页与中间层Nginx的引入

Nginx是什么?架构是怎么样的?你是一个程序员,你在电脑上编辑了一段文本,将它保存为TXT文件,将它拖到浏览器打开,就能看到文件里的内容。但这看起来太过单调,为了让画面更丰富,我们定个规则:在文本边上加两个H1符号,文本就以标题形式展示;加入UL和LI就能变成列表;加入IMG还能让URL文本直接变成对应的图片。这些带尖括号的特殊符号我们叫它标签,只要浏览器识别到这些标签,就展示对应的样式。

为了将这个自带标签的文本跟TXT纯文本区分开来,我们给了它新的后缀名HTML。浏览器只要识别到文件是HTML,就会解析里面的标签,这样我们就有了标题、输入框等各种丰富的内容了。这其实就是我们平时在浏览器中看到的网页。但不同的是,这个HTML文件是浏览器从我们本地电脑文件中打开的,而我们平时访问的网页则是从某台远端服务器将文件传到我们电脑的浏览器后打开的。

那么问题就来了,我们是怎么获得这个远端服务器上的HTML文件的?没有什么是加一层中间层不能解决的,如果有,那就再加一层。这次我们要加的中间层是Nginx。假设我们完全不了解Nginx,来看一下它是怎么设计出来的。看之前你点赞了吗?关注了吗?继续。

HTTP服务器是什么

想要让本地的浏览器获取到放在远端服务器上的HTML文件,那很简单。我们可以在远端服务器启动一个进程,这个进程对外提供HTTP服务,说白了就是提供了个URL。用户在浏览器中输入这个URL回车,浏览器就会向这个进程发起HTTP请求。进程收到浏览器的请求后,就将HTML文件发给浏览器,浏览器完成解析和展示,完美。

而像这种根据浏览器请求返回HTML文件的服务进程,其实就叫HTTP服务器。有了它,前端开发老哥写的各种HTML文件就能部署到远端服务器上,对外提供网页服务了。

反向代理与负载均衡

但一个完整产品往往不只有前端页面,还有后端服务。比如某宝,前端商城页面需要从后端服务那儿获取最新的商品数据。假设现在前端页面已经被加载到浏览器中,浏览器会按页面里写好的代码逻辑向后端商品服务发起请求获取数据。流量小的时候没什么问题,流量变大后,后端服务器扛不住的话,就需要增加商品服务的个数。

服务变多后,每个都有对应的IP和端口,浏览器就不知道该访问哪个服务了。所以我们还需要在这几个后端服务前面加一个进程,对外提供一个URL域名。请求来了,由这个进程均匀转发给背后的几个服务,让每个服务都能处理上请求,也就实现了所谓的负载均衡。像这种屏蔽掉背后具体有哪些服务器的代理方式,就是我们常说的反向代理。

有了反向代理,我们对外就可以只提供一个URL域名,背后根据需要随时扩缩容服务。这个反向代理的功能正好可以加到前面放HTML文件的进程上。那现在这个进程就很灵性了,既可为前端HTML文件提供HTTP服务器的功能,当HTML文件被加载到浏览器并向后端发起请求的时候,这个进程还能为后端服务器提供反向代理的功能。

通用网关能力与扩展性

既然是中间层,所有网络流量都要经过进程,那它高低也算个网关了。于是我们就可以顺理成章地在它上面加入一些通用网关能力。比如加个日志,记录每次调用的结果,方便后续排查问题;又比如加个对输入输出的内容进行压缩的功能,减小网络带宽消耗;又或者是对某个IP进行限流或封禁,甚至还可以修改输入输出的内容。

能实现的功能实在太多,想象空间很大,于是将这部分功能设计为开放接口,让用户通过自定义模块来实现特定功能。这还不够,现在这个网关只支持HTTP,我们其实还能扩展下,让它支持TCP、UDP、HTTP2和WebSocket。你能想到的我都要支持,我本来不支持的,自会有人通过自定义模块帮我支持。

配置文件管理

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

单线程与多Worker进程架构

现在这个网关进程的主要任务就是跟上下游建立网络连接,顺便内部做下处理。多个客户端请求通过网络进入到一个进程,如果用多线程并发处理,那就需要考虑并发问题,影响性能。怎么办呢?很简单,外部不管有多少个网络连接,网关进程收到客户端请求后,都统一塞到一个线程上,在一个线程上处理客户端请求,什么并发问题和线程切换开销完全不存在。

但单个进程要单线程处理那么多流量,哪怕再快压力也不小。万一这里面有美羊羊发的流量,你沸羊羊那么久,怎么忍心让她久等?沸羊羊你说话!怎么办呢?既然多线程不行,那我们就上多进程。于是可以将单个进程改为多个进程,我们管它们叫Worker进程。进程之间互相独立,一个Worker挂了并不影响另外一个Worker进程。

让多个Worker进程同时监听一个IP加端口,一有流量进来,操作系统就会随机给到其中一个进程处理。将进程数量设置为跟操作系统CPU核数一致,那每个进程都能得到一个核,开足马力猛猛干。看到这里问题就来了:为什么多个进程同时监听一个端口不会出现端口冲突?评论区告诉我答案。

共享内存与Proxy Cache缓存

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

作为网关,它在收到前端网页请求后会转发给后端,并将后端处理结果中转给前端。如果它能将响应结果缓存起来,这样下次收到同样的请求,直接将缓存里的数据返回给前端,从而减少响应时间和网络负载。那这个数据是放在共享内存里吗?内存贵,不合适。我们可以维护一些磁盘文件,用于在前端请求后端的过程中暂存后端响应的结果,后面再有相同请求,就可以将磁盘里的数据返回。

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

Master进程与滚动升级

但这还不够,现在每个Worker会分走一部分流量,如果功能更新,所有Worker同时一起重启,上面的网络连接就会全部断掉。更好的方式是创建Worker和关闭Worker挨个陆续执行,这样前端网页连接断开后还能去连另外一个Worker,保证任意时间一直有Worker在工作,也就是所谓的滚动升级。

因此还需要一个新的进程协调各个Worker谁先谁后,这个协调进程就是所谓的Master进程。让Master读取前面提到的nginx.conf配置,统一管理多个Worker。

总结:Nginx到底是什么

到这里,当初那个简陋的单进程网关服务,就变成了一个支持动态配置、多种通用网关能力和多种网络协议,单Master多Worker架构,多个Worker进程之间共享内存和Proxy Cache,对外提供一个IP加端口,支持HTTP服务器和反向代理的高性能网关服务——它就是所谓的Nginx。

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

好了,如果你觉得这个视频对你有帮助,记得点赞并转发给你那不成器的兄弟,文字版的笔记见评论区。最后遗留一个问题,想必大家也发现了,聊到现在它其实也只是某台服务器上的多个进程,一旦服务器挂了,Nginx也就挂了,存在单点问题。那怎么解决Nginx的单点问题呢?Nginx有集群模式吗?评论区告诉我答案。

最后的最后再遗留一个问题,你听说过大数据吗?你知道大家是怎么解决大数据问题的吗?点赞超过10000下期来聊这个话题。如果你感兴趣,记得关注我们,下期见。

On this page