当前位置:文档之家› Nginx模块开发手册

Nginx模块开发手册

Nginx模块开发手册
Nginx模块开发手册

1. 预备知识

你应当比较熟悉C语言。不光是“C-语法",你起码还得知道结构体和预处理指令,同时保证看到指针和函数引用出现时心里不会发毛。否则的话,就算信春哥也是没用的,看看K&R吧。

你得对HTTP协议有一定的了解,毕竟你是在和一个web server打交道。

如果你熟悉Nginx的配置文件就太好不过了。如果不熟悉,也没关系,这里简单介绍一下,知道概念先:Nginx配置文件主要分成四部分:main(全局设置)、server(主机设置)、upstream(上游服务器设置)和location(URL匹配特定位置后的设置)。每部分包含若干个指令。main部分设置的指令将影响其它所有设置;server部分的指令主要用于指定主机和端口;upstream的指令用于设置一系列的后端服务器;location部分用于匹配网页位置(比如,根目录“/”,“/images”,等等)。他们之间的关系式:server继承main,location继承server;upstream既不会继承指令也不会被继承。它有自己的特殊指令,不需要在其他地方的应用。在下面很多地方都会涉及这四个部分,切记。好了,让我们开始吧。

2. Nginx模块委派概述

Nginx的模块有三种角色:

* handlers 处理http请求并构造输出

* filters 处理handler产生的输出

* load-balancers 当有多于一个的后端服务器时,选择一台将http请求发送过去

许多可能你认为是web server的工作,实际上都是由模块来完成的:任何时候,Nginx提供文件或者转发请求到另一个server,都是通过handler来实现的;而当需要Nginx用gzip压缩输出或者在服务端加一些东东的话,filter就派上用场了;Nginx的core模块主要管理网络层和应用层协议,并启动针对特定请求的一系列后续模块。这种分散式的体系结构使得由你自己来实现强大的内部单元成为了可能。

注意:不像Apache的模块那样,Nginx的模块都_不是动态链接的。(换句话说,Nginx的模块都是静态编译的)模块是如何被调用的呢?典型地说,当server启动时,每一个handler都有机会去处理配置文件中的location定义,如果有多个handler被配置成需要处理某一特定的location时,只有其中一个handler能够“获胜”(掌握正确配置规则的你当然不会让这样的冲突发生啦)。

一个handler有三种返回方式:正常;错误;放弃处理转由默认的handler来处理(典型地如处理静态文件的时候)。

如果handler的作用是把请求反向代理到后端服务器,那么就是刚才说的模块的第三种角色load-balancer了。load-balancer主要是负责决定将请求发送给哪个后端服务器。Nginx目前支持两种load-balancer模块:round-robin(轮询,处理请求就像打扑克时发牌那样)和IP hash(众多请求时,保证来自同一ip的请求被分发的同一个后端服务器)。

如果handler返回(译者注:就是http响应,即filter的输入)正确无误,那么fileter就被调用了。每个location配置里都可以添加多个filter,所以说(比如)响应可以被压缩和分块。多个filter的执行顺序是编译时就确定了的。filter采用了经典的“接力链表(CHAIN OF RESPONSIBILITY)”模式:一个filter 被调用并处理,接下来调用下一个filter,直到最后一个filter被调用完成,Nginx 才真正完成响应流程。

最帅的部分是在filter链中,每个filter不会等待之前的filter完全完工,它可以处理之前filter正在输出的内容,这有一点像Unix中的管道。Filter的操作都基于buffers_,buffer通常情况下等于一个页的大小(4k),你也可以在nginx.conf里改变它的大小。这意味着,比如说,模块可以在从后端服务器收到全部的响应之前,就开始压缩这个响应并流化(stream to)给客户端了。好牛逼啊~ 总结一下上面的内容,一个典型的周期应当是这样的:客户端发送HTTP request →Nginx基于location的配置选择一个合适的handler →(如果有) load-balancer选择一个后端服务器→Handler处理请求并顺序将每一个响应buffer 发送给第一个filter →第一个filter讲输出交给第二个filter →第二个给第三个→第三个给第四个→以此类推→最终响应发送给客户端我之所以说“典型地”是因为Ngingx的模块具有很强的定制性。模块开发者需要花很多精力精确定义模块在何时如何产生作用(我认为是件不容易的事)。模块调用实际上是通过一系列的回调函数做到的,很多很多。名义上来说,你的函数可以在以下时候被执行:

