一、概述

架构

nginx在启动后,在unix系统中会以daemon的方式在后台运行,后台进程包含一个master进程和多个worker进程。我们也可以手动地关掉后台模式,让nginx在前台运行,nginx是以多进程的方式来工作的,当然nginx也是支持多线程的方式的,只是我们主流的方式还是多进程的方式。

nginx在启动后,会有一个master进程和多个worker进程。master进程主要用来管理worker进程,包含:接收来自外界的信号,向各worker进程发送信号,监控worker进程的运行状态,当worker进程退出后(异常情况下),会自动重新启动新的worker进程。而基本的网络事件,则是放在worker进程中来处理了。多个worker进程之间是对等的,他们同等竞争来自客户端的请求,各进程互相之间是独立的。一个请求,只可能在一个worker进程中处理,一个worker进程,不可能处理其它进程的请求。worker进程的个数是可以设置的,一般我们会设置与机器cpu核数一致,这里面的原因与nginx的进程模型以及事件处理模型是分不开的。nginx的进程模型,可以由下图来表示:

基本概念

connection

在nginx中connection就是对tcp连接的封装,其中包括连接的socket,读事件,写事件。利用nginx封装的connection,我们可以很方便的使用nginx来处理与连接相关的事情,比如,建立连接,发送与接受数据等。而nginx中的http请求的处理就是建立在connection之上的,所以nginx不仅可以作为一个web服务器,也可以作为邮件服务器。当然,利用nginx提供的connection,我们可以与任何后端服务打交道。

在nginx中,每个进程会有一个连接数的最大上限,这个上限与系统对fd的限制不一样。在操作系统中,通过ulimit -n,我们可以得到一个进程所能够打开的fd的最大数,即nofile,因为每个socket连接会占用掉一个fd,所以这也会限制我们进程的最大连接数,当然也会直接影响到我们程序所能支持的最大并发数,当fd用完后,再创建socket时,就会失败。不过,这里我要说的nginx对连接数的限制,与nofile没有直接关系,可以大于nofile,也可以小于nofile。nginx通过设置worker_connectons来设置每个进程可使用的连接最大值。nginx在实现时,是通过一个连接池来管理的,每个worker进程都有一个独立的连接池,连接池的大小是worker_connections。这里的连接池里面保存的其实不是真实的连接,它只是一个worker_connections大小的一个ngx_connection_t结构的数组。并且,nginx会通过一个链表free_connections来保存所有的空闲ngx_connection_t,每次获取一个连接时,就从空闲连接链表中获取一个,用完后,再放回空闲连接链表里面。

一个nginx能建立的最大连接数,应该是worker_connections * worker_processes。这里说的是最大连接数,对于HTTP请求本地资源来说,能够支持的最大并发数量是worker_connections * worker_processes,而如果是HTTP作为反向代理来说,最大并发数量应该是worker_connections * worker_processes/2。因为作为反向代理服务器,每个并发会建立与客户端的连接和与后端服务的连接,会占用两个连接。

request

request具体到nginx中的数据结构是ngx_http_request_t。ngx_http_request_t是对一个http请求的封装。以下为nginx一个http请求的生命周期图:

Nginx指令

nginx的配置系统由一个主配置文件和其他一些辅助的配置文件构成。这些配置文件均是纯文本文件,全部位于nginx安装目录下的conf目录下。配置文件中以#开始的行,或者是前面有若干空格或者TAB,然后再跟#的行,都被认为是注释,也就是只对编辑查看文件的用户有意义,程序在读取这些注释行的时候,其实际的内容是被忽略的。在nginx.conf中,包含若干配置项。每个配置项由配置指令和指令参数2个部分构成。指令参数也就是配置指令对应的配置值。

配置指令是一个字符串,可以用单引号或者双引号括起来,也可以不括。但是如果配置指令包含空格,一定要引起来。指令的参数使用一个或者多个空格或者TAB字符与指令分开。指令的参数有一个或者多个TOKEN串组成。TOKEN串之间由空格或者TAB键分隔。TOKEN串分为简单字符串或者是复合配置块。复合配置块即是由大括号括起来的一堆内容。一个复合配置块中可能包含若干其他的配置指令。

如果一个配置指令的参数全部由简单字符串构成,也就是不包含复合配置块,那么我们就说这个配置指令是一个简单配置项,否则称之为复杂配置项。例如下面这个是一个简单配置项:

error_page   500 502 503 504  /50x.html;

对于简单配置,配置项的结尾使用分号结束。对于复杂配置项,包含多个TOKEN串的,一般都是简单TOKEN串放在前面,复合配置块一般位于最后,而且其结尾,并不需要再添加分号。例如下面这个复杂配置项

location / {
    root   /home/jizhao/nginx-book/build/html;
    index  index.html index.htm;
}

Nginx模块概述

