[转] Nginx模块开发入门
2015-10-19 15:09
489 查看
前言
Nginx是当前最流行的HTTP Server之一,根据W3Techs的统计,目前世界排名(根据Alexa)前100万的网站中,Nginx的占有率为6.8%。与Apache相比,Nginx在高并发情况下具有巨大的性能优势。Nginx属于典型的微内核设计,其内核非常简洁和优雅,同时具有非常高的可扩展性。Nginx最初仅仅主要被用于做反向代理,后来随着HTTP核 心的成熟和各种HTTP扩展模块的丰富,Nginx越来越多被用来取代Apache而单独承担HTTP Server的责任,例如目前淘宝内各个部门正越来越多使用Nginx取代Apache,据笔者了解,在腾讯和新浪等公司也存在类似情况。
同时,大量的第三方扩展模块也令Nginx越来越强大。例如,由淘宝的工程师清无(王晓哲)和春来(章亦春)所开发的nginx_lua_module可以将Lua语言嵌入到Nginx配置中,从而利用Lua极大增强了Nginx本身的编程能力,甚至可以不用配合其它脚本语言(如PHP或Python等),只靠Nginx本身就可以实现复杂业务的处理。而春来所开发的ngx_openresty更是通过集成LuaJIT等 组件,将Nginx本身变成了一个完全的应用开发平台。目前淘宝数据平台与产品部量子统计的产品都是基于ngx_openresty所开发。对 ngxin_lua_module或ngx_openresty感兴趣的朋友可以参考我在关键词上给出的链接,后续我也可能会写一些与其有关的文章。
本文将会重点关注Nginx模块开发入门及基础。目前Nginx的学习资料非常少,而扩展模块开发相关的资料几乎只有《Emiller's Guide To Nginx Module Development》一文,此文十分经典,但是由于Nginx版本的演进,其中少许内容可能有点过时。本文是笔者在研读这篇文章和Nginx源代码的基础上,对自己学习Nginx模块开发的一个总结。本文将通过一个完整的模块开发实例讲解Nginx模块开发的入门内容。
本文将基于Nginx最新的1.0.0版本,操作系统环境为Linux(Ubuntu10.10)。
前言
Nginx提要
Nginx在Linux下的安装与运行
Nginx配置文件基本结构
Nginx模块工作原理概述
Nginx模块开发实战
定义模块配置结构
定义指令
创建合并配置信息
编写Handler
组合Nginx Module
Nginx模块的安装
Nginx更深入的学习
Nginx参考文献
Nginx提要
开发Nginx扩展当然首要前提是对Nginx有一定的了解,然而本文并不打算详细阐述Nginx的方方面面,诸如Nginx的安装和各种详细配置等内容都可以在Nginx官网的Document中找到,本文在这里只会概括性描述一些后面可能会用到的原理和概念。Nginx在Linux下的安装与运行
使用Nginx的第一步是下载Nginx源码包,例如1.0.0的下载地址为http://nginx.org/download/nginx-1.0.0.tar.gz。下载完后用tar命令解压缩,进入目录后安装过程与Linux下通常步骤无异,例如我想讲Nginx安装到/usr/local/nginx下,则执行如下命令:?
?
?
?
Nginx配置文件基本结构
配置文件可以看做是Nginx的灵魂,Nginx服务在启动时会读入配置文件,而后续几乎一切动作行为都是按照配置文件中的指令进行的,因此如果将Nginx本身看做一个计算机,那么Nginx的配置文件可以看成是全部的程序指令。下面是一个Nginx配置文件的实例:
?
其中“#”表示此行是注释,由于笔者为了学习扩展开发安装了一个纯净的Nginx,因此配置文件没有经过太多改动。
Nginx的配置文件是以block的形式组织的,一个block通常使用大括号“{}”表示。block分为几个层级,整个配置文件为main层 级,这是最大的层级;在main层级下可以有event、http等层级,而http中又会有server block,server block中可以包含location block。
每个层级可以有自己的指令(Directive),例如worker_processes是一个main层级指令,它指定Nginx服务的 Worker进程数量。有的指令只能在一个层级中配置,如worker_processes只能存在于main中,而有的指令可以存在于多个层级,在这种 情况下,子block会继承父block的配置,同时如果子block配置了与父block不同的指令,则会覆盖掉父block的配置。指令的格式是“指 令名 参数1 参数2 … 参数N;”,注意参数间可用任意数量空格分隔,最后要加分号。
在开发Nginx HTTP扩展模块过程中,需要特别注意的是main、server和location三个层级,因为扩展模块通常允许指定新的配置指令在这三个层级中。
最后要提到的是配置文件是可以包含的,如上面配置文件中“include mime.types”就包含了mine.types这个配置文件,此文件指定了各种HTTP Content-type。
一般来说,一个server block表示一个Host,而里面的一个location则代表一个路由映射规则,这两个block可以说是HTTP配置的核心。
下图是Nginx配置文件通常结构图示。
关于Nginx配置的更多内容请参看Nginx官方文档。
Nginx模块工作原理概述
(Nginx本身支持多种模块,如HTTP模块、EVENT模块和MAIL模块,本文只讨论HTTP模块)Nginx本身做的工作实际很少,当它接到一个HTTP请求时,它仅仅是通过查找配置文件将此次请求映射到一个location block,而此location中所配置的各个指令则会启动不同的模块去完成工作,因此模块可以看做Nginx真正的劳动工作者。通常一个 location中的指令会涉及一个handler模块和多个filter模块(当然,多个location可以复用同一个模块)。handler模块负 责处理请求,完成响应内容的生成,而filter模块对响应内容进行处理。因此Nginx模块开发分为handler开发和filter开发(本文不考虑 load-balancer模块)。下图展示了一次常规请求和响应的过程。
Nginx模块开发实战
下面本文展示一个简单的Nginx模块开发全过程,我们开发一个叫echo的handler模块,这个模块功能非常简单,它接收“echo”指令,指令可指定一个字符串参数,模块会输出这个字符串作为HTTP响应。例如,做如下配置:?
直观来看,要实现这个功能需要三步:1、读入配置文件中echo指令及其参数;2、进行HTTP包装(添加HTTP头等工作);3、将结果返回给客户端。下面本文将分部介绍整个模块的开发过程。
定义模块配置结构
首先我们需要一个结构用于存储从配置文件中读进来的相关指令参数,即模块配置信息结构。根据Nginx模块开发规则,这个结构的命名规则为 ngx_http_[module-name]_[main|srv|loc]_conf_t。其中main、srv和loc分别用于表示同一模块在三层 block中的配置信息。这里我们的echo模块只需要运行在loc层级下,需要存储一个字符串参数,因此我们可以定义如下的模块配置:?
?
?
定义指令
一个Nginx模块往往接收一至多个指令,echo模块接收一个指令“echo”。Nginx模块使用一个ngx_command_t数组表示模块 所能接收的所有模块,其中每一个元素表示一个条指令。ngx_command_t是ngx_command_s的一个别称(Nginx习惯于使用“_s” 后缀命名结构体,然后typedef一个同名“_t”后缀名称作为此结构体的类型名),ngx_command_s定义在 core/ngx_config_file.h中:?
?
set是一个函数指针,用于指定一个参数转化函数,这个函数一般是将配置文件中相关指令的参数转化成需要的格式并存入配置结构体。Nginx预定义 了一些转换函数,可以方便我们调用,这些函数定义在core/ngx_conf_file.h中,一般以“_slot”结尾,例如 ngx_conf_set_flag_slot将“on或off”转换为“1或0”,再如ngx_conf_set_str_slot将裸字符串转化为 ngx_str_t。
conf用于指定Nginx相应配置文件内存其实地址,一般可以通过内置常量指定,如NGX_HTTP_LOC_CONF_OFFSET,offset指定此条指令的参数的偏移量。
下面是echo模块的指令定义:
?
参数转化函数的代码为:
?
创建合并配置信息
下一步是定义模块Context。这里首先需要定义一个ngx_http_module_t类型的结构体变量,命名规则为ngx_http_[module-name]_module_ctx,这个结构主要用于定义各个Hook函数。下面是echo模块的context结构:
?
下面是echo模块这个两个函数的代码:
?
create_loc_conf新建一个ngx_http_echo_loc_conf_t,分配内存,并初始化其中的数据,然后返回这个结构的指针;merge_loc_conf将父block域的配置信息合并到create_loc_conf新建的配置结构体中。
其中ngx_conf_merge_str_value不是一个函数,而是一个宏,其定义在core/ngx_conf_file.h中:
?
编写Handler
下面的工作是编写handler。handler可以说是模块中真正干活的代码,它主要有以下四项职责:读入模块配置。
处理功能业务。
产生HTTP header。
产生HTTP body。
下面先贴出echo模块的代码,然后通过分析代码的方式介绍如何实现这四步。这一块的代码比较复杂:
?
?
第一步是获取模块配置信息,这一块只要简单使用ngx_http_get_module_loc_conf就可以了。
第二步是功能逻辑,因为echo模块非常简单,只是简单输出一个字符串,所以这里没有功能逻辑代码。
第三步是设置response header。Header内容可以通过填充headers_out实现,我们这里只设置了Content-type和Content-length等基 本内容,ngx_http_headers_out_t定义了所有可以设置的HTTP Response Header信息:
?
设置好头信息后使用ngx_http_send_header就可以将头信息输出,ngx_http_send_header接受一个ngx_http_request_t类型的参数。
第四步也是最重要的一步是输出Response body。这里首先要了解Nginx的I/O机制,Nginx允许handler一次产生一组输出,可以产生多次,Nginx将输出组织成一个单链表结 构,链表中的每个节点是一个chain_t,定义在core/ngx_buf.h:
?
缓冲数据准备好后,用ngx_http_output_filter就可以输出了(会送到filter进行各种过滤处理)。 ngx_http_output_filter的第一个参数为ngx_http_request_t结构,第二个为输出链表的起始地址&out。 ngx_http_out_put_filter会遍历链表,输出所有数据。
以上就是handler的所有工作,请对照描述理解上面贴出的handler代码。
组合Nginx Module
上面完成了Nginx模块各种组件的开发下面就是将这些组合起来了。一个Nginx模块被定义为一个ngx_module_t结构,这个结构的字段很多,不过开头和结尾若干字段一般可以通过Nginx内置的宏去填充,下面是我们echo模块的模块主体定义:?
这样,整个echo模块就写好了,下面给出echo模块的完整代码:
?
Nginx模块的安装
Nginx不支持动态链接模块,所以安装模块需要将模块代码与Nginx源代码进行重新编译。安装模块的步骤如下:1、编写模块config文件,这个文件需要放在和模块源代码文件放在同一目录下。文件内容如下:
?
?
?
?
?
?
可以看到模块已经正常工作了,也可以在浏览器中打开网址,就可以看到结果:
更深入的学习
本文只是简要介绍了Nginx模块的开发过程,由于篇幅的原因,不能面面俱到。因为目前Nginx的学习资料很少,如果读者希望更深入学习 Nginx的原理及模块开发,那么阅读源代码是最好的办法。在Nginx源代码的core/下放有Nginx的核心代码,对理解Nginx的内部工作机制 非常有帮助,http/目录下有Nginx HTTP相关的实现,http/module下放有大量内置http模块,可供读者学习模块的开发,另外在http://wiki.nginx.org/3rdPartyModules上有大量优秀的第三方模块,也是非常好的学习资料。如有意见建议或疑问欢迎发送邮件至ericzhang.buaa@gmail.com。希望本文对您有所帮助!!!
参考文献
[1] Evan Miller, Emiller's Guide To Nginx Module Development. http://www.evanmiller.org/nginx-modules-guide.html, 2009[2] http://wiki.nginx.org/Configuration
[3] Clément Nedelcu, Nginx Http Server. Packt Publishing, 2010
相关文章推荐
- nginx 安装php
- Nginx停止、卸载、configure配置
- Google perf tools for nginx
- Nginx配置文件详细说明
- Nginx下载和编译安装
- 转 Nginx+FastCGI到底是谁影响超时时间
- windows nginx +php 配置
- nginx系列(八)nginx失效转移与超时处理
- nginx-apache服务器配置
- nginx学习(一)入门
- Nginx 关于 Rewrite 执行顺序详解
- 为Mac配置服务器nginx
- 使用Nginx、Nginx Plus抵御DDOS攻击
- keepalived+haproxy实现nginx与mysql负载均衡
- nginx配置文件详解
- 在Ubuntu上使用Nginx+uwsgi部署django
- LVS Nginx HAProxy 优缺点
- Nginx
- nginx + keepalived 双机热备
- nginx location 指令说明