* server读取配置文件之前

* 读取location和server的每一条配置指令

* 当Nginx初始化main配置段时

* 当Nginx初始化server配置段时(例如:host/port)

* 当Nginx合并server配置和main配置时

* 当Nginx初始化location配置时

* 当Nginx合并location配置和它的父server配置时

* 当Nginx的主进程启动时

* 当一个新的worker进程启动时

* 当一个worker进程退出时

* 当主进程退出时

* handle 一个请求

* Filter响应头

* Filter响应体

* 选择一个后端服务器

* 初始化一个将发往后端服务器的请求

* 重新-初始化一个将发往后端服务器的请求

* 处理来自后端服务器的响应

* 完成与后端服务器的交互

难以置信!有这么多的功能任你处置,而你只需仅仅通过多组有用的钩子(由函数指针组成的结构体)和相应的实现函数。让我们开始接触一些模块吧。

3. Nginx模块的组成

我说过,Nginx模块的构建是很灵活的。这一节讲描述的东西会经常出现。它可以帮助你理解模块,也可以作为开发模块的手册。

3.1. 模块配置Struct(s)

模块的配置struct有三种,分别是main,server和location。绝大多数模块仅需要一个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_uint_t 和ngx_flag_t); 这些只是基本类型的别名而已。(如果想知道具体是什么的别名,可以参考core/ngx_config.h ). 这些类型用在配置结构体中的情形很多。

3.2. 模块指令

模块的指令是定义在一个叫做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, 通常都是以像(e.g.) ngx_str("proxy_pass")这样的方式来实例化. 注意:ngx_str_t 包含一个存放字符串内容的data字段,和一个存放字符串长度的len 字段。Nginx广泛地使用这个类型来存放字符串。

结构体成员type是标识的集合,表明这个指令在哪里出现是合法的、指令的参数有几个。应用中,标识一般是下面多个值的BIT或:

* NGX_HTTP_MAIN_CONF: 指令出现在main配置部分是合法的

* NGX_HTTP_SRV_CONF: 指令在server配置部分出现是合法的config

* NGX_HTTP_LOC_CONF: 指令在location配置部分出现是合法的

* NGX_HTTP_UPS_CONF: 指令在upstream配置部分出现是合法的

* NGX_CONF_NOARGS: 指令没有参数

* NGX_CONF_TAKE1: 指令读入1个参数

* NGX_CONF_TAKE2: 指令读入2个参数

* ...

* NGX_CONF_TAKE7: 指令读入7个参数

* NGX_CONF_FLAG: 指令读入1个布尔型数据("on" or "off")

* NGX_CONF_1MORE: 指令至少读入1个参数

* NGX_CONF_2MORE: 指令至少读入2个参数

这里还有很多其他的选项:core/ngx_conf_file.h. 结构体成员set 是一个函数指针,它指向的函数用来进行模块配置;这个设定函数一般用来将配置文件中的参数传递给程序,并保存在配置结构体中。设定函数有三个入参:

1. 指向结构体ngx_conf_t 的指针, 这个结构体里包含需要传递给指令的参数

2. 指向结构体ngx_command_t 的指针

3. 指向模块自定义配置结构体的指针

设定函数会在遇到指令时执行,Nginx提供了多个函数用来保存特定类型的数据,这些函数包含有:

* ngx_conf_set_flag_slot: 将"on" or "off" 转换成1 or 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中很容易查到。如果你觉得现有这些内置的函数还不能满足你,当然也可以传入自己的函数引用。

这些内置函数是如何知道把数据存放在哪里的呢?这就是接下来两个结构体成员conf 和offset要做的事了. conf 告诉Nginx把数据存在模块的哪个配置中,是main配置、server 配置, 还是location 配置?(通过NGX_HTTP_MAIN_CONF_OFFSET, NGX_HTTP_SRV_CONF_OFFSET, 或者NGX_HTTP_LOC_CONF_OFFSET). offset 确定到底是保存在结构体的哪个位置。

最后, post指向模块在读配置的时候需要的一些零碎变量。一般它是NULL。

ngx_command_t数组以ngx_null_command 为终结符(就好像字符串以'\0'为终结符一样).

3.3. 模块上下文

静态的ngx_http_module_t结构体,包含一大坨函数引用,用来创建和合并三段配置(main,server,location),命名方式一般是:ngx_http__module_ctx. 这些函数引用依次是:

* preconfiguration 在读入配置前调用

* postconfiguration 在读入配置后调用

* create_main_conf 在创建main配置时调用(比如,用来分配空间和设置默认值)

* init_main_conf 在初始化main配置时调用(比如,把原来的默认值用nginx.conf读到的值来覆盖)* init_main_conf 在创建server配置时调用

* merge_srv_conf 合并server和main配置时调用

* create_loc_conf 创建location配置时调用

* merge_loc_conf 合并location和server配置时调用

函数的入参各不相同,取决于他们具体要做的事情。这里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只使用最后两个: 一个用来为特定location配置来分配内存,(叫做ngx_http__create_loc_conf),另一个用来设定默认值以及合并继承过来的配置值(叫做ngx_http__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 */

};

现在开始讲得更深一点。这些配置回调函数看其来很像,所有模块都一样,而且Nginx的API都会用到这个部分,所以值得好好看看。

3.3.1. create_loc_conf

下面这段摘自我自己写的模块circle_gif(源代码),create_loc_conf的骨架大概就是这个样子. 它的入参是(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的包装函数),就不用担心内存的释放了。(TODO: to see why?) UNSET可能的常量有NGX_CONF_UNSET_UINT, NGX_CONF_UNSET_PTR, NGX_CONF_UNSET_SIZE, NGX_CONF_UNSET_MSEC, 以及无所不包的NGX_CONF_UNSET,UNSET让合并函数知道哪些变量是需要覆盖的。

3.3.2. merge_loc_conf

下面的例子是我的模块circle_gif中的合并函数:

static char *

ngx_http_circle_gif_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)

{

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提供了一些好用的合并函数用来合并不同类型的数据(ngx_conf_merge__value),这类函数的入参是:

1. 当前location 的变量值

2. 如果第一个参数没有被设置而采用的值

3. 如果第一第二个参数都没有被设置而采用的值

结果会被保存在第一个参数中。能用的合并函数包括ngx_conf_merge_size_value, ngx_conf_merge_msec_value 等等. 可参见core/ngx_conf_file.h.

问: 第一个参数是传值的,那如何能做到将结果保存到第一个参数中?

答: 这些函数都是由预处理命令定义的(在真正编译之前,它们会被扩展成一些if语句)

同时还需要注意的是错误的产生。函数会往log文件写一些东西,同时返回NGX_CONF_ERROR。这个返回值会将server的启动挂起。(因为被标示为NGX_LOG_EMERG级别,所以错误同时还会输出到标准输出。作为参考,core/ngx_log.h列出了所有的日志级别。)

3.4. 模块定义

接下来我们间接地介绍更深一层:结构体ngx_module_t。该结构体变量命名方式为ngx_http__module。它包含模块的内容和指令执行方式,同时也还包含一些回调函数(退出线程,退出进程,等等)。模块定义在有的时候会被用作查找的关键字,来查找与特定模块相关联的数据。模块定义通常像是这样:

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

};

