NGINX模块开发

•Nginx是当前最流行的HTTP Server之一

•Nginx 模块主要有3 种角色:
–handlers(处理模块) 用于处理HTTP请求,然后产生输出
–filters(过滤模块) 过滤handler产生的输出 (“接力链表(CHAIN OF RESPONSIBILITY)”模型)
–load-balancers(负载均衡模块)当有多于一台的后端备选服务器时,选择一台转发HTTP请求

•一个nginx处理模块可以返回3种结果:正常、错误、或者放弃处理这个请求而让默认处理模块来处理

•nginx的配置文件:nginx.conf。在目录/usr/local/nginx/conf下。配置文件结构如下图:


•一个典型的处理周期:

->客户端发送HTTP 请求

->Nginx 根据配置选择一个合适的处理模块 

-> 负载均衡模块选择一台后端服务器,并负责完成后端的发送接收过程

-> 处理模块进行处理并把输出缓冲放到第一个过滤模块上

-> 第一个过滤模块处理后输出给第二个过滤模块

-> 然后第二个过滤模块又到第三个

-> 依此类推

-> 最后把回复发给客户端



•模块的调用事实上通过一系列的回调函数来实现,很多很多。名义上来说,你的函数可在以下时段执行某些功能:
•• 当服务读配置文件之前
•• 读存在location和 server 或其他任何部分的每一个配置指令
•• 当Nginx初始化全局部分的配置时
•• 当Nginx初始化主机部分(比如主机/端口)的配置时
•• 当Nginx将全局部分的配置与主机部分的配置合并的时候
•• 当Nginx初始化位置部分配置的时候
•• 当Nginx将其上层主机配置与位置部分配置合并的时候
•• 当Nginx的主(master)进程开始的时候
•• 当一个新的工作进程(worker)开始的时候
•• 当一个工作进程退出的时候
•• 当主进程退出的时候
•• 处理请求
•• 过滤回复的头部
•• 过滤回复的主体
•• 选择一台后端服务器
•• 初始化到后端服务器的请求
•• 重新初始化到后端的服务器的请求
•• 处理来自后端服务器的回复
•• 完成与后端服务器的交互

•核心模块的配置结构体:typedef struct {
•    ngx_array_t                servers;         /* ngx_http_core_srv_conf_t */
•    …
•    ngx_http_phase_t           phases[NGX_HTTP_LOG_PHASE + 1];
•}
•注意非常有用的是ngx_http_phase_t           phases[NGX_HTTP_LOG_PHASE + 1],这个函数数组里的函数会在请求处理的各个过程被调用,通过向里面添加自己的函数可以实现各种想要的功能,例如文件重定向,统计功能等。

