【笔记】nginx学习–模块

Posted on Posted in 计算机2,165 views

一、准备

1、源码获取:http://nginx.org/en/download.html

2、源码浏览:https://trac.nginx.org/nginx/browser/nginx?order=name

3、官方文档:http://nginx.org/en/docs/

二、源码编译

此部分为自己编译过程记录

1、源码目录结构    

    从官网下载 nginx-1.10.2 源码后,其目录结构如下:

.
├── auto             自动检测系统环境以及编译相关的脚本
│   ├── cc          关于编译器相关的编译选项的检测脚本
│   ├── lib          nginx编译所需要的一些库的检测脚本
│   ├── os          与平台相关的一些系统参数与系统调用相关的检测
│   └── types         与数据类型相关的一些辅助脚本
├── conf             存放默认配置文件,在make install后,会拷贝到安装目录中去
├── contrib            存放一些实用工具,如geo配置生成工具(geo2nginx.pl)
├── html             存放默认的网页文件,在make install后,会拷贝到安装目录中去
├── man              nginx的man手册
└── src              存放nginx的源代码
    ├── core         nginx的核心源代码,包括常用数据结构的定义,以及nginx初始化运行的核心代码如main函数
    ├── event         对系统事件处理机制的封装,以及定时器的实现相关代码
    │   └── modules    不同事件处理方式的模块化,如select、poll、epoll、kqueue等
    ├── http         nginx作为http服务器相关的代码
    │   └── modules    包含http的各种功能模块
    ├── mail         nginx作为邮件代理服务器相关的代码
    ├── misc         一些辅助代码,测试c++头的兼容性,以及对google_perftools的支持
    └── os          主要是对各种不同体系统结构所提供的系统函数的封装,对外提供统一的系统调用接口

2、依赖库下载

    A、PCRE库:为了重写rewrite

        下载并解压:ftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre/pcre-8.38.tar.bz2

    B、zlib库:为了gzip压缩

        下载并解压:http://zlib.net/zlib-1.2.8.tar.gz

    为了方便,我在nginx目录下新建了一个库目录“external”,并将两个库解压到该目录,注意不用手动配置和编译,这些由nginx完成。

3、配置

    主要的配置可选命令如下:

--prefix=path
#定义一个目录,存放服务器上的文件,也就是nginx的安装目录。默认使用/usr/local/nginx。
--sbin-path=path
#设置nginx的可执行文件的路径,默认为prefix/sbin/nginx.
--conf-path=path
#置在nginx.conf配置文件的路径。nginx允许使用不同的配置文件启动,通过命令行中的-c选项。默认为prefix/conf/nginx.conf.
--pid-path=path
#设置nginx.pid文件,将存储的主进程的进程号。安装完成后,可以随时改变的文件名,在nginx.conf配置文件中使用PID指令。默认情况下,文件名为prefix/logs/nginx.pid.
--error-log-path=path
#设置主错误,警告,和诊断文件的名称。安装完成后,可以随时改变的文件名,在nginx.conf配置文件中使用的error_log指令。默认情况下,文件名为prefix/logs/error.log.
--http-log-path=path
#设置主请求的HTTP服务器的日志文件的名称。安装完成后,可以随时改变的文件名,在nginx.conf配置文件中使用的access_log指令。默认情况下,文件名为prefix/logs/access.log.
--user=name
#设置nginx工作进程的用户。安装完成后,可以随时更改的名称在nginx.conf配置文件中使用的user指令。默认的用户名是nobody。
--group=name
#设置nginx工作进程的用户组。安装完成后,可以随时更改的名称在nginx.conf配置文件中使用的user指令。默认的为非特权用户。
--with-select_module
--without-select_module
#启用或禁用构建一个模块来允许服务器使用select()方法。该模块将自动建立,如果平台不支持的kqueue,epoll,rtsig或/dev/poll。
--with-poll_module
--without-poll_module
#启用或禁用构建一个模块来允许服务器使用poll()方法。该模块将自动建立,如果平台不支持的kqueue,epoll,rtsig或/dev/poll。
--without-http_gzip_module
#不编译压缩的HTTP服务器的响应模块。编译并运行此模块需要zlib库。
--without-http_rewrite_module
#不编译重写模块。编译并运行此模块需要PCRE库支持。
--without-http_proxy_module
#不编译http_proxy模块。
--with-http_ssl_module
#使用https协议模块。默认情况下,该模块没有被构建。建立并运行此模块的OpenSSL库是必需的。
--with-pcre=path
#设置PCRE库的源码路径。PCRE库的源码(版本4.4-8.30)需要从PCRE网站下载并解压。其余的工作是Nginx的./configure和make来完成。正则表达式使用在location指令和ngx_http_rewrite_module模块中。
--with-pcre-jit
#编译PCRE包含“just-in-timecompilation”(1.1.12中,pcre_jit指令)。
--with-zlib=path
#设置的zlib库的源码路径。要下载从zlib(版本1.1.3-1.2.5)的并解压。其余的工作是Nginx的./configure和make完成。ngx_http_gzip_module模块需要使用zlib。
--with-cc-opt=parameters
#设置额外的参数将被添加到CFLAGS变量。例如,当你在FreeBSD上使用PCRE库时需要使用:--with-cc-opt="-I/usr/local/include。.如需要需要增加select()支持的文件数量:--with-cc-opt="-DFD_SETSIZE=2048".
--with-ld-opt=parameters
#设置附加的参数,将用于在链接期间。例如,当在FreeBSD下使用该系统的PCRE库,应指定:--with-ld-opt="-L/usr/local/lib".

    本次配置如下:

