欢迎光临
免费的PDF电子书下载网站

《深入理解Nginx:模块开发与架构解析》(阿里巴巴资深Nginx专家撰写,透彻解析Nginx架构,详解Nginx模块开发方法和技巧) PDF下载

编辑推荐

  *资深Nginx专家撰写,透彻解析Nginx架构,详解Nginx模块开发方法和技巧。

 ;

内容简介

  《深入理解Nginx:模块开发与架构解析》是*资深Nginx技术专家呕心沥血之作,是作者多年的经验结晶,也是目前市场上唯一一本通过还原Nginx设计思想,剖析Nginx架构来帮助读者快速高效开发HTTP模块的图书。

  《深入理解Nginx:模块开发与架构解析》首先通过介绍官方Nginx的基本用法和配置规则,帮助读者了解一般Nginx模块的用法,然后重点介绍如何开发HTTP模块(含HTTP过滤模块)来得到定制的Nginx,其中包括开发一个功能复杂的模块所需要了解的各种知识,如Nginx的基础数据结构、配置项的解析、记录日志的工具以及upstream、subrequest的使用方法等。在此基础上,综合Nginx框架代码分析Nginx的架构,介绍其设计理念和技巧,进一步帮助读者自由、有效地开发出功能丰富、性能一流的Nginx模块。

  《深入理解Nginx:模块开发与架构解析》是*资深Nginx技术专家呕心沥血之作,是作者多年的经验结晶,也是目前市场上唯一一本通过还原Nginx设计思想,剖析Nginx架构来帮助读者快速高效开发HTTP模块的图书。

  《深入理解Nginx:模块开发与架构解析》首先通过介绍官方Nginx的基本用法和配置规则,帮助读者了解一般Nginx模块的用法,然后重点介绍如何开发HTTP模块(含HTTP过滤模块)来得到定制的Nginx,其中包括开发一个功能复杂的模块所需要了解的各种知识,如Nginx的基础数据结构、配置项的解析、记录日志的工具以及upstream、subrequest的使用方法等。在此基础上,综合Nginx框架代码分析Nginx的架构,介绍其设计理念和技巧,进一步帮助读者自由、有效地开发出功能丰富、性能一流的Nginx模块。

作者简介

  陶辉,思科后台工程师,从事服务端开发近十年,擅长Linux分布式架构下的海量数据处理,擅长C/C++开发的高性能高吞吐量网络服务,曾任思科DMS后台架构设计工作,曾在腾讯QQ空间后台个人信息中心、个人档、漂流瓶、空间日志、花藤、好友买卖等项目中担任服务器设计与开发工作,曾在华为中央软件部综合网管平台担任北向接口设计开发工作。拥有丰富的Linux高性能服务器开发经验,丰富的云存储系统开发经验,目前关注云文档管理系统和Nginx的再开发。

《深入理解Nginx:模块开发与架构解析》(阿里巴巴资深Nginx专家撰写,透彻解析Nginx架构,详解Nginx模块开发方法和技巧) PDF下载

目录

前 言

第一部分 Nginx能帮我们做什么
第1章 研究Nginx前的准备工作 ;
1.1 Nginx是什么 ;
1.2 为什么选择Nginx ;
1.3 准备工作 ;
1.3.1 Linux操作系统 ;
1.3.2 使用Nginx的必备软件 ;
1.3.3 磁盘目录 ;
1.3.4 Linux内核参数的优化 ;
1.3.5 获取Nginx源码 ;
1.4 编译安装Nginx ;
1.5 configure详解 ;
1.5.1 configure的命令参数 ;
1.5.2 configure执行流程 ;
1.5.3 configure生成的文件 ;
1.6 Nginx的命令行控制 ;
1.7 小结 ;
第2章 Nginx的配置 ;
2.1 运行中的Nginx进程间的关系 ;
2.2 Nginx配置的通用语法 ;
2.2.1 块配置项 ;
2.2.2 配置项的语法格式 ;
2.2.3 配置项的注释 ;
2.2.4 配置项的单位 ;
2.2.5 在配置中使用变量 ;
2.3 Nginx服务的基本配置 ;
2.3.1 用于调试进程和定位问题的配置项 ;
2.3.2 正常运行的配置项 ;
2.3.3 优化性能的配置项 ;
2.3.4 事件类配置项 ;
2.4 用HTTP核心模块配置一个静态Web服务器 ;
2.4.1 虚拟主机与请求的分发 ;
2.4.2 文件路径的定义 ;
2.4.3 内存及磁盘资源的分配 ;
2.4.4 网络连接的设置 ;
2.4.5 MIME类型的设置 ;
2.4.6 对客户端请求的限制 ;
2.4.7 文件操作的优化 ;
2.4.8 对客户端请求的特殊处理 ;
2.4.9 ngx_http_core_module模块提供的变量 ;
2.5 用HTTP proxy module配置一个反向代理服务器 ;
2.5.1 负载均衡的基本配置 ;
2.5.2 反向代理的基本配置 ;
2.6 小结 ;
第二部分 如何编写HTTP模块
第3章 开发一个简单的HTTP模块 ;
3.1 如何调用HTTP模块 ;
3.2 准备工作 ;
3.2.1 整型的封装 ;
3.2.2 ngx_str_t数据结构 ;
3.2.3 ngx_list_t数据结构 ;
3.2.4 ngx_table_elt_t数据结构 ;
3.2.5 ngx_buf_t数据结构 ;
3.2.6 ngx_chain_t数据结构 ;
3.3 如何将自己的HTTP模块编译进Nginx ;
3.3.1 config文件的写法 ;
3.3.2 利用configure脚本将定制的模块加入到Nginx中 ;
3.3.3 直接修改Makefile文件 ;
3.4 HTTP模块的数据结构 ;
3.5 定义自己的HTTP模块 ;
3.6 处理用户请求 ;
3.6.1 处理方法的返回值 ;
3.6.2 获取URI和参数 ;
3.6.3 获取HTTP头部 ;
3.6.4 获取HTTP包体 ;
3.7 发送响应 ;
3.7.1 发送HTTP头部 ;
3.7.2 将内存中的字符串作为包体发送 ;
3.7.3 经典的“Hello World”示例 ;
3.8 将磁盘文件作为包体发送 ;
3.8.1 如何发送磁盘中的文件 ;
3.8.2 清理文件句柄 ;
3.8.3 支持用户多线程下载和断点续传 ;
3.9 用C++语言编写HTTP模块 ;
3.9.1 编译方式的修改 ;
3.9.2 程序中的符号转换 ;
3.10 小结 ;
第4章 配置、error日志和请求上下文 ;
4.1 http配置项的使用场景 ;
4.2 怎样使用http配置 ;
4.2.1 分配用于保存配置参数的数据结构 ;
4.2.2 设定配置项的解析方式 ;
4.2.3 使用14种预设方法解析配置项 ;
4.2.4 自定义配置项处理方法 ;
4.2.5 合并配置项 ;
4.3 HTTP配置模型 ;
4.3.1 解析HTTP配置的流程 ;
4.3.2 HTTP配置模型的内存布局 ;
4.3.3 如何合并配置项 ;
4.3.4 预设配置项处理方法的工作原理 ;
4.4 error日志的用法 ;
4.5 请求的上下文 ;
4.5.1 上下文与全异步Web服务器的关系 ;
4.5.2 如何使用HTTP上下文 ;
4.5.3 HTTP框架如何维护上下文结构 ;
4.6 小结 ;
第5章 访问第三方服务 ;
5.1 upstream的使用方式 ;
5.1.1 ngx_http_upstream_t结构体 ;
5.1.2 设置upstream的限制性参数 ;
5.1.3 设置需要访问的第三方服务器地址 ;
5.1.4 设置回调方法 
5.1.5 如何启动upstream机制 
5.2 回调方法的执行场景 
5.2.1 create_request回调方法 
5.2.2 reinit_request回调方法 
5.2.3 finalize_request回调方法 
5.2.4 process_header回调方法 
5.2.5 rewrite_redirect回调方法 
5.2.6 input_filter_init与input_filter回调方法 
5.3 使用upstream的示例 
5.3.1 upstream的各种配置参数 
5.3.2 请求上下文 
5.3.3 在create_request方法中构造请求 
5.3.4 在process_header方法中解析包头 
5.3.5 在finalize_request方法中释放资源 
5.3.6 在ngx_http_mytest_handler方法中启动upstream 
5.4 subrequest的使用方式 
5.4.1 配置子请求的处理方式 
5.4.2 实现子请求处理完毕时的回调方法 
5.4.3 处理父请求被重新激活后的回调方法 
5.4.4 启动subrequest子请求 
5.5 subrequest执行过程中的主要场景 
5.5.1 如何启动subrequest 
5.5.2 如何转发多个子请求的响应包体 
5.5.3 子请求如何激活父请求 
5.6 subrequest使用的例子 
5.6.1 配置文件中子请求的设置 
5.6.2 请求上下文 
5.6.3 子请求结束时的处理方法 
5.6.4 父请求的回调方法 
5.6.5 启动subrequest 
5.7 小结 
第6章 开发一个简单的HTTP过滤模块 
6.1 过滤模块的意义 
6.2 过滤模块的调用顺序 
6.2.1 过滤链表是如何构成的 
6.2.2 过滤链表的顺序 
6.2.3 官方默认HTTP过滤模块的功能简介 
6.3 HTTP过滤模块的开发步骤 
6.4 HTTP过滤模块的简单例子 
6.4.1 如何编写config文件 
6.4.2 配置项和上下文 
6.4.3 定义HTTP过滤模块 
6.4.4 初始化HTTP过滤模块 
6.4.5 处理请求中的HTTP头部 
6.4.6 处理请求中的HTTP包体 
6.5 小结 
第7章 Nginx提供的高级数据结构 
7.1 Nginx提供的高级数据结构概述 
7.2 ngx_queue_t双向链表 
7.2.1 为什么设计ngx_queue_t双向链表 
7.2.2 双向链表的使用方法 
7.2.3 使用双向链表排序的例子 
7.2.4 双向链表是如何实现的 
7.3 ngx_array_t动态数组 
7.3.1 为什么设计ngx_array_t动态数组 
7.3.2 动态数组的使用方法 
7.3.3  使用动态数组的例子 
7.3.4 动态数组的扩容方式 
7.4 ngx_list_t单向链表 
7.5 ngx_rbtree_t红黑树 
7.5.1 为什么设计ngx_rbtree_t红黑树 
7.5.2 红黑树的特性 
7.5.3 红黑树的使用方法 
7.5.4 使用红黑树的简单例子 
7.5.5 如何自定义添加成员方法 
7.6 ngx_radix_tree_t基数树 
7.6.1 ngx_radix_tree_t基数树的原理 
7.6.2 基数树的使用方法 
7.6.3 使用基数树的例子 
7.7 支持通配符的散列表 
7.7.1 ngx_hash_t基本散列表 
7.7.2 支持通配符的散列表 
7.7.3 带通配符散列表的使用例子 
7.8 小结 
第三部分 深入Nginx
第8章 Nginx基础架构 
8.1 Web服务器设计中的关键约束 
8.2 Nginx的架构设计 
8.2.1 优秀的模块化设计 
8.2.2 事件驱动架构 
8.2.3 请求的多阶段异步处理 
8.2.4 管理进程、多工作进程设计 
8.2.5 平台无关的代码实现 
8.2.6 内存池的设计 
8.2.7 使用统一管道过滤器模式的HTTP过滤模块 
8.2.8 其他一些用户模块 
8.3 Nginx框架中的核心结构体ngx_cycle_t 
8.3.1 ngx_listening_t结构体 
8.3.2 ngx_cycle_t结构体 
8.3.3 ngx_cycle_t支持的方法 
8.4 Nginx启动时框架的处理流程 
8.5 worker进程是如何工作的 
8.6 master进程是如何工作的 
8.7 小结 
第9章 事件模块 
9.1 事件处理框架概述 
9.2 Nginx事件的定义 
9.3 Nginx连接的定义 
9.3.1 被动连接 
9.3.2 主动连接 
9.3.3 ngx_connection_t连接池 
9.4 ngx_events_module核心模块 
9.4.1 如何管理所有事件模块的配置项 
9.4.2 管理事件模块 
9.5 ngx_event_core_module事件模块 
9.6 epoll事件驱动模块 
9.6.1 epoll的原理和用法 
9.6.2 如何使用epoll 
9.6.3 ngx_epoll_module模块的实现 
9.7 定时器事件 
9.7.1 缓存时间的管理 
9.7.2 缓存时间的精度 
9.7.3 定时器的实现 
9.8 事件驱动框架的处理流程 
9.8.1 如何建立新连接 
9.8.2 如何解决“惊群”问题 
9.8.3 如何实现负载均衡 
9.8.4 post事件队列 
9.8.5 ngx_process_events_and_timers流程 
9.9 文件的异步IO 
9.9.1 Linux内核提供的文件异步IO 
9.9.2 ngx_epoll_module模块中实现的针对文件的异步IO 
9.10 小结 
第10章 HTTP框架的初始化 
10.1 HTTP框架概述 
10.2 管理HTTP模块的配置项 
10.2.1 管理main级别下的配置项 
10.2.2 管理server级别下的配置项 
10.2.3 管理location级别下的配置项 
10.2.4 不同级别配置项的合并 
10.3 监听端口的管理 
10.4 server的快速检索 
10.5 location的快速检索 
10.6 HTTP请求的11个处理阶段 
10.6.1 HTTP处理阶段的普适规则 
10.6.2 NGX_HTTP_POST_READ_PHASE阶段 
10.6.3 NGX_HTTP_SERVER_REWRITE_PHASE阶段 
10.6.4 NGX_HTTP_FIND_CONFIG_PHASE阶段 
10.6.5 NGX_HTTP_REWRITE_PHASE阶段 
10.6.6 NGX_HTTP_POST_REWRITE_PHASE阶段 
10.6.7 NGX_HTTP_PREACCESS_PHASE阶段 
10.6.8 NGX_HTTP_ACCESS_PHASE阶段 
10.6.9 NGX_HTTP_POST_ACCESS_PHASE阶段 
10.6.10 NGX_HTTP_TRY_FILES_PHASE阶段 
10.6.11 NGX_HTTP_CONTENT_PHASE阶段 
10.6.12 NGX_HTTP_LOG_PHASE阶段 
10.7 HTTP框架的初始化流程 
10.8 小结 
第11章 HTTP框架的执行流程 
11.1 HTTP框架执行流程概述 
11.2 新连接建立时的行为 
11.3 第一次可读事件的处理 
11.4 接收HTTP请求行 
11.5 接收HTTP头部 
11.6 处理HTTP请求 
11.6.1 ngx_http_core_generic_phase 
11.6.2 ngx_http_core_rewrite_phase 
11.6.3 ngx_http_core_access_phase 
11.6.4 ngx_http_core_content_phase 
11.7 subrequest与post请求 
11.8 处理HTTP包体 
11.8.1 接收包体 
11.8.2 放弃接收包体 
11.9 发送HTTP响应 
11.9.1 ngx_http_send_header 
11.9.2 ngx_http_output_filter 
11.9.3 ngx_http_writer 
11.10 结束HTTP请求 
11.10.1 ngx_http_close_connection 
11.10.2 ngx_http_free_request 
11.10.3 ngx_http_close_request 
11.10.4 ngx_http_finalize_connection 
11.10.5 ngx_http_terminate_request 
11.10.6 ngx_http_finalize_request 
11.11 小结 
第12章 upstream机制的设计与实现 
12.1 upstream机制概述 
12.1.1 设计目的 
12.1.2 ngx_http_upstream_t数据结构的意义 
12.1.3 ngx_http_upstream_conf_t配置结构体 
12.2 启动upstream 
12.3 与上游服务器建立连接 
12.4 发送请求到上游服务器 
12.5 接收上游服务器的响应头部 
12.5.1 应用层协议的两段划分方式 
12.5.2 处理包体的3种方式 
12.5.3 接收响应头部的流程 
12.6 不转发响应时的处理流程 
12.6.1 input_filter方法的设计 
12.6.2 默认的input_filter方法 
12.6.3 接收包体的流程 
12.7 以下游网速优先来转发响应 
12.7.1 转发响应的包头 
12.7.2 转发响应的包体 
12.8 以上游网速优先来转发响应 
12.8.1 ngx_event_pipe_t结构体的意义 
12.8.2 转发响应的包头 
12.8.3 转发响应的包体 
12.8.4 ngx_event_pipe_read_upstream方法 
12.8.5 ngx_event_pipe_write_to_downstream方法 
12.9 结束upstream请求 
12.10 小结 
第13章 邮件代理模块 
13.1 邮件代理服务器的功能 
13.2 邮件模块的处理框架 
13.2.1 一个请求的8个独立处理阶段 
13.2.2 邮件类模块的定义 
13.2.3 邮件框架的初始化 
13.3 初始化请求 
13.3.1 描述邮件请求的ngx_mail_session_t结构体 
13.3.2 初始化邮件请求的流程 
13.4 接收并解析客户端请求 
13.5 邮件认证 
13.5.1 ngx_mail_auth_http_ctx_t结构体 
13.5.2 与认证服务器建立连接 
13.5.3 发送请求到认证服务器 
13.5.4 接收并解析响应 
13.6 与上游邮件服务器间的认证交互 
13.6.1 ngx_mail_proxy_ctx_t结构体 
13.6.2 向上游邮件服务器发起连接 
13.6.3 与邮件服务器认证交互的过程 
13.7 透传上游邮件服务器与客户端间的流 
13.8 小结 
第14章 进程间的通信机制 
14.1 概述 
14.2 共享内存 
14.3 原子操作 
14.3.1 不支持原子库下的原子操作 
14.3.2 x86架构下的原子操作 
14.3.3 自旋锁 
14.4 Nginx频道 
14.5 信号 
14.6 信号量 
14.7 文件锁 
14.8 互斥锁 
14.8.1 文件锁实现的ngx_shmtx_t锁 
14.8.2 原子变量实现的ngx_shmtx_t锁 
14.9 小结 

