分类: LINUX
2012-03-16 15:39:24
(别人写的 真的很难懂)
HTTP相关的Module都在 src/http 目录和其子目录下, 其中 src/http 下的文件为http模块的核心文件, src/http/modules 下的文件为http模块的扩展模块。
其中:
ngx_http.[c|h]
ngx_http.c 中,注册了 http 这个指令的处理模块,对应ngx_http_block函数
这个函数里面会进行一些conf资源分配/Merge,配置文件解析等工作。 这里面有个一比较重要的工作是注册了nginx http 的 phase handler
phase handler的类型在 ngx_http_core_module 这里定义:
每一个phase的handlers 都是一个数组,里面可以包含多个元素,通过 ngx_array_push 添加新的handler
其中每个phase的处理大都包含了对ngx_request_t 的 write 或者 read event的改写,其中
在 ngx_http_core_content_phase 里面, 有对location handler的调用, 其中的 r->content_handler 就是运行时刻从location handler中注册的,
其中, 在各个phase的结束阶段,一般都是调用
移动request 中 phase_handler的指针,并且示意主程序继续进行。
这里,无论是phase handler,还是 location handler,我们都是可以在程序里进行注册的。
另 外, ngx_http_block 里面调用了 ngx_http_optimize_servers ,这个函数对listening和connection相关的变量进行了初始化和调优,并最终在 ngx_http_add_listening (被ngx_http_add_listening调用) 中注册了listening 的 handler 为 ngx_http_init_connection
这里面,ngx_http_init_connection 注册了connection事件的读操作的回叫函数, 并将写操作设置为空函数
当
新的连接进入的时候,就执行到 ngx_http_init_request, 开始对后面的流程进行处理,主要是将rev的handler
设置为ngx_http_process_request_line , 然后ngx_http_process_request_line
会先后有调度到 ngx_http_process_request_headers 和 ngx_http_process_request
函数对读取过来的event进行处理,其中, ngx_http_process_request_headers
里面会对http的请求头进行解析,ngx_http_process_request 设置event handler
到ngx_http_request_handler ,ngx_http_request_handler
中会根据事件可能是读取还是写入的操作分别调用 request 的 read_event_handler 和
write_event_handler ,所以后续程序对 request 的 [read/write]event_handler 调整 本质上类似对 rev 和 wev的handler的调整,只是回叫函数的参数变更为了 ngx_request_t 而不是之前的ngx_event_t
根据上面代码可以看出, 模块开始使用 ngx_http_block_reading 这个handler对后续的读请求进行处理
在注册完事件后, ngx_http_process_request 会分别调用下面的两个函数
其中, ngx_http_handler 在ngx_http_core_module中定义,处理程序的主请求, ngx_http_run_posted_requests 在ngx_http_request.c 里定义,处理所有提交的子请求数据的输出。
ngx_http_core_module.[c|h]对于 ngx_http_core_module 是http 模块中比较重要的模块, 他本身是一个 NGX_HTTP_MODULE (不同于ngx_http_module, ngx_http_module本质上是一个 NGX_CORE_MODULE
这里面对http block下面的一些指令进行了处理, 比如 server, location 等, 同时, 上面提到的 ngx_http_handler 也在这里面
ngx_http_handler 所作的最核心的工作就是在最后调用 并将 write event 设置为 ngx_http_core_run_phases, 开始依次处理各个阶段的 handler
当handler处理完成后,http的处理流程也就基本上完成了..
run_phases 的过程实际上非常简单, 一次的运行每一个handler, 当任意一个handler返回ok或者所有handler执行完成后,整个流程结束。
这 里需要注意的是, ph的下标变化是根据 r->phase_handler 变量决定的, 所以在每个handler内部,如果想要让主程序继续处理下一个 handler,需要手动的 r->phase_handler++ ,将phase handler数组的下标转移到下一个成员。
关于subrequest在 ngx_http_core_module 里面,我们可以看到一些subrequest的函数,根据evan miller 的文章,我们知道 subrequest是在主请求的基础上发起的子请求,subrequest返回的内容会被附加到自请求上面,他的实现方法就是调用 ngx_http_subrequest 函数,subrequest函数的原形是
在里面,在这个函数里,他会1)创建新的request变量,根据 主request的值去填充这个变量2)注册新的变量的write event handler
3) 并且把subrequet 的request 注册到主request的 posted_requests 变量里
也就是说,一但调用了 ngx_http_subrequest 只后,subrequest已经已经注册到了nginx的事件循环中,和主循环并行进行处理,所以根据evan miller的文章里我们也可以看到,subrequest的串行处理是比较困难的。
关于 internal redirectnginx 的 internal redirect 有两种方式, 一个是调用 ngx_http_internal_redirect 命令, 一个是使用 X-Accel-Redirect 头,其中X-Accel-Redirect 头是交由upstream模块进行的, 在ngx_http_upstream_process_headers函数中,我们可以看到
也就是说,本质上,这两种方法都是通过 ngx_http_internal_redirect 的函数实现的,而ngx_http_internal_redirect 函数又做了些什么呢?
可以看到,其实它只是简单的修改request结构体,并通过 ngx_http_handler 重新进行http处理流程而已。
关 于internal redirect 和 subrequest,他们有类似的地方,都是在最后调用 ngx_http_handler 重新开始对request的处理,但是不同的地方我想主要是 subrequest会新建立一个request结构,原来的request处理并不会结束,而 internal redirect会结束当前的请求处理,使用嗯但前的request结构体来发起请求。
关于upstreamupstream 是nginx里面非常重要的一种处理模式,nginx的很多模块都是使用他来完成的, upstream和普通的handler有很大的不同,比如nginx的location handler 和phase handler, 他们的处理模式非常类似apache的handler,就是获取后同步的进行处理,但是对于有些场合,比如proxy或者fastcgi, nginx进程需要和上游的服务(http,或者php-cgi)进行交互,并且将结果返回给客户端,在交互的过程中,由于后端服务的响应时间各异,如果 后端服务的响应时间过长,nginx等待后端服务响应的过程一之同步阻塞在这里是不现实的,所以nginx采用了异步的方案,每当上游服务器有响应的时候 才进行处理,并将处理结果返回给前端,这样nginx在处理上游请求的时候,可以同时注册多个io时间,使用epoll_wait(linux下默认) 也就是nginx的主事件循环进行处理,大大提高了nginx的并发能里,每个进程可以处理多个连接 ,不会因为一个上游连接阻塞整个nginx进程, 当然这也有依赖于你程序的实现方式。
关于upstream的使用方式, evan miller的文章里已经说的很清楚了,就是可以在location handler里(或者其它插入点中) 注册upstream的一些callback
并 且最后在调用 ngx_http_read_client_request_body 中传入 ngx_http_upstream_init 作为callback function 参数初始化 upstream流程, 在 ngx_http_upsteam_init 里面,会调用 ngx_http_upstream_connect建立连接,并注册读写的event handler
这 里需要注意的是,在处理上游请求的时候,由于是异步的事件,所以每次上游服务器在调用callback的时候并不一定返回的是全部数 据,process_header 函数必须根据判断每次返回的数据包是否完成,如果没有处理完成则返回 NGX_AGAIN,来指示nginx需要重新进入process_header函数进行处理,并知道处理完成的时候返回NGX_OK 来指示nginx完成处理。 具体的例子可以参考 fastcgi 模块的ngx_http_fastcgi_process_header函数
另外, nginx可以针对上游服务的响应body进行处理, 通过注册 u->pipe->input_filter 这个回叫来实现,同样可以参考fastcgi模块,下面是例子
通常在处理的过程中需要自己创建状态机来处理请求的不同状态,对于一些请求相关的信息,可以自己创建结构体,通过