搜档网
当前位置:搜档网 › Emiller的nginx模块开发指引

Emiller的nginx模块开发指引

要非常感谢nginx,它帮助我更加了解蝙蝠侠这个喜剧角色。

蝙蝠侠很快,nginx也很快。蝙蝠侠在与罪恶斗争,nginx在与浪费CPU、内存泄漏等现象做斗争。蝙蝠侠在压力下能保持良好状态,nginx在强大的服务请求压力下表现出色。

但是,蝙蝠侠如果没有那根蝙蝠侠万能腰带(batman utility belt),那他就什么都不是。

在任何时候,蝙蝠侠的万能腰带都应该包括一个锁扣、几个batarang(蝙蝠侠的特殊武器)、几个bat-cuff(护腕)、夜视眼镜、bat-tracer(跟踪器?)、几个bat-darts(蝙蝠镖)...或者还包括一个apple iphone。当蝙蝠侠需要使他的敌人失明、失聪、或者晕倒,或者当他需要跟踪他的敌人,或者给他的敌人发个短信,你最好相信他正在他的万能腰带上找一个合适的工具。这根腰带对蝙蝠侠的行动如此至关重要,所以,当蝙蝠侠在选择穿裤子还是穿腰带的时候,他肯定会选择穿腰带。事实上他确实选择了腰带,这就是为什么蝙蝠侠穿着紧绷的橡胶衣,而没有穿裤子。

虽然nginx没有这样一条万能腰带,但是nginx有一个模块链(module chain),当nginx需要对应答进行gzip或chunked编码时,它会拿出一个模块来做这个工作。当nginx基于IP或http认证来阻拦对某些资源的访问时,也是由一个模块来做这些工作的。同样,当nginx需要和memcahed或者fastCGI交互时,也分别由对应的模块来做相应的工作。

尽管蝙蝠侠的万能腰带上有很多小玩意,但是有时候他还是需要一个新的小工具。也许他有新的敌人,而他现在的武器(如batarang或bat-cuff)都不足以对付这个敌人。也许他需要有新的技能,比如在水下呼吸。所以他会让Lucius Fox来帮他设计这些小工具。

这个文档会告诉你nginx模块链表(module chain)的一些细节,这样你就可以做到像Lucius Fox一样。当你完成这个课程,你将可以设计并写出高质量的模块,来完成nginx以前做不了的事。Nginx的模块系统有很多需要注意的细节,所以你可能需要经常返回这篇文档阅读。我已尽力将这些内容梳理清楚,但我比较愚钝,写nginx模块仍然是很费力的一件事情。

0 前提条件(prerequisites)

你需要熟悉C。不仅仅是C语言语法;你需要熟悉C结构体相关的知识;不能被指针和函数引用所吓倒;对预编译、宏有一定的认识。如果你需要提高一下C语言方面的知识,没有什么比这更好了:K&R。

对HTTP协议的了解很有用,毕竟你是在一个webserver之上工作。

你也应该对nginx的配置文件非常熟悉。如果你不熟悉它,这里有一个简短的介绍:配置

文件中有4种context(分别叫main,server,upstream,location)。每个context 中可以包含数个拥有一个或多个参数的指令。在main context中的指令对所有事情生效;在server context中的指令对一个特定的host/port生效;在upstream context

中的指令对后端的一组server生效;在location context中的指令仅对能匹配到的web地址(如"/","/images"等)生效。一个location context会继承包含它的server context的属性,同样,一个server context会继承main context的属性。Upstream context不会继承任何属性,也不会把自己的属性传递给其它;它有自己的特殊的指令,这些指令不会在其它任何地方生效。我比较多地提到了这4个context,所以...别忘记它们。

让我们开始吧。

1 nginx模块概述

Nginx模块中有3个角色我们将要关注:

1. Handler:处理请求并且产生输出。

2. Filter:对handler产生的输出进行操作(比如gzip压缩,chunked编码等)

3. Load-balancer:当有多个符合条件的后端server可供选择时,从中选择一个以便将请求转发过去。

模块承担着所有你能想到的和webserver相关的实际工作:当nginx寻找一个静态文件,或者将请求代理到另外一台server的时候,这时候有一个handler模块来做这些工作;当nginx对输出进行编码,或者执行有一个服务端的包含(server-side include)操作,它将使用filter模块。Nginx的核心模块很简单,它关心网络通信、应用协议。另外,当处理一个请求时,将所有需要调用的合格模块排好序(以便在处理时依次调用)。这种没有中心控制节点的架构,让你可以写一个非常好的自包含模块来做你想做的事情。

注意:不像apache中的模块,nginx中的模块不是以动态链接库(so)的方式存在。(换句话说,它被编译进nginx这个可执行的bin文件)。

一个模块是如何被调用的?一般情况下,当nginx启动时,每个handler都有一个机会将自己和配置文件中的某个location关联起来;如果有2个以上的模块关联到同一个location,那么仅有其中一个能成功(当然,一个好的配置书写人员不会上这种冲突产生)。Handler能以3种方式返回:所有处理成功;有错误产生;拒绝处理请求并将它

传给默认handler处理(默认handler通常返回一个静态文件)。

如果一个handler是一个到一些后端server组的反向代理,那么就需要用到load-balancer。一个load-balancer决定一个被接收到的请求将要被发送到后端server组中的哪一台。Nginx自带2个load-balancer模块:round-robin(轮询),它像我们在扑克牌游戏中发牌一样,(将请求轮流发送给后端server);iphash,它能保证一个客户端的多次请求可以被同一台后端server处理。

如果handler在处理过程没有产生错误,那么filter将被调用。每个location都可以被关联(hook)多个filter,所以,(举个例子),一个应答可以先被压缩,然后被chunked编码。它们的调用顺序在编译时就决定好了。Filter是一种典型的CHAIN OF RESPONSIBILITY(职责链)设计模式。一个filter被调用,做完它的工作,然后再调用下一个,直到最后一个filter被调用,nginx才完成它对response的处理。

Filter链表中最酷的设计在于,每个filter并不需要等待前一个filter完成后才能开始工作,它可以像unix系统管道一样工作,在前一个filter产生输出的同时处理

Filter在buffer之上操作。Buffer通常的大小为4K(系统页面大小),当然,你可以在nginx.conf中改变这个值。这就意味着,不必等到后端server上接收到整个应答,也就是说,只要接收到应答的一小部分,这个模块就可以开始压缩应答,并把这小部分先返回给客户端。

总结一下主要的概念,典型的处理流程如下:

客户端发送HTTP请求-> nginx根据配置文件中的location配置选择正确的模块-> (如果需要)load-balancer选择一个后端server -> handler处理完它的事情并把每个输出buffer传递给第一个filter -> 第一个filter传递处理后的buffer给第二个filter -> 第二个filter传递给第三个-> ... -> 最终应答发送给客户端

“”

我用到了典型这个词,因为nginx的模块调用非常可定制化。模块何时被调用,以及如何被调用,都给模块开发人员带来很大的负担。调用通过一系列回调函数来实现,这些回调函数有很多。在以下情况下,你都可以指定一个函数来执行:

1. 在server读取配置文件之前

2. 当每一条配置指令出现在每一个loaction和server context的时候

3. 当nginx初始化main配置

4. 当nginx初始化server配置

5. 当nginx将main配置与server配置合并

6. 当nginx初始化location配置

7. 当nginx将某个location父节点server的配置与这个location节点的配置合并

8. 当nginx master进程启动

9. 当nginx worker进程启动

10. 当nginx master进程退出

11. 处理一个请求

12. 操作应答消息头

13. 操作应答消息体

14. 选择一个后端server

15. 初始化对后端server的一个请求

16. 重新初始化到后端server的请求

17. 处理从后端server接收到的应答

18. 完成与后端server的一次交互

通过这些回调函数你能做很多事情,现在是时候深入研究一下nginx的几个模块了。

2 nginx模块的组成部分

我说过,你有非常大的机动性来做一个nginx模块。这一节将描述一些常见的部分。它是一个帮助你读懂一个模块的指引,也是一本写模块时需要翻阅的手册。

2.1模块配置结构(module configuration

structures)

一个模块可以分别为main、server、location这3种context分别定义3种配置结构。事实上,大部分模块仅仅需要一个location配置结构。这些配置结构的命名习惯一般是这样的:ngx_http__(main|srv|loc)_conf_t。这里有一个例子(从dav模块中拿出):

typedef struct {

ngx_uint_t methods;

ngx_flag_t create_full_put_path;

ngx_uint_t access;

} ngx_http_dav_loc_conf_t;

注意,Nginx有一些特殊的数据类型(比如ngx_uin_t、ngx_flag_t)。这些仅仅只是一些元数据类型的别名。

这些结构中的元素由模块指令填充。

2.2 模块指令(module directives)

一个模块的指令出现在一个ngx_command_t数组中,这里有一个例子,来说明他们是如何定义的。这个例子来自于我写的一个小模块

