深入理解nginx upstream共享内存机制

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 == 3) {
   
        size = ngx_parse_size(&value[2
  • 27
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

码农心语

您的鼓励是我写作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值