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