点击这里给我发消息 点击这里给我发消息

Nginx系列教程:nginx_module_development模块开发

添加时间:2013-12-7
    相关阅读: 设计 开发 方案 网络 程序 平台

好像这是唯一的一份模块开发文档.. 以下简称 guide
读代码!!

nginx 程序启动

把 nginx.conf 读入内存
处理模块 ngx_http_module_t 定义的 configuration. 应该是如下的执行顺序
pre
create_main_conf
执行 ngx_command_t 里面定义的函数. 可以视为 init_main_conf 的自动处理部分
init_main_conf
...
postconfig
listen
fork 子进程(真正的服务器进程 master), 父进程退出
master 执行 setsid 脱离终端; getpid 写入 pid 文件; 启动 worker

Handlers, Filters

Handler. Handler 可以做的工作包括:
作为 handler-chain 的一部分, 返回 NGX_DECLINED 指示继续交给后继的 chain 运行.
现在 mod_passport 就仅仅是在这个机制上工作的
handler-chain 分成好几个 phases, 包括 NGX_HTTP_POST_READ_PHASE, NGX_HTTP_SERVER_REWRITE_PHASE, ... 参考 src/http/ngx_http_core_module.h
直接处理 request, 返回 response
Filter. 貌似 handler 的 phases 缺乏处理返回给客户端的内容的阶段. 于是这个任务就在 Filter 里面完成了
Header Filter
Body Filter
Upstream Handler, Load-Balancer

基本上需要用到这个来写模块的可能性就很小了

Upstream Handler. 从guide的翻译:"假设需要和后台服务器通信,比如 FastCGI, Memcached.. 那怎么才能避免网络 IO 阻塞 primary event loop 呢?这就要靠 Nginx 内置的 upstream 网络连接机制, 以及 hook 对应的 handler"
Load-Balancer. 咱们邮件中心应用这个机制的一种可能是把请求 dispatch 到后端的桶上去... 这样恐怕 Upstream 需要能配置为泛域名——因为如果每增加一个桶前面就改一次配置就太恶心了——或者自己实现一个 Upstream 连接机制
这里多说一句,只要架构准备好了,扩展其他业务就简单。比如 nginx 的 smtp/pop3/imap4 反向代理功能

内存池, 数据结构, 以及对应函数

忍不住要抱怨一下, 相比较于 apr, nginx 的内置数据结构及其函数简直太XXXX了, 这直接导致了编写 module 成为一件门槛很高的工作

常用函数的包装(也是为了跨平台编译, 甚至更好的性能), 见 src/core/ngx_string.h
ngx_memset
ngx_memzero
ngx_memcpy
...
资源池 pool, 见 src/core/ngx_palloc.c
ngx_palloc, 这个是最基本的malloc包装
ngx_calloc, 包装完 ngx_palloc 后再 memzero 一下
ngx_pool_cleanup_add, 正是因为这个功能的存在,pool 成为一个资源池而不仅仅是内存池. 调用 ngx_pool_cleanup_add 后返回一个指针 ptr, 然后设置 ptr->handler 为释放资源的函数就可以. 具体参考 ngx_destroy_pool 看看是怎么调用 handler 的
神秘的 temp_pool, 还没有搞清楚为什么许多数据结构里面除了 pool 外还提供了一个 temp_pool
ngx_str_t, 它提供了一个存储 binary string 的方案. 不过并没有提供 realloc 相关的运算(这样的话内存管理就复杂了)
在 log/sprintf 函数族输出的时候, 用 %V 来对应 ngx_str_t *, 以避免哪些没有 '\0' 结尾的字符串输出
ngx_array_t, 本质是一个栈表. 就我所观察, 它是所有复杂数据结构的基石, 好在不难理解.
提示:ngx_array_push 的用法和 ngx_pool_cleanup_add 类似, 也是先返回一个指针, 然后调用者再对这个指针做操作——而不是调用者先在外面把 insert/push 的数据准备好再传递进去. 从此可一窥 nginx 的编程风格.
ngx_list_t
提供一个单向链表, 链表的每个单元是一个固定大小的 array
这个东东比 ngx_array_t 有什么优势呢??array 每次都扩大内存都 double palloc 再 memcpy, ngx_list_t 效率上会好一些.
仍然是 ngx_list_push() 这样的风格
虽然效率高, 但 ngx_list_t 被使用的相比 ngx_array_t 就少多了, 大概和迭代算法写起来稍麻烦有关系.
src/core/ngx_hash.c
ngx_table_elt_t 是在 ngx_hash.h 里面定义的,也算一个常用的数据结构,但和 hash table 没有什么关系
首先是 ngx_hash_keys_arrays_t, 它几乎可以说是一个完备的 hash table
'keys' 成员就是当向里面添加 key/value 的时候, 依次 push 进去的 array
'keys_hash' 和 'hsize' 对应, 用来分布 hash, 在初始化的时候 palloc 好,以后就无法改变了.
ngx_hash_keys_array_init() 里面的 asize 就是初始化 hash table 的 'keys' array 大小.
ngx_hash_add_key() 用来放 key/value
这个数据结构只提供了 add 方法(甚至没有 set), 遍历之也还算简单, 就是没有快速的 get 的实现!!
虽然没有 get, 但 ngx_hash_add_key() 里的 ngx_hash_key_t *hk->key_hash 为接下来的操作埋下了伏笔
看起来 ngx_hash_t 才是真正可以 get(find) 的 hash_table
ngx_hash_t 好像不能一个一个的插入,只能从一个 array table 里面去初始化.
一个有趣的事实是,nginx 自己的模块里面,所有用 ngx_hash_keys_arrays_t 的地方,最后都把 'keys' 用ngx_hash_init() 初始化出一个 ngx_hash_t
(为什么 nginx 要这么设计 hash table 呢?难道和 wildcard 支持相关?没有继续深究了,现有的知识已经足够完成 mod_passport 的功能了)
ngx_rbtree 红黑树
ngx_radix_tree radix树用来放路由表这样的结构是比较好的... 看看代码, 果然是只在 geo_module 里面用到了这个结构
ngx_regex

咨询热线:020-85648757 85648755 85648616 0755-27912581 客服:020-85648756 0755-27912581 业务传真:020-32579052
广州市网景网络科技有限公司 Copyright◎2003-2008 Veelink.com. All Rights Reserved.
广州商务地址:广东省广州市黄埔大道中203号(海景园区)海景花园C栋501室
= 深圳商务地址:深圳市宝源路华丰宝源大厦606
研发中心:广东广州市天河软件园海景园区 粤ICP备05103322号 工商注册