媒体评论

  从耐心帮助读者了解“如何阅读本书”到书中详细的代码解析与注释、大量而精致的各种图表,以及为本书开发的在线支持网站等,无不体现了作者全身心投入本书的写作。更为可贵的是,作者在实际工作中一行行阅读Nginx源代码、不断尝试和探索,耗费了巨大的精力所积累的宝贵经验,无私地和读者分享。这也成就了Nginx这方面的巨作——覆盖了Nginx的安装、配置、模块开发、架构解析和深度应用等各个方面,适合不同层次的读者,并能切实地帮助读者有效地解决Nginx应用中所碰到的困惑与难题。
  ——朱少民 同济大学软件学院教授
  这是国内(或许也是国外)第一本关于Nginx模块开发的书籍。作者有着丰富的Nginx开发和运维经验,其定制的Nginx服务于真实的大并发SaaS应用,因此其作品不是一本泛泛的手册,而是经验教训之心血结晶。这本书的面世,对于致力于打造符合自己应用场景之高性能Web服务器的开发人员来说,无疑是一大福音。
  ——Grant pan, 思科CRDC Senior Manager
  在互联网上,关于如何安装及配置Nginx的文章可谓众多,可惜一直以来却缺少面向开发人员对其架构原理及核心模块进行系统阐述的相关著作。本书面向不同层次的读者,对Nginx的使用、配置、架构原理及模块开发进行了系统而细致的阐述,无论是单纯使用Nginx的系统工程师还是专注于高性能服务器端研发的开发人员,都可以在本书中发现你所需要的内容。向IgorSysoev致敬!感谢陶辉为我们带来这本很棒的书!
  ——范昕 思科(美国),Senior Engineer
  Nginx是一个功能丰富、插件(模块)众多、性能卓越的Web服务器,业界多把它放在业务的最前端充当静态资源服务器或者反向代理服务器,应用广泛。本书循序渐进地揭开了Nginx的面纱,从如何使用原生的Nginx入手,进而以几个简明的例子为主线说明如何开发http模块,最后再综合介绍Nginx的完整设计思路,帮助读者快速、深入地掌握如何基于Nginx开发出高性能服务器。
  ——吴峥涛 *云计算公司 架构师

前沿