static ngx_command_t ngx_http_circle_gif_commands[] = {

{ ngx_string("circle_gif"),

NGX_HTTP_LOC_CONF|NGX_CONF_NOARGS,

ngx_http_circle_gif,

NGX_HTTP_LOC_CONF_OFFSET,

0,

NULL },

{ ngx_string("circle_gif_min_radius"),

NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,

ngx_conf_set_num_slot,

NGX_HTTP_LOC_CONF_OFFSET,

offsetof(ngx_http_circle_gif_loc_conf_t, min_radius),

NULL },

...

ngx_null_command

};

这里有ngx_command_t(我们定义的结构体)的声明,你能在core/ngx_conf_file.h 中找到它。

struct ngx_command_t {

ngx_str_t name;

ngx_uint_t type;

char *(*set)(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);

ngx_uint_t conf;

ngx_uint_t offset;

void *post;

};

看起来有点多,但是每个成员都有它的用途和目的。

Name是指令字符串,不含空格。数据类型是ngx_str_t。举个例子,它经常被这样初始化:ngx_str("proxy_pass")。注意:ngx_str_t是一个包含2个成员变量的结构,data 和len,data为一个字符串,len为该字符串的长度。在大多数需要使用字符串的时候,nginx都使用该结构体。

Type是一组标志位。通过这个标志位,来说明这个指令带几个参数,配置在何处生效。这些标志位可以被按位或,它们包括:

NGX_HTTP_MAIN_CONF:指令在main配置中生效

NGX_HTTP_SRV_CONF:指令在server配置中生效

NGX_HTTP_LOC_CONF:指令在location配置中生效

NGX_CONF_NOARGS:指令不带参数

NGX_CONF_TAKE1:指令带一个参数

NGX_CONF_TAKE2:指令带二个参数

...

NGX_CONF_TAKE7:指令带7个参数

NGX_CONF_FLAG:指令带有一个bool变量参数("on"或"off")

NGX_CONF_1MORE:指令带有一个以上参数(至少一个)

NGX_CONF_2MORE:指令带有二个以上参数(至少二个)

还有一些其它选项,请参见core/ngx_conf_file.h

Set是函数指针,用来设置模块配置结构(module configuration structrue)中的某个部分(某个变量)。一般情况下,这个函数会把指令的参数传递进来,并在配置结构中

设置一个合适的值。这个设置函数带有3个参数:

1. 一个指向ngx_conf_t结构体的指针。该结构体中包含了传递给这个指令的参数。

2. 一个指向当前的ngx_command_t结构体的指针

3. 一个执行模块自定义结构体(module configure structrues)的指针

当系统在解析配置文件时,如果遇到这个指令,则会调用这个设置函数(set所指函数)。Nginx提供了一系列的函数,来设置自定义结构体中不同的类型。这些函数包括:

Ngx_conf_set_flag_slot:将"on"或"off"转换成1或0

Ngx_conf_set_str_slot:将一个字符串保存到一个ngx_str_t结构中

Ngx_conf_set_num_slot:解析一个整数并将它保存到一个int型变量中

Ngx_conf_set_size_slot:解析数据大小("8k","1M",等)并把它保存到size_t变量中

还有一些其它有用的函数(参看core/ngx_conf_file.h)。如果这些系统已有的函数不够用,每个模块也可以把自己的函数放在这。

这些内置函数如何知道把数据存放在哪?这就要提到ngx_command_t中的另外两个成员了,conf和offset。Conf告诉nginx数据将会被保存在main配置,还是server配置,还是location配置中(通过使用NGX_HTTP_MAIN_CONF_OFFSET、NGX_HTTP_SRV_CONF_OFFSET、NGX_HTTP_LOC_CO NF_OFFSET)。接下来,offset说明了配置中的哪部分将被填充。

Post是模块在读取配置时可能会用到的一个指针,通常情况下,这个字段为NULL。

这个command数组以ngx_null_command结束。

2.3 模块上下文(module context)

这是一个ngx_http_module_t类型的静态变量,它有一系列来创建这3种配置并合并它们。它的名字是ngx_http__module_ctx。下面,按顺序列出这些函数:

1. Preconfiguration:配置初始化之前调用

2. Postconfiguration:配置初始化之后调用

3. Creating the main conf:创建main配置(比如malloc,memset)。

4. Initializing the main conf:初始化main配置

5. Creating the server conf:创建server配置

6. Merging it with the main conf:将main配置与server配置合并

7. Creating the location conf:创建location配置

8. Merging it with the server conf:将server配置与location配置合并

这些函数因为完成的功能不同,所以都带有不同的参数。这里有ngx_http_module_t的

定义(来自http/ngx_http_config.h):

typedef struct {

ngx_int_t (*preconfiguration)(ngx_conf_t *cf);

ngx_int_t (*postconfiguration)(ngx_conf_t *cf);

void *(*create_main_conf)(ngx_conf_t *cf);

char *(*init_main_conf)(ngx_conf_t *cf, void *conf);

void *(*create_srv_conf)(ngx_conf_t *cf);

char *(*merge_srv_conf)(ngx_conf_t *cf, void *prev, void *conf); void *(*create_loc_conf)(ngx_conf_t *cf);

char *(*merge_loc_conf)(ngx_conf_t *cf, void *prev, void *conf);

} ngx_http_module_t;

你可以把你不需要用到的函数设置为NULL,nginx将会检测到它。

大部分handler都只用到最后2个函数。Create_loc_conf用来为location配置分配空间,merge_loc_conf用来为location配置初始化,并将它与继承而来的配置合并。如果配置是非法的,可以在merge_loc_conf中返回一个错误,server将因为这个错误而中止启动。

这里有一个模块上下文结构的例子:

static ngx_http_module_t ngx_http_circle_gif_module_ctx = {

NULL, /* preconfiguration */

NULL, /* postconfiguration */

NULL, /* create main configuration */

NULL, /* init main configuration */

NULL, /* create server configuration */

NULL, /* merge server configuration */

ngx_http_circle_gif_create_loc_conf, /* create location configuration * /

ngx_http_circle_gif_merge_loc_conf /* merge location configuration */ };

是时候来更深入的了解一下了。这些配置回调函数在所有的模块中都非常相似,并且它们使用几乎相同的ngix api。了解它们非常有必要。

2.3.1 create_loc_conf

下面有一个真实的create_loc_conf函数,它来自我写的一个circle_gif模块。它的参数是一个指令结构体(ngx_conf_t),返回一个新创建的模块配置结构体(在这个例子中,叫ngx_http_circle_gif_loc_conf_t)。

static void *

ngx_http_circle_gif_create_loc_conf(ngx_conf_t *cf)

{

ngx_http_circle_gif_loc_conf_t *conf;

conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_circle_gif_loc_conf_t));

if (conf == NULL) {

return NGX_CONF_ERROR;

}

conf->min_radius = NGX_CONF_UNSET_UINT;

conf->max_radius = NGX_CONF_UNSET_UINT;

return conf;

}

首先需要注意的是nginx的内存分配。我们使用ngx_palloc(对malloc的包装)和ngx _pcalloc(对calloc的包装)来获得新的内存。(nginx使用内存池ngx_pool_t来管理内存,内存分配后由nginx系统在适当的时候回收)

表示未设置(UNSET)的常量包括:NGX_CONF_UNSET_UINT、NGX_CONF_UNSET_PTR、NGX_CONF_UNSET_SIZE、NGX_CON F_UNSET_MSEC,和一个针对所有类型的NGX_CONF_UNSET。未设置常量用来告诉合并函数这个值可以被覆盖。

2.3.2 merge_loc_conf

下面是我们在circle_gif函数中用到的merge_loc_conf函数:

static char *

ngx_http_circle_gif_merge_loc_conf(ngx_conf_t *cf, void *parent, void *chil d)

{

ngx_http_circle_gif_loc_conf_t *prev = parent;

ngx_http_circle_gif_loc_conf_t *conf = child;

ngx_conf_merge_uint_value(conf->min_radius, prev->min_radius, 10);

ngx_conf_merge_uint_value(conf->max_radius, prev->max_radius, 20);

if (conf->min_radius < 1) {

ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,

"min_radius must be equal or more than 1");

return NGX_CONF_ERROR;

}

if (conf->max_radius < conf->min_radius) {

ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,

"max_radius must be equal or more than min_radius");

return NGX_CONF_ERROR;

}

return NGX_CONF_OK;

}

Nginx为不同的数据类型都提供了很好的merge函数(通过宏定义实现,取名通常为ngx_ conf_merge__value),这种函数包含3个参数:

1. 需要被设置的变量值

2. 如果#1未被设置(==NGX_CONF_UNSET),可继承的值

3. 默认值。如果#1和#2都未被设置,则取该值

最终结果被保存到第一个参数。可用的merge函数包括ngx_conf_merge_size_value、ngx_conf_merge_msec_value等等。你可以到core/ngx_conf_file.h中去看一个完整的列表。

问:这些函数是如何将结果写入第一个参数的呢?第一个参数的传递方式是采用传值(pass by value),而不是传递指针。

“”

答:事实上,这些函数仅仅是一些宏定义。(所以它们在编译之前,会被展开成一些if 语句)

