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缓存设置案例详解
Sep 15 Servers
教你利用Nginx 服务搭建子域环境提升二维地图加载性能的步骤
Sep 25 Servers
详解nginx location指令
Jan 18 Servers
Apache Linkis 中间件架构及快速安装步骤
Mar 16 Servers
Kubernetes中Deployment的升级与回滚
Apr 01 Servers
阿里云日志过滤器配置日志服务
Apr 09 Servers
Windows Server 2016 配置 IIS 的详细步骤
Apr 28 Servers
Windows server 2012搭建FTP服务器
Apr 29 Servers
如何开启Apache,Nginx和IIS服务器的GZIP压缩功能
Apr 29 Servers
Docker部署Mysql8的实现步骤
Jul 07 Servers
Apache Kafka 分区重分配的实现原理解析
Jul 15 Servers
windows server2016安装oracle 11g的图文教程
Jul 15 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
实战mysql导出中文乱码及phpmyadmin导入中文乱码的解决方法
2010/06/11 PHP
Yii Framework框架获取分类下面的所有子类方法
2014/06/20 PHP
PHP两种实现无级递归分类的方法
2017/03/02 PHP
jquery交替变换颜色的三种方法 实例代码
2013/11/19 Javascript
原生js实现淘宝首页点击按钮缓慢回到顶部效果
2014/04/06 Javascript
Nodejs中 npm常用命令详解
2016/07/04 NodeJs
详解Angular中$cacheFactory缓存的使用
2016/08/19 Javascript
jQuery实现页面点击后退弹出提示框的方法
2016/08/24 Javascript
手机端点击图片放大特效PhotoSwipe.js插件实现
2016/08/24 Javascript
Angular工具方法学习
2016/12/26 Javascript
angularjs项目的页面跳转如何实现(5种方法)
2017/05/25 Javascript
iscroll实现下拉刷新功能
2017/07/18 Javascript
React Native中的RefreshContorl下拉刷新使用
2017/10/09 Javascript
js实现Tab选项卡切换效果
2020/07/17 Javascript
VUE 配置vue-devtools调试工具及安装方法
2018/09/30 Javascript
vue-cli3搭建项目的详细步骤
2018/12/05 Javascript
vue设置导航栏、侧边栏为公共页面的例子
2019/11/01 Javascript
JavaScript实现Tab选项卡切换
2020/02/13 Javascript
python提取内容关键词的方法
2015/03/16 Python
进一步探究Python的装饰器的运用
2015/05/05 Python
使用python 3实现发送邮件功能
2018/06/15 Python
Python提取PDF内容的方法(文本、图像、线条等)
2019/09/25 Python
python 实现将Numpy数组保存为图像
2020/01/09 Python
利用Python脚本批量生成SQL语句
2020/03/04 Python
基于python爬取有道翻译过程图解
2020/03/31 Python
python中前缀运算符 *和 **的用法示例详解
2020/05/28 Python
python 识别登录验证码图片功能的实现代码(完整代码)
2020/07/03 Python
pycharm 实现调试窗口恢复
2021/02/05 Python
汉森冲浪板:Hansen Surfboards
2018/05/19 全球购物
超市5.1促销活动
2014/01/15 职场文书
公务员保密承诺书
2014/03/27 职场文书
公益广告标语
2014/06/19 职场文书
护理见习报告范文
2014/11/03 职场文书
2015年小学校长工作总结
2015/05/19 职场文书
java泛型通配符详解
2021/07/25 Java/Android
Vue 打包后相对路径的引用问题
2022/06/05 Vue.js