Nginx源码分析与实践---进程间通信机制(共享内存)
来源:互联网 发布:手机淘宝店装修 编辑:程序博客网 时间:2024/06/01 07:40
Nginx有一个master进程和多个worker进程,那么master进程与worker进程间或worker进程之间是如何通信的呢,又什么时候需要进程间通信呢?
我们知道linux下的进程间通信方式主要有:管道、FIFO、套接字、消息队列、共享内存、信号。那么nginx的进程间通信方式采用的是什么呢?
nginx的3种进程间通信方式为:共享内存、套接字、信号
共享内存
1.什么时候需要使用共享内存呢?
举个栗子:nginx进程间共享的数据就需要使用共享内存,比如服务器中HTTP的连接数:成功建立连接的TCP数、正在发送TCP流的连接数、正在接收TCP流的连接数等等。对于这些共享的数据,就应该使用共享内存。每个worker进程修改的都是共享内存中的数据,修改是对所有进程都有效的。
2.nginx的共享内存是怎么实现的呢?
我们知道,在linux下可以通过mmap分配共享内存,用munmap释放共享内存。nginx共享内存的实现其实就是把这两个方法进行封装。下面看源码:
.../os/unix/ngx_shmem.h:
/* * Copyright (C) Igor Sysoev * Copyright (C) Nginx, Inc. */#ifndef _NGX_SHMEM_H_INCLUDED_#define _NGX_SHMEM_H_INCLUDED_#include <ngx_config.h>#include <ngx_core.h>typedef struct { u_char *addr; /* 共享内存的起始地址 */ size_t size; /* 共享内存的长度 */ ngx_str_t name; /* 共享内存的名字 */ ngx_log_t *log; /* 记录日志的对象 */ ngx_uint_t exists; /* unsigned exists:1; */ /*共享内存是否已经分配过,1:已经分配 */} ngx_shm_t;ngx_int_t ngx_shm_alloc(ngx_shm_t *shm); /* 分配新的共享内存 */void ngx_shm_free(ngx_shm_t *shm); /*释放已经存在的共享内存 */#endif /* _NGX_SHMEM_H_INCLUDED_ */分析:
共享内存通过ngx_shm_t这个结构体进行管理,每个成员的意义都已注释。共享内存的方法就两个:ngx_shm_alloc、ngx_shm_free。一个分配、一个释放。这两个方法其实就是对mmap和munmap进行封装。所以了解这两个方法之前得先看下linux的mmap和munmap函数:
void *mmap(void *addr, size_t len, int prot, int flags, int fd, off_t offset);
返回值:成功:被映射区的起始地址;出错:MAP_FAILED
addr: 指定的fd描述符应被映射到进程地址空间的起始地址,一般为NULL,意思就是让内核自己去选择起始地址
len: 映射到进程地址空间的字节数
prot:对这块共享内存中的数据,我们可以处理的方式,如下:
flags:变动共享内存区中的数据这一行为是共享的还是私有的,即对所有进程可见,还是只对该进程可见。如下:
fd:被映射的文件描述符
offset:被映射区域在文件中的起始位置。
具体的见下图,一目了然。
需要注意的是:nginx的共享内存不是映射文件中的内容。当flags参数中MAP_ANON或MAP_ANONYMOUS,表示不从文件中映射,只从内存中开辟一块连续的线性地址空间出来作为共享内存。因此,这种情况下fd和offset参数就没意义,分别置-1和0即可。
为从某一进程的地址空间中删除一个映射关系,调用munmap。
int munmap(void *addr, size_t len);
成功:0;出错:-1
好了,下面终于可以看ngx_shm_alloc和ngx_shm_free的源码了。
.../os/unix/ngx_shmem.c:
#if (NGX_HAVE_MAP_ANON)ngx_int_tngx_shm_alloc(ngx_shm_t *shm){ /* MAP_ANON:不使用文件映射方式,因此fd,offset无用,相当于在内存开辟一块空间用于共享,由master创建 */ shm->addr = (u_char *) mmap(NULL, shm->size, PROT_READ|PROT_WRITE, MAP_ANON|MAP_SHARED, -1, 0); if (shm->addr == MAP_FAILED) { ngx_log_error(NGX_LOG_ALERT, shm->log, ngx_errno, "mmap(MAP_ANON|MAP_SHARED, %uz) failed", shm->size); return NGX_ERROR; } return NGX_OK;}voidngx_shm_free(ngx_shm_t *shm){ if (munmap((void *) shm->addr, shm->size) == -1) { ngx_log_error(NGX_LOG_ALERT, shm->log, ngx_errno, "munmap(%p, %uz) failed", shm->addr, shm->size); }}#elif (NGX_HAVE_MAP_DEVZERO)可以看到ngx_shm_alloc和ngx_shm_free的确是对mmap和munmap分别进行了封装。而且使用了MAP_ANON,是在内存中开辟了一块空间用于共享内存,而不是将硬盘中的文件映射。
3.nginx是如何使用共享内存的呢?
首先,我们得知道:默认情况下,通过fork派生的子进程并不与其父进程共享内存区。但master与worker进程是父子进程啊,这该怎么办呢?如何让master进程与worker进程共享内存区呢?
解决方法就在于mmap的flags参数。master进程在调用fork之前先指定flags为MAP_SHARED来调用mmap,此时,POSIX是保证父进程中的内存映射关系是存留到子进程中的,父进程对共享内存所做的修改子进程能看到,反过来一样。所以流程是:master进程在内存中以MAP_SHARED方式开辟一块共享内存,并映射到自己进程地址空间中的共享内存区,然后master调用fork,派生子进程,子进程在自己的地址空间内也会继承这块共享内存区。这样问题便解决了。
- Nginx源码分析与实践---进程间通信机制(共享内存)
- nginx进程间的通信机制源码分析(一)----共享内存
- Nginx源码分析与实践---进程间通信机制(套接字)
- nginx源码分析1———进程间的通信机制四(System V内存共享)
- nginx源码分析--进程间通信机制 & 同步机制
- nginx源码分析--nginx进程间通信
- nginx源码分析--nginx进程间通信
- nginx源码分析1———进程间的通信机制一(信号量)
- nginx源码分析1———进程间的通信机制二(自旋锁)
- nginx源码分析1———进程间的通信机制三(mmap)
- nginx源码分析1———进程间的通信机制五(文件锁)
- nginx进程间的通信机制源码分析(二)-------原子操作、自旋锁、文件锁
- Android 进程间通信之匿名共享内存Ashmem源码分析
- Nginx源码分析(2)之——共享内存管理之slab机制
- nginx源码分析1———进程间的通信机制六(UNIX域协议)
- 进程间通信机制之三:共享内存
- Linux进程间通信(IPC)编程实践(七)共享内存的使用-System V共享内存(API)
- Linux进程间通信(IPC)编程实践(八)共享内存的使用-POSIX 共享内存(API)
- 手势解锁功能逻辑的实现【不含手势解锁界面实现】(二)
- eclipse referenced libraries视图
- 《机器学习实战》学习笔记<四>Logistic回归
- C++ 类型转换
- SSH连接失败,报错Host key verification failed——原理和解决方法
- Nginx源码分析与实践---进程间通信机制(共享内存)
- spring集成JDBC
- 设计模式之---单例模式
- 【Java语言】Ja.2.2--浅谈设计模式(二)之单例模式
- git基本操作
- ionic开发常见问题及解决方案(四)
- linux 启动脚本 小工具-今年还剩余多少天
- iOS7应用开发 第5、6集 视图控制器的生命周期
- c++实验三:多分数段函数求值