...仅仅替换掉合适的就可以了。模块可以添加一些回调函数来处理线程/进程的创建和销毁,但是绝大多数模块都用NULL忽略这些东东。(关于这些回调函数的入参,可以参考core/ngx_conf_file.h.)

3.5. 模块装载

模块的装载方式取决于模块的类型:handler、filter还是load-balancer。所以具体的装载细节将留在其各自的章节中再做介绍。

4. Handlers

接下来我们把模块的细节放到显微镜下面来看,它们到底怎么运行的。

4.1. 剖析Handler(非代理)

Handler一般做4件事:获取location配置;生成合适的响应;发送响应头;发送响应体。Handler有一个参数,即请求结构体。请求结构体包含很多关于客户请求的有用信息,比如说请求方法,URI,请求头等等。我们一个个地来看。

3.1.1. 获取location配置

这部分很简单。只需要调用ngx_http_get_module_loc_conf,传入当前请求的结构体和模块定义即可。下面是我的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);

...

现在我们就可以访问之前在合并函数中设置的所有变量了。

4.1.2. 生成响应

这才是模块真正干活的地方,很有趣哦。

这里要用到请求结构体,主要是这些结构体成员:

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 是请求的路径, e.g. "/query.cgi". args 请求串参数中问号后面的参数(e.g. "name=john"). headers_in 包含有很多有用的东西,比如说cookie啊,浏览器信息啊什么的,但是许多模块可能用不到这些东东。如果你感兴趣的话,可以参看http/ngx_http_request.h 。

对于生成输出,这些信息应该是够了。完整的ngx_http_request_t结构体定义在http/ngx_http_request.h。

4.1.3. 发送响应头

响应头存放在结构体headers_out中,它的引用存放在请求结构体中。Handler设置相应的响应头的值,然后调用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/ngx_http_request.h找到。) 举例来说,如果一个模块要设置Content-Type 为"image/gif", Content-Length 为100, 并返回HTTP 200 OK 的响应, 代码应当是这样的:

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);

上面的设定方式针对大多数参数都是有效的。但一些头部的变量设定要比上面的例子要麻烦;比如,content_encoding 还含有类型(ngx_table_elt_t*),所以必须先为此分配空间。可以用一个叫做ngx_list_push 的函数来做,它传入一个ngx_list_t(与数组类似),返回一个list中的新成员(类型是ngx_table_elt_t)。下面的代码设置了Content-Encoding为"deflate"并发送了响应头:

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-Encoding";

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);

当头部有多个值时,这个机制常常被用到。它(理论上讲)使得过滤模块添加、删除某个值而保留其他值的时候更加容易,在操纵字符串的时候,不需要把字符串重新排序。

4.1.4. 发送响应体

现在模块已经生成了一个响应,并存放在了内存中。接下来它需要将这个响应分配给一个特定的缓冲区,然后把这个缓冲区加入到链表,然后调用链表中“发送响应体”的函数。

链表在这里起什么作用呢?Nginx 中,handler模块(其实filter模块也是)生成响应到buffer中是同时完成的;链表中的每个元素都有指向下一个元素的指针,如果是NULL 则说明链表到头了。简单起见,我们假设只有一个buffer。

首先,模块需要先声明buffer和链表:

ngx_buf_t *b;

ngx_chain_t out;

接着,需要给buffer分配空间,并将我们的响应数据指向它:

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 */

现在就可以把数据挂在链表上了:

out.buf = b;

out.next = NULL;

最后,我们发送这个响应体,返回值是链表在一次调用后的状态:(and return the status code of the output filter chain all in one go)

return ngx_http_output_filter(r, &out);

Buffer链是Nginx IO模型中的关键部分,你得比较熟悉它的工作方式。

问: 为什么buffer还需要有个`last_buf`变量啊,我们不是可以通过判断next是否是NULL来知道哪个是链表的最末端了吗?