./configure \
    --prefix=/home/xiaoxia/biye/nginx/server/ \
    --with-http_ssl_module \
    --with-http_dav_module \
    --with-http_flv_module \
    --with-http_realip_module \
    --with-http_gzip_static_module \
    --with-http_stub_status_module \
    --with-mail \
    --with-mail_ssl_module \
    --with-pcre=./external/pcre-8.38 \
    --with-zlib=./external/zlib-1.2.8 \
    --with-debug \
    --http-client-body-temp-path=/var/tmp/nginx/client \
    --http-proxy-temp-path=/var/tmp/nginx/proxy \
    --http-fastcgi-temp-path=/var/tmp/nginx/fastcgi \
    --http-uwsgi-temp-path=/var/tmp/nginx/uwsgi \
    --http-scgi-temp-path=/var/tmp/nginx/scgi

4、编译安装

    A、先编译nginx

make

    问题1:src/core/ngx_regex.h:15:18: fatal error: pcre.h: No such file or directory

    解决:使用老的pcre,之前使用的是 pcre2-10.22.zip

wget 
ftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre/pcre-8.38.tar.bz2

    问题2:/bin/sh: 3: ./configure: Permission denied

        *** [external/zlib-1.2.8/libz.a] Error 126

    解决:在zlib-1.2.8目录中,修改configure文件权限,添加执行权限

nginx-1.10.2/external/zlib-1.2.8# chmod u+x configure

   最终编译的结果位于目录:nginx-1.10.2/objs/下

    B、安装

make install

    因为配置了–prefix,安装到了该目录下。

5、测试

    进入prefix目录,启动nginx:

./nginx


     如果出现:nginx: [emerg] getpwnam("nginx") failed,意思是需要创建nginx用户和组:

groupadd -r nginx
useradd -r -g nginx -s /bin/false -M nginx

    再次运行就好了,如果出现下面错误,手工创建相应目录就好:

nginx: [emerg] mkdir() "/var/tmp/nginx/client/" failed (2: No such file or directory)

    nginx默认监听80端口,因为服务器80端口已被占用,所以修改conf/nginx.conf文件中端口(80->8080)。同时为了方便调试,可以关闭daemon模式(nginx.conf中添加daemon off;) 在浏览器中打开 http://localhost:8080  即可出现:

1481527576170322.png

三、Nginx模型

此部分来自:http://tengine.taobao.org/book/chapter_02.html#nginx

http://tool.oschina.net/apidocs/apidoc?api=nginx-zh

3.1、Nginx的进程模型

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

    1481527943111191.png

3.2、http请求处理流程

1481528448254835.png

3.3、Nginx模块

    nginx将各功能模块组织成一条链,当有请求到达的时候,请求依次经过这条链上的部分或者全部模块,进行处理。每个模块实现特定的功能。例如,实现对请求解压缩的模块,实现SSI的模块,实现与上游服务器进行通讯的模块,实现与FastCGI服务进行通讯的模块。

    有两个模块比较特殊,他们居于nginx core和各功能模块的中间。这两个模块就是http模块和mail模块。这2个模块在nginx core之上实现了另外一层抽象,处理与HTTP协议和email相关协议(SMTP/POP3/IMAP)有关的事件,并且确保这些事件能被以正确的顺序调用其他的一些功能模块。  

3.3.1、模块类型

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

