前言

慕名对Nginx源码进行学习与研究是早在2008年的事情。当时正在为职业规划与未来发展困惑不已,一筹莫展之际不知从哪里得知高性能服务器是一个很有“前途”的努力方向,几经搜索又机缘偶合地得识Lighttpd与Nginx。在逐步了解和熟悉它们的源码后,我开始感到自己的无知与浅薄,发现原来代码也可以写得如此优雅。

我已编著过一本《Lighttpd源码分析》。先解析Lighttpd源码并没有什么特别的原因,只是因为在当时Lighttpd比Nginx要火,应用得也较广;而近几年,凭借专注持续的更新与运作,Nginx后来居上,在全世界的应用仅次于Apache与Microsoft IIShttp://news.netcraft.com/archives/2012/08/02/august-2012-web-server-survey.html。,而且大有赶超IIS的势头。

Nginx提供了一个安全、快速并且灵活的Web Server环境。与其他Web Servers相比,其主要特点是占有系统资源少、并发能力强、稳定性好,这些都是吸引网站架构人员重点关注以及对其进行广泛应用的巨大优点。然而,对于开发工程师而言,更有吸引力的地方却是Nginx是怎样做到如此强劲的功能与性能的,这从因特网上存在大量的Nginx源码分析的博客文章与论坛帖子可见一斑。

既然互联网上已有大量的Nginx源码分析文章,那我现在编写这本《Nginx源码分析》是否多此一举?我会说不是,毕竟它较为完整地梳理了Nginx的相关核心流程。当然,这只是我给出的答案,最终还需要各位读者来回答。我在此阐述一下自己的看法。本书的原始素材是我在最近三四年里地对Nginx代码分析时断断续续地所做的笔记,只不过之前写的笔记过细地逐行注释代码,导致文档中充斥大量的代码。而在这次重新整理后,希望能从比较高一点的角度去解析Nginx,把握全局,搞清楚整体实现原理而不是陷入细节。我个人认为,只要看清楚了Nginx整体的实现原理,对于一时半会没有触及到的细节,在真正遇到那个点时再去理解也是毫不费力,最多只不过还需去查一下Man手册,了解一下系统API而已。授人以鱼不如授人以渔,为了达到这个目标,本书力争尽量少贴代码多画图,当然一些必要的代码仍然是不可或缺的,所以读者还是会在本书看到源代码。虽然我的最初出发点是好的,但是在解析Nginx的某些功能时,我的确遇到了困难,特别是在解析到一大片代码却并没有孰轻孰重的情况下,实在让我很纠结,把代码全部贴上将占去大量的版面,会违背我少贴代码的初衷,不贴上又怕读者不知我所云何物而看不懂。这不仅是因为Nginx代码本身的耦合性较大,也在于我个人的文字描述能力有待提高,所以导致本书或多或少的各种缺点,比如啰嗦的地方、没讲到的细节等,还请各位读者多多包涵。

读者对象

我面试过不少刚本科毕业或研究生毕业的应届生,问得比较多的一句是:写过实际应用的代码么?答:没有。我又问:看过什么优秀的开源代码么?答:没有。这种情况很糟糕。限于国内大学的环境,除了较为简单的课程设计以外,很多大学生在校园内很少有机会写代码或参与实践问题的解决。针对这一点,至少我们可以去看一些有价值的优秀开源代码,毕竟在大学校园里,我们有时间、有地点、有资源(教室、图书馆、电子阅览室等)。所谓他山之石,可以攻玉,在理解这些开源代码的过程中,我们甚至可以尝试写一些扩展功能模块,逼迫自己去主动学习,培养扎实的理论基础知识,锻炼实际的动手编程能力,自己也会因此逐步成长许多。

本书的另一目标读者群为软件开发工程师,这是显而易见的事情。短小精悍的Nginx实现了如此强大的HTTP服务、反向代理服务以及邮件代理服务等,这些功能值得每一位软件开发工程师去学习和研究,况且国内也有不少项目在对Nginx进行二次开发或移植整合,有一本能帮助开发工程师快速开展工作的书籍也许能加快项目进度。

另外,鉴于国内对Nginx的广泛使用,虽然Nginx官网上有不少针对配置使用的文档,但是限于文字描述的简洁性与文档更新的滞后性,对于运维工程师而言,一些配置指令的使用是靠逐步验证来判断其具体使用用法的。通过本书的介绍,我们能从源代码上去找对应配置指令的用法并理解其真实的实际功能,即它让源代码本身就变成一本配置使用手册。所以,对于那些具有强烈意愿知其然又知其所以然的高级运维工程师,本书也是一个不错的选择。

