nginx共享内存的机制详解


Posted in Servers onMarch 21, 2022

1 共享内存申请

共享内存申请比较简单,这里采用的是Linux系统共享内存分配的函数实现的。

#include <sys/ipc.h>
#include <sys/shm.h>


ngx_int_t
ngx_shm_alloc(ngx_shm_t *shm)
{
    int  id;

    id = shmget(IPC_PRIVATE, shm->size, (SHM_R|SHM_W|IPC_CREAT));

    if (id == -1) {
        ngx_log_error(NGX_LOG_ALERT, shm->log, ngx_errno,
                      "shmget(%uz) failed", shm->size);
        return NGX_ERROR;
    }

    ngx_log_debug1(NGX_LOG_DEBUG_CORE, shm->log, 0, "shmget id: %d", id);

    shm->addr = shmat(id, NULL, 0);

    if (shm->addr == (void *) -1) {
        ngx_log_error(NGX_LOG_ALERT, shm->log, ngx_errno, "shmat() failed");
    }

    if (shmctl(id, IPC_RMID, NULL) == -1) {
        ngx_log_error(NGX_LOG_ALERT, shm->log, ngx_errno,
                      "shmctl(IPC_RMID) failed");
    }

    return (shm->addr == (void *) -1) ? NGX_ERROR : NGX_OK;
}


void
ngx_shm_free(ngx_shm_t *shm)
{
    if (shmdt(shm->addr) == -1) {
        ngx_log_error(NGX_LOG_ALERT, shm->log, ngx_errno,
                      "shmdt(%p) failed", shm->addr);
    }
}

2 共享内存实现原理

2.1 共享内存组织

共享内存的管理工作是在:ngx_cycle内完成,主要是利用一个list进行组织。
首先是ngx_list组织形式,采用的是将多个ngx_list_part单元串行组成的链表;同时每个ngx_list_part是由多个ngx_shm_zone_t组成构成。这样做的一个好处就是一次预先分配一个元素组,只有当第一个元素组用完才会申请新的元素组。可以达到减少频繁分配的问题。

nginx共享内存的机制详解

这里需要展开对应ngx_shm_zone单元的介绍:
首先是用户定义自己的数据结构并存入data中;第二部分是初始化函数,用户获取到ngx_shm_zone_t 共享内存单元的时候需要注册自己数据结构的初始化函数,其中zone返回是当前的共享内存的数据,而data返回的是上一次初始化的数据即历史数据;tag存放的是创建共享内存的模块;ngx_shm_t共享内存基本信息包括地址,大小,名称,log输出位置等。

typedef struct {
    u_char      *addr;//共享内存地址
    size_t       size;//大小
    ngx_str_t    name;//名称
    ngx_log_t   *log;
    ngx_uint_t   exists;   /* unsigned  exists:1;  */
} ngx_shm_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;//创建的模块
    ngx_uint_t                noreuse;  /* unsigned  noreuse:1; */
};

初始化函数具体调用位置是在创建完共享内存后即进行初始化ngx_init_cycle函数中进行:

nginx共享内存的机制详解

2.2 slab共享内存管理机制

slab内存分配方式是共享内存的管理机制,主要是利用最优选择的思路,当我们申请内存块时只会返回恰好符合请求大小的内存块。基本原理是把内存按照4k一页分成若干页,将每页放置不同大小的内存块,然后利用bitmap在页首进行标识内存块是否被使用。只需要变量bitmap查找空闲的内存块从而提高查找效率。

nginx共享内存的机制详解

将存放不同大小的内存块的页面利用链表顺序串联,这样利用slots数组存放链表的首页。这样可以直接根据要分配内存大小进行寻址。

nginx共享内存的机制详解

这里还有一个小操作提高查找空闲内存,当一个页面没有空闲的内存块时需要从队列中脱离变成一个单独的节点。

2.3 slab与ngx_shm_zone_t 关系

整体的初始化动作是在ngx_init_zone_pool函数进行:利用shm中addr存放slab_pool对象,并完成slab的初始化动作。

ngx_slab_pool_t  *sp;
sp = (ngx_slab_pool_t *) zn->shm.addr;
sp->addr = zn->shm.addr;
ngx_slab_init(sp);

3 共享内存应用

共享内存的使用场景,这里分析ssl模块的共享内存使用方法,可以推广到其他模块使用。
首先是是进行共享内存的ngx_shm_zone_t分配,这是一个比较简单的操作,从共享内存返回一块空闲的shm_zone.

ngx_shm_zone_t  *shm_zone;//共享内存单元
ngx_conf_t *cf;//ngx配置
ngx_str_t   name;//共享内存名称
ngx_int_t    n;//分配共享内存的大小
ngx_module_t  ngx_stream_ssl_module;//使用共享内存的模块,防止模块间重名
scf->shm_zone = ngx_shared_memory_add(cf, &name, n,&ngx_stream_ssl_module);//从
if (scf->shm_zone == NULL) {
     return NGX_CONF_ERROR;
 }
//初始化函数设置
 scf->shm_zone->init = ngx_ssl_session_cache_init;

初始化函数:data返回的是上一次分配的数据,如果存在直接返回。否则先取出slab_pool进程分配操作调用ngx_slab_alloc分配一个内存块大小,可以是数据结构。这里分配的是一个红黑树结构,分配完成后就可以直接初始化红黑树。

