小知识:nginx共享内存的机制详解

1 共享内存申请

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#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输出位置等。
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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共享内存的机制详解-1猿站网-插图

2.2 slab共享内存管理机制

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

%小知识:nginx共享内存的机制详解-2猿站网-插图

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

%小知识:nginx共享内存的机制详解-3猿站网-插图

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

2.3 slab与ngx_shm_zone_t 关系

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

?
1
2
3
4
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.
?
1
2
3
4
5
6
7
8
9
10
11
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分配一个内存块大小,可以是数据结构。这里分配的是一个红黑树结构,分配完成后就可以直接初始化红黑树。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
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共享内存内容请搜索服务器之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持服务器之家!

原文链接:https://blog.csdn.net/qq_38731735/article/details/123535716

声明: 猿站网有关资源均来自网络搜集与网友提供,任何涉及商业盈利目的的均不得使用,否则产生的一切后果将由您自己承担! 本平台资源仅供个人学习交流、测试使用 所有内容请在下载后24小时内删除,制止非法恶意传播,不对任何下载或转载者造成的危害负任何法律责任!也请大家支持、购置正版! 。本站一律禁止以任何方式发布或转载任何违法的相关信息访客发现请向站长举报,会员发帖仅代表会员个人观点,并不代表本站赞同其观点和对其真实性负责。本网站的资源部分来源于网络,如有侵权烦请发送邮件至:2697268773@qq.com进行处理。
建站知识

小知识:如何在 Linux 下使用 TC 优雅的实现网络限流

2023-3-17 5:08:23

建站知识

小知识:在Linux分区或逻辑卷中创建文件系统的方法

2023-3-17 5:16:43

0 条回复 A文章作者 M管理员
    暂无讨论,说说你的看法吧
个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索