• 售前

  • 售后

热门帖子
入门百科

nginx中共享内存的使用详解

[复制链接]
mzhqyy 显示全部楼层 发表于 2021-10-26 13:43:08 |阅读模式 打印 上一主题 下一主题
在nginx的进程模子下,雷同流量统计、流量控制、数据共享、等需要多个工作进程共同配合完成任务,共享内存是一个紧张的进程通讯的方案。本文介绍在nginx的代码中与共享内存相干的功能,包括ngx_shmem与ngx_slab的利用与留意事项,但不包括ngx_slab中实现的内存管理算法。
ngx_shmem的利用

ngx_shmem.c/h文件只是对mmap()/munmap()体系调用或者shmget()/shmdt()的一个很简朴的封装。实现了ngx风格的底子库,可以申请和释放一段一连的共享内存空间。一样平常用于固定长度的共享数据利用,利用过程中数据长度固定不会伸缩。
  1. typedef struct {
  2.   u_char   *addr;
  3.   size_t    size;
  4.   ...
  5. } ngx_shm_t;
  6. ngx_int_t ngx_shm_alloc(ngx_shm_t *shm);
  7. void ngx_shm_free(ngx_shm_t *shm);
复制代码
在ngxin中共享内存的利用流程,一样平常是由master进程创建,worker进程通过继承的方式得到内存指针。
关于ngx_shmem的利用,可以参考ngx_event_module_init()中部门片断,这部门代码在共享内存中创建了多少个变量,用于记录各个状态(accepted/reading/writing...)的哀求数量,并在ngx_event_module中的几个关键变乱入口对这几个变量举行加减统计操纵。实现统计所有worker进程当前的哀求状态。
  1. shm.size = size;
  2. ngx_str_set(&shm.name, "nginx_shared_zone");
  3. shm.log = cycle->log;
  4. if (ngx_shm_alloc(&shm) != NGX_OK) {
  5.   return NGX_ERROR;
  6. }
  7. shared = shm.addr;
  8. ...
  9. ngx_stat_accepted = (ngx_atomic_t *) (shared + 3 * cl);
  10. ngx_stat_handled = (ngx_atomic_t *) (shared + 4 * cl);
  11. ngx_stat_requests = (ngx_atomic_t *) (shared + 5 * cl);
  12. ngx_stat_active = (ngx_atomic_t *) (shared + 6 * cl);
  13. ngx_stat_reading = (ngx_atomic_t *) (shared + 7 * cl);
  14. ngx_stat_writing = (ngx_atomic_t *) (shared + 8 * cl);
  15. ngx_stat_waiting = (ngx_atomic_t *) (shared + 9 * cl);
复制代码
关于这个功能的更多细节,可以查看代码中的NGX_STAT_STUB宏定义相干代码与ngx_http_stub_status_module。
ngx_slab的利用

ngx_shmem是一层极简的封装,实现了共享内存的根本功能。但我们步调中大部门的场景共享数据并不会一个固定巨细的布局,而更多是像ngx_array、ngx_list、ngx_queue、ngx_rbtree这类巨细可以厘革的数据布局。
我们渴望能有像ngx_pool_t一样可以动态申请释放空间一个内存池。ngx_slab正是一个如许的布局体,原理上与体系的malloc()有相识之处都是通过一系列算法实现对一段段内存片断的申请与释放。只不外ngx_slab操纵的对象是基于ngx_shmem的共享内存。
先看一下ngx_slab的接口
  1. typedef struct {
  2.   ngx_shmtx_t    mutex;
  3.   ...
  4.   void       *data; /* 一般存放从pool中申请获得的根数据地址(pool中第一个申请的数据接口) */
  5.   void       *addr; /* 使用ngx_shmem申请获得的共享内存基地址 */
  6. } ngx_slab_pool_t;
  7. void ngx_slab_init(ngx_slab_pool_t *pool);
  8. void *ngx_slab_alloc(ngx_slab_pool_t *pool, size_t size);
  9. void *ngx_slab_alloc_locked(ngx_slab_pool_t *pool, size_t size);
  10. void *ngx_slab_calloc(ngx_slab_pool_t *pool, size_t size);
  11. void *ngx_slab_calloc_locked(ngx_slab_pool_t *pool, size_t size);
  12. void ngx_slab_free(ngx_slab_pool_t *pool, void *p);
  13. void ngx_slab_free_locked(ngx_slab_pool_t *pool, void *p);
复制代码
可以看到接口并不复杂,alloc与calloc的区别在于是否对申请得到的内存段清零,_locked结尾的接口表示操纵的pool已经是获取到锁的。在ngx_slab_pool_t的布局体有一个ngx_shmtx_t的互斥锁用于同步多进程同时访问pool的并发场景。留意ngx_slab_alloc()会先获取锁、然后申请空间、末了释放锁。而ngx_slab_alloc_locked()则直接申请空间,以为步调已经在其他逻辑中得到锁了。
在nginx的开辟中利用ngx_shmem一样平常需要遵循以下初始化流程:
      
  • 模块在设置解析过程中调用ngx_shared_memory_add()接口,注册一段共享内存。提供共享内存巨细与内存初始化的回调函数。  
  • 框架在ngx_init_cycle()中利用ngx_shmem申请内存,并初始化ngx_slab,然后回调模块注册的初始化函数  
  • 模块利用ngx_slab的申请/是否接口
在这个流程中,涉及到ngx_shared_memory_add()接口与对应的ngx_shm_zone_t布局体。
  1. struct ngx_shm_zone_s {
  2.   void           *data;
  3.   ngx_shm_t         shm;
  4.   ngx_shm_zone_init_pt   init;
  5.   void           *tag;
  6.   void           *sync;
  7.   ngx_uint_t        noreuse; /* unsigned noreuse:1; */
  8. };
  9. ngx_shm_zone_t *ngx_shared_memory_add(ngx_conf_t *cf, ngx_str_t *name,
  10.   size_t size, void *tag);
复制代码
其中值得一提的是noreuse属性,这个属性控制了在nginx的reload过程中是否会重新申请共享内存。
由于关于ngx_init_cycle()函数较长,这个流程可以通过查找/* create shared memory */这个解释或者cycle->shared_memory这个对象查看相干代码。
关于ngx_slab更多细节的利用,发起可以参考ngx_http_limit_conn_module,这是通过共享内存实现毗连数限定的模块,模块复杂度底,是一个很好的参考范例。
参考资料

深入明白Nginx(第2版) https://book.douban.com/subject/26745255/

ngx_http_limit_conn_module http://nginx.org/en/docs/http/ngx_http_limit_conn_module.html

以上就是本文的全部内容,盼望对大家的学习有所帮助,也盼望大家多多支持草根技能分享。

帖子地址: 

回复

使用道具 举报

分享
推广
火星云矿 | 预约S19Pro,享500抵1000!
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

草根技术分享(草根吧)是全球知名中文IT技术交流平台,创建于2021年,包含原创博客、精品问答、职业培训、技术社区、资源下载等产品服务,提供原创、优质、完整内容的专业IT技术开发社区。
  • 官方手机版

  • 微信公众号

  • 商务合作