• nginx 的进程建通信机制-共享内存/channel/信号


    nginx是跨平台的库,但以下分享均为基于linux的

    nginx 进程间通信的方法:

    1、共享内存

    linux 提供了进程间通信的的共享内存的方式,通过mmap和shmget来获取一块连续的内存,然后通过munmapheshmdt来释放这块内存,多个进程均可访问这块共享内存

    nginx定义的结构体

    1. typedef struct {
    2. u_char *addr;
    3. size_t size;
    4. ngx_str_t name;
    5. ngx_log_t *log;
    6. ngx_uint_t exists; /* unsigned exists:1; */
    7. } ngx_shm_t;
    8. // 用于分配内存
    9. ngx_int_t ngx_shm_alloc(ngx_shm_t *shm);
    10. // 用于释放内存
    11. void ngx_shm_free(ngx_shm_t *shm);

    nginx 共享内存接口

    没有使用linux可以直接映射到文件的方式,所以mmap的最后两个参数没有送。

    1. ngx_int_t ngx_shm_alloc(ngx_shm_t *shm)
    2. {
    3. shm->addr = (u_char *) mmap(NULL, shm->size,
    4. PROT_READ|PROT_WRITE,
    5. MAP_ANON|MAP_SHARED, -1, 0);
    6. if (shm->addr == MAP_FAILED) {
    7. ngx_log_error(NGX_LOG_ALERT, shm->log, ngx_errno,
    8. "mmap(MAP_ANON|MAP_SHARED, %uz) failed", shm->size);
    9. return NGX_ERROR;
    10. }
    11. return NGX_OK;
    12. }

    nginx 释放共享内存

    1. void ngx_shm_free(ngx_shm_t *shm)
    2. {
    3. if (munmap((void *) shm->addr, shm->size) == -1) {
    4. ngx_log_error(NGX_LOG_ALERT, shm->log, ngx_errno,
    5. "munmap(%p, %uz) failed", shm->addr, shm->size);
    6. }
    7. }

    使用方式:

    master进程创建,fork子进程来使用。

    2、nginx channel频道

    学习过go语言的应该知道,协程间通讯使用channel,而nginx封装了一个进程间通讯的机制,ngx_channel_t,来实现父子进程间的通讯。

    nginx channel的数据结构

    1. typedef struct {
    2. // 传递的TCP消息中的命令
    3. ngx_uint_t command;
    4. // 进程ID
    5. ngx_pid_t pid;
    6. // 表示发送命令方在ngx_processes进程数组间的序号
    7. ngx_int_t slot;
    8. // 通讯的套接字
    9. ngx_fd_t fd;
    10. } ngx_channel_t;
    1. // 实现channel的读,写,添加,关闭。
    2. ngx_int_t ngx_write_channel(ngx_socket_t s, ngx_channel_t *ch, size_t size,
    3. ngx_log_t *log);
    4. ngx_int_t ngx_read_channel(ngx_socket_t s, ngx_channel_t *ch, size_t size,
    5. ngx_log_t *log);
    6. ngx_int_t ngx_add_channel_event(ngx_cycle_t *cycle, ngx_fd_t fd,
    7. ngx_int_t event, ngx_event_handler_pt handler);
    8. void ngx_close_channel(ngx_fd_t *fd, ngx_log_t *log);

    另外,需要涉及到的另一个接口

    1. typedef struct {
    2. .....
    3. ngx_socket_t channel[2];
    4. ngx_spawn_proc_pt proc;
    5. .....
    6. } ngx_process_t;

    nginx channel 实现方法

    nginx就是通过channel来监控管理worker的子进程,每次创建子进程时,就通过socketpair创建了套接字对,并存储到channel的数组中。

    1. ngx_spawn_process(ngx_cycle_t *cycle, ngx_spawn_proc_pt proc, void *data,
    2. char *name, ngx_int_t respawn)
    3. {
    4. ...
    5. if (socketpair(AF_UNIX, SOCK_STREAM, 0, ngx_processes[s].channel) == -1)
    6. {
    7. ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
    8. "socketpair() failed while spawning \"%s\"", name);
    9. return NGX_INVALID_PID;
    10. }
    11. ...
    12. }

    其中 ngx_processes时所有的进程的数组,包括master进程。

    其中master进程使用channel[0],子进程使用channel[1],channel分别对应socketpair的两个套接字。

    nginx进程间时如果调度来进行ngx_read_channel的呢?

    就是通过nginx 添加事件函数ngx_add_channel_event,然后epoll发现有事件时,实现ngx_channel_handler回调并读取。从而实现进程间通信。

    3、信号 

    信号的数据结构 ngx_signal_t

    1. typedef struct{
    2. //需要处理的信号
    3. int signo;
    4. //信号对应的字符串名称
    5. char*signame;
    6. //这个信号对应着的Nginx命令
    7. char*name;
    8. //收到signo信号后就会回调handler方法
    9. void(*handler) (int signo) ;
    10. }ngx_signal_t

    需要处理的信号定义在signals中

    1. ngx_signal_t signals[] = {
    2. { ngx_signal_value(NGX_RECONFIGURE_SIGNAL),
    3. "SIG" ngx_value(NGX_RECONFIGURE_SIGNAL),
    4. "reload",
    5. ngx_signal_handler },
    6. ......
    7. }

    信号的初始化:

    其实现以下已经注释

    1. // 初始化所有信号
    2. ngx_int_t ngx_init_signals(ngx_log_t *log)
    3. {
    4. ngx_signal_t *sig;
    5. struct sigaction sa;
    6. // 遍历所有信号数组
    7. for (sig = signals; sig->signo != 0; sig++) {
    8. ngx_memzero(&sa, sizeof(struct sigaction));
    9. // 添加回调函数
    10. if (sig->handler) {
    11. sa.sa_sigaction = sig->handler;
    12. sa.sa_flags = SA_SIGINFO;
    13. } else {
    14. sa.sa_handler = SIG_IGN;
    15. }
    16. // 清空信号标志位
    17. sigemptyset(&sa.sa_mask);
    18. // 向系统注册信号的回调。
    19. if (sigaction(sig->signo, &sa, NULL) == -1) {
    20. return NGX_ERROR;
    21. }
    22. }
    23. return NGX_OK;
    24. }

  • 相关阅读:
    java微博 8 CSS
    Spark Core【Spark的内核概述、部署模式、通讯架构】
    汽车租赁服务微信小程序制作开发
    在windows笔记本中安装tensorflow1.13.2版本的gpu环境2
    【Linux-Windows】千兆网口以及千兆网线
    npm install的-S和-D的区别
    【Nacos篇】Nacos基本操作及配置
    MATLAB实战 | 粮食储仓的通风控制问题
    Java8Stream快速使用
    【探索排序算法的魅力:优化、性能与实用技巧】
  • 原文地址:https://blog.csdn.net/hahackeris/article/details/126005028