nginx共享内存分析

栏目: 服务器 · Nginx · 发布时间: 5年前

内容简介:微信公众号:关注可了解更多的关注公众号,有趣有内涵的文章第一时间送达!共享内存是linux下最基本的进程间通信方式。它通过mmap或者shmget系统调用在内存中创建一块连续的线性地址空间,使用munmap或者shmdt系统调用可以释放这块内存。使用共享内存的好处:当多个进程使用同一块共享内存时,在任何一个进程中修改了共享内存中的内容,其他进程通过访问这段共享内存都能够得到修改后的内容。

微信公众号:关注可了解更多的 Nginx 知识。任何问题或建议,请公众号留言;

关注公众号,有趣有内涵的文章第一时间送达!

共享内存

共享内存是 linux 下最基本的进程间通信方式。它通过mmap或者shmget系统调用在内存中创建一块连续的线性地址空间,使用munmap或者shmdt系统调用可以释放这块内存。使用共享内存的好处:当多个进程使用同一块共享内存时,在任何一个进程中修改了共享内存中的内容,其他进程通过访问这段共享内存都能够得到修改后的内容。

数据结构

nginx使用到的数据结构如下:

1 typedef struct {
2    u_char      *addr;    /* 共享内存的起始地址 */
3    size_t       size;    /* 共享内存的长度 */
4    ngx_str_t    name;    /* 共享内存的名字  */
5    ngx_log_t   *log;     /* 记录日志的对象 */
6
7/* unsigned  exists:1;  */ /*共享内存是否已经分配过,1:已经分配 */
8    ngx_uint_t   exists;   
9} ngx_shm_t;
复制代码

共享内存的API

nginx 操作共享内存的 API 有两个,如下:

1ngx_int_t ngx_shm_alloc(ngx_shm_t *shm);    /* 分配新的共享内存 */
2void ngx_shm_free(ngx_shm_t *shm);    /*释放已经存在的共享内存 */
复制代码

实现方式

上面是 nginx 中操作共享内存的两个 api 。我们应该使用上述两个 api 对共享内存进行操作。

为了可移植性, nginx 使用了三种方式来实现上述的两个 api ,三种方式分别如下:

1、不映射文件使用 mmap 分配共享内存

2、以 /dev/zero 文件使用 mmap 映射共享内存。

3、用 shmget 调用来分配共享内存

源码分析

源码很简单,我们对 mmap 实现方式进行简单的分析

 1#if (NGX_HAVE_MAP_ANON)
 2
 3ngx_int_t
 4ngx_shm_alloc(ngx_shm_t *shm)
 5{
 6    /* MAP_ANON:不使用文件映射方式,因此fd,offset无用,相当于在内存开辟一块空间用于共享,由master创建 */
 7    shm->addr = (u_char *) mmap(NULL, shm->size,
 8                                PROT_READ|PROT_WRITE,
 9                                MAP_ANON|MAP_SHARED, -1, 0);
10
11    if (shm->addr == MAP_FAILED) {
12        ngx_log_error(NGX_LOG_ALERT, shm->log, ngx_errno,
13                      "mmap(MAP_ANON|MAP_SHARED, %uz) failed", shm->size);
14        return NGX_ERROR;
15    }
16
17    return NGX_OK;
18}
19
20
21void
22ngx_shm_free(ngx_shm_t *shm)
23{
24    if (munmap((void *) shm->addr, shm->size) == -1) {
25        ngx_log_error(NGX_LOG_ALERT, shm->log, ngx_errno,
26                      "munmap(%p, %uz) failed", shm->addr, shm->size);
27    }
28}
29
30#elif (NGX_HAVE_MAP_DEVZERO)
复制代码

可以看到 ngx_shm_allocngx_shm_free 的确是对 mmapmunmap 分别进行了封装。而且使用了 MAP_ANON ,是在内存中开辟了一块空间用于共享内存,而不是将硬盘中的文件映射。

nginx如何使用共享内存

首先,我们得知道:默认情况下,通过 fork 派生的子进程并不与其父进程共享内存区。但 masterworker 进程是父子进程啊,这该怎么办呢?如何让 master 进程与 worker 进程共享内存区呢?

解决方法就在于 mmapflags 参数。 master 进程在调用 fork 之前先指定 flagsMAP_SHARED 来调用 mmap ,此时, POSIX 是保证父进程中的内存映射关系是存留到子进程中的,父进程对共享内存所做的修改子进程能看到,反过来一样。所以流程是: master 进程在内存中以 MAP_SHARED 方式开辟一块共享内存,并映射到自己进程地址空间中的共享内存区,然后 master 调用 fork ,派生子进程,子进程在自己的地址空间内也会继承这块共享内存区。这样问题便解决了。

mmap/munmap 函数

1void *mmap(void *addr, size_t len, int prot, int flags, int fd, off_t offset);
复制代码
返回值:成功:被映射区的起始地址;出错: MAP_FAILED

addr : 指定的fd描述符应被映射到进程地址空间的起始地址,一般为 NULL ,意思就是让内核自己去选择起始地址

len : 映射到进程地址空间的字节数

prot :对这块共享内存中的数据,我们可以处理的方式,如下:

prot 说明
PROT_READ 数据可读
PROT_WRITE 数据可写
PROT_EXEC 数据可执行
PROT_NONE 数据不可访问

flags :变动共享内存区中的数据这一行为是共享的还是私有的,即对所有进程可见,还是只对该进程可见。如下:

flags 说明
MAP_SHARED 变动是共享的
MAP_PRIVATE 变动是私有的
MAP_FIXED 准确的解释addr参数

fd :被映射的文件描述符

offset :被映射区域在文件中的起始位置。

具体的见下图:

nginx共享内存分析
映射区域

需要注意的是: nginx 的共享内存不是映射文件中的内容。当 flags 参数中 MAP_ANONMAP_ANONYMOUS ,表示不从文件中映射,只从内存中开辟一块连续的线性地址空间出来作为共享内存。因此,这种情况下 fdoffset 参数就没意义,分别置 -10 即可。

为从某一进程的地址空间中删除一个映射关系,调用 munmap

1int  munmap(void *addr, size_t len);
复制代码

成功:0;出错:-1

喜欢本文的朋友们,欢迎长按下图关注订阅号郑尔多斯,更多精彩内容第一时间送达

nginx共享内存分析
郑尔多斯

以上所述就是小编给大家介绍的《nginx共享内存分析》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

零基础学PHP

零基础学PHP

马忠超 / 2008-3 / 56.00元

《零基础学PHP》主要内容:PHP是一种运行于服务器端并完全跨平台的嵌入式脚本编程语言,是目前开发各类Web应用的主流语言之一。PHP因其功能强大、易学易用、可扩展性强、运行速度快和良好的开放性,而成为网站开发者的首选工具,其较高的开发效率,也给开发人员在编写Web应用程序时带来极大的便利。一起来看看 《零基础学PHP》 这本书的介绍吧!

CSS 压缩/解压工具
CSS 压缩/解压工具

在线压缩/解压 CSS 代码

随机密码生成器
随机密码生成器

多种字符组合密码

MD5 加密
MD5 加密

MD5 加密工具