Nginx進程之間的通信機制介紹
進程之間的通信方式如共享內存,套接字、管道、消息隊列、信號等。Nginx框架選擇了三種方式:共享內存、套接字、信號來訪問共享資源。同時Nginx使用了原子操作、信號量、文件鎖來實現各個進程直降安全有序的訪問資源。
1.共享內存
共享內存是Linux下提供的最基本的進程間的通信方式,他通過mmap或者shmget系統調用內存中創建了一塊連續的線性地址空間,通過munmap或者shmdt系統釋放內存。Nginx系統封裝了ngx_shmtx_t結構體, 用於描述一塊共享內存。
1.1數據結構
typedef struct {
ngx_atomic_t lock;
#if (NGX_HAVE_POSIX_SEM)
ngx_atomic_t wait;
#endif
} ngx_shmtx_sh_t;
typedef struct {
#if (NGX_HAVE_ATOMIC_OPS)/*宏定義採用原子鎖控制共享內存*/
ngx_atomic_t *lock;
#if (NGX_HAVE_POSIX_SEM)/*宏定義採用信號量控制內存共享*/
ngx_atomic_t *wait;
ngx_uint_t semaphore;/*等於1,表示成功初始化信號量了*/
sem_t sem;/*信號量,決定內存是否在進程間共享*/
#endif
#else
ngx_fd_t fd;/*文件鎖控制共享內存*/
u_char *name;
#endif
ngx_uint_t spin;
} ngx_shmtx_t;
1.2.創建共享內存
ngx_int_t
ngx_shmtx_create(ngx_shmtx_t *mtx, ngx_shmtx_sh_t *addr, u_char *name)
{
mtx->lock = &addr->lock;
if (mtx->spin == (ngx_uint_t) -1) {
return NGX_OK;
}
mtx->spin = 2048;
#if (NGX_HAVE_POSIX_SEM)
mtx->wait = &addr->wait;
if (sem_init(&mtx->sem, 1, 0) == -1) {
ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, ngx_errno,
"sem_init() failed");
} else {
mtx->semaphore = 1;
}
#endif
return NGX_OK;
}
2.Nginx頻道
ngx_channel_t頻道使用套接字實現(socketpair 方法),它用於創建父子進程間使用的套接字,是Nginx master進程和worker進程之間通信的工具。
2.1 chanel結構體
typedef struct {
ngx_uint_t command;/*TCP 消息中的命令*/
ngx_pid_t pid;/*進程ID,一般是發送命令方的進程*/
ngx_int_t slot;/*在ngx_process進程間的序號*/
ngx_fd_t fd;/*通信套接字的句柄*/
} ngx_channel_t;
2.socketpair方法介紹
Nginx工作時master進程會fork出n個worker進程(具有相同的工作邏輯和功能)。父進程複雜監聽信號,通過 socket pair把信號傳遞給子進程(子進程之間一般不通信)。
3.信號
信號是一種非常短的消息,用於進程之間傳遞消息。Nginx通過定義ngx_signal_t結構體用於描述接收到信號時的行爲。
typedef struct {
int signo;/*需要處理的信號*/
char *signame;/*信號對應的字符串名稱*/
char *name;/*這個信號對應着的 Nginx 命令*/
void (*handler)(int signo, siginfo_t *siginfo, void *ucontext);/*收到 signo 信號後就會回調 handler 方法*/
}ngx_signal_t;