我假设本书的读者已经掌握了C语言,并且对Linux系统有一定程度的了解。不过,即使在开始阅读本书之前,读者在这些方面存在一些不足也无关紧要,我会尽可能地把相关扩展链接标注出来,读者查询一下相关资料即可。

本书的读者对象主要是如下三类人群:

□ 在校大学生;

□ 软件开发工程师;

□ Nginx高级运维工程师。

Nginx版本

本书基于Nginx-1.2.0,该版本是我在重新开始做文档整理时Nginx的最新版本。Nginx源码更新较为频繁,但更新的主要是Bug修正或增添新功能,而其主要架构是稳定的,所以不论哪个版本的Nginx,本书基本都是适用的。

本书讨论环境

我是一名Linux开发工程师,所以本书的讨论环境也就是以Linux为主,使用的所有相关工具都是Linux虽然有一些工具也的确能使用于Windows等其他平台下。下的,比如调试工具gdb、编译工具gcc、测试命令strace/pstack、测试工具wgethttp://www.gnu.org/software/wget/、curlhttp://curl.haxx.se/等。

Nginx本身提供的相关机制,对各种平台都进行了支持,比如I/O多路复用模型就支持epoll、kqueue、eventport等,但本书仍然以Linux平台上的机制为主要讨论对象,像I/O多路复用模型里就是epoll。在没有明确说明的情况,默认的编译模块以附录A为准,且默认以附录B给出的配置运行Nginx。

Linux是广泛使用的操作系统,所以以它为主要实例也是最为方便且有效的方法。我在Intel x86机器上安装了一个CentOShttp://www.centos.org/ 6.2的32位操作系统(系统设置全为默认,比如页大小4KB,应用程序与内核的地址空间划分为3:1等),并且把CentOS 6.2所提供的相关软件开发包也都选择安装上了,这对于我在后继执行相关程序的编译与安装时提供了极大的方便,下面列出了相关系统环境:

□ 操作系统:CentOS release 6.2 (Final)/kernel-2.6.32/32bit;

□ 编译器:gcchttp://gcc.gnu.org/ version 4.4.620110731 (Red Hat 4.4.6-3) (GCC);

□ 调试器:GNU gdbhttp://www.gnu.org/software/gdb/ (GDB) Red Hat Enterprise Linux (7.2-50.el6);

□ Make:GNU Makehttp://www.gnu.org/software/make/ 3.81。

本书内容

本书不是关于Nginx配置指令如何使用的介绍手册,关于那些内容在Nginx官网上有专门的帮助文档http://www.nginx.org/en/docs/和http://wiki.nginx.org/DirectiveIndex,甚至有对应的中文翻译http://wiki.nginx.org/NginxChs。因此本书内容的重点在于解析Nginx的内部实现原理。

虽然限于时间关系而无法做到方方面面的解析,但我尽力把Nginx最核心的线条抽取出来并努力把它们以一种更容易理解的形式展现在各位读者面前。本书一共14章,大部分章节在排列上并没有特别的先后顺序,所以读者在翻阅本书时可以来回跳跃。各章内容简介如下:

第1章,介绍开始本书内容前的准备工作。这是一些基础概念和工具使用,比如什么是Nginx、怎样安装运行Nginx、如何快速方便地阅读Nginx源码以及有哪些相关的知识站点等。

第2章,详细介绍了跟踪与调试的多种手段与技巧。通过实际案例可以看到,这些知识能够极为方便地帮助我们理解Nginx程序内部的相关执行逻辑。

第3章,从3个层次上介绍Nginx的进程模型。首先是最顶层,通过Nginx整体架构框图从宏观上了解Nginx;其次是中间层,对监控进程、工作进程、Cache进程进行逐一介绍,了解它们各自的主要执行逻辑;最后是交互层,即进程之间(套接字、共享内存)以及进程与用户之间(信号)的信息交换。

第4章,Nginx封装了很多有用的数据结构,大多较为简单一看即懂,但其中的内存池、Hash和Radix tree这3个数据结构较为复杂,所以本章对它们做了详细介绍。

第5章,配置指令是用户控制Nginx实际运行逻辑的主要手段,如何将用户设置的配置值转换到Nginx内部并控制Nginx的具体执行,是本章的解析重点。