ngx_int_t
ngx_ssl_session_cache_init(ngx_shm_zone_t *shm_zone, void *data)
{
    size_t                    len;
    ngx_slab_pool_t          *shpool;
    ngx_ssl_session_cache_t  *cache;

    if (data) {
        shm_zone->data = data;
        return NGX_OK;
    }
	//获取slab_pool
    shpool = (ngx_slab_pool_t *) shm_zone->shm.addr;

    if (shm_zone->shm.exists) {
        shm_zone->data = shpool->data;
        return NGX_OK;
    }
	//为数据分配slab内存块
    cache = ngx_slab_alloc(shpool, sizeof(ngx_ssl_session_cache_t));
    if (cache == NULL) {
        return NGX_ERROR;
    }
	//赋值到slab_pool管理
    shpool->data = cache;
    shm_zone->data = cache;
	//红黑树数据初始化
    ngx_rbtree_init(&cache->session_rbtree, &cache->sentinel,
                    ngx_ssl_session_rbtree_insert_value);
	//队列初始化
    ngx_queue_init(&cache->expire_queue);
	//设置log
    len = sizeof(" in SSL session shared cache \"\"") + shm_zone->shm.name.len;
	//为log分配共享内存
    shpool->log_ctx = ngx_slab_alloc(shpool, len);
    if (shpool->log_ctx == NULL) {
        return NGX_ERROR;
    }
	//写log
    ngx_sprintf(shpool->log_ctx, " in SSL session shared cache \"%V\"%Z",
                &shm_zone->shm.name);

    shpool->log_nomem = 0;

    return NGX_OK;
}

到此这篇关于nginx共享内存的机制详解的文章就介绍到这了,更多相关nginx共享内存内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Servers 相关文章推荐
Nginx快速入门教程
Mar 31 Servers
nginx对http请求处理的各个阶段详析
Mar 31 Servers
nginx反向代理时如何保持长连接
Mar 31 Servers
Nginx代理同域名前后端分离项目的完整步骤
Mar 31 Servers
Nginx如何配置Http、Https、WS、WSS的方法步骤
May 11 Servers
Nginx反向代理学习实例教程
Oct 24 Servers
Nginx配置https的实现
Nov 27 Servers
阿里云k8s服务升级时502错误 springboot项目应用
Apr 09 Servers
在Docker容器中部署SQL Server
Apr 11 Servers
超越Nginx的Web服务器caddy优雅用法
Jun 21 Servers
如何让你的Nginx支持分布式追踪详解
Jul 07 Servers
CentOS7 minimal 最小化安装网络设置过程
Dec 24 Servers
Nginx的基本概念和原理
解决xampp安装后Apache无法启动
Nginx图片服务器配置之后图片访问404的问题解决
Shell脚本一键安装Nginx服务自定义Nginx版本
Nginx实现会话保持的两种方式
Mar 18 #Servers
Nginx实现负载均衡的项目实践
Mar 18 #Servers
Nginx中使用Lua脚本与图片的缩略图处理的实现
Mar 18 #Servers
You might like
PHP小教程之实现链表
2014/06/09 PHP
php微信公众号开发之音乐信息
2018/10/20 PHP
鼠标移动到一张图片时变为另一张图片
2006/12/05 Javascript
jquery 常用操作整理 基础入门篇
2009/10/14 Javascript
javascript 设为首页与加入收藏兼容多浏览器代码
2011/01/11 Javascript
Javascript实现关联数据(Linked Data)查询及注意细节
2013/02/22 Javascript
jquery删除指定子元素代码实例
2015/01/13 Javascript
Javascript获取表单名称(name)的方法
2015/04/02 Javascript
javascript获取网页宽高方法汇总
2015/07/19 Javascript
jq实现左侧显示图片右侧文字滑动切换效果
2015/08/04 Javascript
Jquery代码实现图片轮播效果(一)
2015/08/12 Javascript
js实现select下拉框菜单
2015/12/08 Javascript
js实现点击按钮弹出上传文件的窗口
2016/12/23 Javascript
jquery Ajax 全局调用封装实例详解
2017/01/16 Javascript
Vuejs入门教程之Vue生命周期,数据,手动挂载,指令,过滤器
2017/04/19 Javascript
第一个Vue插件从封装到发布
2017/11/22 Javascript
微信小程序WebSocket实现聊天对话功能
2018/07/06 Javascript
手淘flexible.js框架使用和源代码讲解小结
2018/10/15 Javascript
Node.js 如何利用异步提升任务处理速度
2019/01/07 Javascript
详解微信小程序获取当前时间及日期的方法
2019/04/28 Javascript
教你30秒发布一个TypeScript包到NPM的方法步骤
2019/07/22 Javascript
layui插件表单验证提交触发提交的例子
2019/09/09 Javascript
使用vue实现一个电子签名组件的示例代码
2020/01/06 Javascript
解决Vue使用bus总线时,第一次路由跳转时数据没成功传递问题
2020/07/28 Javascript
Python实现发送email的几种常用方法
2014/08/18 Python
跟老齐学Python之网站的结构
2014/10/24 Python
Windows上配置Emacs来开发Python及用Python扩展Emacs
2015/11/20 Python
Python3 queue队列模块详细介绍
2018/01/05 Python
python 定义给定初值或长度的list方法
2018/06/23 Python
一篇文章弄懂Python中所有数组数据类型
2019/06/23 Python
Python实现获取系统临时目录及临时文件的方法示例
2019/06/26 Python
Python将string转换到float的实例方法
2019/07/29 Python
python3连接MySQL8.0的两种方式
2020/02/17 Python
机械工程师岗位职责
2014/06/16 职场文书
小学五年级语文上册教学计划
2015/01/22 职场文书
win server2012 r2服务器共享文件夹如何设置
2022/06/21 Servers