nginx模块开发指南(中文).pdf
《nginx模块开发指南(中文).pdf》由会员分享,可在线阅读,更多相关《nginx模块开发指南(中文).pdf(39页珍藏版)》请在淘文阁 - 分享文档赚钱的网站上搜索。
1、Emiller的的Nginx模块开发指南模块开发指南作者:Evan Miller 草稿:2009年8月 13日 译者:姚伟斌 草稿:2009 年9月21日内容目录内容目录0.预备知识.11.Nginx模块任务委派的主要轮廓.12.Nginx 模块的组成.32.1.模块的配置结构体.32.2.模块的指令.42.3.模块的上下文.62.3.1.创建位置结构体(create_loc_conf).82.3.2.初始化结构体(merge_loc_conf).82.4.模块定义.92.5.模块注册.103.处理模块、过滤模块和 负载均衡模块.103.1.剖析处理模块(非代理).103.1.1.获得位置配置
2、结构体.103.1.2.产生回复.113.1.3.发送HTTP头部.123.1.4.发送HTTP主体.133.2.上游模块剖析(又称代理模块).14i3.2.1.代理模块回调函数的概要.143.2.2.create_request 回调函数.163.2.3.process_header 回调函数.173.2.4.状态保持.183.3.处理模块的注册.194 过滤模块.194.1.剖析头部过滤函数.194.2.剖析主体过滤函数.204.3 过滤函数的注册.225.剖析负载均衡模块.245.1.激活指令.245.2.注册函数.255.3.上游主机初始化函数.275.4.同伴初始化函数.285.5.
3、负载均衡函数.305.6.同伴释放函数.316.完成并编译自定义模块.327.高级话题.33中文版本修改日志.33iiiii翻译说明:在 nginx 的模块编写过程中,时常苦于文档的不足,而源代码中又没多少注释。只有Emiller的这篇英文文档带我入门,在自己研读的过程中,就想将其翻译出来,让其他人能快速的浏览,但是如果你想更深入的进入nginx的代码开发,最好是多读nginx的代码。因其内部的代码是经常改变的,所以本文有可能已经过时。由于本人英语水平一般,接触Nginx时间不多,翻译中碰到的错误在所难免,如果您觉得哪里翻译得不对,请跟我联系:翻译词汇对照表:Backend:后端服务器。Buf
4、fer:缓冲区。Callback:回调函数,一般来说是将某个回调函数赋值给某个函数指针CHAIN OF RESPONSIBILITY:接力链表。Context:上下文,有前后工作环境的意思,主要是前期配置值初始化。Filter:过滤模块/函数,模块和函数的概念似乎有点模糊不清。Handler:处理模块/函数,另外也有指向具体的处理函数的指针或句柄的意思。Installation:原意为安装,我觉得还是译作注册好点。Load-balancer:负载均衡模块/函数。Location:指目录位置,比如http:/ backend。Worker:工作进程,模块真正发挥作用的地方。0.预备知识预备知识对
5、于 C 语言,你应该十分熟悉,对于结构体和预处理命令应有深入的理解,不至于见到大量的指针和函数引用就惊慌失措。如果觉得需要补习,就多看看K&R(C 语言的语法书)。如果你对于HTTP协议已经有了基本概念,那是很有好处的。毕竟你正在Web 服务器上做开发。你应该熟悉Nginx的配置文件。如果不熟悉,也没关系,这里有一些基本理解:Nginx 配置文件主要分成四部分:main(全局设置)、server(主机设置)、upstream(上游服务器设置)和location(URL匹配特定位置后的设置)。每部分包含若干个指令。main部分设置的指令将影响其它所有部分;server部分的指令主要用于指定主机和
6、端口;upstream的指令用于设置后端服务器;location部分用于匹配网页位置(比如,根目录“/”,“/images”等等)。Location部分会继承server 部分的指令,而 server部分的指令会继承main部分;upstream既不继承指令也不会影响其他部分。它有自己的特殊指令,不需要在其他地方的应用。在下面很多地方都会涉及这四个部分,不要忘记哟。让我们开始吧。1.Nginx模块任务委派的模块任务委派的主要轮廓主要轮廓Nginx 模块主要有3 种角色:handlers(处理模块)用于处理HTTP请求,然后产生输出 filters(过滤模块)过滤handler产生的输出 loa
7、d-balancers(负载均衡模块)当有多于一台的后端备选服务器时,选择一台转发HTTP请求模块可以做任何你分配给web服务器的实际工作:当Nginx 发送文件或者转发请求到其他服务器,有处理模块处理模块为其服务;当需要Nginx把输出压缩或者在服务端加一些东西,可以用过滤模块过滤模块;还有一些Nginx的核心模块主要负责管理网络层和应用层协议,以及针对特定应用的一系列模块。Nginx集中式的体系结构让你可以随心所欲地实现一些功能强大的内部单元。注意:Nginx不像apache,模块不是动态添加的(换句话就是说,所有的模块都要预先编译进Nginx的二进制可执行文件)。模块是如何被调用的?典型
8、的讲,当服务器启动,每个处理模块都有机会映射到配置文件中定义的特定位置;如果有多个处理模块映射到同一个位置时,只1有一个会“赢”(聪明如你,当然不会让这些冲突产生)。处理模块主要以三种形式返回:正常、错误、或者放弃处理这个请求而让默认处理模块来处理。如果处理模块把请求反向代理到后端的服务器,就变成另外一类的模块:负载负载均衡模块均衡模块。负载均衡模块的配置中有一组后端服务器,当一个HTTP请求过来时,它决定哪台服务器应当获得这个请求。Nginx的负载均衡模块默认采用两种方法:轮转法,它处理请求的方式就像纸牌游戏一样从头到尾分发;IP哈希法,在众多请求的情况下,它确保来自同一个IP的请求会分发到
9、相同的后端服务器。当然还有一些第三方的负载均衡方法,你可以从这里找到。如果处理模块没有产生错误,过滤模块将被调用。过滤模块能映射到每个位置,而且过滤模块是有先后顺序的,它们的执行顺序在编译时决定。过滤模块是经典的“接力链表(CHAIN OF RESPONSIBILITY)”模型:一个过滤模块被调用,完成其工作,然后调用下一个过滤模块,直到最后一个过滤模块。一般来说压缩模块是比较靠后的,不然压缩以后的内容是很难用来读的。最后,Nginx发出回复。真正 cool的地方是在过滤模块链中,每个过滤模块不会等上一个过滤模块全部完成;它能把前一个过滤模块的输出作为其处理内容;有点像Unix中的流水线。过滤
10、模块能以buffer(缓冲区)为单位进行操作,这些buffer一般都是一页(4K)大小,当然你也可以在nginx.conf文件中进行配置。这意味着,比如模块可以压缩来自后端服务器的回复,然后像流一样的到达客户端,直到整个回复发送完成。所以总结下上面的内容,一个典型的处理周期是这样的:客户端发送 HTTP 请求 -Nginx 根据配置选择一个合适的处理模块 -(如果有)负载均衡模块选择一台后端服务器,并负责完成后端的发送接收过程 -处理模 块进行处理并把输出缓冲放到第一个过滤模块上 -第一个过滤模块处理后输出 给第二个过滤模块 -然后第二个过滤模块又到第三个 -依此类推 -最后把回复 发给客户端
11、。我说“典型”这个词是因为Nginx的模块调用是具有很强的定制性的。模块开发者需要花很多精力精确定义模块在何时如何产生作用(我认为是件不容易的事)。模块的调用事实上通过一系列的回调函数来实现,很多很多。名义上来说,你的函数可在以下时段执行某些功能:当服务读配置文件之前读存在location和 server 或其他任何部分的每一个配置指令当Nginx初始化全局部分的配置时当Nginx初始化主机部分(比如主机/端口)的配置时当Nginx将全局部分的配置与主机部分的配置合并的时候当Nginx初始化位置部分配置的时候当Nginx将其上层主机配置与位置部分配置合并的时候当Nginx的主(master)进
12、程开始的时候当一个新的工作进程(worker)开始的时候2当一个工作进程退出的时候当主进程退出的时候处理请求过滤回复的头部过滤回复的主体选择一台后端服务器初始化到后端服务器的请求重新初始化到后端的服务器的请求处理来自后端服务器的回复完成与后端服务器的交互难以置信,有点应接不暇!有这么多的功能任你处置,而你只需通过多组有用的钩子(由函数指针组成的结构体)和相应的实现函数。现在让我们开始接触一些模块吧。2.Nginx模块的组成模块的组成我说过,Nginx模块的使用是很灵活的。本段描述的东西会经常出现。它引导你理解模块,也可以成为你开始写模块的参考。2.1.模块的配置结构体模块的配置结构体模块的配置
13、结构体的定义有三种,分别是全局,主机和位置的配置结构体。大多数HTTP模块仅仅需要一个位置的配置结构体。名称约定是这样的:ngx_http_(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_t 和 ngx_flag_t),可能是一些基本类型的别名。(如果你好奇的话,可以看这里:core/ngx_con
14、fig.h)这些类型用在配置结构体的情形很多。32.2.模块的指令模块的指令模块的指令出现在静态数组ngx_command_t。这里有一个例子,说明它们是如何被定义的,来自我写的一个小模块: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_MAI
15、N_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 *(
16、*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结构体由包含有字符串的data成员和表示字符串长度的len成员组成。Nginx用这个数据类型来存放字符串。type 是标识的集合,表明这个指令在哪里出现是合法的
17、、指令的参数个数。应用4中,标识一般是下面多个值的位或:NGX_HTTP_MAIN_CONF:指令出现在全局配置部分是合法的NGX_HTTP_SRV_CONF:指令在主机配置部分出现是合法的 NGX_HTTP_LOC_CONF:指令在位置配置部分出现是合法的 NGX_HTTP_UPS_CONF:指令在上游服务器配置部分出现是合法的 NGX_CONF_NOARGS:指令没有参数 NGX_CONF_TAKE1:指令读入一个参数 NGX_CONF_TAKE2:指令读入两个参数.NGX_CONF_TAKE7:指令读入七个参数NGX_CONF_FLAG:指令读入一个布尔型数据 NGX_CONF_1MOR
18、E:指令至少读入1个参数NGX_CONF_2MORE:指令至少读入2个参数 这里有很多另外的选项:core/ngx_conf_file.h。结构体成员set是一个函数指针,用来设定模块的配置;典型地,这个函数会转化读入指令传进来的参数,然后将合适的值保存到配置结构体。这个设定函数有三个参数:1指向 ngx_conf_t结构体的指针,包含从配置文件中指令传过来的参数。2指向当前 ngx_command_t结构体的指针3指向自定义模块配置结构体的指针这个设定函数在指令被遇到的时候就会调用。在自定义的配置结构体中,Nginx提供了多个函数用来保存特定类型的数据,这些函数包含有:5ngx_conf_s
19、et_flag_slot:将on或off转化为 ngx_conf_set_str_slot:将字符串保存为ngx_str_t类型 ngx_conf_set_num_slot:解析一个数字并保存为int型ngx_conf_set_size_slot:解析一个数据大小(如:8k,1m)并保存为 size_t类型还有另外一些,很容易查到(看,core/ngx_conf_file.h)。模块也可以把它们自己函数的引用放在这里,但这样内嵌的类型不是很好。那这些内嵌函数怎么知道要把值保存在哪里呢?ngx_command_t接下来的两个成员 conf和 offset正好可用。conf告诉 Nginx把这个值
20、是放在全局配置部分、主机配置部分还是位置配置部分(用NGX_HTTP_MAIN_CONF_OFFSET,NGX_HTTP_SRV_CONF_OFFSET或NGX_HTTP_LOC_CONF_OFFSET)。然后offset确定到底是保存在结构体的哪个位置。最后,post指向模块在读配置的时候需要的一些零碎变量。一般它是NULL。这个 ngx_command_t 数组在读入ngx_null_command 后停止。2.3.模块的上下文模块的上下文静态的 ngx_http_module_t 结构体,包含一大把函数引用。用来创建三个部分的配置和合并配置。一般结构体命名为ngx_http_module
21、_ctx。以此,这些函数引用包括:在读入配置文件前调用在读入配置文件后调用在创建全局部分配置时调用(比如,用来分配空间和设置默认值)在初始化全局部分的配置时调用(比如,把原来的默认值用nginx.conf读到的值来覆盖)在创建主机部分的配置时调用与全局部分配置合并时调用创建位置部分的配置时掉用与主机部分配置合并时调用这些函数参数不同,依赖于它们的功能。这里有这个结构体的定义,摘自http/ngx_http_config.h,你可以看到属性各不同的回调函数:typedef struct 6 ngx_int_t (*preconfiguration)(ngx_conf_t*cf);ngx_int_
22、t (*postconfiguration)(ngx_conf_t*cf);void *(*create_main_conf)(ngx_conf_t*cf);char *(*init_main_conf)(ngx_conf_t*cf,void*conf);void *(*create_srv_conf)(ngx_conf_t*cf);char *(*merge_srv_conf)(ngx_conf_t*cf,void*prev,void*conf);void *(*create_loc_conf)(ngx_conf_t*cf);char *(*merge_loc_conf)(ngx_conf_
23、t*cf,void*prev,void*conf);ngx_http_module_t;如果某些函数不用,可以设定为NULL,Nginx会剔除它。大多数处理模块只使用最后两个:一个函数用来为特定的位置部分的配置结构体分配内存(称为ngx_http_create_loc_conf),另外一个函数用来设定默认值和与继承过来的配置合并(称为ngx_http_merge_loc_conf)。这个合并函数负责检验读入的数值是否有效,并设定一些默认值。这里有一个模块上下文结构体的例子:static ngx_http_module_t ngx_http_circle_gif_module_ctx=NULL,
24、/*preconfiguration*/NULL,/*postconfiguration*/NULL,/*create main configuration*/NULL,/*init main configuration*/NULL,/*create server configuration*/NULL,/*merge server configuration*/ngx_http_circle_gif_create_loc_conf,/*create location configuration*/ngx_http_circle_gif_merge_loc_conf/*merge locati
25、on configuration*/;现在开始讲得更深一点。这些配置回调函数看其来很相似,几乎所有模块都一样,而且 Nginx的 API都会用到这个部分,所以值得了解。72.3.1.创建位置结构体(创建位置结构体(create_loc_conf)create_loc_conf函数骨架看起来像这个样子,摘自我写的circle_gif模块(看源代码)。它的参数是结构体ngx_conf_t,返回更新的模块配置结构体(例子中是ngx_http_circle_gif_loc_conf_t)。static void*ngx_http_circle_gif_create_loc_conf(ngx_conf_
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- nginx 模块 开发 指南 中文
限制150内