答: 链表可能是不完整的,比如说,当有多个buffer的时候,并不是所有的buffer都属于当前的请求和响应。所以有些buffer可能是buffer链表的表尾,但是不是请求的结束。这给我们引入了接下来的内容……

4.2. 剖析Upstream(又称Proxy) Handler

我已经帮你了解了如何让你的handler来产生响应。有些时候你可以用一小段C代码就可以得到响应,但是通常情况下你需要同另外一台server打交道(比如你正在写一个用来实现某种网络协议的模块)。你当然可以自己实现一套网络编程的东东,但是如果你只收到部分的响应,需要等待余下的响应数据,你会怎么办?你不会想阻塞整个事件处理循环吧?这样会毁掉Nginx的良好性能!幸运的是,Nginx允许你在它处理后端服务器(叫做"upstreams")的机制上加入你的回调函数,因此你的模块将可以和其他的server 通信,同时还不会妨碍其他的请求。这一节将介绍模块如何和一个upstream(如Memcached, FastCGI,或者另一个HTTP server)通信。

4.2.1. Upstream 回调函数概要

与其他模块的回调处理函数不一样,upstream模块的处理函数几乎不做“实事”。它压根不调用ngx_http_output_filter。它仅仅是告诉回调函数什么时候可以向upstream server写数据了,以及什么时候能从upstream server读数据了。实际上它有6个可用的钩子:create_request 生成发送到upstream server的请求缓冲(或者一条缓冲链)reinit_request 在与后端服务器连接被重置的情况下(在create_request 被第二次调用之前)被调用process_header 处理upstream 响应的第一个bit,通常是保存一个指向upstream "payload"的指针abort_request 在客户端放弃请求时被调用inalize_request 在Nginx完成从upstream读取数据后调用input_filter 这是一个消息体的filter,用来处理响应消息体(例如把尾部删除) 这些钩子是怎么勾上去的呢?下面是一个例子,简单版本的代理模块处理函数:

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;

}

看上去都是些例行事务,不过重要的是那些回调函数。同时还要注意的是ngx_http_read_client_request_body,它又设置了一个回调函数,在Nginx完成从客户端读数据后会被调用。这些个回调函数都要做些什么工作呢?通常情况下,reinit_request, abort_request, 和finalize_request用来

设置或重置一些内部状态,但这些都是几行代码的事情。真正做苦力的是create_request 和process_header。

4.2.2. create_request 回调函数

简单起见,假设我有一个upstream server,它读入一个字符打印出两个字符。那么函数应该如何来写呢?create_request需要申请一个buffer来存放“一个字符”的请求,为buffer申请一个链表,并且把链表挂到upstream结构体上。看起来就像这样:

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。r->uri作为一个ngx_str_t类型也是有效的,GET的参数在r->args中,最后别忘了你还能访问请求头和cookie信息。

4.2.3. process_header 回调函数

现在轮到process_header了,就像create_request把链表指针挂到请求结构体上去一样,process_header 把响应指针移到客户端可以接收到的部分。同时它还会从upstream 读入头信息,并且相应的设置发往客户端的响应头。

这里有个小例子,读进两个字符的响应。我们假设第一个字符代表“状态”字符。如果它是问号,我们将返回一个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 character */

u->headers_in.status_n = 200;

break;

}

return NGX_OK;

}

就是这样。操作头部,改变指针,搞定!注意headers_in实际上就是我们之前提到过的头部结构体(http/ngx_http_request.h),但是它位于来自upstream的头中。一个真正的代理模块会在头信息的处理上做很多文章,不光是错误处理,做什么完全取决于你的想法。

但是……如果一个buffer没有能够装下全部的从upstream来的头信息,该怎么办呢?

4.2.4. 状态保持