一个hello world示例
•下面的这堆代码是一个hello world的nginxmodule.
首先进入nginx源码目录。在源码目录下创建一个新目录,hellomodule。
•[@nginxnginx-0.6.36]$ cd hellomodule/
[@nginx hellomodule]$ catconfig
ngx_addon_name=ngx_http_hello_module
HTTP_MODULES=”$HTTP_MODULESngx_http_hello_module”
NGX_ADDON_SRCS=”$NGX_ADDON_SRCS $ngx_addon_dir/ngx_http_hello_module.c”
[@nginx hellomodule]$catngx_http_hello_module.c
#include <ngx_config.h>
#include <ngx_core.h>
#include <ngx_http.h>
typedef struct {
ngx_flag_t flag;
} ngx_http_hello_conf_t;
•staticvoid ngx_http_hello_cleanup(void *data);
static void *ngx_http_hello_create_conf(ngx_conf_t *cf);
static char *ngx_http_hello_merge_conf(ngx_conf_t *cf, void *parent,
void *child);
static char *ngx_http_set_hello(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf);
static ngx_int_t ngx_http_hello_init(ngx_conf_t *cf);
•staticngx_command_t ngx_http_hello_commands[] = {
{ngx_string(”hello”),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
ngx_http_set_hello,
NGX_HTTP_LOC_CONF_OFFSET,
0,
NULL },
•ngx_null_command
};
•staticngx_http_module_t ngx_http_hello_module_ctx = {
NULL, /* preconfiguration */
ngx_http_hello_init, /*
postconfiguration */
NULL, /* create main configuration */
NULL, /* init main configuration */
NULL, /* create server configuration */
NULL, /* merge server configuration */
ngx_http_hello_create_conf, /* create location configration*/
ngx_http_hello_merge_conf /* merge location configration*/
};
ngx_module_t ngx_http_hello_module = {
NGX_MODULE_V1,
&ngx_http_hello_module_ctx, /* module context*/
ngx_http_hello_commands, /* module directives */
NGX_HTTP_MODULE, /* module type */
NULL, /* init master */
NULL, /* init module */
NULL, /* init process */
NULL, /* init thread */
NULL, /* exit thread */
NULL, /* exit process */
NULL, /* exit master */
NGX_MODULE_V1_PADDING
};
•staticngx_int_t
ngx_http_hello_handler(ngx_http_request_t *r)
{
ngx_buf_t *b;
ngx_int_t rc;
ngx_chain_t out;
•u_charhello[] = “hello, world\n”;
int len = strlen((char *)hello);
•b= ngx_pcalloc(r->pool, sizeof(ngx_buf_t));
if (b == NULL) {
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
•out.buf= b;
out.next = NULL;
b->pos = hello;
b->last = hello + len;
b->memory = 1;
b->last_buf = 1;
r->headers_out.status = NGX_HTTP_OK;
r->headers_out.content_length_n = len;
rc = ngx_http_send_header(r);
if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) {
return rc;
}
•returnngx_http_output_filter(r, &out);
}
static char *
ngx_http_set_hello(ngx_conf_t *cf, ngx_command_t *cmd, void*conf)
{
ngx_http_core_loc_conf_t *clcf;
•clcf= ngx_http_conf_get_module_loc_conf(cf,ngx_http_core_module);
clcf->handler = ngx_http_hello_handler;
•returnNGX_CONF_OK;
}
static void *
ngx_http_hello_create_conf(ngx_conf_t *cf)
{
ngx_http_hello_conf_t *conf;
•conf= ngx_pcalloc(cf->pool, sizeof(ngx_http_hello_conf_t));
if (conf == NULL) {
return NGX_CONF_ERROR;
}
/*
* set by ngx_pcalloc():
*
* conf->shm_zone = NULL;
* conf->conn = 0;
*/
•returnconf;
}
static char *
ngx_http_hello_merge_conf(ngx_conf_t *cf, void *parent, void*child)
{
ngx_http_hello_conf_t *prev = parent;
ngx_http_hello_conf_t *conf = child;
•if(conf->flag == 0) {
*conf = *prev;
}
•returnNGX_CONF_OK;
}
static ngx_int_t
ngx_http_hello_init(ngx_conf_t *cf)
{
return NGX_OK;
}
•[@nginxhellomodule]$ cd ..
[@nginx nginx-0.6.36]$ ./configure --add-module=./hellomodule/  --without-http_rewrite_module
并在nginx源码目录下执行make & make install
之后在config目录里的nginx.conf中添加
location = /hello{
hello on;
}
进入/usr/local/nginx/sbin执行./nginx即可启动nginx服务器
这样,启动nginx后, 访问http://ip:port/hello就可以看见hello,world了.
•hello world 的处理过程:

•负载均衡模块:决定哪个后端服务器可以分到特定的请求
•一个负载均衡模块有以下六个方面:
•1.激活配置指令需要调用一个注册函数registration function(比如:hash)
•2.注册函数定义合法的服务器选项(比如:weight=),同时注册上游主机初
•始化函数upstream initialization function
•3.上游主机初始化函数在配置确认好以后被调用:
•a)解析服务器名称,指向特定的IP 地址
•b)为每个socket 分配空间
•c)设定同伴初始化函数peer initialization function 的回调入口
•4.同伴初始化函数在每个请求来临的时候调用一次,设置一个负载均衡函数
•可以进入和操作的数据结构体。
•5.负载均衡函数load-balancing function 决定这个请求的去向;在客户端请求
•来时至少被调用一次(如果后端服务器回复失败,可能要更多次数)。这里
•发生的东西很有趣。
•6.最后,在和特定的后端服务器结束通信的时候,同伴释放函数peer release
•function会更新统计(通信是否成功或失败)。


•编译命令:Makeclean
•./configure--add-module=./hellomodule --without-http_rewrite_module
•Make&& make install
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

noodle_bear

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值