Emiller 的 Nginx 的模块开发指南 已翻译 100%

logbird 投递于 2013/07/30 22:49 (共 45 段, 翻译完成于 10-17)
阅读 9751
收藏 142
10
加载中

要充分了解Nginx, 互联网服务器, 看看蝙蝠侠可能会有帮助, 那个漫画书中角色.

蝙蝠侠动作很快. Nginx也很快. 蝙蝠侠对抗犯罪. Nginx 对抗闲置的CPU周期和内存泄露. Batman在压力下表现出色. Nginx, 作为网络服务器, 在巨大的服务器负载下表现同样出色.

但离开了他的多功能腰带, 蝙蝠侠什么事也做不成.

图1: The Batman utility belt, gripping Christian Bale's love handles.

在任何时候, 蝙蝠侠的多功能腰带中可能藏有撬锁工具, 几只飞镖,  蝙蝠手铐, 一个蝙蝠跟踪器, 一些蝙蝠镖, 夜视仪, 闪光弹, 烟雾弹, 手电筒, 氪星石戒指, 火炬, 或者一个iPhone. 当蝙蝠侠需要制服, 盲, 制聋, 制晕, 跟踪, 阻止, 放烟雾, 或发短消息给坏人时, 你可以确定他一定在摸他的腰带.这个腰带是如此的重要. 如果一定要蝙蝠侠在穿裤子和带腰带之间选一个, 他一定选腰带. 事实上, 他确实选择了多功能腰带. 这也是为什么他要穿橡皮紧身衣了.(图. 1).

Grisson
Grisson
翻译于 2013/08/14 17:50
4

相对于蝙蝠侠的多功能腰带,Nginx有一条模块链(注:module chain). Nginx能够快速地根据需求调用相应的模块,如gzip或整块编码响应、基于IP地址或HTTP授权的访问控制、与Memcache或FastCGI通性。

蝙蝠侠的多功能腰带中有许多的工具,但偶尔他会遇到一些新的敌人,无视蝙蝠镖与手铐,这时他就需要一些新的工具来制服敌人。或者一项新的能力,如在水下呼吸。因此,Lucius Fox成为了那个研发蝙蝠工具的工程师。

图2: Bruce Wayne (蝙蝠侠) 咨询他的工程师,Lucius Fox

crossgate9
crossgate9
翻译于 2013/08/14 23:07
2

本指南的目的是向你讲诉Nginx模块链的细节,这样你就可以像卢修斯·福克斯(蝙蝠侠的军师)一样。当你阅读并掌握了本指南,你就可以设计和创造高质量的模块,使Nginx可以做它以前不可以做的事情。Ninx的模块系统有很多的细节和事实真相,所以你可能会经常使用这个文档。我已经尝试着让概念尽可能的清晰明了,但是坦率的说,编写Nginx仍然很难。

但是谁会说制作批处理工具很容易?

内容列表

  1. 预备知识
  2. 深入Nginx的摸块代理
  3. Nginx模块组件
    1. 模块配置结构
    2. 模块指令
    3. 模块上下文
      1. 创建_loc_conf
      2. 修改_loc_conf
    4. 模块定义
    5. 模块安装
  4. Handlers
    1. Handler剖析 (非代理)
      1. 获取location配置
      2. 生成响应
      3. 发送响应头
      4. 发送响应体
    2. Upstream Handler 剖析
      1. Upstream回调函数概要
      2. create request回调概要
      3. 头处理回调函数概要
      4. 状态保持
    3. Handler装载
  5. 过滤器
    1. Header Filter分析
    2. Body Filter分析
    3. 过滤器装载
  6. 负载均衡
    1. 启用指令
    2. 注册函数
    3. Upstream游初始化函数
    4. 对等初始化函数
    5. 负载均衡函数
    6. 对等释放函数
  7. 编写和变异新的Nginx模块
  8. 高级内容
  9. 参考代码
f
fanhang
翻译于 2013/09/18 23:11
2

0. 预备知识

熟悉C的读者为佳,不仅仅是C的语法,更需要熟悉、并不惧怕结构、指针、函数引用和预处理技术。若你需要充电,没有比K&R更合适的了。

理解HTTP协议,毕竟你要在一个web服务器上工作。

熟悉Nginx的配置文件。如果缺乏这个经验,可以参考下列大纲。

Nginx中有4个上下文 (注:context):main, server, upstream, location。后接一个指令,指令可以带一个或多个参数。

