支持HW团队,就支付宝领取下面的红包吧! (打开支付宝就能领取!er1OEj73Uj), (打开支付宝收索“516503473”), 你领取消费,HW有奖励。红包使用无条件限制,有条件请注意是不是有病毒。

登入 注册 | 验证
| 搜索

博主:初学MPEG

初学MPEG 本博客-采用Python的web框架Django与Mysql数据库,致力于对Python、Django的了解 与研究
Django技术QQ群:XXXXXXX
Python技术QQ群:XXXXXXX

分类

关键字

本站最新博文

友情链接  

[转]Nginx共享内存(一):共享内存的使用

类别:其他 状态:游客可见,可回,自己可关联(良好) 阅读:5853 评论:0 时间:四月 8, 2012, 4:27 p.m.
关键字: nginx 共享内存

  来源:程序非主流http://blog.lifeibo.com/?p=211

在nginx中使用共享内存是非常方便与高效的,这得益于作者为我们封装了共享内存操作的方法,以及结合slab进行共享内存的管理 。我先大致讲讲共享内存使用的几个步骤,然后再结合HttpLimitReqModule来实例分析一下共享内存的使用。在下一篇,将为大家介绍共享内存的实现源码。

首先,要使用共享内存,大致为以下几步,可能不同的应用之间会小有点区别,但我们先学会使用简单的,然后我们等对nginx中的共享内存的原理了解之后,就可以轻松运用了。
1. 一般我们需要几个变量来管理共享内存,一般放到全局的配置结构全中去,或直接一个全局变量。ngx_shm_zone_t指针来引用 我们创建的共享内存、ngx_slab_pool_t指针来管理我们共享内存的分配与释放。
2. 在读取或初始化配置文件时,调用ngx_shared_memory_add向全局共享内存链表中添加一个共享内存,然后保存到之前创建的gx_shm_zone_t指针。接着,注册我们自己的共享内存初始化函数。
3. 在我们自己的初始化函数中, 我们将共享内存初始地址转换为ngx_slab_pool_t指针保存到在步骤一中创建的那个ngx_slab_pool_t指针中。那么在后面,我们就通过这个ngx_slab_pool_t来进行共享内存的分配与释放。

下面,我们结合HttpLimitReqModule来分析一下如何使用共享内存。
1. 首先看看该模块中的几个变量声明:

typedef struct {  
    ngx_shm_zone_t              *shm_zone;    // 保存我们创建的共享内存  
    * * *  
} ngx_http_limit_req_conf_t;  
  
typedef struct {  
    ngx_http_limit_req_shctx_t  *sh;    // 我们的共享数据结构  
    ngx_slab_pool_t             *shpool;  // 共享内存的slab分配  
    * * *  
} ngx_http_limit_req_ctx_t;  
  
// 共享内存结构体  
typedef struct {  
    ngx_rbtree_t                  rbtree;  
    ngx_rbtree_node_t             sentinel;  
    ngx_queue_t                   queue;  
} ngx_http_limit_req_shctx_t;  


2. 在配置文件读取时, 我们会创建共享内存。该模块在配置项limit_req_zone读取时调用函数ngx_http_limit_req_zone,而在此函数中,我们会调用ngx_shared_memory_add来创建我们的共享内存,以及注册我们的初始化函数ngx_http_limit_req_init_zone。看看代码:

static char *  
ngx_http_limit_req_zone(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)  
{  
   ngx_http_limit_req_ctx_t  *ctx;  
    * * *  
   // 创建共享内存  
   shm_zone = ngx_shared_memory_add(cf, &name, size,  
                                     &ngx_http_limit_req_module);  
    if (shm_zone == NULL) {  
        return NGX_CONF_ERROR;  
    }  
  
    // 设置初始化函数  
    shm_zone->init = ngx_http_limit_req_init_zone;  
    // ctx为本地的配置文件,而ctx中保存共享内存的地址  
    // 即ctx->sh与ctx->shpool  
    // 这样通过共享内存就可以拿到对应的ctx了  
    shm_zone->data = ctx;  
  
    * * *  
} 