好了,还记得我说过abort_request, reinit_request和finalize_request 可以用来重置内部状态吗?这是因为许多upstream模块都有其内部状态。模块需要定义一个自定义上下文结构,来标记目前为止从upstream 读到了什么。这跟之前说的“模块上下文”不是一个概念。“模块上下文”是预定义类型,而自定义上下文结构可以包含任何你需要的数据和字段(这可是你自己定义的结构体)。这个结构体在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);

最后一行实际上将自定义上下文结构体注册到了特定的请求和模块名上,以便在稍后取用。当你需要这个结构体时(可能所有的回调函数中都需要它),只需要:

ngx_http_proxy_ctx_t *p;

p = ngx_http_get_module_ctx(r, ngx_http_proxy_module);

指针p 可以得到当前的状态. 设置、重置、增加、减少、往里填数据……你可以随心所欲的操作它。当upstream服务器返回一块一块的响应时,读取这些响应的过程中使用持久状态机是个很nx的办法,它不用阻塞主事件循环。很好很强大!

4.3. Handler的装载

Handler的装载通过往模块启用了的指令的回调函数中添加代码来完成。比如,我的circle gif 中ngx_command_t是这样的:

{ ngx_string("circle_gif"),

NGX_HTTP_LOC_CONF|NGX_CONF_NOARGS,

ngx_http_circle_gif,

0,

0,

NULL }

回调函数是里面的第三个元素,在这个例子中就是那个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;

}

这里可以分为两步:首先,得到当前location的“core”结构体,再分配给它一个handler。很简单,不是吗?我已经把我知道的关于hanler模块的东西全招了,现在可以来说说输出过滤链上的filter模块了。

5. Filters

Filter操作handler生成的响应。头部filter操作HTTP头,body filter操作响应的内容。

5.1. 剖析Header Filter

头部Filter由三个步骤组成:

1. 决定何时操作响应

2. 操作响应

3. 调用下一个filter

举个例子,比如有一个简化版本的“不改变”头部filter:如果客户请求头中的If- Modified-Since和响应头中的Last-Modified相符,它把响应状态设置成304。注意这个头部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;

if_modified_since = ngx_http_parse_time(r->headers_in.if_modified_since->value.data,

r->headers_in.if_modified_since->value.len);

/* step 1: decide whether to operate */

if (if_modified_since != NGX_ERROR &&

if_modified_since == r->headers_https://www.doczj.com/doc/7311699107.html,st_modified_time) {

/* step 2: operate on the header */

r->headers_out.status = NGX_HTTP_NOT_MODIFIED;

r->headers_out.content_type.len = 0;

ngx_http_clear_content_length(r);

ngx_http_clear_accept_ranges(r);

}

/* step 3: call the next filter */

return ngx_http_next_header_filter(r);

}

结构headers_out和我们在hander那一节中看到的是一样的(参考http/ngx_http_request.h),也可以随意处置。

5.2. 剖析Body Filter

因为body filter一次只能操作一个buffer(链表),这使得编写body filter需要一定的技巧。模块需要知道什么时候可以覆盖输入buffer,用新申请的buffer_替换已有的,或者在现有的某个buffer前或后插入一个新buffer。有时候模块会收到许多buffer使得它不得不操作一个_不完整的链表,这使得事情变得更加复杂了。而更加不幸的是,Nginx没有为我们提供上层的API来操作buffer链表,所以body filter是比较难懂(当然也比较难写)。但是,有些操作你还是可以看出来的。

一个body filter原型大概是这个样子(例子代码从Nginx源代码的“chunked”filter中取得):

static ngx_int_t ngx_http_chunked_body_filter(ngx_http_request_t *r, ngx_chain_t *in);

第一个参数是我们的老朋友——请求结构体,第二个参数则是指向当前部分链表(可能包含0,1,或更多的buffer)头的指针。

再来举个例子好了。假设我们想要做的是在每个请求之后插入文本""。首先,我们需要判断给我们的buffer链表中是否已经包含响应的最终buffer。就像之前我说的,这里没有简便好用的API,所以我们只能自己来写个循环:

