目录
- 1. 概述
- 2. 开启upstream共享内存机制
- 3. 源码分析
- 3.1 配置指令分析
- 3.2 共享内存区的初始化
1. 概述
我们知道,nginx的配置是由主进程来加载到内存的,然后fork出各个worker进程,而worker进程自然继承了主进程的内存状态,所以worker进程自然有了加载好的配置信息。然而,每个worker进程运行起来后,它们就各自为政互不干涉的,譬如说upstream功能的各个Real Server的服务器状态也是独立维护的,这样,可能worker A可能已经认为某个后端服务器不可用了,然而worker B却还认为其可用继续将请求发送到这个后端服务器,这就导致多个worker之间的状态不一致。
为了解决这个问题,nginx引入了ngx_http_upstream_zone_module模块来解决这个问题,当upstream的配置加载完成后,ngx_http_upstream_zone_module模块会把peer信息拷贝到分配好的共享内存中,后续每个worker就在共享内存中进行peer信息的读写,从而解决worker之间peer信息不一致的问题,通过共享内存的方式,甚至可以很方便地实现Real Server的运行时动态增删改操作(在nginx的商业版中提供了这个能力)。当然由于是多进程共享,因此需要必然需要用到跨进程的读写锁,在一定程度上可能对性能有些许影响。
2. 开启upstream共享内存机制
ngx_http_upstream_zone_module模块仅提供了一个指令来开启共享内存机制,如下:
语 法:zone name [size]
默 认:-
上下文:upstream
以上指令定义了一个名字为name大小为size的共享内存区,用来保存upstream的配置和运行时状态信息供各个worker进程使用。而且多个upstream可以共享一个同名字的zone,这样子,只要为一个upstream的zone配置指定一个size值就可以了。举例如下:
upstream {zone peer_sh_zone 1m;server 192.168.0.1 weight=1;server 192.168.0.2 weight=1;server 192.168.0.3 weight=1;
}
特别提一下,当然nginx本身也是支持不开启upstream共享内存机制的,只是可能导致多个worker进程各自管理自己的upstream的配置和状态信息,大部分情况下这不会是什么大的问题。
3. 源码分析
以下结合ngx_http_upstream_zone_module和ngx_http_upstream_round_robin两个模块来进行详细分析。
3.1 配置指令分析
在ngx_http_upstream_zone_module中定义了如下配置指令:
static ngx_command_t ngx_http_upstream_zone_commands[] = {{ ngx_string("zone"),NGX_HTTP_UPS_CONF|NGX_CONF_TAKE12,ngx_http_upstream_zone,0,0,NULL },ngx_null_command
};
所以,nginx在分析到upstream块中的zone指令的时候,就会调用ngx_http_upstream_zone函数进行zone指令的解析,下面来分析ngx_http_upstream_zone函数,函数的源码如下:
static char *
ngx_http_upstream_zone(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{ssize_t size;ngx_str_t *value;ngx_http_upstream_srv_conf_t *uscf;ngx_http_upstream_main_conf_t *umcf;uscf = ngx_http_conf_get_module_srv_conf(cf, ngx_http_upstream_module);umcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_upstream_module);value = cf->args->elts;if (!value[1].len) {ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,"invalid zone name \"%V\"", &value[1]);return NGX_CONF_ERROR;}/* 配置的参数个数如果是2个说明有size字段, 以下解析size字段的值 */if (cf->args->nelts ==