同样需要注意的是,该函数是如何产生错误的:它可以在日志文件中记录一些信息,然后返回NGX_CONF_ERROR。这个返回值将会中止nginx的启动。(因为日志记录级别是NGX_LOG_EMERG,这些被记录的信息同样会被打印到标准输出(屏幕)。core/ngx_log.h中定义了一系列日志级别可供参考)

2.4 模块定义(module definition)

下面,我们加上一个间接关联的一层,ngx_module_t结构体。这个变量通常被命名为ngx_http__module。(通常,每个变量是一个全局变量)。这个结构体中包含了模块上下文(module context)和模块指令(directives)的引用(reference,就是指针),还包括一些其它的回调函数(比如exit thread, exit process等)。模块定义(module definition)有时候就是为了用来查找跟模块相关的数据。模块定义通常看起来像这样:

ngx_module_t ngx_http__module = {

NGX_MODULE_V1,

&ngx_http__module_ctx, /* module context */

ngx_http__commands, /* module directives */

NGX_HTTP_MODULE, /* module type */

NULL, /* init master */

NULL, /* init module */

NULL, /* init process */

NULL, /* init thread */

NULL, /* exit thread */

NULL, /* exit process */

NULL, /* exit master */

NGX_MODULE_V1_PADDING

};

...将替换成模块名字。每个模块可以添加一些回调函数,以便在进程/线程创建/退出时调用。但是,大多数模块都保持简单,没有添加这些函数。(core/ngx_conf_file.h有这些函数的参数定义)

2.5 模块安装(module installation)

一个模块的安装方法取决于该模块是一个handler,还是一个filter,或者是一个load-banlancer。细节将在对应的章节中说明。

3 Handler

现在,我们将拿一些简单的模块,仔细来看它们是如何工作的。

3.1 Handler解析(非proxy handler)

Handler大概需要做4件事情:获取location配置;产生一个合适的应答;发送HTTP

函数有一个参数request结构体。头部;发送HTTP消息体。模块中的handler——

Request结构体有很多关于客户端请求的非常有用的信息,比如说HTTP方法、URI、HTTP 头部信息。我们将一个个来看这些4个步骤。

3.1.1 获取location配置

这部分比较简单。你需要做的是调用ngx_http_get_module_loc_conf,传入request结构体和模块定义(一个被全局定义的变量)。这里是在我的circle_gif模块的handler中的相关部分:

static ngx_int_t

ngx_http_circle_gif_handler(ngx_http_request_t *r)

{

ngx_http_circle_gif_loc_conf_t *circle_gif_config;

circle_gif_config = ngx_http_get_module_loc_conf(r, ngx_http_circle_gif_ module);

...

现在,我们可以访问我们在配置merge函数中所设置的变量了。

3.1.2 生成应答

这是模块真正做事的部分,也是非常有趣的部分。

Request结构体在这里将非常有用,特别是下面这些元素:

typedef struct {

...

/* the memory pool, used in the ngx_palloc functions */

ngx_pool_t *pool;

ngx_str_t uri;

ngx_str_t args;

ngx_http_headers_in_t headers_in;

...

} ngx_http_request_t;

Uri是请求访问的路径。如"/query.cgi"。

Args请求中'?'后的部分。如"name=john"。

Headers_in中有很多有用的东西(请求的HTTP头信息)。比如cookie,浏览器信息。但是大多数模块都不需要其中的任何东西,如果你感兴趣,可以查阅http/ngx_http_request.h。

这些信息已经足够产生一个有用的输出。完整的ngx_http_request_t的定义能在http/ngx_http_request.h中找到。

3.1.3 发送HTTP头部

应答头部保存在一个叫headers_out的结构体中。Request结构体中有一个指针指向headers_out结构体。在handler函数中,设置headers_out中的相关变量,然后调用ngx_http_send_header(r)。Headers_out中一些有用的部分包括:

typedef stuct {

...

ngx_uint_t status;

size_t content_type_len;

ngx_str_t content_type;

ngx_table_elt_t *content_encoding;

off_t content_length_n;

time_t date_time;

time_t last_modified_time;

..

} ngx_http_headers_out_t;

(其余的变量定义可以在http/http_request.h中找到)

举个例子,如果一个模块想把content_type设置成"image/gif",content_length设置成100,返回200OK,那么,下面的代码能做

到这些事情:

r->headers_out.status = NGX_HTTP_OK;

r->headers_out.content_length_n = 100;

r->headers_out.content_type.len = sizeof("image/gif") - 1;

r->headers_out.content_type.data = (u_char *) "image/gif";

ngx_http_send_header(r);

大部分合法的HTTP头在这个结构体中都有,你可以很方便的设置它们。但是,有一些HTTP头的设置难度比你上面所看到的要稍大一点。举个例子,content-encoding这HTTP头,它的数据类型是(ngx_table_elt_t*),所以模块必须为它分配内存。我们通过ngx_list_push来分配内存,这个函数带有个ngx_list_t类型的参数,返回一个在链表中创建的新的元素。下面的代码将content-encoding设置为"deflate"并把HTTP头发送出去。

r->headers_out.content_encoding = ngx_list_push(&r->headers_out.headers)

if (r->headers_out.content_encoding == NULL) {

return NGX_ERROR;

}

r->headers_out.content_encoding->hash = 1;

r->headers_out.content_encoding->key.len = sizeof("Content-Encoding") - 1;

r->headers_out.content_encoding->key.data = (u_char *) "Content-Encodin g";

r->headers_out.content_encoding->value.len = sizeof("deflate") - 1;

r->headers_out.content_encoding->value.data = (u_char *) "deflate";

ngx_http_send_header(r);

当一个HTTP头需要同时有多个值的时候,我们通常使用这个机制。理论上,它可以方便地添加或删除某些值,而保持其余的不变,因为不需要返回到字符串操作(使用的是链表)。

3.1.4 发送HTTP消息体

现在,模块已经在内存中产生了一个应答,它需要把这个应答放到一个buffer中,然后把这个buffer放到一个链表中,最后调用"send body"函数输出该链。

这个链表用来做什么?Nginx让handler每次产生一个buffer(这个buffer被放入一

个链接节点中);每个链接节点都有一个指向下一节点的指针,当它是最后一个节点时,指针指向NULL。我们假设只有一个buffer,这样就很简单。

首先,模块需要声明buffer和链接节点:

ngx_buf_t *b;

ngx_chain_t out;

下一步就是为buffer(ngx_buf_t)分配内存,并让它指向我们的应答数据:

b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t));

if (b == NULL) {

ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,

"Failed to allocate response buffer.");

return NGX_HTTP_INTERNAL_SERVER_ERROR;

}

b->pos = some_bytes; /* first position in memory of the data */

b->last = some_bytes + some_bytes_length; /* last position */

b->memory = 1; /* content is in read-only memory */

/* (i.e., filters should copy it rather than rewrite in place) */

b->last_buf = 1; /* there will be no more buffers in the request */

现在,将buffer放到我们的链接节点中:

out.buf = b;

out.next = NULL;

最后,我们发送消息体,并返回真个输出过滤链的状态码:

return ngx_http_output_filter(r, &out);

Buffer链是nginx的I/O模型中最关键的部分,所以你得非常熟悉它们是如何工作的。

问:为什么buffer中会有一个last_buf变量?我们可以通过buffer的next指针指向空来判断这个buffer为整个链表中的最后一个。

答:一个链有可能是不完全的,比如说,有多个buffer,但不是所有的buffer都在这个请求或应答中。有些buffer在链表的末尾,但并不是在整个请求的末尾。这就是我们为什么需要last_buf变量的原因。

3.2 upstream handler(proxy)解析

我为你的handler能产生一个应答而小小的鼓掌。有些时候你可以通过一段C代码来生成

那个应答,但是大部分时候你需要和另外一个server通信(比如说,你要写一个模块实现另外一种网络协议)。你可以自己实现网络通信方面的细节,但是,当你收到一个特定的应答时,发生了些什么?当你等待应答的时候,你不想用自己的事件循环(event loop)来阻塞整个程序的主事件循环。你会使nginx的性能大大降低。幸运的是,nginx让你可以在它已有的机制中设置相应的hook函数(回调函数)来处理和后端server("upstreams")的通信。这样一来,你就可以在不妨碍nginx对其它请求的处理的基础上,实现和后端server通信。本节描述一个模块如何和后端server(upstream)进行通信,比如说,memcached、fastcgi,后者其它HTTP server。

3.2.1 upstream 回调函数(callbacks)概要

函数仅做了一点点实不像其它模块的handler函数,upstream模块的handler“际工作。它不调用ngx_http_output_filter(输出应答),而是仅仅设置了一些回调”

函数。这些回调函数在后端server可读或可写时会被调用。实际上,有6个这样的回调函数(hook):

Create_request创建一个将要被发送到upstream(后端server)的请求(一个buffer或者一个buffer链)

Reinit_request 当到upstream(后端server)的连接被重置(reset)时,这个函数将会被调用(正好在第2次调用create_request之前)。

