一直在努力
分类: 系统运维
2012-05-19 21:34:39
今天开始正式学习nginx的第三方模块,已经从网上四面八方搜集很多资料,已经大概了解nginx简单的模块开发过程。这里将会记录自己独立学习的过程。
入门级经典型文章首推。文中将nginx对比蝙蝠侠,蝙蝠侠的利器是腰带,nginx的利器则是module chain。当Nginx需要响应请求时,将会查找需要工作的module,去执行正确的请求过程。nginx通过http请求解析选择正确的处理模块,Nginx与Memcache或者FastCGI server进行通信,作用就像是对讲机。
学习nginx首先需要首席nginx的配置文件,在nginx源码下面的conf文件夹下的nginx.conf即为全局的配置文件。
下面是一个Nginx配置文件的实例:
nginx配置文件实例
其中核心的部分为http部分,nginx的配置文件是以block为单位的,配置文件的结构如图所示。其中最主要的部分是http、server、location,其中http可以包含多个server,而server可以包含location,最外层的是main,包含整个nginx的全局配置。一般来讲,server block表示一台处理请求的host,而location用户处理子请求,这两个block是nginx模块开发的核心。
每个block内部的即{}之间的内容,结构是 指令和参数,如
location / {
root html;
index index.html index.htm;
}
root为执行的指令,携带的参数是html;index也是同样的。对于指定的定义,在以后的内容中会详细讲解,其实也是非常简单的。如图中的嵌套关系,main block中指令可以被其他的block使用,server的指令可以被他内部的location所使用。因此可以看成是上下文的关系,也称为context。还有一个特殊的block,upstream这部分内容,之后再学习补充。这里需要了解,upstream的指令可以被他所包含的后端处理服务器所使用。
main与event是必须的,main主要用于配置错误日志,进程,权限等等;event主要配置epoll、kqueue、select、poll等等。
nginx标准的HTTP模块,除非在nginx编译时标注模块是不可用的,否则以下模块都是默认加入到了Nginx中。
官方的wiki中详细的列出了自动编译进去的http模块和可选的http模块
Nginx模块有三个重要的角色
Modules事实上是真正工作的:当nginx处理文件或代理一个请求发送到后端服务器,都是有handler模块工作的;当Nginx发送文件或者转发请求到其他服务器,有handler为其服务;当需要Nginx把输出压缩或者在服务端加一些东西,可以用filter;还有一些Nginx的核心模块主要负责管理网络层和应用层协议,以及针对特定应用的一系列模块。Nginx集中式的体系结构让你可以随心所欲地实现一些功能强大的内部单元。
Nginx的模块不像apache一样可以动态添加,需要重新编译,将模块添加到nginx中。
当server启动时,每个handler都有attach到特定的位置,如果多个handler添加到同一个特定的位置,那么只有一个可以获胜,即当配置文件中存在冲突时,只有一个location可以起到作用。Handler的返回分为3中方式:正常、错误、拒绝处理请求使用默认handler处理。
如果handler作为反响代理到一系列后端的server,那么就需要load-banlancer,load-balancer获取请求从后端server中选却处理请求的server。Nginx有两种负载均衡的方式:轮询,即将后端server轮流处理nginx获取到的请求;一种是IP 哈希方法,根据client的IP地址进行哈希选择处理请求的server,这样能够保证client的请求能够由同一个server进行请求处理。
如果handler处理完成没有产生error,那么filter将会被调用。每个location都使用了多钩子到多个filter中,这样能够保证响应能够进行压缩和愤慨。filter的执行顺序在编译的时候就已经确定了。Filter使用的典型“chain of responsibility”设计模式:即按顺序进行,一个filter被调用,工作完成后调用下一个filter直到所有的filter都调用完成,那么nginx才完成了响应。
filterchain并不需要等待之前的filter完全完成,而是可以直接使用前一个filter的输出,类似于unix的pipeline。Filters使用buffer是通常设置page为4KB,可以通过修改nginx.conf修改这个值。这种方法的例子如,模块负责处理后端server发送给client的响应,需要模块压缩,那么在模块接收所有的响应之前,就可以使用已经接收到响应压缩并发送给client。而不用等待所有的响应接收完成。
综上所述,典型的处理流程是:
客户端发送 HTTP 请求 ->Nginx 根据配置选择一个合适的handler - > (如果有load-banlancer负载均衡模块选择一台后端服务器,并负责完成后端的发送接收过程 - >)handler进行处理并把输出缓冲放到第一个filter上 - > 第一个filter处理后输出给第二个filter - > 然后第二个filter又到第三个 - > 依此类推 - > 最后把回复发给客户端。
之所以称这个过程为典型,是因为nginx的模块具有很大的可自定义性,模块的编写者有很大的空间去精确的定义怎样执行一个模块,什么时候执行这个模块。模块的调用实际上是由很多的回调(callback)来实现的。这样的回调非常的多,模块的编写者可以自定义回调的函数,这些回调函数执行的时间如下“
这些都是使用函数回调来处理。