前  言
为什么要写这本书
当我试图在产品的关键位置设计一个高性能Web服务器时,我选择使用成熟的Nginx。选择它的理由为:首先,它对服务器性能上的挖掘已经达到了很高水平,它能尽量使不同的硬件(包括网卡、硬盘、不同的CPU核心)并发运行,同时软件中又没有阻塞进程使之睡眠的代码,从性能上来说,它可以挑战任何服务器。其次,完全基于事件驱动的服务器开发效率往往很不理想,它们要处理的事件过于底层化、细节化,这使得各功能模块无法聚焦于业务,最终产品的功能都较为单一,不会有丰富的可选功能。但Nginx却不然,由于它在软件架构上具有优秀的设计,使得Nginx完全由许多简单的模块构成,各模块(特别是HTTP模块)不用介入底层细节,在尽享分阶段、无阻塞的事件驱动架构下,可以专注于业务功能的实现,这样最终为Nginx带来了大量的官方、第三方的功能模块,使得功能同样强大的Nginx在产品核心位置上足以担当重任,经受住海量请求的考验。
当Nginx已有模块提供的功能不能完全实现我的所有业务需求时,我可以在Nginx的后端再搭建一个实现了缺失功能的非Nginx服务器,将Nginx无法实现的请求反向代理到这台服务器上处理。但这样也有一定的弊端,首先增大了处理请求的开销,其次后端服务器的设计仍然制约着总体性能(它依然需要解决Nginx解决过的无阻塞问题,那样才能像Nginx一样高效),这样做仅适用于对性能要求不高的场景。唯有开发一个实现了所需功能的自定义Nginx模块嵌入到Nginx代码中,才能让自己的业务像Nginx一样充分挖掘服务器的硬件资源,及时地响应百万级别的并发TCP连接。
当我在开发Nginx模块之前,试图在市面上找到一本关于Nginx模块开发的书籍(无论是中文还是英文)时却一无所获。我只能找到如何使用Nginx及其已有模块的书籍。为了开发Nginx模块,我只能通过阅读Nginx极度缺少注释的源代码,并分析各种官方Nginx模块来逐步还原其设计思想,反复尝试、验证着怎样的模块能够使用Nginx的基础架构,和丰富的跨平台工具方法,同时符合Nginx设计思想,使Nginx拥有媲美Linux内核的一流效率。这个过程耗费了我很多的精力,因此,我希望今后的Nginx使用者、开发者在遇到同样的问题时,不至于还要很痛苦地阅读源代码来找到模块开发方法,而是简单地按照章节查阅本书,就可以快速找到怎样简单、高效地开发Nginx模块,把精力放在业务的实现上。这是我写这本书的第一个目的。
当我们产品中运行的Nginx出现了问题时,往往是通过找到错误的配置项、使用方式来解决的,这样也的确能够修复大部分问题。但是更深层次的问题,或者是使用场景比较偏僻,抑或是Nginx自身代码考虑得不够全面时,这些问题往往只能由那些花费大量精力研究Nginx源代码的工程师来解决。我写作本书的第二个目的是希望通过透彻地解析Nginx架构,帮助读者深入理解Nginx,既能够正确地使用它,也能在它出现任何问题时找到根本原因,进而用最合适的方法修复或者回避问题。
Nginx是一个优秀的事件驱动框架,虽然它在HTTP的处理上非常出色,但它绝不仅仅用于Web服务器。Nginx非常适合开发在传输层以TCP对外提供服务的服务器程序。基于Nginx框架开发程序有5个优势:
1)Nginx将网络、磁盘及定时器等异步事件的驱动都做了非常好的封装,基于它开发将可以忽略这些事件处理的细节。
2)Nginx封装了许多平台无关的接口、容器,适用于跨平台开发。
3)优秀的模块化设计,使得开发者可以轻易地复用各种已有的模块,其中既包括基本的读取配置、记录日志等模块,也包括处理请求的诸如HTTP、mail等高级功能模块。
4)Nginx是作为服务器来设计其框架的,因此,它在服务器进程的管理上相当出色,基于它开发服务器程序可以轻松地实现程序的动态升级,子进程的监控、管理,配置项的动态修改生效等。
5)Nginx充分考虑到各操作系统所擅长的“绝活”,能够使用特殊的系统调用更高效地完成任务时,绝不会去使用低效的通用接口。尤其对于Linux操作系统,Nginx不遗余力地做了大量优化。
当我们期望编写一款能够以低负载处理高并发请求并且主要处理基于TCP的服务器程序时,推荐选择Nginx,它可能会带给我们意外的惊喜。这本书的第三部分,将通过分析Nginx的内部架构,帮助读者了解怎样基于Nginx开发高效的TCP服务器程序:通过开发一种新的模块类型,实现一种新的功能框架来提供极佳的扩展性,使得功能子模块仅关注于业务的开发,忽视底层事件的处理。这是我写作本书的第三个目的。
除了这3个主要目的外,我还希望通过这本书向大家展示Nginx在服务器开发上的许多巧妙设计,它们或在抽象设计上精妙,或通过操作系统精确、节省地使用硬件资源,这些细节之处的设计都体现了IgorSysoev的不凡功底。即使我们完全不使用Nginx,学习这些技巧也将有助于我们服务器编程水平的提升。
读者对象
本书适合以下读者阅读。
对Nginx及如何将它搭建成一个高性能的Web服务器感兴趣的读者。
希望通过开发特定的HTTP模块实现高性能Web服务器的读者。
希望了解Nginx的架构设计,学习怎样充分使用服务器上的硬件资源的读者。
了解如何快速定位、修复Nginx中深层次Bug的读者。
希望利用Nginx提供的框架,设计出任何基于TCP的、无阻塞的、易于扩展的服务器的读者。
背景知识
如果仅希望了解怎样使用已有的Nginx功能搭建服务器,那么阅读本书不需要什么先决条件。但如果希望通过阅读本书的第二、第三部分,来学习Nginx的模块开发和架构设计技巧,则必须了解C语言的基本语法。在阅读本书第三部分时,需要读者对TCP有一个基本的了解,同时对Linux操作系统也应该有简单的了解。
如何阅读本书
我很希望将本书写成一本“step bystep”式(循序渐进式)的书籍,因为这样最能节省读者的时间,然而,由于3个主要写作目的想解决的问题都不是那么简单,所以这本书只能做一个折中的处理。
在第一部分的前两章中,将只探讨如何使用Nginx这一问题。阅读这一部分的读者不需要了解C语言,就可以学习如何部署Nginx,学习如何向其中添加各种官方、第三方的功能模块,如何通过修改配置文件来更改Nginx及各模块的功能,如何修改Linux操作系统上的参数来优化服务器性能,最终向用户提供企业级的Web服务器。这一部分介绍配置项的方式,更偏重于带领对Nginx还比较陌生的读者熟悉它,通过了解几个基本Nginx模块的配置修改方式,进而使读者可以通过查询官网、第三方网站来了解如何使用所有Nginx模块的用法。
在第二部分的第3章~第7章中,都是以例子来介绍HTTP模块的开发方式的,这里有些接近于“step bystep”的学习方式,我在写作这一部分时,会通过循序渐进的方式使读者能够快速上手,同时会穿插着介绍其常见用法的基本原理。
在第三部分,将开始介绍Nginx的完整框架,阅读到这里时将会了解第二部分中HTTP模块为何以此种方式开发,同时将可以轻易地开发出Nginx模块。这一部分并不仅仅满足于阐述Nginx架构,而是会探讨其为何如此设计,只有这样才能抛开HTTP框架、邮件代理框架,实现一种新的业务框架、一种新的模块类型。
对于Nginx的使用还不熟悉的读者应当从第1章开始学习,前两章将帮助你快速了解Nginx。
使用过Nginx,但对如何开发Nginx的HTTP模块不太了解的读者可以直接从第3章开始学习,在这一章阅读完后,即可编写一个功能大致完整的HTTP模块。然而,编写企业级的模块必须阅读完第4章才能做到,这一章将会介绍编写产品线上服务器程序时必备的3个手段。第5章举例说明了两种编写复杂HTTP模块的方式,在第三部分会对这两种方式有进一步的说明。第6章介绍一种特殊的HTTP模块—HTTP过滤模块的编写方法。第7章探讨基础容器的用法,这同样是复杂模块的必备工具。
如果读者对于普通HTTP模块的编写已经很熟悉,想深入地实现更为复杂的HTTP模块,或者想了解邮件代理服务器的设计与实现,或者希望编写一种新的处理其他协议的模块,或者仅仅想了解Nginx的架构设计,都可以直接从第8章开始学习,这一章会从整体上系统介绍Nginx的模块式设计。第9章的事件框架是Nginx处理TCP的基础,这一章无法跳过。阅读第8、第9章时可能会遇到许多第7章介绍过的容器,这时可以回到第7章查询其用法和意义。第10章~第12章介绍HTTP框架,通过这3章的学习会对HTTP模块的开发有深入的了解,同时可以学习HTTP框架的优秀设计。第13章简单地介绍了邮件代理服务器的设计,它近似于简化版的HTTP框架。第14章介绍了进程间同步的工具。
为了不让读者陷入代码的“汪洋大海”中,在本书中大量使用了图表,这样可以使读者快速、大体地了解流程和原理。关键地方会直接给出代码,并添加注释加以说明。希望这种方式能够帮助读者减少阅读花费的时间,更快、更好地把握Nginx,同时深入到细节中。
在本书开始写作时,由于Nginx的最新稳定版本是1.0.14,所以本书是基于此版本来编写的。截止到本书编写完成时,Nginx的稳定版本已经上升到了1.2.4。但这不会对本书的阅读造成困扰,因为本书主要是在介绍Nginx的基本框架代码,以及怎样使用这些框架代码开发新的Nginx模块,而不是介绍Nginx的某些功能。在这些基本框架代码中,Nginx一般不会做任何改变,否则已有的大量Nginx模块将无法工作,这种损失也是不可承受的。而且,Nginx框架为具体的功能模块提供了足够的灵活性,修改功能时很少需要修改框架代码。
Nginx是跨平台的服务器,然而这本书将只针对最常见的Linux操作系统进行分析,这样做一方面是篇幅所限,另一方面则是本书的写作目的主要在于告诉读者如何基于Nginx编写代码,而不是怎样在一个具体的操作系统上修改配置来使用Nginx。因此,即使本书以Linux系统为代表讲述Nginx,也不会影响使用其他操作系统的读者阅读,因为操作系统的差别对阅读本书的影响实在是非常小。
勘误和支持
由于作者的水平有限,加之编写的时间也很仓促,书中难免会出现一些错误或者不准确的地方,恳请读者批评指正。为此,我特意创建了一个在线支持与应急方案的二级站点:http://nginx.weebly.com。读者可以将书中的错误发布在Bug勘误表页面中,同时如果你遇到任何问题,也可以访问Q&A页面,我将尽量在线上为读者提供最满意的解答。书中的全部源文件都将发布在这个网站上,我也会将相应的功能更新及时发布出来。如果你有更多的宝贵意见,也欢迎你发送邮件至我的邮箱russelltao@foxmail.com,期待能够听到读者的真挚反馈。
致谢
我首先要感谢Igor Sysoev,他在Nginx设计上展现的功力令人折服,正是他的工作成果才让本书的诞生有了意义。
lisa是机械工业出版社华章公司的优秀编辑,非常值得信任。在这半年的写作过程中,她花费了很多时间、精力来阅读我的书稿,指出了许多文字和格式上的错误,她提出的建议大大提高了本书的可读性。
在这半年时间内,一边工作一边写作给我带来了很大的压力,所以我要感谢我的父母在生活上对我无微不至的照顾,使我可以全力投入到写作中。繁忙的工作之余,写作又占用了休息时间的绝大部分,感谢我的太太对我的体谅和鼓励,让我始终以高昂的斗志投入到本书的写作中。
感谢我工作中的同事们,正是在与他们一起工作的日子里,我才不断地对技术有新的感悟;正是那些充满激情的岁月,才使得我越来越热爱服务器技术的开发。
谨以此书,献给我最亲爱的家人,以及众多热爱Nginx的朋友。

陶 辉