Process_header 处理upstream应答的头一小块,并且设置一个到upstream有效负载的指针。

Abort_request 当客户端中断请求时,这个函数将被调用。

Finalize_request当nginx完成从upstream读取应答时,会调用finalize_request。

Inpurt_filter 是一个可以在读取到的应答消息体上进行操作的filter。

这些函数是如何被设置的?下面是一个例子,一个简化版本的proxy模块的handler函数:

static ngx_int_t

ngx_http_proxy_handler(ngx_http_request_t *r)

{

ngx_int_t rc;

ngx_http_upstream_t *u;

ngx_http_proxy_loc_conf_t *plcf;

plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module);

/* set up our upstream struct */

u = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_t));

if (u == NULL) {

return NGX_HTTP_INTERNAL_SERVER_ERROR;

}

u->peer.log = r->connection->log;

u->peer.log_error = NGX_ERROR_ERR;

u->output.tag = (ngx_buf_tag_t) &ngx_http_proxy_module;

u->conf = &plcf->upstream;

/* attach the callback functions */

u->create_request = ngx_http_proxy_create_request;

u->reinit_request = ngx_http_proxy_reinit_request;

u->process_header = ngx_http_proxy_process_status_line;

u->abort_request = ngx_http_proxy_abort_request;

u->finalize_request = ngx_http_proxy_finalize_request;

r->upstream = u;

rc = ngx_http_read_client_request_body(r, ngx_http_upstream_init);

if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {

return rc;

}

return NGX_DONE;

}

它做了一些通常handler该做的事情,但是重要的部分在于这些回调函数。同时,注意一下ngx_http_read_client_request_body这个函数。这里设置了另外一个回调函数。当nginx完成从客户端读取时,将调用该函数。

这些回调函数将做些什么呢?通常,reinit_request,abort_request和finalize_request会设置或者重置一些内部状态,一般只有几行。而真正有用的函数是create_request和process_header。

3.2.2 create_request回调函数

为了让问题变得简单,让我们假设我们有一个后端server,它读取一个字节,并且打印出2个字节。那么我们的函数将是什么样的呢?

Create_request函数需要为这个单字节的请求分配一个buffer,为这个buffer分配一个链表节点,然后把upstream结构体(中的request_buf指针)指向该链表节点。

它看起来将像这样:

static ngx_int_t

ngx_http_character_server_create_request(ngx_http_request_t *r)

{

/* make a buffer and chain */

ngx_buf_t *b;

ngx_chain_t *cl;

b = ngx_create_temp_buf(r->pool, sizeof("a") - 1);

if (b == NULL)

return NGX_ERROR;

cl = ngx_alloc_chain_link(r->pool);

if (cl == NULL)

return NGX_ERROR;

/* hook the buffer to the chain */

cl->buf = b;

/* chain to the upstream */

r->upstream->request_bufs = cl;

/* now write to the buffer */

b->pos = "a";

b->last = b->pos + sizeof("a") - 1;

return NGX_OK;

}

这并不像想象的那么糟糕,是吧?当然,在实际中,在一些应用场景下,你可能需要使用请求URI。它以ngx_str_t类型存在于r->uri,GET参数在在r->args中。不要忘了你能访问请求头和cookie。

3.2.3 process_header回调函数

现在,是时候来讲process_header这个函数了。就像create_request在request 结构体中添加了一个指针一样,process_header将应答指针(response pointer)移到客户端将要接收的部分。它从后端server(upstream)读取header,并且设置相应的客户端应答header。

这里有一个非常小的例子,读取那个2个字节的应答。让我们假设第一个字节是状态码

("status" character)。如果是一个疑问号,我们就不理会第二字节,返回客户端404文件未找到。如果是一个空格符,我们就以200 OK返回另外一个字符到客户端。确实,这不是一个很有用的协议,但它是一个很好的例证。我们如何来写这个process_header函数?

static ngx_int_t

ngx_http_character_server_process_header(ngx_http_request_t *r)

{

ngx_http_upstream_t *u;

u = r->upstream;

/* read the first character */

switch(u->buffer.pos[0]) {

case '?':

r->header_only; /* suppress this buffer from the client */

u->headers_in.status_n = 404;

break;

case ' ':

u->buffer.pos++; /* move the buffer to point to the next charact er */

u->headers_in.status_n = 200;

break;

}

return NGX_OK;

}

就这么简单。处理头部,改变指针,就完成了。注意headers_in实际上是一个应答头部结构体,像我们之前所看到的(cf.http/ngx_http_request.h),但是它能被从后端server(upstream)接收到的header所填充。一个真正的代理模块(proxying module)将做更多的头部处理,这里没有提及到错误处理,但是你有了一个大概的了解。但是,当我们从后端server所接收到的包中没有包含整个头部,该怎么办?

3.2.4 保持状态(keeping state)

还记得我说过,abort_request、reinit_request、reinit_request,能够被用来重置内部状态。这是因为很多upstream模块有内部状态。模块需要定义一个自定义context结构体来保存和跟踪此刻从后端server收到了多少数据。这里和上面说

的"Module Context"不一样。那是一个系统事先定义好的结构。而这个自定义context 结构体则可以包含任何你所需要的元素和数据。这个context结构体可以在create_request函数中初始化,可能会像这样:

ngx_http_character_server_ctx_t *p; /* my custom context struct */

p = ngx_pcalloc(r->pool, sizeof(ngx_http_character_server_ctx_t));

if (p == NULL) {

return NGX_HTTP_INTERNAL_SERVER_ERROR;

}

ngx_http_set_ctx(r, p, ngx_http_character_server_module);

最后一行实际上是将自定义context结构体以一个模块名注册到一个特殊的请求之上,以便后续可以很方便地获得。任何时候,当你需要这个context结构体时,(很有可能在其它的回调函数中),只需要这样做:

ngx_http_proxy_ctx_t *p;

p = ngx_http_get_module_ctx(r, ngx_http_proxy_module);

指针p将指向当前状态。设置、重设、在里面放任何数据,想怎么做就这么做。当一个后端server以块(chunk)的形式返回数据,我们使用一个持久的状态机来读取数据,而且不会阻塞程序的主循环,这是一个非常好的方法。

3.3 Handler installation

Handler通过在指令结构体中所指定的回调函数中添加代码来完成安装(该指令能使这个

模块生效)。举个例子,我的circle gif指令结构体是这样:

{ ngx_string("circle_gif"),

NGX_HTTP_LOC_CONF|NGX_CONF_NOARGS,

ngx_http_circle_gif,

0,

0,

NULL }

在这个例子中,回调函数是第3个参数ngx_http_circle_gif。回忆一下,这个回调函数的参数包括:指令结构体(ngx_conf_t,包含用户参数),相关的ngx_command_t结构体,和一个到模块配置结构的指针。对于我的circle gif模块来说,这个函数会像这样:

static char *

ngx_http_circle_gif(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)

{

ngx_http_core_loc_conf_t *clcf;

clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);

clcf->handler = ngx_http_circle_gif_handler;

return NGX_CONF_OK;

}

这里有2个步骤:首先,为这个location获取core模块的locale配置,然后为handler赋值。非常简单,是吧?

现在,我已经说了所有我知道的关于handler模块的一切。是时候转移到filter模块上了,以及在输出过滤链上的一些组件。

4 Filters

Filters对handlers产生的应答进行操作。Header filter对HTTP头进行操作,body filter对HTTP体进行操作。

4.1 Header filter分析

一个header filter包括3个基本步骤:

1. 决定是否需要对某个应答进行操作

2. 对某个应答进行操作

3. 调用下一个filter

举个例子,这里有一个"not modified"header filter的简化版本,如果客户端的

If-Modified-Since头与服务端应答中的Last-Modified头相匹配的话,就把状态码设置为"304 Not Modified"。注意,header filter仅有一个参数,即ngx_http_request_t结构体。这样,我们就可以访问客户端头部和马上就可以发送的应答头部。

static

ngx_int_t ngx_http_not_modified_header_filter(ngx_http_request_t *r)

