系统相关
首页 > 系统相关> > ngx——共享内存

ngx——共享内存

作者:互联网

0. 简介

共享内存是ngx实现 进程间 全局对象 的方法,
比如 一个抗cc模块,需要记录 cc数据,但 进程间内存隔离,导致 工作进程 只能记录访问自己的 cc数据,
所以需要申请一个共享内存,在共享内存上构造cc数据,多个工作进程互斥操作 该对象。

1 ngx_shm_zone_t

 25 typedef struct ngx_shm_zone_s  ngx_shm_zone_t;
 26
 27 typedef ngx_int_t (*ngx_shm_zone_init_pt) (ngx_shm_zone_t *zone, void *da    ta);
 28
 29 struct ngx_shm_zone_s {
 30     void                     *data;
 31     ngx_shm_t                 shm;
 32     ngx_shm_zone_init_pt      init;    // 初始化本内存块时,用户的hook
 33     void                     *tag;     // 用户表示
 34     void                     *sync;
 35     ngx_uint_t                noreuse;  /* unsigned  noreuse:1; */
 36 };

 16 typedef struct {
 17     u_char      *addr;     // 起始地址
 18     size_t       size;     // 大小
 19     ngx_str_t    name;     // 共享块名称
 20     ngx_log_t   *log;
 21     ngx_uint_t   exists;   /* unsigned  exists:1;  */
 22 } ngx_shm_t;

ngx_shm_zone_t.tag 解释:
当模块A,使用 共享块名称sun 取得共享块sun 时,若模块B 也用共享块名称sun获得 共享块sun,
但是共享块sun已经被 模块A占用,所以为了表示 当前共享块用户,添加 tag 属性。
通常 tag 等于 所属模块的 地址。

ngx_shm_zone_t.data :
基于本共享块的 对象
一个共享块,应该专注于一个共享对象的实现,所以 一个共享块只需要一个 data指针

2. 登记 共享内存 需求