免费在线读

  第一部分
  Nginx能帮我们做什么
  本部分内容
  第1章 研究Nginx前的准备工作
  第2章 Nginx的配置
  
  第1章 研究Nginx前的准备工作
  2012年,Nginx荣获年度云计算开发奖(2012 Cloud Award for Developer of theYear),并成长为世界第二大Web服务器。全世界流量最高的前1000名网站中,超过25%都使用Nginx来处理海量的互联网请求。Nginx已经成为业界高性能Web服务器的代名词。
  那么,什么是Nginx?它有哪些特点?我们选择Nginx的理由是什么?如何编译安装Nginx?这种安装方式背后隐藏的又是什么样的思想呢?本章将会回答上述问题。
  1.1 Nginx是什么
  人们在了解新事物时,往往习惯通过类比来帮助自己理解事物的概貌。那么,我们在学习Nginx时也采用同样的方式,先来看看Nginx的竞争对手—Apache、Lighttpd、Tomcat、Jetty、IIS,它们都是Web服务器,或者叫做WWW(WorldWide Web)服务器,相应地也都具备Web服务器的基本功能:基于REST架构风格,以统一资源描述符(UniformResource Identifier,URI)或者统一资源定位符(Uniform ResourceLocator,URL)作为沟通依据,通过HTTP为浏览器等客户端程序提供各种网络服务。然而,由于这些Web服务器在设计阶段就受到许多局限,例如当时的互联网用户规模、网络带宽、产品特点等局限,并且各自的定位与发展方向都不尽相同,使得每一款Web服务器的特点与应用场合都很鲜明。
  Tomcat和Jetty面向Java语言,先天就是重量级的Web服务器,它的性能与Nginx没有可比性,这里略过。
  IIS只能在Windows操作系统上运行。Windows作为服务器在稳定性与其他一些性能上都不如类UNIX操作系统,因此,在需要高性能Web服务器的场合下,IIS可能会被“冷落”。
  Apache的发展时期很长,而且是目前毫无争议的世界第一大Web服务器,图1-1中是12年来(2010~2012年)世界Web服务器的使用排名情况。
  从图1-1中可以看出,Apache目前处于领先地位。
  Apache有许多优点,如稳定、开源、跨平台等,但它出现的时间太长了,在它兴起的年代,互联网的产业规模远远比不上今天,所以它被设计成了一个重量级的、不支持高并发的Web服务器。在Apache服务器上,如果有数以万计的并发HTTP请求同时访问,就会导致服务器上消耗大量内存,操作系统内核对成百上千的Apache进程做进程间切换也会消耗大量CPU资源,并导致HTTP请求的平均响应速度降低,这些都决定了Apache不可能成为高性能Web服务器,这也促使了Lighttpd和Nginx的出现。观察图1-1中Nginx成长的曲线,体会一下Nginx抢占市场时的“咄咄逼人”吧。
  
  图1-1 Netcraft对于644 275754个站点31.4M个域名Web服务器使用情况的调查结果(2012年3月)
  Lighttpd和Nginx一样,都是轻量级、高性能的Web服务器,欧美的业界开发者比较钟爱Lighttpd,而国内的公司更青睐Nginx,Lighttpd使用得比较少。
  在了解了Nginx的竞争对手之后,相信大家对Nginx也有了直观感受,下面让我们来正式地认识一下Nginx吧。
  提示 Nginx发音:engine [
d3In] X。
  来自俄罗斯的Igor Sysoev在为RamblerMedia(http://www.rambler.ru/)工作期间,使用C语言开发了Nginx。Nginx作为Web服务器,一直为俄罗斯著名的门户网站RamblerMedia提供着出色、稳定的服务。
  Igor Sysoev将Nginx的代码开源,并且赋予其最自由的2-clause BSD-likelicense许可证。由于Nginx使用基于事件驱动的架构能够并发处理百万级别的TCP连接,高度模块化的设计和自由的许可证使得扩展Nginx功能的第三方模块层出不穷,而且优秀的设计带来了极佳的稳定性,因此其作为Web服务器被广泛应用到大流量的网站上,包括腾讯、新浪、网易、淘宝等访问量巨大的网站。
  2012年2月和3月Netcraft对Web服务器的调查如表1-1所示,可以看出,Nginx的市场份额越来越大。
  表1-1 Netcraft对于Web服务器市场占有率前4位软件的调查(2012年2月和3月)
  Web服务器    2012年2月   市场占有率    2012年3月   市场占有率    占有率变化
  Apache    106 664 061   57.45%    108 035 584   57.46%    0.01
  Nginx    23 590 737   12.71%    24 011 199   12.77%    0.06
  Microsoft IIS    22 363 730   12.05%    22 537 872   11.99%    –0.06
  Google Web Server    14 316 485   7.71%    14 438 358   7.68%    –0.03
  
  Nginx是一个跨平台的Web服务器,可运行在Linux、FreeBSD、Solaris、AIX、MacOS、Windows等操作系统上,并且它还可以使用当前操作系统特有的一些高效API来提高自己的性能。
  例如,对于高效处理大规模并发连接,它支持Linux上的epoll(epoll是Linux上处理大并发网络连接的利器,9.6.1节中将会详细说明epoll的工作原理)、Solaris上的eventports和FreeBSD上的kqueue等。
  又如,对于Linux,Nginx支持其独有的sendfile系统调用,这个系统调用可以高效地把硬盘中的数据发送到网络上(不需要先把硬盘数据复制到用户态内存上再发送),这极大地减少了内核态与用户态数据间的复制动作。
  种种迹象都表明,Nginx以性能为王。
  2011年7月,Nginx正式成立公司,由Igor Sysoev担任CTO,立足于提供商业级的Web服务器。
  1.2 为什么选择Nginx
  为什么选择Nginx?因为它具有以下特点:
  (1)更快
  这表现在两个方面:一方面,在正常情况下,单次请求会得到更快的响应;另一方面,在高峰期(如有数以万计的并发请求),Nginx可以比其他Web服务器更快地响应请求。
  实际上,本书第三部分中大量的篇幅都是在说明Nginx是如何做到这两点的。
  (2)高扩展性
  Nginx的设计极具扩展性,它完全是由多个不同功能、不同层次、不同类型且耦合度极低的模块组成。因此,当对某一个模块修复Bug或进行升级时,可以专注于模块自身,无须在意其他。而且在HTTP模块中,还设计了HTTP过滤器模块:一个正常的HTTP模块在处理完请求后,会有一串HTTP过滤器模块对请求的结果进行再处理。这样,当我们开发一个新的HTTP模块时,不但可以使用诸如HTTP核心模块、events模块、log模块等不同层次或者不同类型的模块,还可以原封不动地复用大量已有的HTTP过滤器模块。这种低耦合度的优秀设计,造就了Nginx庞大的第三方模块,当然,公开的第三方模块也如官方发布的模块一样容易使用。
  Nginx的模块都是嵌入到二进制文件中执行的,无论官方发布的模块还是第三方模块都是如此。这使得第三方模块一样具备极其优秀的性能,充分利用Nginx的高并发特性,因此,许多高流量的网站都倾向于开发符合自己业务特性的定制模块。
  (3)高可靠性
  高可靠性是我们选择Nginx的最基本条件,因为Nginx的可靠性是大家有目共睹的,很多家高流量网站都在核心服务器上大规模使用Nginx。Nginx的高可靠性来自于其核心框架代码的优秀设计、模块设计的简单性;另外,官方提供的常用模块都非常稳定,每个worker进程相对独立,master进程在1个worker进程出错时可以快速“拉起”新的worker子进程提供服务。
  (4)低内存消耗
  一般情况下,10 000个非活跃的HTTPKeep-Alive连接在Nginx中仅消耗2.5MB的内存,这是Nginx支持高并发连接的基础。
  从第3章开始,我们会接触到Nginx在内存中为了维护一个HTTP连接所分配的对象,届时将会看到,实际上Nginx一直在为用户考虑(尤其是在高并发时)如何使得内存的消耗更少。
  (5)单机支持10万以上的并发连接
  这是一个非常重要的特性!随着互联网的迅猛发展和互联网用户数量的成倍增长,各大公司、网站都需要应付海量并发请求,一个能够在峰值期顶住10万以上并发请求的Server,无疑会得到大家的青睐。理论上,Nginx支持的并发连接上限取决于内存,10万远未封顶。当然,能够及时地处理更多的并发请求,是与业务特点紧密相关的,本书第8~11章将会详细说明如何实现这个特点。
  (6)热部署
  master管理进程与worker工作进程的分离设计,使得Nginx能够提供热部署功能,即可以在7×24小时不间断服务的前提下,升级Nginx的可执行文件。当然,它也支持不停止服务就更新配置项、更换日志文件等功能。
  (7)最自由的BSD许可协议
  这是Nginx可以快速发展的强大动力。BSD许可协议不只是允许用户免费使用Nginx,它还允许用户在自己的项目中直接使用或修改Nginx源码,然后发布。这吸引了无数开发者继续为Nginx贡献自己的智慧。
  以上7个特点当然不是Nginx的全部,拥有无数个官方功能模块、第三方功能模块使得Nginx能够满足绝大部分应用场景,这些功能模块间可以叠加以实现更加强大、复杂的功能,有些模块还支持Nginx与Perl、Lua等脚本语言集成工作,大大提高了开发效率。这些特点促使用户在寻找一个Web服务器时更多考虑Nginx。
  当然,选择Nginx的核心理由还是它能在支持高并发请求的同时保持高效的服务。
  如果Web服务器的业务访问量巨大,就需要保证在数以百万计的请求同时访问服务时,用户可以获得良好的体验,不会出现并发访问量达到一个数字后,新的用户无法获取服务,或者虽然成功地建立起了TCP连接,但大部分请求却得不到响应的情况。
  通常,高峰期服务器的访问量可能是正常情况下的许多倍,若有热点事件的发生,可能会导致正常情况下非常顺畅的服务器直接“挂死”。然而,如果在部署服务器时,就预先针对这种情况进行扩容,又会使得正常情况下所有服务器的负载过低,这会造成大量的资源浪费。因此,我们会希望在这之间取得平衡,也就是说,在低并发压力下,用户可以获得高速体验,而在高并发压力下,更多的用户都能接入,可能访问速度会下降,但这只应受制于带宽和处理器的速度,而不应该是服务器设计导致的软件瓶颈。
  事实上,由于中国互联网用户群体的数量巨大,致使对Web服务器的设计往往要比欧美公司更加困难。例如,对于全球性的一些网站而言,欧美用户分布在两个半球,欧洲用户活跃时,美洲用户通常在休息,反之亦然。而国内巨大的用户群体则对业界的程序员提出更高的挑战,早上9点和晚上20点到24点这些时间段的并发请求压力是非常巨大的。尤其节假日、寒暑假到来之时,更会对服务器提出极高的要求。
  另外,国内业务上的特性,也会引导用户在同一时间大并发地访问服务器。例如,许多SNS网页游戏会在固定的时间点刷新游戏资源或者允许“偷菜”等好友互动操作。这些会导致服务器处理高并发请求的压力增大。
  上述情形都对我们的互联网服务在大并发压力下是否还能够给予用户良好的体验提出了更高的要求。若要提供更好的服务,那么可以从多方面入手,例如,修改业务特性、引导用户从高峰期分流或者把服务分层分级、对于不同并发压力给用户提供不同级别的服务等。但最根本的是,Web服务器要能支持大并发压力下的正常服务,这才是关键。
  快速增长的互联网用户群以及业内所有互联网服务提供商越来越好的用户体验,都促使我们在大流量服务中用Nginx取代其他Web服务器。Nginx先天的事件驱动型设计、全异步的网络I/O处理机制、极少的进程间切换以及许多优化设计,都使得Nginx天生善于处理高并发压力下的互联网请求,同时Nginx降低了资源消耗,可以把服务器硬件资源“压榨”到极致。
  1.3 准备工作
  由于Linux具有免费、使用广泛、商业支持越来越完善等特点,本书将主要针对Linux上运行的Nginx来进行介绍。需要说明的是,本书不是使用手册,而是介绍Nginx作为Web服务器的设计思想,以及如何更有效地使用Nginx达成目的,而这些内容在各操作系统上基本是相通的(除了第9章关于事件驱动方式以及第14章的进程间同步方式在类UNIX操作系统上略有不同以外)。
  1.3.1 Linux操作系统
  首先我们需要一个内核为Linux 2.6及以上版本的操作系统,因为Linux2.6及以上内核才支持epoll,而在Linux上使用select或poll来解决事件的多路复用,是无法解决高并发压力问题的。
  我们可以使用uname -a命令来查询Linux内核版本,例如:
  :wehf2wng001:root > uname -a
  Linux wehf2wng001 2.6.18-128.el5 #1 SMP Wed Jan 21 10:41:14 EST2009 x86_64 x86_64 x86_64 GNU/Linux
  执行结果表明内核版本是2.6.18,符合我们的要求。
  1.3.2 使用Nginx的必备软件
  如果要使用Nginx的常用功能,那么首先需要确保该操作系统上至少安装了如下软件。
  (1)GCC编译器
  GCC(GNU CompilerCollection)可用来编译C语言程序。Nginx不会直接提供二进制可执行程序(1.2.x版本中已经开始提供某些操作系统上的二进制安装包了,不过,本书探讨如何开发Nginx模块是必须通过直接编译源代码进行的),这有许多原因,本章后面会详述。我们可以使用最简单的yum方式安装GCC,例如:
  yum install -y gcc
  GCC是必需的编译工具。在第3章会提到如何使用C++来编写NginxHTTP模块,这时就需要用到G++编译器了。G++编译器也可以用yum安装,例如:
  yum install -y gcc-c++
  Linux上有许多软件安装方式,yum只是其中比较方便的一种,其他方式这里不再赘述。
  (2)PCRE库
  PCRE(Perl Compatible Regular Expressions,Perl兼容正则表达式)是由PhilipHazel开发的函数库,目前为很多软件所使用,该库支持正则表达式。它由RegEx演化而来,实际上,Perl正则表达式也是源自于HenrySpencer写的RegEx。
  如果我们在配置文件nginx.conf里使用了正则表达式,那么在编译Nginx时就必须把PCRE库编译进Nginx,因为Nginx的HTTP模块要靠它来解析正则表达式。当然,如果你确认不会使用正则表达式,就不必安装它。其yum安装方式如下:
  yum install -y pcre pcre-devel
  pcre-devel是使用PCRE做二次开发时所需要的开发库,包括头文件等,这也是编译Nginx所必须使用的。
  (3)zlib库
  zlib库用于对HTTP包的内容做gzip格式的压缩,如果我们在nginx.conf里配置了gzipon,并指定对于某些类型(content-type)的HTTP响应使用gzip来进行压缩以减少网络传输量,那么,在编译时就必须把zlib编译进Nginx。其yum安装方式如下:
  yum install -y zlib zlib-devel
  同理,zlib是直接使用的库,zlib-devel是二次开发所需要的库。
  (4)OpenSSL开发库
  如果我们的服务器不只是要支持HTTP,还需要在更安全的SSL协议上传输HTTP,那么就需要拥有OpenSSL了。另外,如果我们想使用MD5、SHA1等散列函数,那么也需要安装它。其yum安装方式如下:
  yum install -y openssl openssl-devel
  上面所列的4个库只是完成Web服务器最基本功能所必需的。
  Nginx是高度自由化的Web服务器,它的功能是由许多模块来支持的。而这些模块可根据我们的使用需求来定制,如果某些模块不需要使用则完全不必理会它。同样,如果使用了某个模块,而这个模块使用了一些类似zlib或OpenSSL等的第三方库,那么就必须先安装这些软件。
  1.3.3 磁盘目录
  要使用Nginx,还需要在Linux文件系统上准备以下目录。
  (1)Nginx源代码存放目录
  该目录用于放置从官网上下载的Nginx源码文件,以及第三方或我们自己所写的模块源代码文件。
  (2)Nginx编译阶段产生的中间文件存放目录
  该目录用于放置在configure命令执行后所生成的源文件及目录,以及make命令执行后生成的目标文件和最终连接成功的二进制文件。默认情况下,configure命令会将该目录命名为objs,并放在Nginx源代码目录下。
  (3)部署目录
  该目录存放实际Nginx服务运行期间所需要的二进制文件、配置文件等。默认情况下,该目录为/usr/local/nginx。
  (4)日志文件存放目录
  日志文件通常会比较大,当研究Nginx的底层架构时,需要打开debug级别的日志,这个级别的日志非常详细,会导致日志文件的大小增长得极快,需要预先分配一个拥有更大磁盘空间的目录。
  1.3.4 Linux内核参数的优化
  由于默认的Linux内核参数考虑的是最通用的场景,这明显不符合用于支持高并发访问的Web服务器的定义,所以需要修改Linux内核参数,使得Nginx可以拥有更高的性能。
  在优化内核时,可以做的事情很多,不过,我们通常会根据业务特点来进行调整,当Nginx作为静态Web内容服务器、反向代理服务器或是提供图片缩略图功能(实时压缩图片)的服务器时,其内核参数的调整都是不同的。这里只针对最通用的、使Nginx支持更多并发请求的TCP网络参数做简单说明。
  首先,需要修改/etc/sysctl.conf来更改内核参数。例如,最常用的配置:
  fs.file-max = 999999
  net.ipv4.tcp_tw_reuse = 1
  net.ipv4.tcp_keepalive_time = 600
  net.ipv4.tcp_fin_timeout = 30
  net.ipv4.tcp_max_tw_buckets = 5000
  net.ipv4.ip_local_port_range = 1024    61000
  net.ipv4.tcp_rmem = 4096 32768 262142
  net.ipv4.tcp_wmem = 4096 32768 262142
  net.core.netdev_max_backlog = 8096
  net.core.rmem_default = 262144
  net.core.wmem_default = 262144
  net.core.rmem_max = 2097152
  net.core.wmem_max = 2097152
  net.ipv4.tcp_syncookies = 1
  net.ipv4.tcp_max_syn.backlog=1024
  然后执行sysctl -p命令,使上述修改生效。
  上面的参数意义解释如下:
  file-max:这个参数表示进程(比如一个worker进程)可以同时打开的最大句柄数,这个参数直接限制最大并发连接数,需根据实际情况配置。
  tcp_tw_reuse:这个参数设置为1,表示允许将TIME-WAIT状态的socket重新用于新的TCP连接,这对于服务器来说很有意义,因为服务器上总会有大量TIME-WAIT状态的连接。
  tcp_keepalive_time:这个参数表示当keepalive启用时,TCP发送keepalive消息的频度。默认是2小时,若将其设置得小一些,可以更快地清理无效的连接。
  tcp_fin_timeout:这个参数表示当服务器主动关闭连接时,socket保持在FIN-WAIT-2状态的最大时间。
  tcp_max_tw_buckets:这个参数表示操作系统允许TIME_WAIT套接字数量的最大值,如果超过这个数字,TIME_WAIT套接字将立刻被清除并打印警告信息。该参数默认为180000,过多的TIME_WAIT套接字会使Web服务器变慢。
  tcp_max_syn_backlog:这个参数表示TCP三次握手建立阶段接收SYN请求队列的最大长度,默认为1024,将其设置得大一些可以使出现Nginx繁忙来不及accept新连接的情况时,Linux不至于丢失客户端发起的连接请求。
  ip_local_port_range:这个参数定义了在UDP和TCP连接中本地(不包括连接的远端)端口的取值范围。
  net.ipv4.tcp_rmem:这个参数定义了TCP接收缓存(用于TCP接收滑动窗口)的最小值、默认值、最大值。
  net.ipv4.tcp_wmem:这个参数定义了TCP发送缓存(用于TCP发送滑动窗口)的最小值、默认值、最大值。
  netdev_max_backlog:当网卡接收数据包的速度大于内核处理的速度时,会有一个队列保存这些数据包。这个参数表示该队列的最大值。
  rmem_default:这个参数表示内核套接字接收缓存区默认的大小。
  wmem_default:这个参数表示内核套接字发送缓存区默认的大小。
  rmem_max:这个参数表示内核套接字接收缓存区的最大大小。
  wmem_max:这个参数表示内核套接字发送缓存区的最大大小。
  注意 滑动窗口的大小与套接字缓存区会在一定程度上影响并发连接的数目。每个TCP连接都会为维护TCP滑动窗口而消耗内存,这个窗口会根据服务器的处理速度收缩或扩张。
  参数wmem_max的设置,需要平衡物理内存的总大小、Nginx并发处理的最大连接数量(由nginx.conf中的worker_processes和worker_connections参数决定)而确定。当然,如果仅仅为了提高并发量使服务器不出现OutOfMemory问题而去降低滑动窗口大小,那么并不合适,因为滑动窗口过小会影响大数据量的传输速度。rmem_default、wmem_default、rmem_max、wmem_max这4个参数的设置需要根据我们的业务特性以及实际的硬件成本来综合考虑。
  tcp_syncookies:该参数与性能无关,用于解决TCP的SYN攻击。
  1.3.5 获取Nginx源码
  可以在Nginx官方网站(http://nginx.org/en/download.html)获取Nginx源码包。将下载的nginx-1.0.14.tar.gz源码压缩包放置到准备好的Nginx源代码目录中,然后解压。例如:
  tar -zxvf nginx-1.0.14.tar.gz
  本书编写时的Nginx最新稳定版本为1.0.14(如图1-2所示),本书后续部分都将以此版本作为基准。当然,本书将要说明的Nginx核心代码一般不会有改动(否则大量第三方模块的功能就无法保证了),即使下载其他版本的Nginx源码包也不会影响阅读本书。
  
  图1-2 Nginx的不同版本
  1.4 编译安装Nginx
  安装Nginx最简单的方式是,进入nginx-1.0.14目录后执行以下3行命令:
  ./configure
  make
  make install
  configure命令做了大量的“幕后”工作,包括检测操作系统内核和已经安装的软件,参数的解析,中间目录的生成以及根据各种参数生成一些C源码文件、Makefile文件等。
  make命令根据configure命令生成的Makefile文件编译Nginx工程,并生成目标文件、最终的二进制文件。
  makeinstall命令根据configure执行时的参数将Nginx部署到指定的安装目录,包括相关目录的建立和二进制文件、配置文件的复制。
  1.5 configure详解
  可以看出,configure命令至关重要,下文将详细介绍如何使用configure命令,并分析configure到底是如何工作的,从中我们也可以看出Nginx的一些设计思想。
  1.5.1 configure的命令参数
  使用help命令可以查看configure包含的参数。
  ./configure --help
  这里不一一列出help的结果,只是把它的参数分为了四大类型,下面将会详述各类型下所有参数的用法和意义。
  1. 路径相关的参数
  表1-2列出了Nginx在编译期、运行期中与路径相关的各种参数。
  表1-2 configure支持的路径相关参数
  参数名称    意 义    默 认 值
  --prefix=PATH    Nginx安装部署后的根目录   默认为/usr/local/nginx目录。注意:这个目标的设置会影响其他参数中的相对目录。例如,如果设置了--sbin-path=sbin/nginx,那么实际上可执行文件会被放到/usr/local/nginx/sbin/nginx中
  --sbin-path=PATH    可执行文件的放置路径   /sbin/nginx
  --conf-path=PATH    配置文件的放置路径   /conf/nginx.conf
  --error-log-path=PATH   error日志文件的放置路径。error日志用于定位问题,可输出多种级别(包括debug调试级别)的日志。它的配置非常灵活,可以在nginx.conf里配置为不同请求的日志并输出到不同的log文件中。这里是默认的Nginx核心日志路径   /logs/error.log
  --pid-path=PATH    pid文件的存放路径。这个文件里仅以ASCII码存放着Nginx master的进程ID,有了这个进程ID,在使用命令行(例如nginx -sreload)通过读取master进程ID向master进程发送信号时,才能对运行中的Nginx服务产生作用   /logs/nginx.pid
  --lock-path=PATH    lock文件的放置路径   /logs/nginx.lock
  --builddir=DIR   configure执行时与编译期间产生的临时文件放置的目录,包括产生的Makefile、C源文件、目标文件、可执行文件等   /objs
  --with-perl_modules_path=PATH    perlmodule放置的路径。只有使用了第三方的perl module,才需要配置这个路径   无
  --with-perl=PATH    perlbinary放置的路径。如果配置的Nginx会执行Perl脚本,那么就必须要设置此路径   无
  --http-log-path=PATH   access日志放置的位置。每一个HTTP请求在结束时都会记录的访问日志   /logs/access.log
  --http-client-body-temp-path=PATH   处理HTTP请求时如果请求的包体需要暂时存放到临时磁盘文件中,则把这样的临时文件放置到该路径下   /client_body_temp
  --http-proxy-temp-path=PATH   Nginx作为HTTP反向代理服务器时,上游服务器产生的HTTP包体在需要临时存放到磁盘文件时(详见12.8节),这样的临时文件将放到该路径下   /proxy_temp
  --http-fastcgi-temp-path=PATH   Fastcgi所使用临时文件的放置目录    /fastcgi_temp
  --http-uwsgi-temp-path=PATH   uWSGI所使用临时文件的放置目录    /uwsgi_temp
  --http-scgi-temp-path=PATH   SCGI所使用临时文件的放置目录    /scgi_temp
  
  2. 编译相关的参数
  表1-3列出了编译Nginx时与编译器相关的参数。
  表1-3 configure支持的编译相关参数
  编译参数    意 义
  --with-cc=PATH    C编译器的路径
  --with-cpp=PATH    C预编译器的路径
  --with-cc-opt=OPTIONS   如果希望在Nginx编译期间指定加入一些编译选项,如指定宏或者使用-I加入某些需要包含的目录,这时可以使用该参数达成目的
  --with-ld-opt=OPTIONS   最终的二进制可执行文件是由编译后生成的目标文件与一些第三方库链接生成的,在执行链接操作时可能会需要指定链接参数,--with-ld-opt就是用于加入链接时的参数。例如,如果我们希望将某个库链接到Nginx程序中,需要在这里加入--with-ld-opt=-llibraryName-LlibraryPath,其中libraryName是目标库的名称,libraryPath则是目标库所在的路径
  --with-cpu-opt=CPU   指定CPU处理器架构,只能从以下取值中选择:pentium、pentiumpro、pentium3、pentium4、athlon、opteron、sparc32、sparc64、ppc64
  
  3. 依赖软件的相关参数
  表1-4~表1-8列出了Nginx依赖的常用软件支持的参数。
  表1-4 PCRE的设置参数
  PCRE库的设置参数    意 义
  --without-pcre   如果确认Nginx不用解析正则表达式,也就是说,nginx.conf配置文件中不会出现正则表达式,那么可以使用这个参数
  --with-pcre    强制使用PCRE库
  --with-pcre=DIR   指定PCRE库的源码位置,在编译Nginx时会进入该目录编译PCRE源码
  --with-pcre-opt=OPTIONS   编译PCRE源码时希望加入的编译选项
  
  
  表1-5 OpenSSL的设置参数
  OpenSSL库的设置参数    意 义
  --with-openssl=DIR   指定OpenSSL库的源码位置,在编译Nginx时会进入该目录编译OpenSSL源码
  注意:如果Web服务器支持HTTPS,也就是SSL协议,Nginx要求必须使用OpenSSL。可以访问http://www.openssl.org/免费下载
  --with-openssl-opt=OPTIONS   编译OpenSSL源码时希望加入的编译选项
  
  表1-6 原子库的设置参数
  atomic(原子)库的设置参数    意 义
  --with-libatomic   强制使用atomic库。atomic库是CPU架构独立的一种原子操作的实现。它支持以下体系架构:x86(包括i386和x86_64)、PPC64、Sparc64(v9或更高版本)或者安装了GCC4.1.0及更高版本的架构。14.3节介绍了原子操作在Nginx中的实现
  --with-libatomic=DIR    atomic库所在的位置
  
  表1-7 散列函数库的设置参数
  散列函数库的设置参数    意义
  --with-MD5=DIR   指定MD5库的源码位置,在编译Nginx时会进入该目录编译MD5源码
  注意:Nginx源码中已经有了MD5算法的实现,如果没有特殊需求,那么完全可以使用Nginx自身实现的MD5算法
  --with-MD5-opt=OPTIONS    编译MD5源码时希望加入的编译选项
  ---with-MD5-asm    使用MD5的汇编源码
  --with-SHA1=DIR   指定SHA1库的源码位置,在编译Nginx时会进入该目录编译SHA1源码。
  注意:OpenSSL中已经有了SHA1算法的实现。如果已经安装了OpenSSL,那么完全可以使用OpenSSL实现的SHA1算法
  --with-SHA1-opt=OPTIONS   编译SHA1源码时希望加入的编译选项
  --with-SHA1-asm    使用SHA1的汇编源码
  
  表1-8 zlib库的设置参数
  zlib库的设置参数    意 义
  --with-zlib=DIR   指定zlib库的源码位置,在编译Nginx时会进入该目录编译zlib源码。如果使用了gzip压缩功能,就需要zlib库的支持
  --with-zlib-opt=OPTIONS   编译zlib源码时希望加入的编译选项
  --with-zlib-asm=CPU   指定对特定的CPU使用zlib库的汇编优化功能,目前仅支持两种架构:pentium和pentiumpro
  
  4. 模块相关的参数
  除了少量核心代码外,Nginx完全是由各种功能模块组成的。这些模块会根据配置参数决定自己的行为,因此,正确地使用各个模块非常关键。在configure的参数中,我们把它们分为五大类。
  事件模块。
  默认即编译进入Nginx的HTTP模块。
  默认不会编译进入Nginx的HTTP模块。
  邮件代理服务器相关的mail 模块。
  其他模块。
  (1)事件模块
  表1-9中列出了Nginx可以选择哪些事件模块编译到产品中。
  表1-9 configure支持的事件模块参数
  编译参数    意 义
  --with-rtsig_module    使用rtsig module处理事件驱动
  默认情况下,Nginx是不安装rtsig module的,即不会把rtsigmodule编译进最终的Nginx二进制程序中
  --with-select_module    使用selectmodule处理事件驱动
  select是Linux提供的一种多路复用机制,在epoll调用没有诞生前,例如在Linux2.4及其之前的内核中,select用于支持服务器提供高并发连接
  默认情况下,Nginx是不安装select module的,但如果没有找到其他更好的事件模块,该模块将会被安装
  --without-select_module    不安装select module
  --with-poll_module    使用poll module处理事件驱动
  poll的性能与select类似,在大量并发连接下性能都远不如epoll。默认情况下,Nginx是不安装pollmodule的
  --without-poll_module    不安装poll module
  --with-aio_module    使用AIO方式处理事件驱动
  注意:这里的aio module只能与FreeBSD操作系统上的kqueue事件处理机制合作,Linux上无法使用
  默认情况下是不安装aio module的
  
  (2)默认即编译进入Nginx的HTTP模块
  表1-10列出了默认就会编译进Nginx的核心HTTP模块,以及如何把这些HTTP模块从产品中去除。
  表1-10 configure中默认编译到Nginx中的HTTP模块参数
  默认安装的HTTP 模块    意 义
  --without-http_charset_module    不安装http charsetmodule。这个模块可以将服务器发出的HTTP响应重编码
  --without-http_gzip_module    不安装http gzipmodule。在服务器发出的HTTP响应包中,这个模块可以按照配置文件指定的content-type对特定大小的HTTP响应包体执行gzip压缩
  --without-http_ssi_module    不安装http ssimodule。该模块可以在向用户返回的HTTP响应包体中加入特定的内容,如HTML文件中固定的页头和页尾
  --without-http_userid_module    不安装http useridmodule。这个模块可以通过HTTP请求头部信息里的一些字段认证用户信息,以确定请求是否合法
  --without-http_access_module    不安装http accessmodule。这个模块可以根据IP地址限制能够访问服务器的客户端
  --without-http_auth_basic_module    不安装http authbasic module。这个模块可以提供最简单的用户名/密码认证
  --without-http_autoindex_module    不安装httpautoindex module。该模块提供简单的目录浏览功能
  --without-http_geo_module    不安装http geomodule。这个模块可以定义一些变量,这些变量的值将与客户端IP地址关联,这样Nginx针对不同的地区的客户端(根据IP地址判断)返回不一样的结果,例如不同地区显示不同语言的网页
  --without-http_map_module    不安装http mapmodule。这个模块可以建立一个key/value映射表,不同的key得到相应的value,这样可以针对不同的URL做特殊处理。例如,返回302重定向响应时,可以期望URL不同时返回的Location字段也不一样
  --without-http_split_clients_module    不安装httpsplit client module。该模块会根据客户端的信息,例如IP地址、header头、cookie等,来区分处理
  --without-http_referer_module    不安装http referermodule。该模块可以根据请求中的referer字段来拒绝请求
  --without-http_rewrite_module    不安装http rewritemodule。该模块提供HTTP请求在Nginx服务内部的重定向功能,依赖PCRE库
  --without-http_proxy_module    不安装http proxymodule。该模块提供基本的HTTP反向代理功能
  --without-http_fastcgi_module    不安装http fastcgimodule。该模块提供FastCGI功能
  --without-http_uwsgi_module    不安装http uwsgimodule。该模块提供uWSGI功能
  --without-http_scgi_module    不安装http scgimodule。该模块提供SCGI功能
  --without-http_memcached_module    不安装httpmemcachedmodule。该模块可以使得Nginx直接由上游的memcached服务读取数据,并简单地适配成HTTP响应返回给客户端
  --without-http_limit_zone_module    不安装http limitzone module。该模块针对某个IP地址限制并发连接数。例如,使Nginx对一个IP地址仅允许一个连接
  --without-http_limit_req_module    不安装http limitreq module。该模块针对某个IP地址限制并发请求数
  --without-http_empty_gif_module    不安装http emptygifmodule。该模块可以使得Nginx在收到无效请求时,立刻返回内存中的1×1像素的GIF图片。这种好处在于,对于明显的无效请求不会去试图浪费服务器资源
  --without-http_browser_module    不安装http browsermodule。该模块会根据HTTP请求中的user-agent字段(该字段通常由浏览器填写)来识别浏览器
  --without-http_upstream_ip_hash_module    不安装httpupstream ip hashmodule。该模块提供当Nginx与后端server建立连接时,会根据IP做散列运算来决定与后端哪台server通信,这样可以实现负载均衡
  
  (3)默认不会编译进入Nginx的HTTP模块
  表1-11列出了默认不会编译至Nginx中的HTTP模块以及把它们加入产品中的方法。
  
  
  表1-11 configure中默认不会编译到Nginx中的HTTP模块参数
  可选的HTTP 模块    意 义
  --with-http_ssl_module    安装http sslmodule。该模块使Nginx支持SSL协议,提供HTTPS服务。
  注意:该模块的安装依赖于OpenSSL开源软件,即首先应确保已经在之前的参数中配置了OpenSSL
  --with-http_realip_module    安装http realipmodule。该模块可以从客户端请求里的header信息(如X-Real-IP或者X-Forwarded-For)中获取真正的客户端IP地址
  --with-http_addition_module    安装http addtionmodule。该模块可以在返回客户端的HTTP包体头部或者尾部增加内容
  --with-http_xslt_module    安装http xsltmodule。这个模块可以使XML格式的数据在发给客户端前加入XSL渲染
  注意:这个模块依赖于libxml2和libxslt库,安装它前首先确保上述两个软件已经安装
  --with-http_image_filter_module    安装httpimage_filtermodule。这个模块将符合配置的图片实时压缩为指定大小(width*height)的缩略图再发送给用户,目前支持JPEG、PNG、GIF格式。
  注意:这个模块依赖于开源的libgd库,在安装前确保操作系统已经安装了libgd
  --with-http_geoip_module    安装http geoipmodule。该模块可以依据MaxMind GeoIP的IP地址数据库对客户端的IP地址得到实际的地理位置信息
  注意:该库依赖于MaxMindGeoIP的库文件,可访问http://geolite.maxmind.com/download/geoip/database/GeoLiteCity.dat.gz获取
  --with-http_sub_module    安装http submodule。该模块可以在Nginx返回客户端的HTTP响应包中将指定的字符串替换为自己需要的字符串
  例如,在HTML的返回中,将替换为
  --with-http_dav_module    安装http davmodule。这个模块可以让Nginx支持Webdav标准,如支持Webdav协议中的PUT、DELETE、COPY、MOVE、MKCOL等请求
  --with-http_flv_module    安装http flvmodule。这个模块可以在向客户端返回响应时,对FLV格式的视频文件在header头做一些处理,使得客户端可以观看、拖动FLV视频
  --with-http_mp4_module    安装http mp4module。该模块使客户端可以观看、拖动MP4视频
  --with-http_gzip_static_module    安装http gzipstaticmodule。如果采用gzip模块把一些文档进行gzip格式压缩后再返回给客户端,那么对同一个文件每次都会重新压缩,这是比较消耗服务器CPU资源的。gzipstatic模块可以在做gzip压缩前,先查看相同位置是否有已经做过gzip压缩的.gz文件,如果有,就直接返回。这样就可以预先在服务器上做好文档的压缩,给CPU减负
  --with-http_random_index_module    安装http randomindex module。该模块在客户端访问某个目录时,随机返回该目录下的任意文件
  --with-http_secure_link_module    安装http securelinkmodule。该模块提供一种验证请求是否有效的机制。例如,它会验证URL中需要加入的token参数是否属于特定客户端发来的,以及检查时间戳是否过期
  --with-http_degradation_module    安装httpdegradationmodule。该模块针对一些特殊的系统调用(如sbrk)做一些优化,如直接返回HTTP响应码为204或者444。目前不支持Linux系统
  --with-http_stub_status_module    安装http stubstatusmodule。该模块可以让运行中的Nginx提供性能统计页面,获取相关的并发连接、请求的信息(14.2.1节中简单介绍了该模块的原理)
  --with-google_perftools_module    安装googleperftools module。该模块提供Google的性能测试工具
  
  (4)邮件代理服务器相关的mail模块
  表1-12列出了把邮件模块编译到产品中的参数。
  表1-12 configure提供的邮件模块参数
  可选的mail 模块    意 义
  --with-mail   安装邮件服务器反向代理模块,使Nginx可以反向代理IMAP、POP3、SMTP等协议。该模块默认不安装
  --with-mail_ssl_module    安装mail sslmodule。该模块可以使IMAP、POP3、SMTP等协议基于SSL/TLS协议之上使用。该模块默认不安装并依赖于OpenSSL库
  --without-mail_pop3_module    不安装mail pop3module。在使用--with-mail参数后,pop3 module是默认安装的,以使Nginx支持POP3协议
  --without-mail_imap_module    不安装mail imapmodule。在使用--with-mail参数后,imap module是默认安装的,以使Nginx支持IMAP
  --without-mail_smtp_module    不安装mail smtpmodule。在使用--with-mail参数后,smtp module是默认安装的,以使Nginx支持SMTP
  
  5.其他参数
  configure还接收一些其他参数,表1-13中列出了相关参数的说明。
  表1-13 configure提供的其他参数
  其他一些参数    意 义
  --with-debug   将Nginx需要打印debug调试级别日志的代码编译进Nginx。这样可以在Nginx运行时通过修改配置文件来使其打印调试日志,这对于研究、定位Nginx问题非常有帮助
  --add-module=PATH   当在Nginx里加入第三方模块时,通过这个参数指定第三方模块的路径。这个参数将在下文如何开发HTTP模块时使用到
  --without-http    禁用HTTP服务器
  --without-http-cache    禁用HTTP服务器里的缓存Cache特性
  --with-file-aio   启用文件的异步I/O功能来处理磁盘文件,这需要Linux内核支持原生的异步I/O
  --with-ipv6    使Nginx支持IPv6
  --user=USER    指定Nginx worker进程运行时所属的用户
  注意:不要将启动worker进程的用户设为root,在worker进程出问题时master进程要具备停止/启动worker进程的能力
  --group=GROUP    指定Nginx worker进程运行时所属的组
  
  1.5.2 configure执行流程
  我们看到configure命令支持非常多的参数,读者可能会好奇它在执行时到底做了哪些事情,本节将通过解析configure源码来对它有一个感性的认识。configure由Shell脚本编写,中间会调用/auto/目录下的脚本。这里将只对configure脚本本身做分析,对于它所调用的auto目录下的其他工具脚本则只做功能性的说明。
  configure脚本的内容如下:
  #!/bin/sh
  
  # Copyright (C) Igor Sysoev
  # Copyright (C) Nginx, Inc.
  
  #auto/options脚本处理configure命令的参数。例如,如果参数是--help,那么显示支持的所有参数格式。options脚本会定义后续工作将要用到的变量,然后根据本次参数以及默认值设置这些变量
  . auto/options
  
  #auto/init脚本初始化后续将产生的文件路径。例如,Makefile、ngx_modules.c等文件默认情况下将会在/objs/
  . auto/init
  
  #auto/sources脚本将分析Nginx的源码结构,这样才能构造后续的Makefile文件
  . auto/sources
  
  #编译过程中所有目标文件生成的路径由—builddir=DIR参数指定,默认情况下为/objs,此时这个目录将会被创建
  test -d $NGX_OBJS || mkdir $NGX_OBJS
  
  #开始准备建立ngx_auto_headers.h、autoconf.err等必要的编译文件
  echo > $NGX_AUTO_HEADERS_H
  echo > $NGX_AUTOCONF_ERR
  
  #向objs/ngx_auto_config.h写入命令行带的参数
  echo "#define NGX_CONFIGURE "$NGX_CONFIGURE"" >$NGX_AUTO_CONFIG_H
  
  #判断DEBUG标志,如果有,那么在objs/ngx_auto_config.h文件中写入DEBUG宏
  if [ $NGX_DEBUG = YES ]; then
      have=NGX_DEBUG . auto/have
  fi
  
  #现在开始检查操作系统参数是否支持后续编译
  if test -z "$NGX_PLATFORM"; then
      echo "checking for OS"
  
      NGX_SYSTEM=`uname -s 2>/dev/null`
      NGX_RELEASE=`uname -r 2>/dev/null`
      NGX_MACHINE=`uname -m 2>/dev/null`
  
  #屏幕上输出OS名称、内核版本、32位/64位内核
      echo " + $NGX_SYSTEM $NGX_RELEASE$NGX_MACHINE"
  
     NGX_PLATFORM="$NGX_SYSTEM:$NGX_RELEASE:$NGX_MACHINE";
  
      case "$NGX_SYSTEM" in
          MINGW32_*)
             NGX_PLATFORM=win32
          ;;
      esac
  
  else
      echo "building for $NGX_PLATFORM"
      NGX_SYSTEM=$NGX_PLATFORM
  fi
  
  #检查并设置编译器,如GCC是否安装、GCC版本是否支持后续编译nginx
  . auto/cc/conf
  
  #对非Windows操作系统定义一些必要的头文件,并检查其是否存在,以此决定configure后续步骤是否可以成功
  if [ "$NGX_PLATFORM" != win32 ]; then
      . auto/headers
  fi
  
  #对于当前操作系统,定义一些特定的操作系统相关的方法并检查当前环境是否支持。例如,对于Linux,在这里使用sched_setaffinity设置进程优先级,使用Linux特有的sendfile系统调用来加速向网络中发送文件块
  . auto/os/conf
  
  #定义类UNIX 操作系统中通用的头文件和系统调用等,并检查当前环境是否支持
  if [ "$NGX_PLATFORM" != win32 ]; then
      . auto/unix
  fi
  
  #最核心的构造运行期modules的脚本。它将会生成ngx_modules.c文件,这个文件会被编译进Nginx中,其中它所做的唯一的事情就是定义了ngx_modules数组。ngx_modules指明Nginx运行期间有哪些模块会参与到请求的处理中,包括HTTP请求可能会使用哪些模块处理,因此,它对数组元素的顺序非常敏感,也就是说,绝大部分模块在ngx_modules数组中的顺序其实是固定的。例如,一个请求必须先执行ngx_http_gzip_filter_module模块重新修改HTTP响应中的头部后,才能使用ngx_http_header_filter模块按照headers_in结构体里的成员构造出以TCP流形式发送给客户端的HTTP响应头部。注意,我们在--add-module=参数里加入的第三方模块也在此步骤写入到ngx_modules.c文件中了
  . auto/modules
  
  #conf脚本用来检查Nginx在链接期间需要链接的第三方静态库、动态库或者目标文件是否存在
  . auto/lib/conf
  
  #处理Nginx安装后的路径
  case ".$NGX_PREFIX" in
      .)
         NGX_PREFIX=${NGX_PREFIX:-/usr/local/nginx}
          have=NGX_PREFIXvalue=""$NGX_PREFIX/"" . auto/define
      ;;
  
      .!)
          NGX_PREFIX=
      ;;
  
      *)
          have=NGX_PREFIXvalue=""$NGX_PREFIX/"" . auto/define
      ;;
  esac
  
  #处理Nginx安装后conf文件的路径
  if [ ".$NGX_CONF_PREFIX" != "." ]; then
      have=NGX_CONF_PREFIXvalue=""$NGX_CONF_PREFIX/"" . auto/define
  fi
  
  #处理Nginx安装后,二进制文件、pid、lock等其他文件的路径可参见configure参数中路径类选项的说明
  have=NGX_SBIN_PATH value=""$NGX_SBIN_PATH"" . auto/define
  have=NGX_CONF_PATH value=""$NGX_CONF_PATH"" . auto/define
  have=NGX_PID_PATH value=""$NGX_PID_PATH"" . auto/define
  have=NGX_LOCK_PATH value=""$NGX_LOCK_PATH"" . auto/define
  have=NGX_ERROR_LOG_PATH value=""$NGX_ERROR_LOG_PATH"" .auto/define
  
  
  have=NGX_HTTP_LOG_PATH value=""$NGX_HTTP_LOG_PATH"" .auto/define
  have=NGX_HTTP_CLIENT_TEMP_PATHvalue=""$NGX_HTTP_CLIENT_TEMP_PATH"" . auto/define
  have=NGX_HTTP_PROXY_TEMP_PATHvalue=""$NGX_HTTP_PROXY_TEMP_PATH"" . auto/define
  have=NGX_HTTP_FASTCGI_TEMP_PATHvalue=""$NGX_HTTP_FASTCGI_TEMP_PATH"" . auto/define
  have=NGX_HTTP_UWSGI_TEMP_PATHvalue=""$NGX_HTTP_UWSGI_TEMP_PATH"" . auto/define
  have=NGX_HTTP_SCGI_TEMP_PATH value=""$NGX_HTTP_SCGI_TEMP_PATH"". auto/define
  
  #创建编译时使用的objs/Makefile文件
  . auto/make
  
  #为objs/Makefile加入需要连接的第三方静态库、动态库或者目标文件
  . auto/lib/make
  
  #为objs/Makefile加入install功能,当执行makeinstall时将编译生成的必要文件复制到安装路径,建立必要的目录
  . auto/install
  
  # 在ngx_auto_config.h文件中加入NGX_SUPPRESS_WARN宏、NGX_SMP宏
  . auto/stubs
  
  #在ngx_auto_config.h文件中指定NGX_USER和NGX_GROUP宏,如果执行configure时没有参数指定,默认两者皆为nobody(也就是默认以nobody用户运行进程)
  have=NGX_USER value=""$NGX_USER"" . auto/define
  have=NGX_GROUP value=""$NGX_GROUP"" . auto/define
  
  #显示configure执行的结果,如果失败,则给出原因
  . auto/summary
  
  1.5.3 configure生成的文件
  当configure执行成功时会生成objs目录,并在该目录下产生以下目录和文件:
  |---ngx_auto_headers.h
  |---autoconf.err
  |---ngx_auto_config.h
  |---ngx_modules.c
  |---src
  |    |---core
  |    |---event
  |    |    |---modules
  |    |---os
  |    |    |---unix
  |    |    |---win32
  |    |---http
  |    |    |---modules
  |    |   |      |---perl
  |    |---mail
  |    |---misc
  |---Makefile
  上述目录和文件介绍如下。
  1)src目录用于存放编译时产生的目标文件。
  2)Makefile文件用于编译Nginx工程以及在加入install参数后安装Nginx。
  3)autoconf.err保存configure执行过程中产生的结果。
  4)ngx_auto_headers.h和ngx_auto_config.h保存了一些宏,这两个头文件会被src/core/ngx_config.h及src/os/unix/ngx_linux_config.h文件(可将“linux”替换为其他UNIX操作系统)引用。
  5)ngx_modules.c是一个关键文件,我们需要看看它的内部结构。一个默认配置下生成的ngx_modules.c文件内容如下:
  #include
  #include
  
  …
  
  ngx_module_t *ngx_modules[] = {
      &ngx_core_module,
      &ngx_errlog_module,
      &ngx_conf_module,
      &ngx_events_module,
      &ngx_event_core_module,
      &ngx_epoll_module,
      &ngx_http_module,
      &ngx_http_core_module,
      &ngx_http_log_module,
      &ngx_http_upstream_module,
      &ngx_http_static_module,
      &ngx_http_autoindex_module,
      &ngx_http_index_module,
      &ngx_http_auth_basic_module,
      &ngx_http_access_module,
      &ngx_http_limit_zone_module,
      &ngx_http_limit_req_module,
      &ngx_http_geo_module,
      &ngx_http_map_module,
      &ngx_http_split_clients_module,
      &ngx_http_referer_module,
      &ngx_http_rewrite_module,
      &ngx_http_proxy_module,
      &ngx_http_fastcgi_module,
      &ngx_http_uwsgi_module,
      &ngx_http_scgi_module,
      &ngx_http_memcached_module,
      &ngx_http_empty_gif_module,
      &ngx_http_browser_module,
      &ngx_http_upstream_ip_hash_module,
      &ngx_http_write_filter_module,
      &ngx_http_header_filter_module,
      &ngx_http_chunked_filter_module,
     &ngx_http_range_header_filter_module,
      &ngx_http_gzip_filter_module,
      &ngx_http_postpone_filter_module,
      &ngx_http_ssi_filter_module,
      &ngx_http_charset_filter_module,
      &ngx_http_userid_filter_module,
      &ngx_http_headers_filter_module,
      &ngx_http_copy_filter_module,
      &ngx_http_range_body_filter_module,
     &ngx_http_not_modified_filter_module,
      NULL
  };
  ngx_modules.c文件就是用来定义ngx_modules数组的。
  ngx_modules是非常关键的数组,它指明了每个模块在Nginx中的优先级,当一个请求同时符合多个模块的处理规则时,将按照它们在ngx_modules数组中的顺序选择最靠前的模块优先处理。对于HTTP过滤模块而言则是相反的,因为HTTP框架在初始化时,会在ngx_modules数组中将过滤模块按先后顺序向过滤链表中添加,但每次都是添加到链表的表头,因此,对HTTP过滤模块而言,在ngx_modules数组中越是靠后的模块反而会首先处理HTTP响应(参见第6章及第11章的11.9节)。
  因此,ngx_modules中模块的先后顺序非常重要,不正确的顺序会导致Nginx无法工作,这是auto/modules脚本执行后的结果。读者可以体会一下上面的ngx_modules中同一种类型下(第8章会介绍模块类型,第10章、第11章将介绍的HTTP框架对HTTP模块的顺序是最敏感的)各个模块的顺序以及这种顺序带来的意义。
  可以看出,在安装过程中,configure做了大量的幕后工作,我们需要关注在这个过程中Nginx做了哪些事情。configure除了寻找依赖的软件外,还针对不同的UNIX操作系统做了许多优化工作。这是Nginx跨平台的一种具体实现,也体现了Nginx追求高性能的一贯风格。
  configure除了生成Makefile外,还生成了ngx_modules.c文件,它决定了运行时所有模块的优先级(在编译过程中而不是编码过程中)。对于不需要的模块,既不会加入ngx_modules数组,也不会编译进Nginx产品中,这也体现了轻量级的概念。
  1.6 Nginx的命令行控制
  在Linux中,需要使用命令行来控制Nginx服务器的启动与停止、重载配置文件、回滚日志文件、平滑升级等行为。默认情况下,Nginx被安装在目录/usr/local/nginx/中,其二进制文件路径为/usr/local/nginc/sbin/nginx,配置文件路径为/usr/local/nginx/conf/nginx.conf。当然,在configure执行时是可以指定把它们安装在不同目录的。为了简单起见,本节只说明默认安装情况下的命令行的使用情况,如果读者安装的目录发生了变化,那么替换一下即可。
  (1)默认方式启动
  直接执行Nginx二进制程序。例如:
  /usr/local/nginx/sbin/nginx
  这时,会读取默认路径下的配置文件:/usr/local/nginx/conf/nginx.conf。
  实际上,在没有显式指定nginx.conf配置文件路径时,将打开在configure命令执行时使用--conf-path=PATH指定的nginx.conf文件(参见1.5.1节)。
  (2)另行指定配置文件的启动方式
  使用-c参数指定配置文件。例如:
  /usr/local/nginx/sbin/nginx -c /tmp/nginx.conf
  这时,会读取-c参数后指定的nginx.conf配置文件来启动Nginx。
  (3)另行指定安装目录的启动方式
  使用-p参数指定Nginx的安装目录。例如:
  /usr/local/nginx/sbin/nginx -p /usr/local/nginx/
  (4)另行指定全局配置项的启动方式
  可以通过-g参数临时指定一些全局配置项,以使新的配置项生效。例如:
  /usr/local/nginx/sbin/nginx -g "pid /var/nginx/test.pid;"
  上面这行命令意味着会把pid文件写到/var/nginx/test.pid中。
  -g参数的约束条件是指定的配置项不能与默认路径下的nginx.conf中的配置项相冲突,否则无法启动。就像上例那样,类似这样的配置项:pidlogs/nginx.pid,是不能存在于默认的nginx.conf中的。
  另一个约束条件是,以-g方式启动的Nginx服务执行其他命令行时,需要把-g参数也带上,否则可能出现配置项不匹配的情形。例如,如果要停止Nginx服务,那么需要执行下面代码:
  /usr/local/nginx/sbin/nginx -g "pid /var/nginx/test.pid;" -sstop
  如果不带上-g "pid/var/nginx/test.pid;",那么找不到pid文件,也会出现无法停止服务的情况。
  (5)测试配置信息是否有错误
  在不启动Nginx的情况下,使用-t参数仅测试配置文件是否有错误。例如:
  /usr/local/nginx/sbin/nginx -t
  执行结果中显示配置是否正确。
  (6)在测试配置阶段不输出信息
  测试配置选项时,使用-q参数可以不把error级别以下的信息输出到屏幕。例如:
  /usr/local/nginx/sbin/nginx -t -q
  (7)显示版本信息
  使用-v参数显示Nginx的版本信息。例如:
  /usr/local/nginx/sbin/nginx -v
  (8)显示编译阶段的参数
  使用-V参数除了可以显示Nginx的版本信息外,还可以显示配置编译阶段的信息,如GCC编译器的版本、操作系统的版本、执行configure时的参数等。例如:
  /usr/local/nginx/sbin/nginx -V
  (9)快速地停止服务
  使用-sstop可以强制停止Nginx服务。-s参数其实是告诉Nginx程序向正在运行的Nginx服务发送信号量,Nginx程序通过nginx.pid文件中得到master进程的进程ID,再向运行中的master进程发送TERM信号来快速地关闭Nginx服务。例如:
  /usr/local/nginx/sbin/nginx -s stop
  实际上,如果通过kill命令直接向nginxmaster进程发送TERM或者INT信号,效果是一样的。例如,先通过ps命令来查看nginx master的进程ID:
  :ahf5wapi001:root > ps -ef | grep nginx
  root     10800    1  0 02:27 ?       00:00:00 nginx: master process ./nginx
  root     10801 10800  0 02:27?        00:00:00 nginx: workerprocess
  接下来直接通过kill命令来发送信号:
  kill -s SIGTERM 10800
  或者:
  kill -s SIGINT 10800
  上述两条命令的效果与执行/usr/local/nginx/sbin/nginx -s stop是完全一样的。
  (10)“优雅”地停止服务
  如果希望Nginx服务可以正常地处理完当前所有请求再停止服务,那么可以使用-s quit参数来停止服务。例如:
  /usr/local/nginx/sbin/nginx -s quit
  该命令与快速停止Nginx服务是有区别的。当快速停止服务时,worker进程与master进程在收到信号后会立刻跳出循环,退出进程。而“优雅”地停止服务时,首先会关闭监听端口,停止接收新的连接,然后把当前正在处理的连接全部处理完,最后再退出进程。
  与快速停止服务相似,可以直接发送QUIT信号给master进程来停止服务,其效果与执行-squit命令是一样的。例如:
  kill -s SIGQUIT
  如果希望“优雅”地停止某个worker进程,那么可以通过向该进程发送WINCH信号来停止服务。例如:
  kill -s SIGWINCH
  (11)使运行中的Nginx重读配置项并生效
  使用-s reload参数可以使运行中的Nginx服务重新加载nginx.conf文件。例如:
  /usr/local/nginx/sbin/nginx -s reload
  事实上,Nginx会先检查新的配置项是否有误,如果全部正确就以“优雅”的方式关闭,再重新启动Nginx来实现这个目的。类似的,-s是发送信号,仍然可以用kill命令发送HUP信号来达到相同的效果。
  kill -s SIGHUP
  
  (12)日志文件回滚
  使用-sreopen参数可以重新打开日志文件,这样可以先把当前日志文件改名或转移到其他目录中进行备份,再重新打开时就会生成新的日志文件。这个功能使得日志文件不至于过大。例如:
  /usr/local/nginx/sbin/nginx -s reopen
  当然,这与使用kill命令发送USR1信号效果相同。
  kill -s SIGUSR1
  (13)平滑升级Nginx
  当Nginx服务升级到新的版本时,必须要将旧的二进制文件Nginx替换掉,通常情况下这是需要重启服务的,但Nginx支持不重启服务来完成新版本的平滑升级。
  升级时包括以下步骤:
  1)通知正在运行的旧版本Nginx准备升级。通过向master进程发送USR2信号可达到目的。例如:
  kill -s SIGUSR2
  这时,运行中的Nginx会将pid文件重命名,如将/usr/local/nginx/logs/nginx.pid重命名为/usr/local/nginx/logs/nginx.pid.oldbin,这样新的Nginx才有可能启动成功。
  2)启动新版本的Nginx,可以使用以上介绍过的任意一种启动方法。这时通过ps命令可以发现新旧版本的Nginx在同时运行。
  3)通过kill命令向旧版本的master进程发送SIGQUIT信号,以“优雅”的方式关闭旧版本的Nginx。随后将只有新版本的Nginx服务运行,此时平滑升级完毕。
  (14)显示命令行帮助
  使用-h或者-?参数会显示支持的所有命令行参数。
  1.7 小结
  本章介绍了Nginx的特点以及在什么场景下需要使用Nginx,同时介绍了如何获取Nginx以及如何配置、编译、安装运行Nginx。本章还深入介绍了最为复杂的configure过程,这部分内容是学习本书第二部分和第三部分的基础。
  
  
  第2章 Nginx的配置
  Nginx拥有大量官方发布的模块和第三方模块,这些已有的模块可以帮助我们实现Web服务器上很多的功能。使用这些模块时,仅仅需要增加、修改一些配置项即可。因此,本章的目的是熟悉Nginx的配置文件,包括配置文件的语法格式、运行所有Nginx服务必须具备的基础配置以及使用HTTP核心模块配置静态Web服务器的方法,最后还会介绍反向代理服务器。
  通过本章的学习,读者可以:熟练地配置一个静态Web服务器;对影响Web服务器性能的各个配置项有深入的理解;对配置语法有全面的了解。通过互联网或其他途径得到任意模块的配置说明,然后可通过修改nginx.conf文件来使用这些模块的功能。
  2.1 运行中的Nginx进程间的关系
  在正式提供服务的产品环境下,部署Nginx时都是使用一个master进程来管理多个worker进程,一般情况下,worker进程的数量与服务器上的CPU核心数相等。每一个worker进程都是繁忙的,它们在真正地提供互联网服务,master进程则很“清闲”,只负责监控管理worker进程。worker进程之间通过共享内存、原子操作等一些进程间通信机制来实现负载均衡等功能(第9章将会介绍负载均衡机制,第14章将会介绍负载均衡锁的实现)。
  部署后Nginx进程间的关系如图2-1所示。
  Nginx是支持单进程(master进程)提供服务的,那么为什么产品环境下要按照master-worker方式配置同时启动多个进程呢?这样做的好处主要有以下两点:
  由于master进程不会对用户请求提供服务,只用于管理真正提供服务的worker进程,所以master进程可以是唯一的,它仅专注于自己的纯管理工作,为管理员提供命令行服务,包括诸如启动服务、停止服务、重载配置文件、平滑升级程序等。master进程需要拥有较大的权限,例如,通常会利用root用户启动master进程。worker进程的权限要小于或等于master进程,这样master进程才可以完全地管理worker进程。当任意一个worker进程出现错误从而导致coredump时,master进程会立刻启动新的worker进程继续服务。
  多个worker进程处理互联网请求不但可以提高服务的健壮性(一个worker进程出错后,其他worker进程仍然可以正常提供服务),最重要的是,这样可以充分利用现在常见的SMP多核架构,从而实现微观上真正的多核并发处理。因此,用一个进程(master进程)来处理互联网请求肯定是不合适的。另外,为什么要把worker进程数量设置得与CPU核心数量一致呢?这正是Nginx与Apache服务器的不同之处。在Apache上每个进程在一个时刻只处理一个请求,因此,如果希望Web服务器拥有并发处理的请求数更多,就要把Apache的进程或线程数设置得更多,通常会达到一台服务器拥有几百个工作进程,这样大量的进程间切换将带来无谓的系统资源消耗。而Nginx则不然,一个worker进程可以同时处理的请求数只受限于内存大小,而且在架构设计上,不同的worker进程之间处理并发请求时几乎没有同步锁的限制,worker进程通常不会进入睡眠状态,因此,当Nginx上的进程数与CPU核心数相等时(最好每一个worker进程都绑定特定的CPU核心),进程间切换的代价是最小的。
  
  图2-1 部署后Nginx进程间的关系
  举例来说,如果产品中的服务器CPU核心数为8,那么就需要配置8个worker进程(见图2-2)。
   如果对路径部分都使用默认配置,那么Nginx运行目录为/usr/local/nginx,其目录结构如下。
  |---sbin
  |    |---nginx
  |---conf
  |    |---koi-win
  |    |---koi-utf
  |    |---win-utf
  |    |---mime.types
  |    |---mime.types.default
  |    |---fastcgi_params
  |    |---fastcgi_params.default
  |    |---fastcgi.conf
  |    |---fastcgi.conf.default
  |    |---uwsgi_params
  |    |---uwsgi_params.default
  |    |---scgi_params
  |    |---scgi_params.default
  |    |---nginx.conf
  |    |---nginx.conf.default
  |---logs
  |    |---error.log
  |    |---access.log
  |    |---nginx.pid
  |---html
  |    |---50x.html
  |    |---index.html
  |---client_body_temp
  |---proxy_temp
  |---fastcgi_temp
  |---uwsgi_temp
  |---scgi_temp
  
  图2-2 worker进程的数量尽量与CPU核心数相等
  2.2 Nginx配置的通用语法
  Nginx的配置文件其实是一个普通的文本文件。下面来看一个简单的例子。
  user  nobody;
  
  worker_processes  8;
  error_log  /var/log/nginx/error.log error;
  
  #pid       logs/nginx.pid;
  
  events {
      use epoll;
      worker_connections  50000;
  }
  
  http {
      include      mime.types;
      default_type application/octet-stream;
  
      log_format  main  $remote_addr[$time_local] "$request"
                       $status $bytes_sent "$http_referer"
                       "$http_user_agent" "$http_x_forwarded_for";
  
      access_log  logs/access.log  mainbuffer=32k;
  
      …
  }
  在这段简短的配置代码中,每一行配置项的语法格式都将在2.2.2节介绍,出现的events和http块配置项将在2.2.1节介绍,以#符号开头的注释将在2.2.3节介绍,类似“buffer=32k”这样的配置项的单位将在2.2.4节介绍。
  2.2.1 块配置项
  块配置项由一个块配置项名和一对大括号组成。具体示例如下:
  events {
  …
  }
  
  http {
      upstream backend {
          server127.0.0.1:8080;
      }
  
      gzip on;
      server {
          …
          location /webstatic{
             gzip off;
          }
      }
  }
  上面代码段中的events、http、server、location、upstream等都是块配置项,块配置项之后是否如“location/webstatic{...}”那样在后面加上参数,取决于解析这个块配置项的模块,不能一概而论,但块配置项一定会用大括号把一系列所属的配置项全包含进来,表示大括号内的配置项同时生效。所有的事件类配置都要在events块中,http、server等配置也遵循这个规定。
  块配置项可以嵌套。内层块直接继承外层块,例如,上例中,server块里的任意配置都是基于http块里的已有配置的。当内外层块中的配置发生冲突时,究竟是以内层块还是外层块的配置为准,取决于解析这个配置项的模块,第4章将会介绍http块内配置项冲突的处理方法。例如,上例在http模块中已经打开了“gzipon;”,但其下的location/webstatic又把gzip关闭了:gzipoff;,最终,在/webstatic的处理模块中,gzip模块是按照gzip off来处理请求的。
  2.2.2 配置项的语法格式
  从上文的示例可以看出,最基本的配置项语法格式如下:
  配置项名 配置项值1 配置项值2 … ;
  下面解释一下配置项的构成部分。
  首先,在行首的是配置项名,这些配置项名必须是Nginx的某一个模块想要处理的,否则Nginx会认为配置文件出现了非法的配置项名。配置项名输入结束后,将以空格作为分隔符。
  其次是配置项值,它可以是数字或字符串(当然也包括正则表达式)。针对一个配置项,既可以只有一个值,也可以包含多个值,配置项值之间仍然由空格符来分隔。当然,一个配置项对应的值究竟有多少个,取决于解析这个配置项的模块。我们必须根据某个Nginx模块对一个配置项的约定来更改配置项,第4章将会介绍模块是如何约定一个配置项的格式。
  最后,每行配置的结尾需要加上分号。
  注意 如果配置项值中包括语法符号,比如空格符,那么需要使用单引号或双引号括住配置项值,否则Nginx会报语法错误。例如:
  log_format  main  $remote_addr - $remote_user[$time_local] "$request" ;
  
  2.2.3 配置项的注释
  如果有一个配置项暂时需要注释掉,那么可以加“#”注释掉这一行配置。例如:
  #pid       logs/nginx.pid;
  2.2.4 配置项的单位
  大部分模块遵循一些通用的规定,如指定空间大小时不用每次都定义到字节、指定时间时不用精确到毫秒。
  当指定空间大小时,可以使用的单位包括:
  K或者k千字节(KiloByte,KB)。
  M或者m兆字节(MegaByte,MB)。
  例如:
  gzip_buffers     4 8k;
  client_max_body_size 64M;
  当指定时间时,可以使用的单位包括:
  ms(毫秒),s(秒),m(分钟),h(小时),d(天),w(周,包含7天),M(月,包含30天),y(年,包含365天)。
  例如:
  expires     10y;
  proxy_read_timeout    600;
  client_body_timeout     2m;
  注意 配置项后的值究竟是否可以使用这些单位,取决于解析该配置项的模块。如果这个模块使用了Nginx框架提供的相应解析配置项方法,那么配置项值才可以携带单位。第4章中详细描述了Nginx框架提供的14种预设解析方法,其中一些方法将可以解析以上列出的单位。
  2.2.5 在配置中使用变量
  有些模块允许在配置项中使用变量,如在日志记录部分,具体示例如下。
  log_format  main  $remote_addr - $remote_user[$time_local] "$request"
                       $status $bytes_sent "$http_referer"
                       "$http_user_agent" "$http_x_forwarded_for";
  其中,remote_addr是一个变量,使用它的时候前面要加上$符号。需要注意的是,这种变量只有少数模块支持,并不是通用的。
  许多模块在解析请求时都会提供多个变量(如本章后面提到的http core module、http proxymodule、http upstreammodule等),以使其他模块的配置可以即时使用。我们在学习某个模块提供的配置说明时可以关注它是否提供变量。
  提示 在执行configure命令时,我们已经把许多模块编译进Nginx中,但是否启用这些模块,一般取决于配置文件中相应的配置项。换句话说,每个Nginx模块都有自己感兴趣的配置项,大部分模块都必须在nginx.conf中读取某个配置项后才会在运行时启用。例如,只有当配置http{...}这个配置项时,ngx_http_module模块才会在Nginx中启用,其他依赖ngx_http_module的模块也才能正常使用。
  2.3 Nginx服务的基本配置
  Nginx在运行时,至少必须加载几个核心模块和一个事件类模块。这些模块运行时所支持的配置项称为基本配置—所有其他模块执行时都依赖的配置项。
  下面详述基本配置项的用法。由于配置项较多,所以把它们按照用户使用时的预期功能分成了以下4类:
  用于调试、定位问题的配置项。
  正常运行的必备配置项。
  优化性能的配置项。
  事件类配置项(有些事件类配置项归纳到优化性能类,这是因为它们虽然也属于events {}块,但作用是优化性能)。
  有这么一些配置项,即使没有显式地进行配置,它们也会有

《深入理解Nginx:模块开发与架构解析》(阿里巴巴资深Nginx专家撰写,透彻解析Nginx架构,详解Nginx模块开发方法和技巧) pdf下载声明

本pdf资料下载仅供个人学习和研究使用,不能用于商业用途,请在下载后24小时内删除。如果喜欢,请购买正版

pdf下载地址

版权归出版社和作者所有,下载链接已删除。如果喜欢,请购买正版!

链接地址:《深入理解Nginx:模块开发与架构解析》(阿里巴巴资深Nginx专家撰写,透彻解析Nginx架构,详解Nginx模块开发方法和技巧)