在main中的指令是全局的,被应用在所有适用的对象上;

在server中的指令只会被应用在特定的主机/端口上;

在upstream中的指令会被应用到一系列的后端服务器上;

在location中的指令只会被应用到特定匹配的web路径上,如("/", "/images"等)

继承方面,location继承其父亲server的配置,server继承main的配置。upstream既不向上继承,也不向下传授其配置,其独特的指令,不会被应用到其它任何地方。

在后续的内容中,会多次提到这4个上下文,千万别忘记。

那么,出发!

crossgate9
crossgate9
翻译于 2013/08/14 23:21
4

高度概述Nginx的模块所担当的角色

我们将介绍Nginx模块具有的三个角色:

  • 处理器:处理请求,然后生成输出
  • 过滤器:通过处理器维护所生成的输出
  • 负载均衡器:当有多个后台服务器都满足条件时,为发送来的请求选择一个后台服务器。

模块做了你可能想到的与互联网服务器相关的所有”真正的工作“:当Nginx处理文件或者做为代理把请求转给一个服务器时,处理器模块就做这方面的工作;当Nginx压缩输出或者执行服务端的包含项时,它就使用过滤器模块。Nginx的“核心”实际上关心的是所有的网络和应用协议,并且建立一个能够处理请求的模块队列。这种分散式结构使你可以用一个友好的自包含单元做你想做的事情。

注意:与Apache里的模块不同,Nginx模块是非动态链接的。(换句话说,它们要完全编译到Nginx的二进制包里。)

几点人
几点人
翻译于 2013/08/16 11:00
2

怎样调用模块呢?通常在服务器启动的时候,每个处理器都有机会把自己与配置里所定义的特定位置关联起来;如果有多个处理器与一个特定的位置关联,那么只有一个获得“关联”(不过一个好的配置编写者不会让这种冲突发生。)处理器可以以三种方式返回:如果一切都正常,返回一个错误,或者处理器拒绝处理请求,转由默认的处理器处理(通常处理的是静态文件)。

如果处理器刚好是某些后台服务器的反向代理,那么这就是另一类型模块的用武之地:负载均衡器。负载均衡器考虑了请求和一组后台服务器,然后决定哪个服务器将处理请求。Nginx装载了两个负载均衡模块:轮询方法,它就像扑克游戏开始时发牌那样分发请求,还有"IP散列“方法,它确保特定客户端的多个请求都选中同一个后台服务器。

几点人
几点人
翻译于 2013/08/16 12:06
2

如果处理器没有生成错误,那么就调用了过滤器。多个过滤器可以和一个位置挂钩,这样(例如)响应就可以压缩然后再组包。它们的执行顺序是在编译的时候确定的。过滤器采用的是古典的”职责链“设计模式:调用一个过滤器,它就执行它的工作,然后调用下一个过滤器,直到调用了最后一个过滤器,这时Nginx才完成响应。

过滤器链真正酷的地方是每个过滤器都不会等待前一个过滤器结束;它可以处理前一个过滤器正在生成的输出,有点像Unix的管道。过滤器是在缓冲上运行的,缓冲器大小通常是页的大小(4K),然而你可以在ngnx.conf里更改缓冲大小。例如,这意味着模块在从后台接受到整个响应之前就可以压缩来自后端服务器的响应,然后以流的方式发送给客户端。很好!

几点人
几点人
翻译于 2013/08/16 12:32
2

简而言之,典型的处理循环是:

客户端发送 HTTP 请求 → Nginx 依据给定的 location 配置文件选择合适的handler  → (如果可用) 负载均衡器选择一个后端服务器 → Handler 处理自己的事情并将每个输出缓冲传递给第一个 filter → 第一个 filter 将输出传递给第二个 filter → 第二个传给第三个 → 第三个传给第四个 → 以此类推。 → 最后的响应被发送给客户端