nginx的内部结构是由核心部分和一系列的功能模块所组成。这样划分是为了使得每个模块的功能相对简单,便于开发,同时也便于对系统进行功能扩展。nginx将各功能模块组织成一条链,当有请求到达的时候,请求依次经过这条链上的部分或者全部模块,进行处理。每个模块实现特定的功能。例如,实现对请求解压缩的模块,实现SSI的模块,实现与上游服务器进行通讯的模块。

模块分类

nginx的模块根据其功能基本上可以分为以下几种类型:

event module: 搭建了独立于操作系统的事件处理机制的框架,及提供了各具体事件的处理。包括ngx_events_module, ngx_event_core_module和ngx_epoll_module等。nginx具体使用何种事件处理模块,这依赖于具体的操作系统和编译选项。

phase handler: 此类型的模块也被直接称为handler模块。主要负责处理客户端请求并产生待响应内容,比如ngx_http_static_module模块,负责客户端的静态页面请求处理并将对应的磁盘文件准备为响应内容输出。

output filter: 也称为filter模块,主要是负责对输出的内容进行处理,可以对输出进行修改。例如,可以实现对输出的所有html页面增加预定义的footbar一类的工作,或者对输出的图片的URL进行替换之类的工作。

upstream: upstream模块实现反向代理的功能,将真正的请求转发到后端服务器上,并从后端服务器上读取响应,发回客户端。upstream模块是一种特殊的handler,只不过响应内容不是真正有自己产生的,而是从后端服务器上读取的。

load-balancer: 负载均衡模块,实现特定的算法,在众多的后端服务器中,选择一个服务器出来作为某个请求的转发服务器。

handler模块

Handler模块就是接受来自客户端的请求并产生输出的模块,目前第三方开发模块最可能开发的就是三种类型的模块,即handler,filter和load-balancer。

二、OpenResty介绍及安装

OpenResty介绍

OpenResty (也称为 ngx_openresty)是一个全功能的 Web 应用服务器,它打包了标准的 Nginx 核心,很多的常用的第三方模块,以及它们的大多数依赖项。OpenResty 通过汇聚各种设计精良的 Nginx 模块。从而将 Nginx 有效的变成一个强大的 Web 应用服务器,这样, Web 开发人员可以使用 Lua 脚本语言调动 Nginx 支持的各种C以及Lua 模块。 OpenResty 的目标是让你的Web服务直接跑在 Nginx 服务内部,充分利用 Nginx 的非阻塞 I/O 模型,不仅仅对 HTTP 客户端请求,甚至于对远程后端诸如MySQL,PostgreSQL, Memcache 以及 ~Redis 等都进行一致的高性能响应。

OpenResty安装

1、下载OpenResty http://openresty.org/download/ngx_openresty-1.4.2.8.tar.gz

2、解压openresty   gunzip -c ngx_openresty-1.4.2.8.tar.gz | tar xvf -

3、./configure \
  --prefix=/home/spdev/nginx/openresty/local \
  --sbin-path=/home/spdev/nginx/openresty/sbin \
  --user=spdev\
  --group=spd\
  --with-debug \
  --with-http_dav_module \
  --with-http_ssl_module \
  --with-http_stub_status_module \
  --with-http_addition_module \
  --with-http_flv_module \
  --without-http_memcached_module \
  --without-http_redis2_module \
  --without-http_redis_module  \
  --without-lua_redis_parser  \
  --without-mail_pop3_module \
  --without-mail_imap_module \
  --without-mail_smtp_module \
  
  make
  make install

 其中--with是自定义安装需要模块,--without是不安装默认安装的模块。

第三方模块安装

1、服务器新建目录如:/home/spdev/nginx/tb_module
  
2、下载第三方模块,如淘宝合并js模块
(svn checkout http://code.taobao.org/svn/nginx_concat_module/trunk/ 
 $NGINX_CONCAT_MODULE)。

3、./configure 中增加参数,--add-module=$NGINX_CONCAT_MODULE

./configure \
  --prefix=/home/spdev/nginx/openresty/local \
  --sbin-path=/home/spdev/nginx/openresty/sbin \
  --user=spdev\
  --group=spd\
  --with-debug \
  --with-http_dav_module \
  --with-http_ssl_module \
  --with-http_stub_status_module \
  --with-http_addition_module \
  --with-http_flv_module \
  --without-http_memcached_module \
  --without-http_redis2_module \
  --without-http_redis_module  \
  --without-lua_redis_parser  \
  --without-mail_pop3_module \
  --without-mail_imap_module \
  --without-mail_smtp_module \
  --add-module=/home/spdev/nginx/tb_module/$NGINX_CONCAT_MODULE \

4、make make install

三、Nginx简单命令

Nginx默认配置文件nginx.conf位于nginx安装目录conf目录下,执行命令需切换至对应目录。

nginx    启动Nginx
nginx -c </path/to/config>  Nginx 指定一个配置文件,来代替缺省的。
nginx -t 不运行,仅仅测试配置文件语法的正确性。
nginx -v 显示 nginx 的版本。
nginx -V 显示 nginx 的版本,编译器版本和配置参数。 
nginx -s reload 更改了配置后无需重启Nginx,平滑重启。
nginx -s stop  停止Nginx