Nginx 模块系统:前篇
Nginx 模块系统:前篇
从 Nginx 第一个版本至今已有 17 个年头,在这十余年里,Nginx 一直把持着 Web 服务软件第一梯队的宝座,它背后的丰富的模块系统,犹如蒙古铁骑举着 Nginx 的旗帜,扫荡了全球该领域的大半的市场。
但是我们知道,软件编译是十分耗时的,非常不利于“快速行军”,除了堆硬件外,Nginx 是如何保持相对高速的迭代过程的呢?这背后模块系统和动态模块设计功不可没。
本篇作为第一篇,聊聊书本之外的 Nginx 模块的一些事情,希望能让你对 Nginx 的模块有更立体的认知。
写在前面
2015 年 Nginx 首席工程师 Ruslan Ermilov 的一篇 PPT 分享粗略的提到了 Nginx 模块系统进化过程,以及如何进行动态模块开发。随后在 Nginx 1.19.7 版本中,代码仓库也正式增加了动态模块的编译方式和相关代码。
在一年之后 2016 年 10 月末,一篇来自 Nginx 官方技术博客的文章 “Compiling Third-Party Dynamic Modules for NGINX and NGINX Plus”正式宣布了 Nginx 的新版本 1.9.11 正式支持三方动态模块功能。
自此之后,构建动态模块,再也不单单是社区其他开源的 “Nginx Like” 软件的特权,使用 Nginx 官方发行软件也能够进行更快速的开发、迭代了。
早在 2012 年的秋天,Tengine 团队推出的 1.4.0 版本便支持了该功能,相比较 Nginx 官方团队迟到的 DSO 功能,足足早了 4 年,我们不知道这四年间基于 Nginx 里做 intra 相关的开发者对着屏幕漫长的编译过程,白白消耗了多少时间。但是我们知道在在此期间的阿里云的业务增幅都是三位数的增长,作为阿里巴巴所有业务七层流量入口,提供了大量“应用功能”的 Tengine 功不可没。
但是迟到总比不到强,不是么。
在聊动态模块之前,我们首先要了解它的模块系统。
Nginx 的模块系统
Nginx 的模块系统主要分为“核心功能模块”和“动态模块”,其中动态模块又分为官方模块和三方模块。某种意义上来看,Nginx 的模块算是一种 AOP 思想的应用实践。
Nginx 的内部模块系统
Nginx 能保持高度曝光发展到今天,除了因为有大量三方模块外,这些拥有稳定质量的内部模块同样功不可没。
分别是负责内部通用数据类型、数据对象、内存管理、文件管理、哈希校验、网络通信、锁、网络连接、日志管理、计时器的“核心模块”;负责在不同操作系统,使用不同的事件方案最优解的“事件模块”;负责门面担当、提供高性能 Web 服务的 “HTTP 模块”;提供通用 TCP 代理服务功能的“流模块”;负责邮件服务代理功能的“邮件功能”;以及解决系统差异的“OS 模块”。时至今日,这些模块还在保持着比较高的频率进行小步迭代,不断进行优化。
这些模块是 Nginx 的一部分,在一次次编译后,伴随着二进制软件包被分发至千家万户,跨越国界、跨越操作系统,大到绵延数个国家的跨国商业公司、小到你家里的路由器、甚至是电梯里的工控机中都能看到它的身影。
如果 Nginx 缺少了以上任何一个模块、或者模块和 Nginx 主文件版本不一致,软件都将停止工作、或者无法提供高质量的服务能力,可以被称之“亲儿子模块”,都属于标准的静态模块。
前文提到过,软件编译是十分耗时的,文件/功能越多,依赖越多,时间越长。Nginx 最初版本出现时,算上三方模块,Nginx 一共只有三十余模块,但是时至今日,仅仅是官方模块文档中收录的三方模块,就有一百五十多个,还有许多模块散落在各种代码开源平台、个人博客中。
随着 Nginx 版本迭代更新,如果这些模块没有跟上版本迭代而和 Nginx 一起重新构建编译,那么原本的功能便会失效或者引起软件故障。漫长的编译过程,对于模块维护者,尤其是为爱发电的开源作者们来说,无疑是一个不必要的负担。
所以在 Tengine / Openresty 一经推出 Lua 模块之后,便吸引了大量“刚需”用户,在保持差不多 Nginx 性能的水准下,大幅降低了开发的时间成本和学习成本。
于是官方在 2016 年正式推出了支持“三方动态模块”的功能,也就是下文将要提到的外部模块。
Nginx 的外部模块
提到 Nginx 的外部模块,其实分为两类,一类是官方为了保持具备 Nginx 核心功能的软件包小巧、资源占用高效,而特意剥离出来的拥有完整功能,但是不是每个人都需要的模块。另外一类则是完全由社区用户、一些商业公司提供的功能模块。早些时候,官方推出了一个专门用于陈列动态模块的页面,如果你感兴趣可以访问页面进行更直观的了解。
可以说前者同样是属于“亲儿子”阵营,只是“常常住校”不常在家里,后者只是的名誉上的儿子,我们一般称呼为“干儿子”。
这类模块可以单独进行编译,相比较带着 Nginx 这个妈一起构建,时间缩短了至少一个量级,并且可以做到相同 Nginx 版本下,随意组合模块使用,不论是在分发体验,还是使用体验上都有了巨大的“进化”。
在工程效率有了质的提升之后,Nginx 官方推出的软件功能也越来越多,官方在同年年末博客文章中提到的战略产品 Nginx Plus 的主要功能几乎都是由动态模块实现:Brotli、Cookie-Flag、Encrypted-Session、FIPS Status Check、GeoIP、GeoIP2、Headers-More、HTTP Substitutions Filter、Image-Filter、Lua、njs Scripting Language、NGINX ModSecurity WAF、NGINX Developer Kit、OpenTracing、Phusion Passenger Open Source、Perl、Prometheus-njs、RTMP、Set-Misc、SPNEGO、XSLT...
能够动态的加载外部模块好归好,但是也有许多问题和挑战。虽然每个现代操作系统都提供了类似 dlopen 的动态链接库的系统接口,但是玩过应用“动态化”的工程师都知道这里面是个深坑。比如常见的 “Dependency hell” 的问题,类似这个 Bug;一些加载失败的场景检测和对应的处理;或者是五花八门的跨平台编译错误,如果你有耐心,可以在官方问题追踪系统中找到更多的内容。
相比较之前没有动态模块时的状况来看,Nginx 工程师需要承担的 “客服” 解释答疑、以及修复问题相关工作,明显变多了,但是好处也是实打实的:软件生态更开放了、编译效率提升了。F5 公司的股价在五年内也由最初 100 刀涨到了一度接近翻番,某种程度印证了一句老话“做产品不如做渠道、做渠道不如做平台、做平台不如做生态”。
最后
观察 Nginx 以及一些其他的基于开源软件成长起来的历程,会发现许多好的软件都是相似的,拥有部分开放的规范和接入能力,允许社区进行贡献,然后深入某个或者某些领域功能,不断进行模块功能优化,最终形成拥有相对完整的生态,细分场景又可以打的很深入的局面。
下篇文章中,我们继续聊聊 Nginx 模块的另外一个话题,如何编写和编译一个 Nginx 模块。
--EOF
我们有一个小小的折腾群,里面聚集了一些喜欢折腾的小伙伴。
在不发广告的情况下,我们在里面会一起聊聊软硬件、HomeLab、编程上的一些问题,也会在群里不定期的分享一些技术沙龙的资料。
喜欢折腾的小伙伴欢迎扫码添加好友。(请注明来源和目的,备注实名,否则不会通过审核)
本文使用「署名 4.0 国际 (CC BY 4.0)」许可协议,欢迎转载、或重新修改使用,但需要注明来源。 署名 4.0 国际 (CC BY 4.0)
本文作者: 苏洋
创建时间: 2021 年 03 月 05 日统计字数: 4013 字阅读时间: 9 分钟阅读本文链接: https://soulteary.com/2021/03/05/nginx-module-system-part-1.html
版权声明: 本文为 InfoQ 作者【soulteary】的原创文章。
原文链接:【http://xie.infoq.cn/article/327b90ff9ef7186e2ce970479】。文章转载请联系作者。
评论