我说 "典型" 是因为 Nginx 的模块调用时是有着 极致地 可定制性的。精确地定义一个模块如何运行和何时运行对模块编写者来说是个极大的负担 (我碰巧认为是个极大的负担)。调用实际上是通过一系列的回调函数执行的,而且有好多回调函数。就是说,你可以提供一个函数,让它运行在:

  • 仅当服务器读取配置文件前
  • 对 location 和 server 的每一个配置指令,当它出现时;
  • 当 Nginx 初始化主配置时
  • 当 Nginx 初始化服务器 (即 host/port) 配置时
  • 当 Nginx 合并服务器配置和主配置时
  • 当 Nginx 初始化 location 配置时
  • 当 Nginx 合并 location 配置和它的父服务器配置时
  • 当 Nginx 的主进程启动时
  • 当一个新的 worker 进程启动时
  • 当一个 worker 进程退出时
  • 当主进程退出时
  • 处理一个请求时
  • 过滤响应头时
  • 过滤相应体时
  • 选择一个后端服务器时
  • 初始化一个发往后端服务器的请求时
  • 重新初始化一个发往后端服务器的请求时
  • 处理来自后端服务器的响应时
  • 完成和后端服务器的交互时

天哪! 有点势不可挡。你已经得到了好多任由自己处置的能量,但你依然可以仅仅用其中的几个钩子和相应的函数做一些有用的事情。该是钻研一些模块的时候了。

开源中国首席投资人
开源中国首席投资人
翻译于 2013/10/04 00:11
2

2. Nginx模块组件

正如我所说的,当提及到使用Nginx模块,你有很多灵活性的选择。这一节描述是经常出现的部分。这作为一个理解模块的指南,也在你想自己写一个模块的时候充当一个参考。

2.1. 模块配置结构

模块能定义三个配置结构,一个主结构,一个服务器结构,一个位置上下文。大多数模块只需要一个位置配置。它们的命名习惯是ngx_http_<module name>_(main|srv|loc)_conf_t。这是一个从dav模块的例子:

typedef struct {
    ngx_uint_t  methods;
    ngx_flag_t  create_full_put_path;
    ngx_uint_t  access;
} ngx_http_dav_loc_conf_t;

注意Nginx有特殊的数据类型(ngx_uint_tandngx_flag_t);这是你知道和喜欢的基本数据类型的别名(如果感到好奇,参见 core/ngx_config.h ).

配置结构中的元素被模块指令填充。

徐继开
徐继开
翻译于 2013/08/28 15:51
2

2.2.模块指令

模块指令出现于静态数组ngx_command_ts。这里是从我写的一个小模块中摘取的,关于它们是如何声明的例子:

static ngx_command_t  ngx_http_circle_gif_commands[] = {
    { ngx_string("circle_gif"),
      NGX_HTTP_LOC_CONF|NGX_CONF_NOARGS,
      ngx_http_circle_gif,
      NGX_HTTP_LOC_CONF_OFFSET,
      0,
      NULL },

    { ngx_string("circle_gif_min_radius"),
      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
      ngx_conf_set_num_slot,
      NGX_HTTP_LOC_CONF_OFFSET,
      offsetof(ngx_http_circle_gif_loc_conf_t, min_radius),
      NULL },
      ...
      ngx_null_command
};

这里是ngx_command_t(我们所定义的结构)的声明, 在 core/ngx_conf_file.h 中:

struct ngx_command_t {
    ngx_str_t             name;
    ngx_uint_t            type;
    char               *(*set)(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
    ngx_uint_t            conf;
    ngx_uint_t            offset;
    void                 *post;
};

它看起来有点多,但是每个元素都有其目的。

name是指令字符串,没有空格。它的数据类型是ngx_str_t,通常它被实例化的方式为(例如)ngx_str("proxy_pass")。注意:ngx_str_t是一个具有数据元素的数据结构,它是一个字符串,和一个len元素,这个len元素是这个字符串的长度。在大多数你需要一个字符串的地方,Nginx使用的就是这样的数据结构。

super0555
super0555
翻译于 2013/09/04 13:00
2
本文中的所有译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接。
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。
加载中

评论(6)

seared2008
seared2008
深入了解nginx的工作过程
vingzhang
vingzhang
不明觉厉
Ken5233
Ken5233
辛苦翻译了 这么长的篇幅
浩子b
浩子b
测试
z
zx32342342

引用来自“Lax”的评论

这里已经有一个相对完整的翻译可以供参考
http://code.google.com/p/emillers-guide-to-nginx-module-chn/wiki/NginxModuleDevGuide_CHN

2009年之后有3次改动,更新一下即可。

赞 这个翻译不错
Lax
Lax
这里已经有一个相对完整的翻译可以供参考
http://code.google.com/p/emillers-guide-to-nginx-module-chn/wiki/NginxModuleDevGuide_CHN

2009年之后有3次改动,更新一下即可。
返回顶部
顶部