3. 然后接下来,在读取配置文件完成后,进程在对共享内存做初始化时,会调用我们的初始化函数ngx_http_limit_req_init_zone。为说明情况,我对代码进行了简化。

static ngx_int_t  
ngx_http_limit_req_init_zone(ngx_shm_zone_t *shm_zone, void *data)  
{  
    ngx_http_limit_req_ctx_t  *octx = data;  
    ngx_http_limit_req_ctx_t  *ctx;  
  
    ctx = shm_zone->data;  
  
    * * *  
    // 在做reload操作时,会传进来  
    if (octx) {  
        if (ngx_strcmp(ctx->var.data, octx->var.data) != 0) {  
            ngx_log_error(NGX_LOG_EMERG, shm_zone->shm.log, 0,  
                          "limit_req \"%V\" uses the \"%V\" variable "  
                          "while previously it used the \"%V\" variable",  
                          &shm_zone->shm.name, &ctx->var, &octx->var);  
            return NGX_ERROR;  
        }  
  
        // 由于octx是本地内存中分配的,也是在old_cycle中分配的,所以需要在新的ctx中重新初始化一下  
        // 所以这里只是关于本地内存的重新初始化,而关于共享内存中的初始化工具就不需要再做了  
        ctx->sh = octx->sh;  
        ctx->shpool = octx->shpool;  
  
        return NGX_OK;  
    }  
  
    // 下面是关于共享内存中数据结构的初始化  
  
    // 将共享内存指针转换成slab分配池管理,并保存  
    ctx->shpool = (ngx_slab_pool_t *) shm_zone->shm.addr;  
  
    if (shm_zone->shm.exists) {  
        ctx->sh = ctx->shpool->data;  
  
        return NGX_OK;  
    }  
  
    // 之后,就可以使用此共享内存进行空间的分配了  
    ctx->sh = ngx_slab_alloc(ctx->shpool, sizeof(ngx_http_limit_req_shctx_t));  
    if (ctx->sh == NULL) {  
        return NGX_ERROR;  
    }  
  
    return NGX_OK;  
}  

4. 在后面的模块中,我们可以使用ngx_slab_alloc_locked以及ngx_slab_free_locked进行共享内存的分配与释放了。关于slab分配器的使用与分析,在我之前的文章中已有介绍:)。比如,在ngx_http_limit_req_handler中进行使用:

static ngx_int_t  
ngx_http_limit_req_handler(ngx_http_request_t *r)  
{  
    * * *  
    // 在共享内存中创建一个结点  
    node = ngx_slab_alloc_locked(ctx->shpool, n);  
    if (node == NULL) {  
  
        // 共享内存空间不足,则尝试释放一点空间  
        ngx_http_limit_req_expire(ctx, 0);  
  
        node = ngx_slab_alloc_locked(ctx->shpool, n);  
        if (node == NULL) {  
            ngx_shmtx_unlock(&ctx->shpool->mutex);  
            return NGX_HTTP_SERVICE_UNAVAILABLE;  
        }  
    }  
  
    // 下面对该结点进行初始化操作  
    lr = (ngx_http_limit_req_node_t *) &node->color;  
  
    node->key = hash;  
    lr->len = (u_char) len;  
  
    tp = ngx_timeofday();  
    lr->last = (ngx_msec_t) (tp->sec * 1000 + tp->msec);  
  
    lr->excess = 0;  
    ngx_memcpy(lr->data, vv->data, len);  
  
    // 加入到rbtree里面  
    ngx_rbtree_insert(&ctx->sh->rbtree, node);  
  
    * * *  
} 

好啦,共享内存的使用还是比较简单的!Have fun!!!

操作:

Please Login (or Sign Up) to leave a comment