{

time_t if_modified_since;

2019年nginx安装手册

Nginx安装手册 1nginx安装环境 nginx是C语言开发,建议在linux上运行,本教程使用作为安装环境。 ?gcc 安装nginx需要先将官网下载的源码进行编译,编译依赖gcc环境,如果没有gcc环境,需要安装gcc:yum install gcc-c++ ?PCRE PCRE(Perl Compatible Regular Expressions)是一个Perl库,包括perl 兼容的正则表达式库。nginx的http模块使用pcre来解析正则表达式,所以需要在linux上安装pcre库。yum install -y pcre pcre-devel 注:pcre-devel是使用pcre开发的一个二次开发库。nginx也需要此库。 ?zlib zlib库提供了很多种压缩和解压缩的方式,nginx使用zlib对http包的内容进行gzip,所以需要在linux上安装zlib库。 yum install -y zlib zlib-devel ?openssl OpenSSL 是一个强大的安全套接字层密码库,囊括主要的密码算法、常用的密钥和证书封装管理功能及SSL协议,并提供丰富的应用程序供测试或其它目的使用。 nginx不仅支持http协议,还支持https(即在ssl协议上传输http),所以需要在linux 安装openssl库。 yum install -y openssl openssl-devel 2编译安装 将拷贝至linux服务器。 解压: tar -zxvf --help查询详细参数(参考本教程附录部分:nginx编译参数) 参数设置如下: ./configure \ --prefix=/usr/local/nginx \ --pid-path=/var/run/nginx/ \ --lock-path=/var/lock/ \ --error-log-path=/var/log/nginx/ \

在centos上搭建nginx图片服务器(包含上传模块)

安装Nginx 和相关的插件 (Image Filter Module & Upload Module & Upload Progress Module) (1) install essential sys library $ yum -y install gcc-c++ $ yum -y install zlib zlib-devel openssl openssl-devel pcre pcre-devel gd gd-devel (2)install nginx & related module plugin $ wget https://https://www.sodocs.net/doc/a52228968.html,/masterzen/nginx-upload-progress-module/archive/v0.9.1.tar.gz $ wget https://https://www.sodocs.net/doc/a52228968.html,/vkholodkov/nginx-upload-module/archive/2.2.0.tar.gz $ wget https://www.sodocs.net/doc/a52228968.html,/download/nginx-1.3.8.tar.gz $ tar zxvf *.tar.gz $ cd /nginx-1.3.8/conf (3)configure nginx.conf $ vi nginx.conf #user root; worker_processes 1; #error_log logs/error.log; #error_log logs/error.log notice; #error_log logs/error.log info; #pid logs/nginx.pid; events { worker_connections 1024; } http { include mime.types; default_type application/octet-stream; #log_format main '$remote_addr - $remote_user [$time_local] "$request" ' # '$status $body_bytes_sent "$http_referer" ' # '"$http_user_agent" "$http_x_forwarded_for"';

手把手教你开发Nginx模块

手把手教你开发Nginx模块 前面的哪些话 关于Nginx模块开发的博客资料,网上很多,很多。但是,每篇博客都只提要点,无法"step by step"照着做,对于初次接触Nginx开发的同学,只能像只盲目的蚂蚁瞎燥急!该篇文章没有太多技术深度,只是一步一步说明白Nginx模块的开发过程。 开发环境搭建 工欲善其事,必先利其器。个人推荐Eclipse CDT 作为IDE,原因很简单,代码提示与补全功能很全,完胜Codeblock这类...相信与否,试过就知道。 在ubuntu下搭建开发环境: 安装GCC编译器 apt-get install build-essential 安装pcre/openssl/zlib开发库 apt-get install libpcre3-dev apt-get install libssl-dev apt-get install libzip-dev 必需安装nginx核心模块依赖的pcre,openssl,zilib开发库 安装JRE/Eclipse CDT apt-get install openjdk-8-jre wget http://ftp.yz.yamagata-u.ac.jp/pub/eclipse//technology/epp/downloads/release/neon/R/eclipse-cpp-neon-R-linux-gtk-x86_64.tar.gz && tzr -xzvf eclipse-cpp-neon-R-linux-gtk-x86_64.tar.gz 下载nginx源码 wget https://www.sodocs.net/doc/a52228968.html,/download/nginx-1.10.1.tar.gz && tar -xzvf nginx-1.10.1.tar.gz 配置CDT Build Environment 添加变量,值Nginx src下各模块路径,用冒号分隔,例如: /root/Workspace/nginx-1.10.1/src/core:/root/Workspace/nginx-1.10.1/src/event:/root/Workspace/nginx-1.10.1/src/http:/root/Workspace/nginx-1.10.1/src/mail:/root/Workspace/n ginx-1.10.1/src/stream:/root/Workspace/nginx-1.10.1/src/os/unix 添加环境变量,创建C项目时自动作为-I选项 image image Nginx模块编译流程 Nginx使用configure脚本分析环境,自动生成objs结果。哪么configure如何编译第三方模块?答案是--add-module指定第三方模块目录,并将目录存为$ngx_addon_dir环境变量。执行$ngx_addon_dir/config脚本,读取模块配置。在config中的环境变量分为2种:小写的本地环境变量,大写的全局环境变量。例如: ngx_addon_name=ngx_http_mytest_module

Eclipse + nginx module + debug

Liunx下使用Eclipse 开发nginx module,进行单步调试 Author: chuantong.huang@https://www.sodocs.net/doc/a52228968.html, Date:2010-10-26 1)取Nginx最新代码: wget https://www.sodocs.net/doc/a52228968.html,/download/nginx-0.7.67.tar.gz tar -xvf nginx-0.7.67.tar.gz cd nginx-0.7.67 2)建立模块目录与代码 pwd # 进入Nginx源代码目录,如: /home/toon/workspace/nginx-0.7.67 mkdir ngx_module_echo vim ngx_module_echo/config 其内容为: ngx_addon_name=ngx_module_echo HTTP_MODULES="$HTTP_MODULES ngx_module_echo" NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/ngx_module_echo.c" CORE_LIBS="$CORE_LIBS " vim ngx_module_echo/ngx_module_echo.c 其内容: 参考nginx的echo模块代码,自己google下,或参考以下: https://www.sodocs.net/doc/a52228968.html,/p/ngx_ext.html 3)建立Makefile 利用nginx提供的configrue脚本生成Makefile文件: ./configure --without-http_rewrite_module --without-http-cache --add-module=/home/toon/workspace/nginx-0.7.67/ngx_module_echo/ --with-debug 注意:这里要指定moduel目录(与Nginx源码目录下),还要指定debug编译. BTW:Eclipse 中执行Build project时会执行make clean all,会删除Makefile,故此时应该再执行configure生成Makefile 可以先make一次,编译出objs/nginx文件。

Windows下编译Nginx并添加模块

Windows下编译Nginx并添加模块 一.准备工作 1.环境安装 1.安装vs2010或vs2013等vs工具。 2.安装ActivePerl,安装完成后,将其安装路径加入到PATH环境变量。 3.安装MinGW,下载mingw-get-setup.exe,安装完成后,将其安装路径加入到PATH环境变量。(记得安装的时候装上msys,不懂就全勾了) 4.安装nasm,安装完成后,将其安装路径加入到PATH环境变量。 2.下载编译nginx源码文件 1.nginx源码:nginx-1.1 2.2 2.pcre:pcre-8.40 3.zlib:zlib-1.2.11 4.openssl:openssl-1.0.2l 3.下载添加模块文件 1.文件上传模块: nginx-upload-module 2.rtmp模块:nginx-rtmp-module 3.文件上传进度条模块:nginx-upload-progress-module 二.编译并添加模块 1.将上述7个压缩包文件解压至文件夹msys文件目录下,如C:\MinGW\msys\1.0\home\$UESRNAME\。 2.找到msys.bat的路径并双击msys.bat,运行。如下图所示

3.打开msys.bat后如下所示 右击上方编辑栏,选择编辑,粘贴,可进行粘贴复制功能。 4.cd 至nginx源码路径,并在源码路径下执行下面语句: auto/configure --with-cc=cl --builddir=objs --prefix= \ --conf-path=conf/nginx.conf --pid-path=logs/nginx.pid \ --http-log-path=logs/access.log --error-log-path=logs/error.log \ --sbin-path=nginx.exe --http-client-body-temp-path=temp/client_body_temp \ --http-proxy-temp-path=temp/proxy_temp \ --http-fastcgi-temp-path=temp/fastcgi_temp \ --with-cc-opt=-DFD_SETSIZE=1024 --with-pcre=../pcre-8.40 \ --with-zlib=../zlib-1.2.11 --with-openssl=../openssl-1.0.2l \ --with-select_module --with-http_ssl_module \ --with-http_sub_module \ --add-module=../nginx-upload-module-2.255 \ --add-module=../nginx-upload-progress-module-master \ --add-module=../nginx-rtmp-module-master \ 其中pcre,zlib,openssl的语句需根据版本号的不同进行改变,最后增加的模块也需更具实际情况进行相应的改变,步骤4操作如下图所示:

系统概要设计报告(模板)

xx平台 系统概要设计 版本<1.0>

文档信息及版本历史 版权信息 本文件内容由【xx公司】负责解释 本文件的版权属于【xx公司】 任何形式的散发都必须先得到本文档版本所属单位的许可

【目录】 1概述 (4) 1.1编写目的 (4) 1.2适用范围 (4) 1.3读者对象 (4) 1.4术语和缩写 (4) 1.5参考资料 (4) 2设计概述 (5) 2.1设计约束 (5) 2.2设计策略 (5) 2.3技术实现 (5) 3系统概述 (5) 4系统总体结构 (6) 4.1物理结构 (6) 4.2逻辑结构 (6) 5短息服务器 (7) 5.1短信发送流程............................................................................. 错误!未定义书签。 5.2短信接收流程............................................................................. 错误!未定义书签。 5.3订阅流程(短信方式) (7) 5.4取消订阅流程(短信方式)..................................................... 错误!未定义书签。6医疗短信平台WEB系统.. (8) 6.1医院注册流程............................................................................. 错误!未定义书签。 6.2后台管理流程............................................................................. 错误!未定义书签。 6.3订阅/取消订阅流程(WEB方式) (9) 7运行环境 (9) 7.1软件平台 (9) 7.2硬件平台 (9) 8系统备份设计 (10) 9系统容错设计 (10) 10设计约定 (10) 11待解决问题 (10)

Nginx的介绍和使用

1.什么是Nginx Nginx(发音同engine x)是一款轻量级的Web 服务器/反向代理服务器及电子邮件(IMAP/POP3)代理服务器,并在一个BSD-like 协议下发行。由俄罗斯的程序设计师Igor Sysoev所开发,最初供俄国大型的入口网站及搜寻引擎Rambler(俄文:Рамблер)使用。其特点是占有内存少,并发能力强,事实上nginx的并发能力确实在同类型的网页伺服器中表现较好.目前中国大陆使用nginx网站用户有:新浪、网易、腾讯,另外知名的微网志Plurk 也使用nginx。 优点: (1)Nginx 可以在大多数 Unix like OS 上编译运行,并有 Windows 移植版。 Nginx 的1.2.6稳定版已经于2012年12月11日发布,[1]1.3.10开发版已经于2012年12月25日发布,如果新建站点,建议使用最新稳定版作为生产版本,已有站点升级急迫性不高。Nginx 的源代码使用 2-clause BSD-like license。 (2)Nginx 是一个很强大的高性能Web和反向代理服务器,它具有很多非常优越的特性: 在高连接并发的情况下,Nginx是Apache服务器不错的替代品:Nginx在美国是做虚拟主机生意的老板们经常选择的软件平台之一。能够支持高达 50,000 个并发连接数的响应,感谢Nginx为我们选择了 epoll and kqueue作为开发模型。 (3)Nginx作为负载均衡服务器:Nginx 既可以在内部直接支持 Rails 和 PHP 程序对外进行服务,也可以支持作为 HTTP代理服务器对外进行服务。Nginx采用C进行编写,不论是系统资源开销还是CPU使用效率都比 Perlbal 要好很多。 作为邮件代理服务器:Nginx 同时也是一个非常优秀的邮件代理服务器(最早开发这个产品的目的之一也是作为邮件代理服务器),Last. fm 描述了成功并且美妙的使用经验。 (4)Nginx 是一个安装非常的简单,配置文件非常简洁(还能够支持perl语法),Bugs非常少的服务器:Nginx 启动特别容易,并且几乎可以做到7*24不间断运行,即使运行数个月也不需要重新启动。你还能够不间断服务的情况下进行软件版本的升级。 2.下载和安装Nginx Nginx的官方网站是https://www.sodocs.net/doc/a52228968.html,/cn/,英文主页为https://www.sodocs.net/doc/a52228968.html,,从这里可以获得Nginx 的最新版本信息。Nginx有三个版本:稳定版、开发版和历史稳定版。开发版更新较快,包含最新的功能和bug的修复,但同时也可能会遇到新的bug,开发版一旦更新稳定下来,就会被加入稳定版分支中。然而有些新功能不一定会被加到旧的稳定版中去。稳定版本更新较慢,但是bug较少,可以作为生产环境的首选,因此通常建议使用稳定版。历史稳定版本为以往稳定版本的汇总,不包含最新的功能。 这里选择当前的稳定版本nginx-0.7.65作为介绍对象,开始介绍编译安装。在安装Nginx 之前,确保系统已经安装了gcc、 openssl-devel、 pcre-devel和zlib-devel软件库。Linux开发库是在安装系统时通过手动选择安装的,gcc、 openssl-devel、zlib-devel三个

NGINX 介绍

优点 Nginx性能概述 常见问题(FAQ) 安装Nginx 优点 Nginx性能概述 常见问题(FAQ) 安装Nginx 展开 nginx map Nginx 可以在大多数Unix like OS 上编译运行,并有Windows 移植版。目前Nginx 的1.0.0稳定版已发布,开发版本为0.9.x,稳定版为0.8.x,历史稳定版为 0.7.x,建议使用0.8系列作为生产版本。 Nginx 的源代码使用2-clause BSD-like license。 Nginx 是一个很牛的高性能Web和反向代理服务器,它具有很多非常优越的特性: 在高连接并发的情况下,Nginx是Apache服务器不错的替代品:Nginx 在美国是做虚拟主机生意的老板们经常选择的软件平台之一。能够支持高

达50,000 个并发连接数的响应,感谢Nginx为我们选择了epoll and kqueue作为开发模型。 Nginx作为负载均衡服务器:Nginx 既可以在内部直接支持Rails 和PHP 程序对外进行服务,也可以支持作为 HTTP代理服务器对外进行服务。Nginx采用C进行编写,不论是系统资源开销还是CPU使用效率都比Perlbal 要好很多。 作为邮件代理服务器:Nginx 同时也是一个非常优秀的邮件代理服务器(最早开发这个产品的目的之一也是作为邮件代理服务器),Last. fm 描述了成功并且美妙的使用经验。 Nginx 是一个安装非常的简单,配置文件非常简洁(还能够支持perl 语法),Bugs非常少的服务器:Nginx 启动特别容易,并且几乎可以做到7*24不间断运行,即使运行数个月也不需要重新启动。你还能够不间断服务的情况下进行软件版本的升级。 编辑本段Nginx性能概述 HTTP基础功能 处理静态文件,索引文件以及自动索引; 反向代理加速(无缓存),简单的负载均衡和容错; FastCGI,简单的负载均衡和容错; 模块化的结构。过滤器包括gzipping, byte ranges, chunked responses, 以及 SSI-filter 。在SSI过滤器中,到同一个proxy 或者FastCGI 的多个子请求并发处理; SSL 和TLS SNI 支持; IMAP/POP3 代理服务功能: 使用外部 HTTP 认证服务器重定向用户到 IMAP/POP3 后端; 使用外部 HTTP 认证服务器认证用户后连接重定向到内部的SMTP 后端; 其他HTTP功能 基于名称和基于IP的虚拟服务器; Keep-alive and pipelined connections support;保持活动和支持管线连接; Flexible configuration;灵活的配置; Reconfiguration and online upgrade without interruption of the client processing;重构,未经客户处理中断在线升级;

Windows环境下的Nginx高并发实现

Software Development ? 软件开发 Electronic Technology & Software Engineering 电子技术与软件工程? 47 【关键词】Windows 服务器 Nginx 反向代理 高并发 1 引言 Nginx 是高性能的Http 和反向代理服务器,在Linux 环境下,其可以采用epoll 作为网络I/O 模型。在高并发连接的情况下,其是Apache 服务器不错的替代品。Nginx 具有高并 Windows 环境下的Nginx 高并发实现 文/岳晋 温宇 黄旻亮 发连接、内存占用低、成本低等特点。 Nginx 运行时,会存在一个主进程和多个工作进程。工作进程的数目可以在配置文件中进行指定,通常设置为CPU 的核数。主进程用于管理工作进程的运行,并处置工作进程的异常情况。借助于主进程和工作进程的模式,Nginx 可以实现平滑升级、配置即时生效等功能。而工作进程的任务相对单一,主要用于处理业务请求,它们彼此独立,互不影响。此外,借助于异步非阻塞的工作机制,Nginx 可以处理上万的并发请求。 反向代理是Nginx 的主要应用场景之一。 反向代理是相对于正向代理来说,一般情况下,内网的客户机通过代理服务器访问公网上服务的这种模式是正向代理。与此相反,当代理服务器的作用是将后台服务器隐藏起来,并根据客户机的请求,分发给后台服务器的这种方式是反向代理。Nginx 反向代理的原理如图1所示。 图1中,Nginx 代理服务器接收到来自客户端的请求,根据自己的配置,决定将该请求转发给哪个业务服务器。当业务服务器处理完 该请求后,将响应结果交给Nginx 代理服务器,Nginx 代理服务器再将响应内容返回给客户机。 反向代理可以保护后端服务器,此外,还可以用作负载均衡,来平衡后端服务器的性能压力。Nginx 通过proxy_pass 命令和upstream 模块,就可以实现反向代理。如果后台服务和Nginx 在同一机器上,但运行在不同的端口上,Nginx 可以将请求转发到后台服务运行的端口上。通常情况下,后台服务和Nginx 不在一台服务器上,这时候Nginx 可以将请求发送给upstream 模块,再通过upstream 模块转发给后台服务器。而且在upstream 模块中,也可以进行负载均衡相关的配置。 Nginx 的另一主要应用场景是负载均衡。负载均衡是在各服务器之间均衡业务压力,Nginx 的负载均衡策略包括轮询、指定权重、fair 、ip_hash 和url_hash 等。 2 Nginx性能调优相关配置 2.1 stub_status监控模块 得以提高。随着大量产品的借用,构件会趋于成熟,软件BOM 表也随之趋于成熟。这有利于同领域的其他产品借用或者部分借用。 对生产率的影响:一般来说,大约80%~90%的复用可使软件生产率提高25%~40%。 对成本的影响:软件复用率越高时,新研构件越少,耗费的人力成本和时间成本都会大大降低。 对管理的影响:在PDS 等系统中归档了的软件BOM 表,记录了关于该产品所用的所有软件构件的数据信息,如构件的名称、版本、基本内容、复用/新研等信息,以及构件与构件之间的嵌套关系。它对于质量管理中从最终产品追溯零件、组件起到关键作用。软件BOM 表以信息共享为基础,是综合管理、资源调度的重要依据。另外,软件BOM 表中复用/新研的数据也可作为安排软件开发计划的依据。 6 结束语 本文针对基于软件BOM 的构件化开发过 <<上接46页 程,阐述了软件BOM 的设计流程、设计形式及其应用价值。可以看出在构件化软件开发过程中,软件BOM 设计是不可缺少的重要环节。软件BOM 在“工厂”式的软件加工过程中起着连接设计与制造的纽带作用,对提高软件生产率和软件质量、降低软件开发成本都起着至关重要的作用。因此,做好软件需求分析、软件BOM 设计、构件设计、构件测试等,且每个环节都进行专家审核和评审,才能有效地提高软件开发的质量,推动软件工程的发展。 参考文献 [1]史济民.软件工程原理、方法与应用[M]. 北京:高等教育出版社,1990. [2]李航.基于通用试验体系结构支撑 平台的组件框架设计模式[J].软件,2013,34(5):85-87. [3]刘凤.基于软件构件技术的阮建华雷达 [J].现代雷达,2016(2). [4]STEPHEN M, WELBY P. Modular open s y s t e m s a r c h i t e c t u r e i n D o D acquisition[R]. Washington: DOPSR, 2014. [5]NELSON J A. Radar open system a r c h i t e c t u r e p r o v i d e s n e t centricity[J]. IEEE Aerospace and Electronic Systems Magazine, 2010, 25(10):17-20. [6]Wang Yongliang, Ding Qianjun, L i R o n g f e n g. A d a p t i v e A r r a y Processing[M]. Bejing: Tsinghua University Press, 2009. [7]Karl Wiegers, Joy Beatty.软件需求[M] 北京:清华大学出版社,2016,8-12.[8]莱芬韦尔,威德里格.软件需求管理: 统一化方法[M].北京:高等教育出版社,2002:18-21. 作者简介 王艳丽(1981-),女,硕士研究生。工程师。研究方向为雷达信号处理。 作者单位 南京电子技术研究所 江苏省南京市 210039

nginx 负载均衡宕机配置

1.摘要 (1)结论 详细描述了nginx记录失效节点的6种状态(time out、connect refuse、500、502、503、504,后四项5XX需要配置proxy_next_upstream中的状态才可以 生效)、失效节点的触发条件和节点的恢复条件、所有节点失效后nginx会进 行恢复并进行重新监听。 (2)Nginx 负载均衡方式介绍 Nginx的负载均衡方式一共有4种:rr(轮询模式)、ip_hash、fair、url_hash。(3)Ngxin负载均衡和相关反向代理配置内容 Nginx负载均衡和与容错相关的反向代理的配置。 (4)获取后端流程 后端server的自动容错流程图。 (5)测试环境和测试结果 针对几种错误方式进行自动容错测试。 2.结论 (1)nginx 判断节点失效状态 Nginx 默认判断失败节点状态以connect refuse和time out状态为准,不以HTTP错误状态进行判断失败,因为HTTP只要能返回状态说明该节点还可以正常连接,所以nginx判断其还是存活状态;除非添加了proxy_next_upstream指令设置对404、502、503、504、500和time out等错误进行转到备机处理,在next_upstream过程中,会对fails进行累加,如果备用机处理还是错误则直接返回错误信息(但404不进行 记录到错误数,如果不配置错误状态也不对其进行错误状态记录),综述,nginx记录错误数量只记录timeout 、connect refuse、502、500、503、504这6种状态,timeout和connect refuse是永远被记录错误状态,而502、500、503、504只有在配置proxy_next_upstream后nginx才会记录这4种HTTP错误到fails中,当fails大 于等于max_fails时,则该节点失效; (2)nginx 处理节点失效和恢复的触发条件 nginx可以通过设置max_fails(最大尝试失败次数)和fail_timeout(失效时间,在到达最大尝试失败次数后,在fail_timeout的时间范围内节点被置为失效,除非所 有节点都失效,否则该时间内,节点不进行恢复)对节点失败的尝试次数和失效时间 进行设置,当超过最大尝试次数或失效时间未超过配置失效时间,则nginx会对节点 状会置为失效状态,nginx不对该后端进行连接,直到超过失效时间或者所有节点都失效后,该节点重新置为有效,重新探测; (3)所有节点失效后nginx将重新恢复所有节点进行探测 如果探测所有节点均失效,备机也为失效时,那么nginx会对所有节点恢复为有效,重新尝试探测有效节点,如果探测到有效节点则返回正确节点内容,如果还是全 部错误,那么继续探测下去,当没有正确信息时,节点失效时默认返回状态为502,但是下次访问节点时会继续探测正确节点,直到找到正确的为止。

Nginx源代码分析

Nginx源代码分析 1.Nginx代码的目录和结构 nginx的源码目录结构层次明确,从自动编译脚本到各级的源码,层次都很清晰,是一个大型服务端软件构建的一个范例。以下是源码目录结构说明: ├─auto 自动编译安装相关目录 │├─cc 针对各种编译器进行相应的编译配置目录,包括Gcc、Ccc等 │├─lib 程序依赖的各种库,包括md5,openssl,pcre等 │├─os 针对不同操作系统所做的编译配置目录 │└─types ├─conf 相关配置文件等目录,包括nginx的配置文件、fcgi相关的配置等 ├─contrib ├─html index.html └─src 源码目录 ├─core 核心源码目录,包括定义常用数据结构、体系结构实现等 ├─event 封装的事件系统源码目录 ├─http http服务器实现目录 ├─mail 邮件代码服务器实现目录 ├─misc 该目录当前版本只包含google perftools包 └─os nginx对各操作系统下的函数进行封装以及实现核心调用的目录。2.基本数据结构 2.1.简单的数据类型 在core/ngx_config.h 目录里面定义了基本的数据类型的映射,大部分都映射到c语言自身的数据类型。 typedef intptr_t ngx_int_t; typedef uintptr_t ngx_uint_t; typedef intptr_t ngx_flag_t; 其中ngx_int_t,nginx_flag_t,都映射为intptr_t;ngx_uint_t映射为uintptr_t。 这两个类型在/usr/include/stdint.h的定义为: /* Types for `void *' pointers. */ #if __WORDSIZE == 64 # ifndef __intptr_t_defined

NginWEB服务器架构设计解决方案精修订

N g i n W E B服务器架构设计解决方案 集团标准化工作小组 #Q8QGGQT-GX8G08Q8-GNQGJ8-MHHGN#

Nginx是俄罗斯人编写的十分轻量级的HTTP服务器,Nginx,它的发音为“engine X”,是一个高性能的HTTP和反向代理服务器,同时也是一个IMAP/POP3/SMTP 代理服务器.Nginx是由俄罗斯人 Igor Sysoev 为俄罗斯访问量第二的站点开发的,它已经在该站点运行超过两年半了。Igor Sysoev在建立的项目时,使用基于BSD许可。 据说他当初是F5的成员之一,英文主页:。 俄罗斯的一些大网站已经使用它超过两年多了,一直表现不凡,相信想了解nginx的朋友都读过阿叶大哥的利用nginx实现负载均衡.直到2007年4月,俄罗斯大约有20%左右的虚拟主机是由nignx服务或代理的。Google在线安全博客中统计nginx服务或代理了大约所有Internet虚拟主机的 4%。而netcraft的统计显示,nginx服务的主机在过去的一年里以四倍的速度增长。短短的几年里,它的排名已跃进第9。(参见: Nginx以事件驱动的方式编写,所以有非常好的性能,同时也是一个非常高效的反向代理、负载平衡。其拥有匹配 Lighttpd的性能,同时还没有Lighttpd的内存泄漏问题,而且Lighttpd的mod_proxy也有一些问题并且很久没有更新。 因此我打算用其替代Apache应用于Linux服务器上。但是Nginx并不支持cgi方式运行,原因是可以减少因此带来的一些程序上的漏洞。那么我们必须使用FastCGI方式来执行PHP程序。 现在,Igor将源代码以类BSD许可证的形式发布。Nginx因为它的稳定性、丰富的模块库、灵活的配置和低系统资源的消耗而闻名.业界一致认为它是+mod_proxy_balancer的轻量级代替者,不仅是因为响应静态页面的速度非常快,而且它的模块数量达到Apache的近 2/3。对proxy 和 rewrite模块的支持很彻底,还支持mod_fcgi、ssl、vhosts ,适合用来做mongrel clusters的前端HTTP 响应。 nginx做为HTTP服务器,有以下几项基本特性: 处理静态文件,索引文件以及自动索引;打开文件描述符缓冲. 无缓存的反向代理加速,简单的负载均衡和容错. FastCGI,简单的负载均衡和容错. 模块化的结构。包括gzipping, byte ranges, chunked responses,以及 SSI-filter等filter。如果由FastCGI或其它代理服务器处理单页中存在的多个SSI,则这项处理可以并行运行,而不需要相互等待。 支持SSL 和 TLSSNI. Nginx专为性能优化而开发,性能是其最重要的考量,实现上非常注重效率。它支持内核Poll模型,能经受高负载的考验,有报告表明能支持高达 50,000个并发连接数。 Nginx具有很高的稳定性。其它HTTP服务器,当遇到访问的峰值,或者有人恶意发起慢速连接时,也很可能会导致服务器物理内存耗尽频繁交换,失去响应,只能重启服务器。例如当前apache一旦上到200个以上进程,web响应速度就明显非常缓慢了。而Nginx采取了分阶段资源分配技术,使得它的 CPU

win764位下配置http2nginxnodejs

最近要调研http2能给页面带来多少访问速度的提升,所以自己先搭一个环境测试一下; 一、CA数字证书: 要升级http2首先是要把http升级到https,https升级就需要CA证书,但由于现代的浏览器都已默认安装了一些网络证书,所以我们访问淘宝,京东之类的网站就不需要让用户自己安装了,其它没有安装的证书就得用户自己得去安装了; 现在网络上的很多https证书,有免费的也有付费的,但作为我是用于自己调试与测试用,当然找免费的了,但免费的证书需要申请与审核,时间也是得等,加上功能上也有限制,好吧,我是迫不及待的用证书,来调试,最后找到了OpenSSL,自己来创建证书,省去申请的时间,那现在就说说OpenSSL 如何创建一个ca证书,服务器证书与客户端证书; 安装准备: 下载OpenSSL我用的版本是openssl-1.1.0 下载安装ActivePerl最新版本即可; 下载安装nasm最新版本即可; 下载安装Visual Studio 2015 自己上度娘找吧,很多; 先把OpenSSL解压到E盘,目录名称为openssl-1.1.0; 点击开始按钮,选择Visual Studio Tools 下的64位编译机,定位到 E://openssl-1.1.0

输入命令: //初始化文件目录 $ perl Configure VC-WIN64A --prefix=E:/openssl-1.1.0/win64_OpenSSL --ope nssldir=E:/openssl-1.1.0/win64_SSL $ nmake $ nmake test

$ nmake install 注意,以上的安装方法一定要参考该版本的安装方法,这个安装方法的文件一般叫INSTALL,网上有很多方法,都是老版本来的; 生成密钥、证书 第一步,为服务器端和客户端准备公钥、私钥 # 生成服务器端私钥 genrsa -out server.key 1024 # 生成服务器端公钥 rsa -in server.key -pubout -out server.pem # 生成客户端私钥 genrsa -out client.key 1024 # 生成客户端公钥 rsa -in client.key -pubout -out client.pem 第二步,生成CA 证书 # 生成CA私钥 genrsa-out ca.key 1024 # X.509Certificate Signing Request (CSR) Management. req-config "E:\openssl-1.1.0\win64_SSL\https://www.sodocs.net/doc/a52228968.html,f" -new-key ca.key-o ut ca.csr # X.509Certificate Data Management.

Nginx源码分析

Nginx源代码分析 l00117893 1.Nginx代码的目录和结构 nginx的源码目录结构层次明确,从自动编译脚本到各级的源码,层次都很清晰,是一个大型服务端软件构建的一个范例。以下是源码目录结构说明: ├─auto 自动编译安装相关目录 │├─cc 针对各种编译器进行相应的编译配置目录,包括Gcc、Ccc等 │├─lib 程序依赖的各种库,包括md5,openssl,pcre等 │├─os 针对不同操作系统所做的编译配置目录 │└─types ├─conf 相关配置文件等目录,包括nginx的配置文件、fcgi相关的配置等 ├─contrib ├─html index.html └─src 源码目录 ├─core 核心源码目录,包括定义常用数据结构、体系结构实现等 ├─event 封装的事件系统源码目录 ├─http http服务器实现目录 ├─mail 邮件代码服务器实现目录 ├─misc 该目录当前版本只包含google perftools包 └─os nginx对各操作系统下的函数进行封装以及实现核心调用的目录。2.基本数据结构 2.1.简单的数据类型 在core/ngx_config.h 目录里面定义了基本的数据类型的映射,大部分都映射到c语言自身的数据类型。 typedef intptr_t ngx_int_t; typedef uintptr_t ngx_uint_t; typedef intptr_t ngx_flag_t; 其中ngx_int_t,nginx_flag_t,都映射为intptr_t;ngx_uint_t映射为uintptr_t。

高可用服务设计概述

高可用服务设计概述

1. 负载均衡与反向代理 当我们的应用单实例不能支撑用户请求时,就需要扩容,从一天服务器扩容到两台、几十台、几百台。然而用户访问时是通过如https://www.sodocs.net/doc/a52228968.html,的方式访问,在请求时,浏览器首先会查询DNS服务器获取对应的IP,然后通过此IP访问对应的服务。 对于负载均衡需要关心的几个方面如下: ?上游服务器配置:使用upstream server配置上游服务器。 ?负载均衡算法:配置多个上游服务器时的负载均衡机制。 ?失败重试机制:配置当超时或上游服务器不存活时,是否需要重试其他上游服务器。 ?服务器心跳检查:上游服务器的健康检查/心跳检查。 Nginx提供的负载均衡机制可以实现服务器的负载均衡、故障转移、失败重试、容错、健康检查等,当某些上游服务器出现问题时可以将请求转到其他上游服务器以保障高可用,并通过OpenResty实现更智能的负载均衡,如将热点与非热点流量分离、正常流量与爬虫流量分离等。Nginx负载均衡器本身也是一台反向代理服务器,将用户请求通过Ningx代理到内网中的某台上游服务器处理,反向代理服务器可以对响应结果进行缓存、压缩等处理以提升性能。

负载均衡算法 负载均衡算法用来解决用户请求到来时如何选择upstream server进行处理,默认采用的是round-robin (轮询),同时支持其他几种算法。 ?round-robin:轮询,默认负载均衡算法,即以轮询的方式将请求转发到上游服务器,通过配合weight配置可以实现基于权重的轮询。 ?ip-hash:根据客户IP进行负载均衡,即相同的IP将负载均衡到同一个upstream server。 ?hash key [consistent]:对某一个key进行哈希或者使用一致性哈希算法进行负载均衡。使用Hash算法那存在的问题是,当添加/删除一台服务器时,将导致很多key被重新负载均衡到不同的服务器(从而导致后端肯可能出现问题);因此,建议考虑使用一致性hash算法,这样当添加/删除一台服务器时,只有少数key将被重新负载均衡到不同的服务器。 ?哈希算法:此处是根据请求uri进行负载均衡,可以使用Nginx变量,因此可以实现复杂的算法。失败重试 当fail_timeout时间内失败了max_fails次请求,则认为该上游服务器不可用/不存活,然后将摘掉该上游服务器,fail_timeout时间后会再次将该服务器加入到存活上游服务器列表进行重试。

nginx学习总结

Nginx学习总结 Nginx概述及注意事项 ?nginx是一个高性能的 HTTP 和反向代理服务器,也是一个 IMAP/POP3/SMTP 代理服务 器。 ?目前Nginx使用简单的轮巡(polling)算法来实现负载均衡,所以无法做基本 链接计数的负载均衡。 ?目前官方 Nginx 并不支持 Windows,您只能在包括 Linux、UNIX、BSD 系统下安装和 使用; ?Nginx 本身只是一个 HTTP 和反向代理服务器,它无法像 Apache 一样通过安装各种模 块来支持不同的页面脚本,例如 PHP、CGI 等; ?Nginx 支持简单的负载均衡和容错; ?支持作为基本 HTTP 服务器的功能,例如日志、压缩、Byte ranges、Chunked responses、 SSL、虚拟主机等等,应有尽有。 Nginx优势 ?在高连接并发的情况下,Nginx是Apache服务器不错的替代品:Nginx在美国是 做虚拟主机生意的老板们经常选择的软件平台之一。能够支持高达 50,000 个并发连接数的响应,感谢Nginx为我们选择了epoll and kqueue作为开发模型。 ?Nginx作为负载均衡服务器:Nginx 既可以在内部直接支持Rails 和PHP 程序 对外进行服务,也可以支持作为HTTP代理服务器对外进行服务。Nginx采用C 进行编写,不论是系统资源开销还是CPU使用效率都比 Perlbal 要好很多。 ?作为邮件代理服务器:Nginx 同时也是一个非常优秀的邮件代理服务器(最早 开发这个产品的目的之一也是作为邮件代理服务器),Last. fm 描述了成功并且美妙的使用经验。 ?Nginx 是一个安装非常的简单,配置文件非常简洁(还能够支持perl语法), Bugs非常少的服务器:Nginx 启动特别容易,并且几乎可以做到7*24不间断运行,即使运行数个月也不需要重新启动。

相关主题