第6章,Nginx提供的丰富功能基本都是通过模块来实现的,根据每个模块的具体功能不同而分为不同的类型,比如Handler模块、Filter模块、Load-balance模块等。通过对它们的综合概述,让读者从宏观上了解每类Nginx模块的功能。

第7章,与事件相关的实现将在本章介绍。这包括I/O多路复用模型、I/O读写事件、超时事件等。另外,由于Nginx工作进程的主要任务就是处理事件,所以各个工作进程之间的负载均衡也一并介绍。

第8章,变量机制。这里所提到的变量主要是指Nginx用户在配置文件里所使用的可变符号,这些符号大多会随着客户端请求的不同而不同,类似于编程语言里的变量,本章将详细阐述Nginx对它们的具体实现。

第9章,介绍一个完整的客户端请求,包括Web服务器端处理该请求并响应相关数据的过程。在这个过程中,Nginx充当Web服务器直接处理客户端请求,而不是转发到后端服务器。

第10章,对于到达Nginx的客户端请求,Nginx首先要做的就是对它进行定位,也就是找到其所对应的Server与Location,从而提供处理该请求的正确上下文环境,请求处理才能得以继续。这就是本章的主要内容。

第11章,与第9章内容类似,但本章提到的Nginx充当的是代理角色,即它把请求转发给后端PHP服务器进行处理,然后接收其响应并把响应数据发给最终客户端,即一个完整的Nginx+Fastcgi+PHP的客户端请求处理响应过程。

第12章,详细介绍一些Filter模块实例,比如ngx_http_not_modified_filter_module、ngx_http_headers_filter_module等。

第13章,详细介绍两种Load-balance策略的实现,即加权轮询策略与IP哈希策略。

第14章,详细介绍Nginx如何通过Handler模块实现对客户端的访问控制。

另外,附录A给出的是默认configure下的Nginx编译模块,附录B是编写本书时所默认使用的Nginx运行配置,而附录C给出一个HTTP状态码简单介绍的列表,方便读者查阅。

最后,就我个人而言,本书最大的遗憾就是其目前的层次仅达到What与How的程度,即它只介绍了Nginx是什么,有什么功能特性,内部如何运作,具体如何实现,而没有介绍其为什么是这样而不是那样,为什么这样的设计能达到高性能。限于时间关系,这第三个层次(即Why)的内容就暂留给各位读者自己去独立思考吧。不过在此之前,需要充分理解和掌握本书所介绍的前两个层次内容。

致谢

首先,感谢Igor Sysoevhttp://sysoev.ru/en/大师以及Nginx Inc.http://www.nginx.com/为我们提供了如此优秀的开源项目,他们对Nginx的持续改进,让我们看到越来越强大的Nginx。

感谢互联网上众多的知识分享者,帮助我对Nginx代码的理解,特别是在我开始重新整理Nginx文档时,互联网上已涌现出大量的Nginx相关文档,虽然比较零散,但的确加速了我对文档的整理进度。这些内容大多来自博客、论坛、问答等,虽然我无法把他们一一列出,但这并不妨碍我对他们的感激之情。部分参考链接如下。

http://openresty.org/

http://tengine.taobao.org/book/index.html

http://blog.csdn.net/dingyujie/article/category/782920

http://www.aosabook.org/en/nginx.html

http://www.evanmiller.org/nginx-modules-guide.html

http://www.evanmiller.org/nginx-modules-guide-advanced.html

http://blog.lifeibo.com/?cat=4

http://www.pagefault.info/?cat=7

感谢本书编辑对我的各种指导,使我的写作水平有了很大的提高。

最后,感谢在工作和生活中帮助过我的所有人,感谢你们,正是因为有了你们,才有了本书的面世。

本书的相关网站

我维护了一个包含本书相关信息的网站:http://lenky.info/ngx_book/,其中主要包括了本书的勘误表、内容扩展和修改;同时,如果读者有关于本书或Nginx的任何问题,都可以在此页面进行留言,我会尽量经常查看并且及时回复读者提出的相关问题。另外,我的个人电子邮箱为:lenky0401@gmail.com

作为本书的作者,我以兢兢业业的态度力求做到准确无误,但限于时间仓促和个人水平,书中难免会有一些纰漏,这不乏笔误,有叙述不清楚的地方,甚至有我个人理解的错误。针对这些可能存在的不足给读者带来的任何困惑与阻碍,在此提前说声抱歉,请各位读者和同行多多包涵,如果能提出宝贵的意见,我将洗耳恭听,感激不尽。最后,也请大家时时关注一下上面提到的这个网址,有任何问题,我都会及时在那公布。