描述
开 本: 16开纸 张: 胶版纸包 装: 平装-胶订是否套装: 否国际标准书号ISBN: 9787121364365
产品特色
编辑推荐
精心雕琢,认真原创!
专注、深入、聚集!
资深技术专家Nginx源码研习书强势升级!
深入新版Nginx源码(Stable1.16.0)!
详细剖析Nginx核心运行机制!
便捷、轻松地开发和定制Nginx!
专注、深入、聚集!
资深技术专家Nginx源码研习书强势升级!
深入新版Nginx源码(Stable1.16.0)!
详细剖析Nginx核心运行机制!
便捷、轻松地开发和定制Nginx!
内容简介
Nginx是著名的Web服务器,性能优异,运行效率远超传统的Apache、Tomcat,广泛应用于国内外诸多*互联网公司。Nginx的一个突出特点是其灵活优秀的模块化架构,可以在不修改核心的前提下增加任意功能,自2004年发布至今,已经拥有百余个官方及非官方的功能模块(如proxy、mysql、redis、rtmp、lua等),使得Nginx成长为了一个近乎“全能”的服务器软件。Nginx功能强大,架构复杂,学习、维护和开发的门槛较高。为了帮助读者跨越这一障碍,本书深入*的Nginx源码(Stable 1.16.0),详细剖析了模块体系、动态插件、功能框架、内存分配、进程模型、事件驱动、线程池、TCP/UDP/HTTP处理等Nginx核心运行机制,在此基础上讲解如何使用C、C 、JavaScript、Lua等语言来增强扩展Nginx,让任何人都能够便捷、轻松地开发和定制Nginx,进而应用到自己的实际工作中,创造出更多的价值。本书结构严谨、脉络清晰、论述精确、详略得当、图文并茂,值得广大软件开发工程师、系统运维工程师和编程爱好者拥有。
目 录
目录
第0章 导读 1
0.1 于本书 1
0.2 读者对象 3
0.3 读者要求 4
0.4 运行环境 5
0.5 本书的结构 5
0.6 如何阅读本书 6
0.7 本书的源码 7
第1章 Nginx入门 8
1.1 关于Nginx 8
1.1.1 历史 9
1.1.2 特点 9
1.1.3 进程模型 10
1.1.4 版本 12
1.2 安装Nginx 12
1.2.1 准备工作 13
1.2.2 快速安装 13
1.2.3 运行命令 14
1.2.4 验证安装 15
1.2.5 定制安装 16
1.3 配置Nginx 18
1.3.1 语法格式 19
1.3.2 进程管理 20
1.3.3 动态模块 22
1.3.4 运行日志 22
1.3.5 事件机制 22
1.4 HTTP服务 23
1.4.1 基本配置 24
1.4.3 location配置 25
1.4.4 file配置 26
1.5 TCP/UDP服务 27
1.6 反向代理 28
1.6.1 上游集群 28
1.6.2 负载均衡 29
1.6.3 代理转发 30
1.7 变量 30
1.8 总结 32
第2章 Nginx开发准备 33
2.1 源码结构 33
2.2 源码特点 34
2.2.1 代码风格 34
2.2.2 代码优化 35
2.2.3 面向对象思想 35
2.3 头文件 36
2.4 总结 36
第3章 Nginx基础设施 37
3.1 常数 37
3.1.1 环境信息 37
3.1.2 版本信息 38
3.1.3 错误码 38
3.2 整数类型 39
3.2.1 标准整数类型 39
3.2.2 自用整数类型 40
3.2.3 无效值 40
3.3 内存池 42
3.3.1 结构定义 42
3.3.2 操作函数 43
3.3.3 用法示例 44
3.4 字符串 44
3.4.1 结构定义 44
3.4.2 操作函数 45
3.4.3 用法示例 48
3.5 时间 49
3.5.1 结构定义 49
3.5.2 操作函数 49
3.5.3 用法示例 50
3.6 日期 50
3.6.1 结构定义 50
3.6.2 操作函数 51
3.6.3 用法示例 52
3.7 运行日志 52
3.7.1 结构定义 52
3.7.2 操作函数 53
3.7.3 用法示例 54
3.8 摘要算法 54
3.8.1 Times33 55
3.8.2 CRC 55
3.8.3 MurmurHash 56
3.8.4 MD5 57
3.8.5 SHA-1 57
3.9 数据编码 58
3.9.1 Base64 58
3.9.2 HTML/JSON 59
3.10 总结 60
第4章 Nginx高级数据结构 61
4.1 动态数组 61
4.1.1 结构定义 62
4.1.2 操作函数 63
4.1.3 用法示例 64
4.2 单向链表 65
4.2.1 结构定义 65
4.2.2 操作函数 66
4.2.3 用法示例 66
4.3 双端队列 68
4.3.1 结构定义 68
4.3.2 操作函数 69
4.3.3 用法示例 71
4.4 红黑树 72
4.4.1 结构定义 73
4.4.2 操作函数 75
4.4.3 用法示例 76
4.5 缓冲区 78
4.5.1 结构定义 78
4.5.2 操作函数 80
4.5.3 用法示例 81
4.6 数据块链 82
4.6.1 结构定义 82
4.6.2 操作函数 83
4.6.3 用法示例 83
4.7 总结 84
第5章 Nginx开发概述 85
5.1 开发示例 85
5.1.1 模块设计 85
5.1.2 配置解析 86
5.1.3 处理函数 88
5.1.4 模块集成 90
5.1.5 编译脚本 91
5.1.6 测试验证 92
5.2 开发流程 92
5.2.1 设计 93
5.2.2 开发 93
5.2.3 编译 94
5.2.4 测试验证 94
5.2.5 调优 94
5.2.6 流程图 95
5.3 编译脚本 95
5.3.1 运行机制 96
5.3.2 脚本变量 96
5.3.3 添加模块 97
5.3.4 脚本格式 97
5.3.5 旧式脚本 98
5.4 总结 99
第6章 Nginx模块体系 100
6.1 模块架构 100
6.1.1 结构定义 100
6.1.2 模块的签名 102
6.1.3 模块的种类 103
6.1.4 模块的函数指针表 104
6.1.5 模块的类图 105
6.1.6 模块的组织形式 106
6.1.7 模块的静态加载 108
6.1.8 模块的动态加载 110
6.2 配置解析 113
6.2.1 结构定义 113
6.2.2 基本流程 116
6.2.3 存储模型 118
6.2.4 访问配置数据 122
6.2.5 配置数据的位置 123
6.2.6 配置数据的解析 124
6.2.7 配置数据的合并 126
6.2.8 配置指令的类型 127
6.3 源码分析 128
6.3.1 ngx_core_module 128
6.3.2 ngx_errlog_module 130
6.4 总结 132
第7章 Nginx功能框架 134
7.1 框架简介 134
7.1.1 模块分类 134
7.1.2 处理流程 135
7.1.3 请求的处理阶段 137
7.1.4 请求结构体 138
7.1.5 请求的环境数据 140
7.2 处理引擎 141
7.2.1 函数原型 141
7.2.2 处理函数的存储方式 141
7.2.3 内容处理函数 142
7.2.4 引擎的数据结构 143
7.2.5 引擎的初始化 144
7.2.6 引擎的运行机制 145
7.2.7 日志阶段的处理 148
7.3 过滤引擎 148
7.3.1 函数原型 148
7.3.2 过滤函数链表 149
7.3.3 过滤函数的顺序 150
7.3.4 过滤链表的运行机制 152
7.3.5 请求体过滤 153
7.4 源码分析 153
7.4.1 ngx_http_static_module 154
7.4.2 ngx_http_not_modified_filter_module 155
7.5 总结 156
第8章 Nginx请求处理 158
8.1 状态码 158
8.2 请求结构体 159
8.3 请求行 160
8.3.1 请求方法 160
8.3.2 协议版本号 161
8.3.3 资源标识符 161
8.4 请求头 162
8.5 请求体 163
8.5.1 结构定义 163
8.5.2 操作函数 164
8.6 响应头 164
8.6.1 结构定义 164
8.6.2 操作函数 165
8.7 响应体 166
8.8 源码分析 166
8.8.1 ngx_http_static_module 166
8.8.2 ngx_http_not_modified_filter_module 168
8.9 开发示例:content handler 169
8.9.1 模块设计 169
8.9.2 配置数据 169
8.9.3 处理函数 170
8.9.4 注册函数 171
8.9.5 模块集成 172
8.9.6 编译脚本 173
8.9.7 测试验证 173
8.10 开发示例:filter 173
8.10.1 模块设计 173
8.10.2 配置数据 174
8.10.3 环境数据 174
8.10.4 注册过滤函数 175
8.10.5 过滤响应头 175
8.10.6 过滤响应体 176
8.10.7 模块集成 178
8.10.8 编译脚本 179
8.10.9 测试验证 179
8.11 总结 180
第9章 Nginx请求转发 181
9.1 框架简介 181
9.1.1 工作原理 182
9.1.2 请求结构体 183
9.1.3 上游结构体 184
9.1.4 上游配置参数 185
9.2 请求转发 186
9.2.1 回调函数 186
9.2.2 初始化 188
9.2.3 设置参数 189
9.2.4 启动连接 190
9.2.5 处理响应头 190
9.2.6 处理响应体 191
9.3 负载均衡 192
9.3.1 结构定义 192
9.3.2 初始化模块入口 196
9.3.3 初始化地址列表 197
9.3.4 初始化算法 199
9.3.5 执行算法 200
9.4 源码分析 200
9.4.1 ngx_http_memcached_module 201
9.4.2 ngx_http_upstream_ip_hash_module 203
9.5 开发示例:upstream 206
9.5.1 模块设计 206
9.5.2 配置数据 206
9.5.3 上行数据 208
9.5.4 下行数据 208
9.5.5 启动转发 209
9.5.6 注册函数 210
9.5.7 模块集成 210
9.5.8 编译脚本 211
9.5.9 测试验证 212
9.6 开发示例:balance 212
9.6.1 模块设计 212
9.6.2 配置数据 212
9.6.3 算法数据结构 213
9.6.4 模块入口 213
9.6.5 算法实现 214
9.6.6 模块集成 215
9.6.7 编译脚本 216
9.6.8 测试验证 216
9.7 总结 216
第10章 Nginx子请求 218
10.1 框架简介 218
10.1.1 工作原理 219
10.1.2 请求结构体 220
10.1.3 回调函数 221
10.1.4 待处理请求链表 223
10.1.5 子请求存储结构 223
10.2 运行机制 223
10.2.1 创建子请求 224
10.2.2 处理引擎 228
10.2.3 数据整理 229
10.3 开发示例 230
10.3.1 模块设计 231
10.3.2 配置数据 231
10.3.3 环境数据 231
10.3.4 回调函数 231
10.3.5 处理函数 232
10.3.6 注册函数 233
10.3.7 测试验证 234
10.4 总结 234
第11章 Nginx变量 236
11.1 结构定义 236
11.1.1 变量 237
11.1.2 复杂变量 238
11.1.3 变量的存储 239
11.1.4 请求结构体 239
11.2 操作变量 240
11.2.1 添加变量 240
11.2.2 获取变量 241
11.2.3 修改变量 242
11.2.4 编译复杂变量 242
11.2.5 获取复杂变量 242
11.3 开发示例:变量 243
11.3.1 模块设计 243
11.3.2 定义变量 243
11.3.3 添加变量 244
11.3.4 获取变量 244
11.3.5 测试验证 245
11.4 开发示例:复杂变量 246
11.4.1 模块设计 246
11.4.2 定义复杂变量 246
11.4.3 编译复杂变量 246
11.4.4 获取复杂变量 247
11.4.5 测试验证 247
11.5 总结 247
第12章 Nginx内存管理机制 249
12.1 基本系统调用 250
12.1.1 malloc 250
12.1.2 posix_memalign 251
12.1.3 free 251
12.2 块式内存池 252
12.2.1 结构定义 252
12.2.2 常量定义 255
12.2.3 创建内存池 255
12.2.4 分配内存 257
12.2.5 分配大块内存 258
12.2.6 分配小块内存 259
12.2.7 释放内存 264
12.2.8 清理机制 264
12.2.9 清空内存池 265
12.2.10 销毁内存池 266
12.3 页式内存池 267
12.3.1 结构定义 268
12.3.2 常量定义 270
12.3.3 初始化内存池 271
12.3.4 分配内存 273
12.3.5 分配大块内存 275
12.3.6 分配小块内存 277
12.3.7 释放内存 280
12.4 总结 282
第13章 Nginx进程机制 284
13.1 基本系统调用 284
13.1.1 errno 284
13.1.2 getrlimit 285
13.2 进程系统调用 285
13.2.1 getpid 285
13.2.2 fork 286
13.2.3 waitpid 286
13.3 信号系统调用 287
13.3.1 kill 287
13.3.2 sigactio
第0章 导读 1
0.1 于本书 1
0.2 读者对象 3
0.3 读者要求 4
0.4 运行环境 5
0.5 本书的结构 5
0.6 如何阅读本书 6
0.7 本书的源码 7
第1章 Nginx入门 8
1.1 关于Nginx 8
1.1.1 历史 9
1.1.2 特点 9
1.1.3 进程模型 10
1.1.4 版本 12
1.2 安装Nginx 12
1.2.1 准备工作 13
1.2.2 快速安装 13
1.2.3 运行命令 14
1.2.4 验证安装 15
1.2.5 定制安装 16
1.3 配置Nginx 18
1.3.1 语法格式 19
1.3.2 进程管理 20
1.3.3 动态模块 22
1.3.4 运行日志 22
1.3.5 事件机制 22
1.4 HTTP服务 23
1.4.1 基本配置 24
1.4.3 location配置 25
1.4.4 file配置 26
1.5 TCP/UDP服务 27
1.6 反向代理 28
1.6.1 上游集群 28
1.6.2 负载均衡 29
1.6.3 代理转发 30
1.7 变量 30
1.8 总结 32
第2章 Nginx开发准备 33
2.1 源码结构 33
2.2 源码特点 34
2.2.1 代码风格 34
2.2.2 代码优化 35
2.2.3 面向对象思想 35
2.3 头文件 36
2.4 总结 36
第3章 Nginx基础设施 37
3.1 常数 37
3.1.1 环境信息 37
3.1.2 版本信息 38
3.1.3 错误码 38
3.2 整数类型 39
3.2.1 标准整数类型 39
3.2.2 自用整数类型 40
3.2.3 无效值 40
3.3 内存池 42
3.3.1 结构定义 42
3.3.2 操作函数 43
3.3.3 用法示例 44
3.4 字符串 44
3.4.1 结构定义 44
3.4.2 操作函数 45
3.4.3 用法示例 48
3.5 时间 49
3.5.1 结构定义 49
3.5.2 操作函数 49
3.5.3 用法示例 50
3.6 日期 50
3.6.1 结构定义 50
3.6.2 操作函数 51
3.6.3 用法示例 52
3.7 运行日志 52
3.7.1 结构定义 52
3.7.2 操作函数 53
3.7.3 用法示例 54
3.8 摘要算法 54
3.8.1 Times33 55
3.8.2 CRC 55
3.8.3 MurmurHash 56
3.8.4 MD5 57
3.8.5 SHA-1 57
3.9 数据编码 58
3.9.1 Base64 58
3.9.2 HTML/JSON 59
3.10 总结 60
第4章 Nginx高级数据结构 61
4.1 动态数组 61
4.1.1 结构定义 62
4.1.2 操作函数 63
4.1.3 用法示例 64
4.2 单向链表 65
4.2.1 结构定义 65
4.2.2 操作函数 66
4.2.3 用法示例 66
4.3 双端队列 68
4.3.1 结构定义 68
4.3.2 操作函数 69
4.3.3 用法示例 71
4.4 红黑树 72
4.4.1 结构定义 73
4.4.2 操作函数 75
4.4.3 用法示例 76
4.5 缓冲区 78
4.5.1 结构定义 78
4.5.2 操作函数 80
4.5.3 用法示例 81
4.6 数据块链 82
4.6.1 结构定义 82
4.6.2 操作函数 83
4.6.3 用法示例 83
4.7 总结 84
第5章 Nginx开发概述 85
5.1 开发示例 85
5.1.1 模块设计 85
5.1.2 配置解析 86
5.1.3 处理函数 88
5.1.4 模块集成 90
5.1.5 编译脚本 91
5.1.6 测试验证 92
5.2 开发流程 92
5.2.1 设计 93
5.2.2 开发 93
5.2.3 编译 94
5.2.4 测试验证 94
5.2.5 调优 94
5.2.6 流程图 95
5.3 编译脚本 95
5.3.1 运行机制 96
5.3.2 脚本变量 96
5.3.3 添加模块 97
5.3.4 脚本格式 97
5.3.5 旧式脚本 98
5.4 总结 99
第6章 Nginx模块体系 100
6.1 模块架构 100
6.1.1 结构定义 100
6.1.2 模块的签名 102
6.1.3 模块的种类 103
6.1.4 模块的函数指针表 104
6.1.5 模块的类图 105
6.1.6 模块的组织形式 106
6.1.7 模块的静态加载 108
6.1.8 模块的动态加载 110
6.2 配置解析 113
6.2.1 结构定义 113
6.2.2 基本流程 116
6.2.3 存储模型 118
6.2.4 访问配置数据 122
6.2.5 配置数据的位置 123
6.2.6 配置数据的解析 124
6.2.7 配置数据的合并 126
6.2.8 配置指令的类型 127
6.3 源码分析 128
6.3.1 ngx_core_module 128
6.3.2 ngx_errlog_module 130
6.4 总结 132
第7章 Nginx功能框架 134
7.1 框架简介 134
7.1.1 模块分类 134
7.1.2 处理流程 135
7.1.3 请求的处理阶段 137
7.1.4 请求结构体 138
7.1.5 请求的环境数据 140
7.2 处理引擎 141
7.2.1 函数原型 141
7.2.2 处理函数的存储方式 141
7.2.3 内容处理函数 142
7.2.4 引擎的数据结构 143
7.2.5 引擎的初始化 144
7.2.6 引擎的运行机制 145
7.2.7 日志阶段的处理 148
7.3 过滤引擎 148
7.3.1 函数原型 148
7.3.2 过滤函数链表 149
7.3.3 过滤函数的顺序 150
7.3.4 过滤链表的运行机制 152
7.3.5 请求体过滤 153
7.4 源码分析 153
7.4.1 ngx_http_static_module 154
7.4.2 ngx_http_not_modified_filter_module 155
7.5 总结 156
第8章 Nginx请求处理 158
8.1 状态码 158
8.2 请求结构体 159
8.3 请求行 160
8.3.1 请求方法 160
8.3.2 协议版本号 161
8.3.3 资源标识符 161
8.4 请求头 162
8.5 请求体 163
8.5.1 结构定义 163
8.5.2 操作函数 164
8.6 响应头 164
8.6.1 结构定义 164
8.6.2 操作函数 165
8.7 响应体 166
8.8 源码分析 166
8.8.1 ngx_http_static_module 166
8.8.2 ngx_http_not_modified_filter_module 168
8.9 开发示例:content handler 169
8.9.1 模块设计 169
8.9.2 配置数据 169
8.9.3 处理函数 170
8.9.4 注册函数 171
8.9.5 模块集成 172
8.9.6 编译脚本 173
8.9.7 测试验证 173
8.10 开发示例:filter 173
8.10.1 模块设计 173
8.10.2 配置数据 174
8.10.3 环境数据 174
8.10.4 注册过滤函数 175
8.10.5 过滤响应头 175
8.10.6 过滤响应体 176
8.10.7 模块集成 178
8.10.8 编译脚本 179
8.10.9 测试验证 179
8.11 总结 180
第9章 Nginx请求转发 181
9.1 框架简介 181
9.1.1 工作原理 182
9.1.2 请求结构体 183
9.1.3 上游结构体 184
9.1.4 上游配置参数 185
9.2 请求转发 186
9.2.1 回调函数 186
9.2.2 初始化 188
9.2.3 设置参数 189
9.2.4 启动连接 190
9.2.5 处理响应头 190
9.2.6 处理响应体 191
9.3 负载均衡 192
9.3.1 结构定义 192
9.3.2 初始化模块入口 196
9.3.3 初始化地址列表 197
9.3.4 初始化算法 199
9.3.5 执行算法 200
9.4 源码分析 200
9.4.1 ngx_http_memcached_module 201
9.4.2 ngx_http_upstream_ip_hash_module 203
9.5 开发示例:upstream 206
9.5.1 模块设计 206
9.5.2 配置数据 206
9.5.3 上行数据 208
9.5.4 下行数据 208
9.5.5 启动转发 209
9.5.6 注册函数 210
9.5.7 模块集成 210
9.5.8 编译脚本 211
9.5.9 测试验证 212
9.6 开发示例:balance 212
9.6.1 模块设计 212
9.6.2 配置数据 212
9.6.3 算法数据结构 213
9.6.4 模块入口 213
9.6.5 算法实现 214
9.6.6 模块集成 215
9.6.7 编译脚本 216
9.6.8 测试验证 216
9.7 总结 216
第10章 Nginx子请求 218
10.1 框架简介 218
10.1.1 工作原理 219
10.1.2 请求结构体 220
10.1.3 回调函数 221
10.1.4 待处理请求链表 223
10.1.5 子请求存储结构 223
10.2 运行机制 223
10.2.1 创建子请求 224
10.2.2 处理引擎 228
10.2.3 数据整理 229
10.3 开发示例 230
10.3.1 模块设计 231
10.3.2 配置数据 231
10.3.3 环境数据 231
10.3.4 回调函数 231
10.3.5 处理函数 232
10.3.6 注册函数 233
10.3.7 测试验证 234
10.4 总结 234
第11章 Nginx变量 236
11.1 结构定义 236
11.1.1 变量 237
11.1.2 复杂变量 238
11.1.3 变量的存储 239
11.1.4 请求结构体 239
11.2 操作变量 240
11.2.1 添加变量 240
11.2.2 获取变量 241
11.2.3 修改变量 242
11.2.4 编译复杂变量 242
11.2.5 获取复杂变量 242
11.3 开发示例:变量 243
11.3.1 模块设计 243
11.3.2 定义变量 243
11.3.3 添加变量 244
11.3.4 获取变量 244
11.3.5 测试验证 245
11.4 开发示例:复杂变量 246
11.4.1 模块设计 246
11.4.2 定义复杂变量 246
11.4.3 编译复杂变量 246
11.4.4 获取复杂变量 247
11.4.5 测试验证 247
11.5 总结 247
第12章 Nginx内存管理机制 249
12.1 基本系统调用 250
12.1.1 malloc 250
12.1.2 posix_memalign 251
12.1.3 free 251
12.2 块式内存池 252
12.2.1 结构定义 252
12.2.2 常量定义 255
12.2.3 创建内存池 255
12.2.4 分配内存 257
12.2.5 分配大块内存 258
12.2.6 分配小块内存 259
12.2.7 释放内存 264
12.2.8 清理机制 264
12.2.9 清空内存池 265
12.2.10 销毁内存池 266
12.3 页式内存池 267
12.3.1 结构定义 268
12.3.2 常量定义 270
12.3.3 初始化内存池 271
12.3.4 分配内存 273
12.3.5 分配大块内存 275
12.3.6 分配小块内存 277
12.3.7 释放内存 280
12.4 总结 282
第13章 Nginx进程机制 284
13.1 基本系统调用 284
13.1.1 errno 284
13.1.2 getrlimit 285
13.2 进程系统调用 285
13.2.1 getpid 285
13.2.2 fork 286
13.2.3 waitpid 286
13.3 信号系统调用 287
13.3.1 kill 287
13.3.2 sigactio
前 言
缘起
最早接触Nginx大概是在2011年,面对着一个全新的Web服务器,和大多数人一样最初我也是一片茫然,能找到的参考资料十分有限,安装、配置、运行几乎都是“摸着石头过河”,犯过许多低级错误。
随着对Nginx逐渐熟悉,它的高并发处理能力给我留下了深刻的印象,作为一个开源软件的爱好者,很自然地想要探究一下它的内部工作原理。我由此开始了对Nginx源码的钻研之路,中间经过了很多的艰辛曲折,走过了不少的弯路。
我最常用的工作语言是C ,所以在阅读Nginx源码时也总以C 的面向对象方式来思考和理解,以对象作为切入点记笔记、画UML:从最简单的ngx_str_t、ngx_array_t入手,然后到ngx_request_t、ngx_upstream_t等复杂的结构,再围绕着这些对象研究相关的功能函数和处理流程,梳理代码逻辑的同时也摸索着使用C 编写Nginx模块的方法,逐渐积累了一些用起来颇为顺手的小工具——当然还是比较初级的形式。
五年多前,我被调到了新的工作岗位,需要重度使用Nginx开发,这让我以前的零散积累终于有了用武之地。那段时间里使用C/C 陆续做了很多东西,也借着机会重新优化了原有的工具代码。
繁忙的工作之余,我有了种进一步整理经验的迫切感,因为只有系统完整地分享这些知识,才能让更多的人基于Nginx二次开发,让Nginx更好地为网络世界服务。
同一时间,市面上也出现了一些Nginx开发相关的资料、书籍,但在我看来却有“粗制滥造”之嫌:行文混乱,“车轱辘话”“口头禅”满天飞,甚至大段照抄指令说明,还有对源码的曲解,未免有点儿“误人子弟”,读起来实在是难受。终于,在“忍无可忍”的心态之下,我动起了写作本书的念头。
经过近一年的努力,现在这本书终于呈现在了读者面前,结构上基本反映了我学习研究Nginx时的心路历程,从最初的“一无所知”起步,逐渐深入到定制开发的层次,希望能与读者“心有戚戚焉”。
Nginx随感
毫无疑问,Nginx是目前这个星球上所能获得的最强劲的Web服务器(没有之一),同时也是目前最成熟、最优秀的TCP/HTTP服务器开发框架。
Nginx资源消耗低,并发处理性能高,配置灵活,能够连接CGI、PHP、MySQL、Memcached等多种后端,还有着出色的负载均衡能力,可以整合封装各种service,构建稳定高效的服务。如今Nginx已经成为了网站架构里不可或缺的关键组件,广泛应用于国内外许多大型IT企业内部。每一个繁忙的网站背后,可能都有Nginx默默工作的身影。
在Nginx出现之前,使用C/C 开发Web服务器是项比较“痛苦”的工作,虽然有很多网络程序库可以使用(例如asio、libevent、thrift等),但它们通常只关注较底层的基础功能实现,离成熟的“框架”相距甚远,不仅开发过程烦琐低效,而且程序员还必须要处理配置管理、进程间通信、协议解析等许多Web服务之外的其他事情,才能开发出一个较为完善的服务器程序。但即使开发出了这样的服务器,通常性能上也很难得到保证,会受到程序库和开发者水平等因素的限制——很长一段时间里,C/C 在Web服务器领域都没有大展拳脚的机会。
Nginx的横空出世为Web服务器开辟了一个崭新的天地,它搭建了一个高性能的服务器开发框架,而且是一个完整的、全功能的服务器。模块化的架构设计很好地分离了底层支撑模块和上层逻辑模块,底层模块处理了配置、并发等服务器的外围功能,核心支撑模块定义了主体的TCP/HTTP处理框架。开发者可以把大部分精力集中在上层的业务功能实现上,再也不必去为其他杂事而分心,提高了软件的开发效率。
在Nginx框架里C/C 程序员可以尽情发挥自己的专长,充分利用Nginx无阻塞处理的优势,打造出高质量的Web应用服务器,与其他系统一较高下。
Nginx和C/C
Igor Sysoev选择用C语言(准确地说是ANSI C)来实现Nginx肯定是经过了认真的考虑。
作为与UNIX一同诞生的编程语言,C语言一直是系统级编程的首选。和其他高级语言相比,它简单可靠,更接近计算机底层硬件,运行效率更高。指针更是C语言的一大特色,善用指针能够完成许多其他语言无法完成的工作。
以C语言实现的Nginx没有“虚拟机”的成本,省略了不必要的中间环节,直接操纵计算机硬件,从根本上提高了Web服务器的处理能力。虽然C语言不直接支持面向对象,但Nginx灵活运用了指针,采用“结构体 函数指针”的形式,达到了同样的效果,从而使软件拥有了良好的结构。
C 是仅次于C的系统级编程语言,在兼容C的同时又增加了异常、模板等新特性,还支持面向对象、泛型、函数式、模板元等多种编程范式,可以说是计算机语言里的一个“庞然大物”。C 的特性很多,有的也很好用,但总体上的确比较复杂,易学难精,容易被误用和滥用,导致低效、难维护的代码,我想这可能是Igor Sysoev放弃使用C 的一个重要原因。
另一个可能的原因是C语言本身已经非常稳定,几十年来没有太大的变动,在各个系统里都支持得非常好。而C 在1998年才有了第一个标准,而且现在还在发展之中,语言特性还不够稳定(例如export、register等曾经的关键字在C 11里就已经被废弃),许多编译器对C 的支持程度也有差异,这与Nginx的高可移植性目标明显不符。
但C 毕竟还是有很多的优点,类可以更好地封装信息、异常简化了错误处理、模板能够在编译期执行类型计算。在C 11标准颁布之后C 更是几乎变成了一门“全新”的语言,auto/decltype/nullptr/noexcept等新关键字增强了语言的描述能力,标准库也扩充了相当多的组件,易用性和稳定性都大大提升。
在Nginx里使用C 时要对C 的长处和不足有清醒的认识,避免多层次继承、虚函数等影响效率的编程范式,只使用经过充分验证的、能够切实提高开发效率和性能的语言特性和库,避免华而不实的技术炫耀,尽量做到像Nginx源码那样质朴踏实。只有这样,才能够发挥出“1 1>2”的作用,让Nginx从C 中得到更进一步的发展动力。
Nginx和OpenResty
多年以前Nginx开发使用的语言只能是C和C ,而现在,越来越多的开发者开始转向了OpenResty,使用Lua搭建高并发、高性能、高扩展性的Web Server。
我接触OpenResty的时间并不算很长,大约在五年左右。由于C/C 程序员“天生的傲慢”,一开始对OpenResty确实有点儿“抵触情绪”,总觉得脚本程序比不上C/C 实现。然而随着使用的增多,特别是在研究了它的源码之后,我不得不感慨OpenResty的精致、完美和强大,简直是所有Nginx开发者“梦寐以求的至宝”。
由于agentzh对Nginx的运行机制了如指掌,OpenResty的核心部分——ngx_lua一个模块就涵盖了access/rewrite/content/log等多个处理阶段,再搭配上小巧灵活的Lua和高效的LuaJIT,我们就能够在更高级的业务层次上使用“胶水”代码来调用组合Nginx底层功能,轻松开发出丰富Web服务,极大地节约了宝贵的时间和精力。
当然,OpenResty并不只有ngx_lua,围绕着ngx_lua还有众多的库和辅助工具,构成了一个相当完善的生态环境,这些组件相互支撑,利用得当可以更好地提高生产效率。
OpenResty现在正处于蓬勃发展的阶段,今后的OpenResty也许不仅限于Nginx和Web Server,而将成为一个更通用的开发平台,工作语言也不仅限于Lua,可能还会有其他新的语言(例如agentzh正在做的edgelang和fanlang),让我们拭目以待。
“大事件”
2019年,Nginx身上发生了一件了不得的“大事件”:在独立运营了8年之后,Nginx.Inc公司正式被它的“竞争对手”F5 Networks收购。
收购的价格并不算高,只有6.7亿美元。可以比较一下去年被微软收购的源码托管网站GitHub,出价是75亿。对于Nginx这个几乎占据了互联网一半份额的顶尖Web服务器来说,感觉实在是有点低。
这也算得上是开源软件商业化的又一个标志性案例了。再往前,还有IBM以340亿美元收购RedHat、Sun以10亿美元收购MySQL(但后来又被Oracle收购)。昔日的一个个免费开源明星软件,怀着使命和愿景陆续走向商业化,但又在这条道路上最终倒下。理想终究败给了现实,令人不得不感慨这个“美丽而又残酷”的世界。[ 出自《进击的巨人 Season 1》片尾曲“美しき残酷な世界”。]
目前“硕果仅存”的同级知名开源软件应该只有Apache和Linux了。值得注意的是它们并没有成立商业公司,而是以基金会的形式运作,通过赞助和会员制等形式来筹措资金。另一方面也确实是因为它们的“体量”足够大,能够把“免费”“开源”的大旗继续打下去。
当然,Nginx和F5都发表了官方声明,表示Nginx会继续保持开源,共同维护开源社区的活力。在这一点上我选择相信他们,相信被收购后的Nginx会有更加光明的未来。
再补上一句私心话:“还等着在Nginx上跑HTTP/3呢。”
新版的变化
我一直是C 语言的坚定拥护者,很早就在积极推动使用C 开发定制Nginx,但这几年下来感觉“收效甚微”:一是C语言开发的惯性太大,二是操作系统对C 标准支持不力,无法用上11/14的特性。几番折腾下来,有点“心灰意冷”了。
所以这次的新版就改以C作为主力开发语言,同时“忍痛割爱”,大幅度删减了各章节的C 代码,C 的全部内容都压缩到一个章节里(第20章),不再详细介绍C 封装类的具体实现和内部工作原理,也许这样会更贴近目前Nginx开发的现状。
上一版编写时比较匆忙,有些重要知识没来得及讲,这次“清退”C 后腾出了大量的
最早接触Nginx大概是在2011年,面对着一个全新的Web服务器,和大多数人一样最初我也是一片茫然,能找到的参考资料十分有限,安装、配置、运行几乎都是“摸着石头过河”,犯过许多低级错误。
随着对Nginx逐渐熟悉,它的高并发处理能力给我留下了深刻的印象,作为一个开源软件的爱好者,很自然地想要探究一下它的内部工作原理。我由此开始了对Nginx源码的钻研之路,中间经过了很多的艰辛曲折,走过了不少的弯路。
我最常用的工作语言是C ,所以在阅读Nginx源码时也总以C 的面向对象方式来思考和理解,以对象作为切入点记笔记、画UML:从最简单的ngx_str_t、ngx_array_t入手,然后到ngx_request_t、ngx_upstream_t等复杂的结构,再围绕着这些对象研究相关的功能函数和处理流程,梳理代码逻辑的同时也摸索着使用C 编写Nginx模块的方法,逐渐积累了一些用起来颇为顺手的小工具——当然还是比较初级的形式。
五年多前,我被调到了新的工作岗位,需要重度使用Nginx开发,这让我以前的零散积累终于有了用武之地。那段时间里使用C/C 陆续做了很多东西,也借着机会重新优化了原有的工具代码。
繁忙的工作之余,我有了种进一步整理经验的迫切感,因为只有系统完整地分享这些知识,才能让更多的人基于Nginx二次开发,让Nginx更好地为网络世界服务。
同一时间,市面上也出现了一些Nginx开发相关的资料、书籍,但在我看来却有“粗制滥造”之嫌:行文混乱,“车轱辘话”“口头禅”满天飞,甚至大段照抄指令说明,还有对源码的曲解,未免有点儿“误人子弟”,读起来实在是难受。终于,在“忍无可忍”的心态之下,我动起了写作本书的念头。
经过近一年的努力,现在这本书终于呈现在了读者面前,结构上基本反映了我学习研究Nginx时的心路历程,从最初的“一无所知”起步,逐渐深入到定制开发的层次,希望能与读者“心有戚戚焉”。
Nginx随感
毫无疑问,Nginx是目前这个星球上所能获得的最强劲的Web服务器(没有之一),同时也是目前最成熟、最优秀的TCP/HTTP服务器开发框架。
Nginx资源消耗低,并发处理性能高,配置灵活,能够连接CGI、PHP、MySQL、Memcached等多种后端,还有着出色的负载均衡能力,可以整合封装各种service,构建稳定高效的服务。如今Nginx已经成为了网站架构里不可或缺的关键组件,广泛应用于国内外许多大型IT企业内部。每一个繁忙的网站背后,可能都有Nginx默默工作的身影。
在Nginx出现之前,使用C/C 开发Web服务器是项比较“痛苦”的工作,虽然有很多网络程序库可以使用(例如asio、libevent、thrift等),但它们通常只关注较底层的基础功能实现,离成熟的“框架”相距甚远,不仅开发过程烦琐低效,而且程序员还必须要处理配置管理、进程间通信、协议解析等许多Web服务之外的其他事情,才能开发出一个较为完善的服务器程序。但即使开发出了这样的服务器,通常性能上也很难得到保证,会受到程序库和开发者水平等因素的限制——很长一段时间里,C/C 在Web服务器领域都没有大展拳脚的机会。
Nginx的横空出世为Web服务器开辟了一个崭新的天地,它搭建了一个高性能的服务器开发框架,而且是一个完整的、全功能的服务器。模块化的架构设计很好地分离了底层支撑模块和上层逻辑模块,底层模块处理了配置、并发等服务器的外围功能,核心支撑模块定义了主体的TCP/HTTP处理框架。开发者可以把大部分精力集中在上层的业务功能实现上,再也不必去为其他杂事而分心,提高了软件的开发效率。
在Nginx框架里C/C 程序员可以尽情发挥自己的专长,充分利用Nginx无阻塞处理的优势,打造出高质量的Web应用服务器,与其他系统一较高下。
Nginx和C/C
Igor Sysoev选择用C语言(准确地说是ANSI C)来实现Nginx肯定是经过了认真的考虑。
作为与UNIX一同诞生的编程语言,C语言一直是系统级编程的首选。和其他高级语言相比,它简单可靠,更接近计算机底层硬件,运行效率更高。指针更是C语言的一大特色,善用指针能够完成许多其他语言无法完成的工作。
以C语言实现的Nginx没有“虚拟机”的成本,省略了不必要的中间环节,直接操纵计算机硬件,从根本上提高了Web服务器的处理能力。虽然C语言不直接支持面向对象,但Nginx灵活运用了指针,采用“结构体 函数指针”的形式,达到了同样的效果,从而使软件拥有了良好的结构。
C 是仅次于C的系统级编程语言,在兼容C的同时又增加了异常、模板等新特性,还支持面向对象、泛型、函数式、模板元等多种编程范式,可以说是计算机语言里的一个“庞然大物”。C 的特性很多,有的也很好用,但总体上的确比较复杂,易学难精,容易被误用和滥用,导致低效、难维护的代码,我想这可能是Igor Sysoev放弃使用C 的一个重要原因。
另一个可能的原因是C语言本身已经非常稳定,几十年来没有太大的变动,在各个系统里都支持得非常好。而C 在1998年才有了第一个标准,而且现在还在发展之中,语言特性还不够稳定(例如export、register等曾经的关键字在C 11里就已经被废弃),许多编译器对C 的支持程度也有差异,这与Nginx的高可移植性目标明显不符。
但C 毕竟还是有很多的优点,类可以更好地封装信息、异常简化了错误处理、模板能够在编译期执行类型计算。在C 11标准颁布之后C 更是几乎变成了一门“全新”的语言,auto/decltype/nullptr/noexcept等新关键字增强了语言的描述能力,标准库也扩充了相当多的组件,易用性和稳定性都大大提升。
在Nginx里使用C 时要对C 的长处和不足有清醒的认识,避免多层次继承、虚函数等影响效率的编程范式,只使用经过充分验证的、能够切实提高开发效率和性能的语言特性和库,避免华而不实的技术炫耀,尽量做到像Nginx源码那样质朴踏实。只有这样,才能够发挥出“1 1>2”的作用,让Nginx从C 中得到更进一步的发展动力。
Nginx和OpenResty
多年以前Nginx开发使用的语言只能是C和C ,而现在,越来越多的开发者开始转向了OpenResty,使用Lua搭建高并发、高性能、高扩展性的Web Server。
我接触OpenResty的时间并不算很长,大约在五年左右。由于C/C 程序员“天生的傲慢”,一开始对OpenResty确实有点儿“抵触情绪”,总觉得脚本程序比不上C/C 实现。然而随着使用的增多,特别是在研究了它的源码之后,我不得不感慨OpenResty的精致、完美和强大,简直是所有Nginx开发者“梦寐以求的至宝”。
由于agentzh对Nginx的运行机制了如指掌,OpenResty的核心部分——ngx_lua一个模块就涵盖了access/rewrite/content/log等多个处理阶段,再搭配上小巧灵活的Lua和高效的LuaJIT,我们就能够在更高级的业务层次上使用“胶水”代码来调用组合Nginx底层功能,轻松开发出丰富Web服务,极大地节约了宝贵的时间和精力。
当然,OpenResty并不只有ngx_lua,围绕着ngx_lua还有众多的库和辅助工具,构成了一个相当完善的生态环境,这些组件相互支撑,利用得当可以更好地提高生产效率。
OpenResty现在正处于蓬勃发展的阶段,今后的OpenResty也许不仅限于Nginx和Web Server,而将成为一个更通用的开发平台,工作语言也不仅限于Lua,可能还会有其他新的语言(例如agentzh正在做的edgelang和fanlang),让我们拭目以待。
“大事件”
2019年,Nginx身上发生了一件了不得的“大事件”:在独立运营了8年之后,Nginx.Inc公司正式被它的“竞争对手”F5 Networks收购。
收购的价格并不算高,只有6.7亿美元。可以比较一下去年被微软收购的源码托管网站GitHub,出价是75亿。对于Nginx这个几乎占据了互联网一半份额的顶尖Web服务器来说,感觉实在是有点低。
这也算得上是开源软件商业化的又一个标志性案例了。再往前,还有IBM以340亿美元收购RedHat、Sun以10亿美元收购MySQL(但后来又被Oracle收购)。昔日的一个个免费开源明星软件,怀着使命和愿景陆续走向商业化,但又在这条道路上最终倒下。理想终究败给了现实,令人不得不感慨这个“美丽而又残酷”的世界。[ 出自《进击的巨人 Season 1》片尾曲“美しき残酷な世界”。]
目前“硕果仅存”的同级知名开源软件应该只有Apache和Linux了。值得注意的是它们并没有成立商业公司,而是以基金会的形式运作,通过赞助和会员制等形式来筹措资金。另一方面也确实是因为它们的“体量”足够大,能够把“免费”“开源”的大旗继续打下去。
当然,Nginx和F5都发表了官方声明,表示Nginx会继续保持开源,共同维护开源社区的活力。在这一点上我选择相信他们,相信被收购后的Nginx会有更加光明的未来。
再补上一句私心话:“还等着在Nginx上跑HTTP/3呢。”
新版的变化
我一直是C 语言的坚定拥护者,很早就在积极推动使用C 开发定制Nginx,但这几年下来感觉“收效甚微”:一是C语言开发的惯性太大,二是操作系统对C 标准支持不力,无法用上11/14的特性。几番折腾下来,有点“心灰意冷”了。
所以这次的新版就改以C作为主力开发语言,同时“忍痛割爱”,大幅度删减了各章节的C 代码,C 的全部内容都压缩到一个章节里(第20章),不再详细介绍C 封装类的具体实现和内部工作原理,也许这样会更贴近目前Nginx开发的现状。
上一版编写时比较匆忙,有些重要知识没来得及讲,这次“清退”C 后腾出了大量的
评论
还没有评论。