`
russelltao
  • 浏览: 157718 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

nginx module开发5 (完结)

 
阅读更多

upstream机制

Nginx提供的upstream机制,是nginx设计理念的忠实体现。异步、无阻塞,这是nginx的追求,任何对这种设计思想的违反,都会导致nginx达不到它预期的性能,包括nginx提供的fastCGI也是如此。

Upstream到底用来干什么呢?就是nginx在正常的请求处理过程中,需要访问其他SERVER,这时,nginx提供了这样的机制,把底层的http通讯全部做完。最重要的是,upstream保证了在这个请求中对其他SERVER的通讯,完全是无阻塞和异步的。个人认为,如果nginx没有提供upstream,当开发者遇到这种情形要么自己写一套多路复用IO处理机制来做,要么放弃异步去调用connection里的同步方法,就不能称为真正的高性能异步WEB SERVER了。

Upstream实现得其实非常狭隘,因为nginx试图把upstream做成一种proxy,也就是说nginx会对其他SERVER访问后,对client的返回也接管,这个很恶心。如果你不需要这个功能,需要在ngx_http_upstream_process_header里,调用你的module处理response后就返回,不要继续向下执行。

Upstream有六个需要module developer实现的方法,分别是:

ngx_int_t(*create_request)(ngx_http_request_t *r);

ngx_int_t(*reinit_request)(ngx_http_request_t *r);

ngx_int_t(*process_header)(ngx_http_request_t *r);

void(*abort_request)(ngx_http_request_t *r);

void(*finalize_request)(ngx_http_request_t *r,

ngx_int_t rc);

ngx_int_t(*rewrite_redirect)(ngx_http_request_t *r,

ngx_table_elt_t *h, size_t prefix);

upstream在真正实现HTTP通讯时会调用到这些函数。那么upstream的是如何进行的?首先,我们需要调用ngx_http_upstream_init来开始upstream之旅了。

ngx_http_upstream_init首先会去调用create_request函数,这时开发者可以在这里把HTTP请求构造好。构造完请求包后,nginx会去连接remote server,这又是一个异步事件,所以需要注册回调函数为ngx_http_upstream_handler,也就是说,当连接成功建立后,nginxepoll会调用ngx_http_upstream_handler来处理建立好的这个连接,同时把发送HTTP请求的处理函数注册为ngx_http_upstream_send_request_handler

现在与remote server建立好连接了,ngx_http_upstream_handle调用ngx_http_upstream_send_request_handler来发送create_request完成的HTTP请求包了。这里实际完成发送请求任务的是ngx_http_upstream_send_request方法,而ngx_http_upstream_send_request又是调用ngx_output_chain来把请求发送出去。成功以后,开始等待读事件的来临,如果有数据返回,则调用ngx_http_upstream_process_header来处理remote serverresponse了,等到确认接收到完整的response后,会调用我们实现的process_header注册函数来处理responseupstream处理完后会调用注册的finalize_request函数来清理开发者需要做的工作。

内存使用

Nginx给用户提供了内存池功能,所以developer在使用时,应当尽量避免绕过nginx内存池来操作内存。

这里不去分析nginx内存池的实现,只简要的说明如何使用它。

申请一块内存时,必须先拿到内存池的指针,然后传入内存块大小,nginx实际上会移动指针指向内存池中的空闲内存,如果失败则返回NULL,内存池大小有限且可配,所以我们必须每次申请内存都要检查是否申请成功。

我们看下最简单的一个分配buf函数:

ngx_buf_t *

ngx_create_temp_buf(ngx_pool_t *pool, size_t size)

{

ngx_buf_t*b;

b =ngx_calloc_buf(pool);

if (b ==NULL) {

returnNULL;

}

b->start= ngx_palloc(pool, size);

if(b->start == NULL) {

returnNULL;

}

b->pos =b->start;

b->last= b->start;

b->end =b->last + size;

b->temporary = 1;

return b;

}

可以看到,很简单的从内存池中申请到,释放则由pool自动进行,很好的垃圾回收机制。

配置文件的使用

ngx_command_t中,定义好需要读取的配置项名称,以及处理该配置项的方法,这样就可以nginx.conf里放置相应的配置项,在module里使用。

例如:

nginx.conf里加入下行配置:

dmsargname dcname filesize blobid;

则需要在module里的ngx_command_t数组里分配如下:

{

ngx_string("dmsargname"),

NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LMT_CONF|NGX_CONF_TAKE1234,

ngx_read_dmsargname,

NGX_HTTP_LOC_CONF_OFFSET,

offsetof(ngx_webex_DMD_loc_conf_t,argnameFromDC),

NULL

},

实际的处理函数为ngx_read_dmsargnameNGX_CONF_TAKE1234意为最多读取四个参数。

读取参数函数简易实现:

static char * /* {{{ ngx_read_datastore */

ngx_read_dmsargname(ngx_conf_t *cf, ngx_command_t*cmd, void *conf)

{

ngx_http_core_loc_conf_t *clcf;

ngx_webex_DMD_loc_conf_t *ulcf = conf;

ngx_str_t *value;

value =cf->args->elts;

clcf =ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);

ulcf->argnameFromDC= value[1];

ulcf->argnameFilesize= value[2];

ulcf->argnameBlobID= value[3];

returnNGX_CONF_OK;

}

Nginx封装的常用数据结构

这个必须要说下,因为处理http请求时,必须处理head,无论是读取head还是插入head,都需要和ngx_list_t这个数据结构打交道,nginx框架是把head都放到ngx_list_theaders;数据结构里的。

list一共有三种操作:

ngx_list_create();//创建及初始化队列

ngx_list_init();//初始化队列

ngx_list_push();//找到下一个插入位置的指针并返回

很明显,设计者为了灵活性,没有提供遍历方法,那么首先,应该怎么遍历它?比如,拿到一个request后,最应该先分析head了。

画个图看看:

ngx_list_t

pool

nalloc

size

part

last

<!--[if gte vml 1]> <![endif]-->

ngx_list_part_s

nelts

elts

next

<!--[if gte vml 1]> <![endif]-->

ngx_table_elt_t

Key

Value

Hash

lowcase

图表 <!--[if supportFields]>SEQ 图表 /* ARABIC <![endif]-->5<!--[if supportFields]><![endif]-->-nginx封装的list结构

当然ngx_table_elt_t结构只是head里的ngx_list_t所用,实际上每个元素可以是任意类型,由elts指针所指。

ngx_list_t里的nallocsize,分别表示元素桶的数量和每个元素的大小,所以这里大家可以看出,该数据结构是定长内存组成的了吧。元素桶这个概念,大家可以理解为ngx_list_part_s结构,这个结构里可以保存多个元素,元素数量由nelts决定。每个元素是由ngx_list_part_s->elts指向的,长度为ngx_list_t->size

给段遍历list取得每个head的代码看看:

part =&r->upstream->headers_in.headers.part;

header= part->elts;

for (i= 0; /* void */; i++) {

if (i >= part->nelts) {

if (part->next == NULL) {

break;

}

part = part->next;

header = part->elts;

i = 0;

}

if(header[i].hash == 0) {

continue;

}

//header[i].key就是head的名字,header[i].value就是head的值了

}

总结

开发nginx module,可以非常灵活的实现自己需要的功能。很多时候我们需要修改源码才能实现自己的特定功能,比如,nginxthumbnail resize功能,不支持实时的对每一个请求按照指定的size来压缩,实际上在它的代码中完全可以做到,只需要稍微修改下源码而已。

又如upstreamnginx把它当足是个proxy机制,如果我们想让它只做为异步网络调用,也只需要在upstream_process_header里做些改动。

在需要某些特殊的功能时,我们最应该首先阅读nginx的源码,通常都会发现很多意想不到的收获。

Nginx的性能确实不错,对http协议的处理也很高效,在我们需要高性能webserver时,应该去优先考虑它。

分享到:
评论

相关推荐

    nginx module开发指南(中文版)

    ### Nginx Module 开发详解 #### 模块的角色与功能 Nginx 的模块扮演着不同的角色,这些角色共同确保了服务器能够高效且灵活地处理 HTTP 请求。 1. **Handlers** (处理器): 这些模块负责处理 HTTP 请求并构造响应...

    fastdfs-nginx-module_v1.16.tar.gz源码包,nginx支

    标题中的"fastdfs-nginx-module_v1.16.tar.gz"是一个开源项目,它是一个用于Nginx服务器的模块,旨在使Nginx能够与FastDFS文件存储系统无缝集成。FastDFS是一个轻量级的开源分布式文件系统,适用于互联网和企业内部...

    lua-nginx-module-0.10.13

    Lua-Nginx-Module由OpenResty团队开发,旨在提供一种轻量级、高效且易于使用的机制,使开发者能够在Nginx内部处理复杂的业务逻辑,如动态内容生成、流量控制、API网关等功能,从而避免了传统的CGI或FastCGI等模型...

    lua-nginx-module-master.zip

    总之,"lua-nginx-module-master.zip"包含的lua-nginx-module是将Lua语言的强大功能引入Nginx的关键,它为开发人员提供了一种灵活且高效的方式,以应对复杂的Web服务场景。正确理解和使用这个模块,可以显著提升...

    headers-more-nginx-module-0.34

    《headers_more_nginx_module_0.34:深入解析Nginx扩展模块的增强功能》 在Web服务器领域,Nginx以其高性能、高并发能力而广受赞誉。而headers_more_nginx_module作为Nginx的一个扩展模块,进一步提升了其在处理...

    redis2-nginx-module-0.15

    Redis2-NGINX-Module 是由 OpenResty 团队开发的,OpenResty 是一个基于 NGINX 的高性能 Web 和反向代理服务器,它包含了大量的 LuaJIT 脚本支持,能够进行动态编程。通过这个模块,开发者可以在 NGINX 配置中直接...

    echo-nginx-module-0.58.tar.gz

    而为了更好地优化和调试Nginx的配置,开发者们开发了一系列的模块,其中echo-nginx-module是其中之一。本文将详细解析echo-nginx-module的功能、使用场景以及如何配合Nginx进行调试。 一、echo-nginx-module概述 ...

    Nginx Module Extension

    通过上述分析,《Nginx Module Extension》这本书不仅深入介绍了Nginx的核心特性,还提供了详细的自定义模块开发指南。对于希望深入了解并充分利用Nginx强大功能的专业人士来说,这是一本非常有价值的参考资料。无论...

    echo-nginx-module-0.61.tar.gz

    echo-nginx-module是Nginx的一个扩展模块,由Philipp Kewisch(@agentzh)开发,它提供了一系列用于处理HTTP响应体的指令,极大地丰富了Nginx的输出处理能力。echo-nginx-module的主要目标是支持HTTP服务器内部的...

    lua-nginx-module-0.10.9rc7

    ngx_devel_kit(简称ndk)是一个用于开发Nginx模块的工具集,它提供了很多用于编写C语言扩展的便利函数。在0.10.9rc7这个版本中,可能需要特定的ndk版本才能确保所有功能正常运行。如果版本不匹配,可能会遇到如时间...

    fastdfs-nginx-module

    《FastDFS与Nginx整合:fastdfs-nginx-module详解》 FastDFS是一个开源的、高性能的、轻量级的分布式文件系统,主要用于解决大容量存储和负载均衡的问题。而Nginx则是一款功能强大的HTTP和反向代理服务器,常用于...

    headers-more-nginx-module-0.30.tar.gz

    标题中的"headers-more-nginx-module-0.30.tar.gz"是一个开源软件模块的压缩包,主要用于扩展Nginx服务器的功能。Nginx是一款高性能、轻量级的Web服务器/反向代理服务器,广泛应用于互联网服务。这个特定的模块,...

    nginx插件iconv

    1. **安装依赖**:首先确保系统已经安装了Nginx的开发库(通常包括`pcre-dev`、`openssl-dev`等)以及`libiconv`和其开发库`libiconv-dev`。 2. **获取源码**:下载`iconv-nginx-module`的源代码,这可能是一个Git...

    windows平台nginx编译nginx-http-flv-module

    5. **编译HTTP FLV Module**:将HTTP FLV Module的源代码添加到Nginx的源码树中,或者通过配置脚本指定其位置。 6. **编译和安装**:执行`make`和`make install`来编译Nginx及模块,并将其安装到指定的目录。 7. *...

    Nginx模块开发入门

    关于Nginx模块开发的学习资源相对较少,《Emiller's Guide To Nginx Module Development》是一篇经典的文章,但其中的部分内容可能因Nginx版本更新而不适用。因此,对于初学者而言,最好的学习方式是从官方文档开始...

    带nginx-rtmp-module模块的Nginx

    nginx-rtmp-module是一个由Arut开发的开源项目,它允许Nginx接收、处理和分发RTMP流,适用于直播服务的搭建。在Windows系统上编译Nginx并集成此模块,为Windows平台上的开发者和用户提供了一种便捷的实现实时流媒体...

    drizzle-nginx-module-master.zip_drizzle_keepalive_nginx_nginx my

    "drizzle-nginx-module"是Nginx的一个扩展,由Drizzle项目开发,主要目的是优化Nginx与MySQL之间的通信。Drizzle是一款轻量级的数据库管理系统,旨在提供高并发、低延迟的服务,与Nginx的特性相得益彰。这个模块引入...

    lua-nginx-module.zip

    5. 缓存机制:lua-nginx-module支持基于内存的缓存,可以提高高并发场景下的响应速度。 四、lua-nginx-module的使用 在使用lua-nginx-module时,我们需要在Nginx配置文件中引入该模块,并定义Lua脚本。例如,以下...

    nginx-rtmp-module

    Nginx-RTMP-Module 是由 Lavf57 开发的一个开源项目,其核心功能是添加对 RTMP 协议的支持,使得 Nginx 可以作为 RTMP 服务器接收来自编码器的音视频流,同时也可以将这些流推送到其他 RTMP 服务器或直接分发给...

Global site tag (gtag.js) - Google Analytics