有了解过 Nginx 的底层实现吗?

这类问题定位其实很明确,性价比确实没那么高,不算是高频八股。但是如果自己项目有涉及,加上恰好被问到的话,那就可以成为加分项。(但是确实难以去作为一个主动介绍的程度,只能说是一个防备式的准备)

以及 Nginx 实现原理有涉及一些常见八股,所以在各种深层原理中性价比就偏高。虽然被问的概率还是总体相对低。

反正还是来速成一下。上面和下面的说法都是个人见解,欢迎指出错误。

---

 内存池:
常见的优化,几乎高性能框架都会设计到内存池

池这种思想我个人概括为:不是要用就分配用完就释放,而是用完不马上销毁,后边就能像是预分配一样反复利用

nginx 里的要点是: 在os内核层的页式管理上的应用层继续使用了「内存块」的管理方案来管理申请到的大片内存,减少应用层分配碎片和频繁的系统调用

effective-go里面就有一个挺有意思的简单例子,这里也分享一
https://github.com/bingohuang/effective-go-zh-en/blob/master/14_Concurrency.md 翻到最后
概括来说就是 rpc 标准包里边在网络io接受字节流数据的时候,用户态缓冲区我们预分配好放在一个channel中来维护,在用完之后可以回来被复用
我觉得这种简单漏桶模型的思想其实是跟池类似的,不过没有池那么灵活了

 基于Reactor的多进程并发模型处理大量反向代理等连接事件:(评论区学习的)
反向代理,大家应该都知道,就是你的请求过来了,我们帮请求放拿到响应再返回给你。

Reactor 模型是一种设计模式,在很多高并发高性能IO系统中也都有用到,比如 Redis、RabbitMQ。
Reactor 模型的主要特点可以概括为:事件循环、事件分发、非阻塞io。
除了这些高性能系统,浏览器运行js和epoll本身也算是利用了这种设计思想。

而 Nginx,概括来说就是:**多进程、非阻塞异步IO** 的并发模型。
我们从典型的运行过程来认识这个模型:
1. 主进程负责管理配置和生成 worker 进程
2. 每个worker开自己的单线程进行事件循环,基于特定的多路复用模型进行单线程处理连接建立和响应事件(其实这里我个人有一定疑问,除非说epoll_wait本身就算是一种异步了)

为什么不用多进程?(评论区大佬贡献的问题)这里我个人理解原因主要是:
1. 为了 worker 隔离从而确保稳定性
2. worker 的设计具有一定独立性,本身就有进程的体量,也是为了实现横向扩展的能力

nginx实际实现,就是在每个工作进程(worker process)中都开一个事件循环来等待事件,得到之后进行分发,分发之后的处理也使用非阻塞io,完成之后回调相关函数做后续操作(事件驱动)。

然后其中我们获取事件的方式,就交给了os内核的io多路复用机制:
这里我们知道,epoll解决的问题是进行网络io的时候如何高效建立连接和监听请求的。
传统建立tcp连接的方式,分阻塞和非阻塞两种。
阻塞就是监听连接建立和io过程都阻塞不能做其他事;非阻塞就是通过忙轮询的方式来看是否有连接,可以暂时做别的事情,不过io过程也是阻塞的。
这里结合网络编程伪代码理解会更好

而epoll可以实现多路复用,在单线程内,我们可以同时处理多个连接。
具体来说,epoll用红黑树存储事件和他们对应的socket,当有网络连接事件过来的时候,红黑树会扫一遍看看哪些事件要被触发,然后相关socket会进入就绪队列。
一般最简单的一种用法,我们通过阻塞的方式获取到当前所有就绪队列的socket,如果是 我们用来监听的 server socket,那么就accept然后建立新的事件和 client socket加入红黑树,如果是client socket我们就正常处理io事件。
总结就是有高效查找、事件触发等优势,以此可以高效处理大量连接(和io过程关系不大,主要还是连接建立和连接事件触发两大块)
始终使用「边缘触发」的就绪队列维护方式(用户必须一次处理完阻塞获取的所有事件,否则会清理掉)来应付高并发。

不过确实nginx只在linux上使用epoll,而且这个其实反向代理关联不会特别大,多一个建立连接的目标而已,上游的连接建立依然会使用 epoll。复杂还是复杂在网络编程的实现,不过能说出来这些感觉已经够了。

 零拷贝处理静态文件:
就是除了kafka,nginx也用了零拷贝
nginx 利用 location 来进行动静分离。动态资源我们反向代理直接丢给服务器处理。
nginx 可以利用他自己的优化来单独去处理对静态文件的请求,除了缓存就是零拷贝了。
详细原理就不多说了,看小林会更好点。
要说详细了我也不会,实际实现还挺复杂的,除了sendfile还有其他调用,只能跟面试官嘤嘤嘤了
我感觉说简单了到知道dma是用来承接cpu的一部分操作来处理一次磁盘io过程,然后零拷贝是用来继续减少从用户缓冲区发送到内核socket的两次拷贝和一次上下文切换的。

---

个人笔记有不对请指出
牛佬们其他有关于nginx的常见考点也可以分享下 非常感谢
全部评论
漏桶模型?那里好像说的有些问题,这里只是用户态缓冲区放在 channel 中维护,用完可复用
1 回复 分享
发布于 08-21 00:53 北京
就被问到过一次关于nginx的题目,问题是为什么使用多进程而不是多线程?
1 回复 分享
发布于 08-24 17:49 广东
天翼云科技有限公司
校招火热招聘中
官网直投
mark了
点赞 回复 分享
发布于 08-10 21:16 浙江

相关推荐

08-18 20:54
安徽大学 Java
点赞 评论 收藏
分享
5 28 评论
分享
牛客网
牛客企业服务