ngx_chain_t *chain_link;

int chain_contains_last_buffer = 0;

for ( chain_link = in; chain_link != NULL; chain_link = chain_link->next ) {

if (chain_link->buf->last_buf)

chain_contains_last_buffer = 1;

}

如果我们没有最后的缓冲区,就返回:

if (!chain_contains_last_buffer)

return ngx_http_next_body_filter(r, in);

很好,现在最后一个缓冲区已经存在链表中了。接下来我们分配一个新缓冲区:

ngx_buf_t *b;

b = ngx_calloc_buf(r->pool);

if (b == NULL) {

return NGX_ERROR;

}

把数据放进去:

b->pos = (u_char *) "";

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

把这个缓冲区挂在新的链表上:

ngx_chain_t added_link;

added_link.buf = b;

added_link.next = NULL;

最后,把这个新链表挂在先前链表的末尾:

chain_link->next = added_link;

并根据变化重置变量"last_buf"的值:

chain_link->buf->last_buf = 0;

added_link->buf->last_buf = 1;

再将修改过的链表传递给下一个输出过滤函数:

return ngx_http_next_body_filter(r, in);

现有的函数做了比我们更多的工作,比如mod_perl($response->body =~ s/$//),但是缓冲区链确实是一个强大的构想,它可以让程序员渐进地处理数据,这使得客户端可以尽可能早地得到响应。但是依我来看,缓冲区链表实在需要一个更为干净的接口,这样程序员也可以避免操作不一致状态的链表。但是目前为止,所有的操作风险都得自己控制。

5.3. Filter的装载

Filter在在回调函数post-configuration中被装载。header filter和body filter都是在这里被装载的。

我们以chunked filter模块为例来具体看看:

static ngx_http_module_t ngx_http_chunked_filter_module_ctx = {

NULL, /* preconfiguration */

ngx_http_chunked_filter_init, /* postconfiguration */

...

};

ngx_http_chunked_filter_init中的具体实现如下:

static ngx_int_t

ngx_http_chunked_filter_init(ngx_conf_t *cf)

{

ngx_http_next_header_filter = ngx_http_top_header_filter;

ngx_http_top_header_filter = ngx_http_chunked_header_filter;

ngx_http_next_body_filter = ngx_http_top_body_filter;

ngx_http_top_body_filter = ngx_http_chunked_body_filter;

return NGX_OK;

}

发生了什么呢?好吧,如果你还记得,过滤模块组成了一条”接力链表“。当handler生成一个响应

后,调用2个函数:ngx_http_output_filter它调用全局函数ngx_http_top_body_filter;以及ngx_http_send_header 它调用全局函数ngx_top_header_filter。

ngx_http_top_body_filter 和ngx_http_top_header_filter是body和header各自的头部filter链的”链表头“。链表上的每一个”连接“都保存着链表中下一个连接的函数引用(分别是ngx_http_next_body_filter 和ngx_http_next_header_filter)。当一个filter完成工作之后,它只需要调用下一个filter,直到一个特殊的被定义成”写“的filter被调用,这个”写“filter的作用是包装最终的HTTP响应。你在这个filter_init 函数中看到的就是,模块把自己添加到filter链表中;它先把旧的”头部“filter当做是自己的”下一个“,然后再声明”它自己“是”头部“filter。(因此,最后一个被添加的filter会第一个被执行。)

边注: 这到底是怎么工作的?

每个filter要么返回一个错误码,要么用`return ngx_http_next_body_filter();`来作为返回语句

因此,如果filter顺利链执行到了链尾(那个特别定义的的”写“filter),将返回一个"OK"响应,但如果执行过程中遇到了错误,链将被砍断,同时Nginx将给出一个错误的信息。这是一个单向的,错误快速返回的,只使用函数引用实现的链表。帅啊!

6. Load-balancers

Load-balancer用来决定哪一个后端将会收到请求;具体的实现是round-robin方式或者把请求进行hash。本节将介绍load-balancer模块的装载及其调用。我们将用upstream_hash_module(full source)作例子。upstream_hash将对nginx.conf里配置的变量进行hash,来选择后端服务器。

一个load-balancer分为六个部分:

1. 启用配置指令(e.g, hash;) 将会调用注册函数

2. 注册函数将定义一些合法的server 参数(e.g., weight=) 并注册一个upstream初始化函数

3. upstream初始化函数将在配置经过验证后被调用,并且:

* 解析server 名称为特定的IP地址

* 为每个sokcet连接分配空间

* 设置对端初始化函数的回调入口

4. 对端初始化函数将在每次请求时被调用一次,它主要负责设置一些负载均衡函数将会使用的数据结构。

5. 负载均衡函数决定把请求分发到哪里;每个请求将至少调用一次这个函数(如果后端服务器失败了,那就是多次了),有意思的事情就是在这里做的。

6. 最后,对端释放函数可以在与对应的后端服务器结束通信之后更新统计信息(成功或失败)

好像很多嘛,我来逐一讲讲。

6.1. 启用指令

指令声明,既确定了他们在哪里生效又确定了一旦流程遇到指令将要调用什么函数。load-balancer的指令需要置NGX_HTTP_UPS_CONF标志位,一遍让Nginx知道这个指令只会在upstream块中有效。同

时它需要提供一个指向注册函数的指针。下面列出的是upstream_hash模块的指令声明:

{ ngx_string("hash"),

NGX_HTTP_UPS_CONF|NGX_CONF_NOARGS,

ngx_http_upstream_hash,

0,

0,

NULL },

都是些很眼熟的东西。

6.2. 注册函数

上面的回调函数ngx_http_upstream_hash就是所谓的注册函数。之所以这样叫(我起得名字)是因为它注册了把upstream初始化函数和周边的upstream配置注册到了一块。另外,注册函数还定义了特定upstream 块中的server指令的一些选项(如weight=, fail_timeout=),下面是upstream_hash模块的注册函数:ngx_http_upstream_hash(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)

{

ngx_http_upstream_srv_conf_t *uscf;

ngx_http_script_compile_t sc;

ngx_str_t *value;

ngx_array_t *vars_lengths, *vars_values;

value = cf->args->elts;

/* the following is necessary to evaluate the argument to "hash" as a $variable */

ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));