需要使用共享内存的模块,调用 ngx_shared_memory_add
如 limit_req 模块 在配置解析时,登记 共享块 需求。

   832 static char *
   833 ngx_http_limit_req_zone(ngx_conf_t *cf, ngx_command_t *cmd, void *conf       )
   834 {
   941     shm_zone = ngx_shared_memory_add(cf, &name, size,
   942                                      &ngx_http_limit_req_module);
   956     shm_zone->init = ngx_http_limit_req_init_zone;
   957     shm_zone->data = ctx;

ngx_shared_memory_add,将 共享块信息 加入 链表 cf->cycle->shared_memory.part,
若 链表中已经存在共享块信息,则直接返回。

3. ngx 分配共享内存

解析完所有模块配置后,ngx 收集了所有模块 对 共享内存块 的需求,
并进行分配内存

    38 ngx_cycle_t *
    39 ngx_init_cycle(ngx_cycle_t *old_cycle)
    40 {
   165     if (old_cycle->shared_memory.part.nelts) {
   166         n = old_cycle->shared_memory.part.nelts;
   167         for (part = old_cycle->shared_memory.part.next; part; part = p       art->next)
   168         {
   169             n += part->nelts;
   170         }
   171
   172     } else {
   173         n = 1;
   174     }
   175
   176     ngx_list_init(&cycle->shared_memory, pool, n, sizeof(ngx_shm_z       one_t);

            // 解析配置,登记 模块 对共享内存的需求
   278     ngx_conf_param(&conf);
   284     ngx_conf_parse(&conf, &cycle->conf_file);

   413     /* create shared memory */
   415     part = &cycle->shared_memory.part;
   416     shm_zone = part->elts;
   418     for (i = 0; /* void */ ; i++) {
   438         opart = &old_cycle->shared_memory.part;
   439         oshm_zone = opart->elts;

   441         for (n = 0; /* void */ ; n++) {
   452             if (shm_zone[i].shm.name.len != oshm_zone[n].shm.name.len)        {
   453                 continue;
   454             }
   456             if (ngx_strncmp(shm_zone[i].shm.name.data,
   457                             oshm_zone[n].shm.name.data,
   458                             shm_zone[i].shm.name.len)
   459                 != 0)
   460             {
   461                 continue;
   462             }
   464             if (shm_zone[i].tag == oshm_zone[n].tag
   465                 && shm_zone[i].shm.size == oshm_zone[n].shm.size
   466                 && !shm_zone[i].noreuse)
   467             {
                      // 找到上个周期的 共享内存块,继承上周期内存块
   468                 shm_zone[i].shm.addr = oshm_zone[n].shm.addr;
   472
   473                 if (shm_zone[i].init(&shm_zone[i], oshm_zone[n].data)
   474                     != NGX_OK)
   475                 {
   476                     goto failed;
   477                 }
   478
   479                 goto shm_zone_found;
   480             }
   482             break;
   483         }
               // 若上周期没有对应 内存块,则分配
   485         if (ngx_shm_alloc(&shm_zone[i].shm) != NGX_OK) {
   486             goto failed;
   487         }
   488         // 使用 slab 算法管理 共享块
   489         if (ngx_init_zone_pool(cycle, &shm_zone[i]) != NGX_OK) {
   490             goto failed;
   491         }
   492         // 使用模块的 hook 初始化
   493         if (shm_zone[i].init(&shm_zone[i], NULL) != NGX_OK) {
   494             goto failed;
   495         }
   496
   497     shm_zone_found:
   498
   499         continue;
   500     }

4. 模块对 初始化基于共享块的 对象

ngx 传入参数,
shm_zone : 可使用的共享块
data : 上周期的 shm.data
用户需要 记录共享内存池地址,并在内存池上构造 自己的共享对象。

   698 static ngx_int_t
   699 ngx_http_limit_req_init_zone(ngx_shm_zone_t *shm_zone, void *data)
   700 {
   701     ngx_http_limit_req_ctx_t  *octx = data;
   702
   703     size_t                     len;
   704     ngx_http_limit_req_ctx_t  *ctx; 
   705
   706     ctx = shm_zone->data;   //  limit模块在 申请共享块时,设置 shm_zone->data = ctx;
   708     if (octx) {  // 若有上周期数据,则直接继承
   721
   722         ctx->sh = octx->sh;   // limit模块自己的数据结构
   723         ctx->shpool = octx->shpool;  // 基于共享块的内存池 
   724
   725         return NGX_OK;
   726     }
   727
   728     ctx->shpool = (ngx_slab_pool_t *) shm_zone->shm.addr;
   729
   730     if (shm_zone->shm.exists) {
   731         ctx->sh = ctx->shpool->data;
   732
   733         return NGX_OK;
   734     }
   735
   736     ctx->sh = ngx_slab_alloc(ctx->shpool, sizeof(ngx_http_limit_req_sh       ctx_t));
   737     if (ctx->sh == NULL) {
   738         return NGX_ERROR;
   739     }
   741     ctx->shpool->data = ctx->sh;
   743     ngx_rbtree_init(&ctx->sh->rbtree, &ctx->sh->sentinel,
   744                     ngx_http_limit_req_rbtree_insert_value);
   745
   746     ngx_queue_init(&ctx->sh->queue);
   747
   748     len = sizeof(" in limit_req zone \"\"") + shm_zone->shm.name.len;
   749
   750     ctx->shpool->log_ctx = ngx_slab_alloc(ctx->shpool, len);
   751     if (ctx->shpool->log_ctx == NULL) {
   752         return NGX_ERROR;
   753     }
   754
   755     ngx_sprintf(ctx->shpool->log_ctx, " in limit_req zone \"%V\"%Z",
   756                 &shm_zone->shm.name);
   757
   758     ctx->shpool->log_nomem = 0;
   759
   760     return NGX_OK;
   761 }

5. 共享块使用

 62 void ngx_slab_sizes_init(void);
 63 void ngx_slab_init(ngx_slab_pool_t *pool);    // 重新构造 slab 机制,意味从前从内存块分配的内存全部失效
 64 void *ngx_slab_alloc(ngx_slab_pool_t *pool, size_t size);
 65 void *ngx_slab_alloc_locked(ngx_slab_pool_t *pool, size_t size);
 66 void *ngx_slab_calloc(ngx_slab_pool_t *pool, size_t size);
 67 void *ngx_slab_calloc_locked(ngx_slab_pool_t *pool, size_t size);
 68 void ngx_slab_free(ngx_slab_pool_t *pool, void *p);
 69 void ngx_slab_free_locked(ngx_slab_pool_t *pool, void *p);

标签:zone,ngx,void,ctx,共享内存,slab,shm
来源: https://www.cnblogs.com/yangxinrui/p/16263600.html