Nginx源码分析(1)之——共享内存的配置、分配及初始化
2016-03-23 16:25
841 查看
在Nginx里,一块完整的共享内存以数据结构ngx_shm_zone_t来封装表示。
要在Nginx里使用一个共享内存,需要在配置文件里加上该共享内存的相关信息(添加一条指令),如:共享内存的名称,共享内存的大小等。因此在配置解析阶段,解析到相应的指令时,会创建对应的共享内存(此时创建的仅仅是代表共享内存的结构体:ngx_shm_zone_t,真实共享内存的分配在ngx_init_cycle(&init_cycle)解析完配置后进行并初始化)。见:
最后,推荐两本书:
《深入剖析Nginx》 by 高群凯
《深入理解Nginx ——模块开发与架构解析》 by 陶辉
typedef struct { u_char *addr; // 分配的共享内存的实际地址(这里实际共享内存的分配,根据当前系统可提供的接口,可以调用mmap或者shmget来进行分配,具体的用法,自己man吧) size_t size; // 共享内存的大小 ngx_str_t name; // 该字段用作共享内存的唯一标识,能让Nginx知道想使用哪个共享内存 ngx_log_t *log; ngx_uint_t exists; /* unsigned exists:1; */ } ngx_shm_t; typedef struct ngx_shm_zone_s ngx_shm_zone_t; typedef ngx_int_t (*ngx_shm_zone_init_pt) (ngx_shm_zone_t *zone, void *data); struct ngx_shm_zone_s { void *data; // 指向自定义数据结构,一般用来初始化时使用,可能指向本地地址 ngx_shm_t shm; // 真正的共享内存所在 ngx_shm_zone_init_pt init; // 这里有一个钩子函数,用于实际共享内存进行分配后的初始化 void *tag; // 区别于shm.name,shm.name没法让Nginx区分到底是想新创建一个共享内存,还是使用已存在的旧的共享内存 // 因此这里引入tag字段来解决该问题,tag一般指向当前模块的ngx_module_t变量,见:... };
要在Nginx里使用一个共享内存,需要在配置文件里加上该共享内存的相关信息(添加一条指令),如:共享内存的名称,共享内存的大小等。因此在配置解析阶段,解析到相应的指令时,会创建对应的共享内存(此时创建的仅仅是代表共享内存的结构体:ngx_shm_zone_t,真实共享内存的分配在ngx_init_cycle(&init_cycle)解析完配置后进行并初始化)。见:
int ngx_cdecl main(int argc, char *const *argv) // 在master进程中 { cycle = ngx_init_cycle(&init_cycle); { if (ngx_conf_parse(&conf, &cycle->conf_file) != NGX_CONF_OK) { // 解析配置 { 解析到http指令(进入ngx_http_block()) { // 会依次执行 typedef struct { ngx_int_t (*preconfiguration)(ngx_conf_t *cf); /* 执行顺序4 */ ngx_int_t (*postconfiguration)(ngx_conf_t *cf); /* 执行顺序8 */ void *(*create_main_conf)(ngx_conf_t *cf); /* 执行顺序1 */ char *(*init_main_conf)(ngx_conf_t *cf, void *conf); /* 执行顺序5 */ void *(*create_srv_conf)(ngx_conf_t *cf); /* 执行顺序2 */ char *(*merge_srv_conf)(ngx_conf_t *cf, void *prev, void *conf); /* 执行顺序6 */ void *(*create_loc_conf)(ngx_conf_t *cf); /* 执行顺序3 */ char *(*merge_loc_conf)(ngx_conf_t *cf, void *prev, void *conf); /* 执行顺序7 */ } ngx_http_module_t; 同时,还有个执行顺序4.5: struct ngx_command_s { /* 执行顺序4.5 */ ngx_str_t name; ngx_uint_t type; char *(*set)(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); ngx_uint_t conf; ngx_uint_t offset; void *post; }; for (m = 0; ngx_modules[m]; m++) { if (module->create_main_conf) {ctx->main_conf[mi] = module->create_main_conf(cf);} if (module->create_srv_conf) {ctx->srv_conf[mi] = module->create_srv_conf(cf);} if (module->create_loc_conf) {ctx->loc_conf[mi] = module->create_loc_conf(cf);} } for (m = 0; ngx_modules[m]; m++) { if (module->preconfiguration) {if (module->preconfiguration(cf) != NGX_OK) {} } rv = ngx_conf_parse(cf, NULL); { /* * 指令的解析 * 共享内存配置相关的指令也在这里进行解析 * 详细见: * ngx_shm_zone_t * * ngx_shared_memory_add(ngx_conf_t *cf, ngx_str_t *name, size_t size, void *tag) */ } for (m = 0; ngx_modules[m]; m++) { if (module->init_main_conf) {rv = module->init_main_conf(cf, ctx->main_conf[mi]);} rv = ngx_http_merge_servers(cf, cmcf, module, mi); } for (m = 0; ngx_modules[m]; m++) { if (module->postconfiguration) {if (module->postconfiguration(cf) != NGX_OK)} } } } // in ngx_init_cycle(&init_cycle) line: 462 if (ngx_shm_alloc(&shm_zone[i].shm) != NGX_OK) /* 实际共享内存分配的地方 */ line: 466 if (ngx_init_zone_pool(cycle, &shm_zone[i]) != NGX_OK) /* 共享内存管理机制的初始化 * 共享内存的使用涉及另外两个主题: * 1、多进程共同使用时之间的互斥问题 * 2、引入特定的使用方式(slab机制,这在下一个主题:“Nginx源码分析(2)之——共享内存管理之slab机制”中进行介绍),以提高性能 */ line: 470 if (shm_zone[i].init(&shm_zone[i], NULL) != NGX_OK) /* 分配之后的初始化 */ } } ngx_shm_zone_t * ngx_shared_memory_add(ngx_conf_t *cf, ngx_str_t *name, size_t size, void *tag) { ngx_uint_t i; ngx_shm_zone_t *shm_zone; ngx_list_part_t *part; /* * Nginx中所有的共享内存都以list链表的形式组织在全局变量cf->cycle->shared_memory中 * 在创建新的共享内存之前,会对该链表进行遍历查找以及冲突检测, * 对于已经存在且不存在冲突时,对共享内存直接进行返回并引用 * 存在且不存在冲突:共享内存的名称相同,大小相同,且tag指向的是同一个模块 * 有冲突,则报错 * 否则,重新分配ngx_shm_zone_t,并挂到全局链表cf->cycle->shared_memory中,最后进行结构初始化 * shm_zone = ngx_list_push(&cf->cycle->shared_memory); * 至此: * 仅仅是创建了共享内存的结构体:ngx_shm_zone_t,ngx_shm_zone_t.shm.addr指向的真实共享内存并没有进行实际的分配 */ part = &cf->cycle->shared_memory.part; shm_zone = part->elts; for (i = 0; /* void */ ; i++) { if (i >= part->nelts) { if (part->next == NULL) { break; } part = part->next; shm_zone = part->elts; i = 0; } if (name->len != shm_zone[i].shm.name.len) { continue; } if (ngx_strncmp(name->data, shm_zone[i].shm.name.data, name->len) != 0) { continue; } if (tag != shm_zone[i].tag) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "the shared memory zone \"%V\" is " "already declared for a different use", &shm_zone[i].shm.name); return NULL; } if (size && size != shm_zone[i].shm.size) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "the size %uz of shared memory zone \"%V\" " "conflicts with already declared size %uz", size, &shm_zone[i].shm.name, shm_zone[i].shm.size); return NULL; } return &shm_zone[i]; } shm_zone = ngx_list_push(&cf->cycle->shared_memory); if (shm_zone == NULL) { return NULL; } shm_zone->data = NULL; shm_zone->shm.log = cf->cycle->log; shm_zone->shm.size = size; shm_zone->shm.name = *name; shm_zone->shm.exists = 0; shm_zone->init = NULL; shm_zone->tag = tag; return shm_zone; }
最后,推荐两本书:
《深入剖析Nginx》 by 高群凯
《深入理解Nginx ——模块开发与架构解析》 by 陶辉
相关文章推荐
- ubuntu14.04 LEMP(linux+nginx+mysql+php5)构建环境
- Puppet模块(八):keepalived模块
- Puppet模块(七):nginx模块
- Nginx Location配置总结
- zabbix 监控Nginx
- nginx 502错误
- 使用nginx配置Laravel中的虚拟站点
- [nginx] 网上最全面nginx教程(近100篇文章整理)
- centos直接yum安装nginx
- Nginx多站点配置
- Nginx的 UDP 负载均衡
- Nginx服务状态监控
- 配置Nginx多核CPU,worker_cpu_affinity使用方法和范例
- nginx开启gzip
- CentOS 6.6 安装 nginx
- nginx动静分离
- lvs+nginx负载均衡部署
- nginx 动、静分离 配置
- nginx缓存及压缩模块
- nginx负载均衡