3.3.2、常见模块

    核心模块

        主模块 / 事件模块 / HTTP 模块;

    基本模块

        HTTP Access / HTTP Auth Basic / HTTP AutoIndex / HTTP DAV / HTTP FastCGI / 

        HTTP Gzip Compression / HTTP Headers / HTTP Index / HTTP Log / HTTP Proxy /

        HTTP Rewrite / HTTP Upstream;

    其他模块

        HTTP Empty GIF / HTTP GEO / HTTP Real IP / HTTP SSI / HTTP Stub Status /

        HTTP Memcached / HTTP limit_zone / HTTP Secure Link;

    第三方模块

        HTTP Upstream Request Hash / Notice / nginx_substitutions_filter / Http Access Key /

        ngx_cache_purge / NginxHttpOwnerMatch 模块(解决链接型文件跨站访问);

四、模块开发示例

此部分参考实现:http://blog.csdn.net/poechant/article/details/7627828

4.1、准备工作

    实现目标:从底层实现,在浏览器中请求服务器的 .evan 后缀的资源时,返回对应的.html文件的属性,例如请求http://localhost/hello.evan时,返回hello.html文件的属性。

    命名该模块为:ngx_http_evan_module

    模块目录组织如下:

ngx_http_evan_module
    |_____________ngx_http_evan_module.c
    |_____________config

    而在nginx配置文件nginx.conf的server中,需要添加配置如下:

location ~ \.evan$ {
            evan $request_uri;
}

4.2、编码

4.2.1、定义的数据结构

    1、定义一个结构体:

typedef struct {
    ngx_str_t output_words;
} ngx_http_evan_conf_t;

    2、定义三个变量:

// Structure for the evan command
static ngx_command_t ngx_http_hello_world_commands[] = {
    {
        ngx_string("evan"),             // The command name
        NGX_HTTP_LOC_CONF | NGX_CONF_TAKE1,
        ngx_http_evan,                  // The command handler
        NGX_HTTP_LOC_CONF_OFFSET,
        offsetof(ngx_http_evan_conf_t,output_words),
        NULL
    },
    ngx_null_command
};

// Structure for the evan context
static ngx_http_module_t ngx_http_evan_module_ctx = {
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    ngx_http_evan_create_loc_conf,
    ngx_http_evan_merge_loc_conf
};

// Structure for the evan module, the most important thing
ngx_module_t ngx_http_evan_module = {
    NGX_MODULE_V1,
    &ngx_http_hello_world_module_ctx,
    ngx_http_hello_world_commands,
    NGX_HTTP_MODULE,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NGX_MODULE_V1_PADDING
};

    3、定义三个函数:

static char* ngx_http_evan(ngx_conf_t* cf, ngx_command_t* cmd, void* conf);
static void* ngx_http_evan_create_loc_conf(ngx_conf_t* cf)
static char* ngx_http_evan_merge_loc_conf(ngx_conf_t* cf, void* parent, void* child)

4.2.2、完整代码

    完整代码和nginx.conf详细见:

             https://git.oschina.net/evan-xia/x_1612_ngx_http_evan_module

4.2.3、config

ngx_addon_name=ngx_http_evan_module
HTTP_MODULES="$HTTP_MODULES ngx_http_evan_module"
NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/ngx_http_evan_module.c"

4.3、编译测试

    1、现在在2.3节中的configure命令末尾添加该模块:

        \
    --add-module=../x_1612_ngx_http_evan_module/ngx_http_evan_module

    2、然后在nginx根目录下运行该命令进行配置;

    3、成功之后可以直接make;

    问题1:make时提示,needed by `objs/nginx'.  Stop.et `objs/addon/ngx_http_evan_module/ngx_http_evan_module.o

    解决:出现这个错误是自定义模块的文件编码有问题,可以使用fromdos/doc2unix工具来解决。在ubuntu中:

# 安装fromdos
sudo aptitude install tofrodos
# 进入模块目录,修改文件,如config文件
fromdos config

    4、安装和测试

    make install后运行nginx,然后在浏览器中输入:http://localhost:8080/index.evan,结果如下:

1481631208347736.png

五、参考:

1、http://tengine.taobao.org/book/chapter_02.html#nginx nginx平台初探(100%)

2、http://tool.oschina.net/apidocs/apidoc?api=nginx-zh

3、http://weibo.com/ttarticle/p/show?id=2309403949643745620312

4、https://www.kancloud.cn/kancloud/master-nginx-develop/51827 Nginx开发从入门到精通

5、http://www.xiaozhou.net/compile-nginx-manually-2015-07-23.html

6、http://blog.csdn.net/poechant/article/details/7627828

7、http://blog.csdn.net/poechant/article/details/7657955


转载标明出处:https://blog.evanxia.com/2016/12/1186