vars_lengths = NULL;

vars_values = NULL;

sc.cf = cf;

sc.source = &value[1];

sc.lengths = &vars_lengths;

sc.values = &vars_values;

https://www.doczj.com/doc/7311699107.html,plete_lengths = 1;

https://www.doczj.com/doc/7311699107.html,plete_values = 1;

if (ngx_http_script_compile(&sc) != NGX_OK) {

return NGX_CONF_ERROR;

}

/* end of $variable stuff */

uscf = ngx_http_conf_get_module_srv_conf(cf, ngx_http_upstream_module);

/* the upstream initialization function */

uscf->peer.init_upstream = ngx_http_upstream_init_hash;

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.doczj.com/doc/7311699107.html,/masterzen/nginx-upload-progress-module/archive/v0.9.1.tar.gz $ wget https://https://www.doczj.com/doc/7311699107.html,/vkholodkov/nginx-upload-module/archive/2.2.0.tar.gz $ wget https://www.doczj.com/doc/7311699107.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.doczj.com/doc/7311699107.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.doczj.com/doc/7311699107.html, Date:2010-10-26 1)取Nginx最新代码: wget https://www.doczj.com/doc/7311699107.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.doczj.com/doc/7311699107.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.doczj.com/doc/7311699107.html,/cn/,英文主页为https://www.doczj.com/doc/7311699107.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.doczj.com/doc/7311699107.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.doczj.com/doc/7311699107.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不间断运行,即使运行数个月也不需要重新启动。

相关主题
文本预览
相关文档 最新文档