Nginx 소스 코드 학습 - 프로 세 스 통신

Nginx 서버 는 Master - Worker 모델 을 사용 할 때 세 가지 통신 과 관련 됩 니 다. Linux 시스템 과 Nginx 통신, Master 프로 세 스 와 Worker 프로 세 스 통신, Worker 프로 세 스 간 통신 도 세 가지 서로 다른 통신 체 제 를 사용 합 니 다.
Linux 신호
    Linux 시스템 과 Nginx 는 신 호 를 통 해 통신 합 니 다. 예 를 들 어 Linux 명령 줄 에서 두 드 리 는 것 입 니 다. / nginx - s stop 은 실제 시스템 에서 Master 프로 세 스 를 새로 엽 니 다. 이 프로 세 스 는 원래 Master 에 신 호 를 보 내 고 신 호 를 보 내 면 이 프로 세 스 가 끊 깁 니 다. 원래 Master 프로 세 스 는 신 호 를 받 은 후에 해당 하 는 작업 을 수행 합 니 다.
1. 신호 정의 및 등록
Nginx 는 ngx 를 정의 합 니 다.signal_t 구조 체 는 신 호 를 받 는 행 위 를 설명 하 는 데 사용 된다.
typedef struct { //signals
    int     signo;   //       
    char   *signame; //          
    char   *name;    //        Nginx  
    void  (*handler)(int signo); //  signo       handler  
} ngx_signal_t;

Nginx 는 시작 할 때 ngx 를 호출 합 니 다.init_signals 함수, 이 함 수 는 sigaction 시스템 호출 을 통 해 모든 신 호 를 초기 화하 고 해당 하 는 신호 처리 함 수 를 등록 합 니 다.모든 초기 화 작업 이 완료 되면 Master 프로 세 스 가 ngx 를 호출 합 니 다.master_process_cycle 함수 가 자체 이벤트 순환 에 들 어가 신 호 를 감청 하고 신 호 를 받 으 면 대응 하 는 신호 처리 함 수 를 실행 합 니 다.
ngx_int_t ngx_init_signals(ngx_log_t *log)
{
    ngx_signal_t      *sig;
    struct sigaction   sa;

    for (sig = signals; sig->signo != 0; sig++) {
        ngx_memzero(&sa, sizeof(struct sigaction));
        sa.sa_handler = sig->handler;
        sigemptyset(&sa.sa_mask);
        if (sigaction(sig->signo, &sa, NULL) == -1) {
#if (NGX_VALGRIND)
            ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
                          "sigaction(%s) failed, ignored", sig->signame);
#else
            ngx_log_error(NGX_LOG_EMERG, log, ngx_errno,
                          "sigaction(%s) failed", sig->signame);
            return NGX_ERROR;
#endif
        }
    }
    return NGX_OK;
}

2. 신호 전송
실행. / nginx - s stop 명령 을 실행 하면 새로운 Master 프로 세 스 가 시 작 됩 니 다. 이 프로 세 스 는 - s 매개 변수 에 따라 사용자 가 Nginx 에 신 호 를 보 내야 한 다 는 것 을 알 고 ngx 를 통 해get_options () 함수 가 보 낼 신 호 를 분석 한 후 ngx 를 실행 합 니 다.signal_process () 함수, 이 함 수 는 먼저 원래 Master 프로 세 스 의 pid 를 가 져 온 다음 에 원래 Master 프로 세 스에 구체 적 인 신 호 를 보 내 통신 을 완성 합 니 다.
case 's':
                if (*p) {
                    ngx_signal = (char *) p;

                } else if (argv[++i]) {
                    ngx_signal = argv[i];

                } else {
                    ngx_log_stderr(0, "option \"-s\" requires parameter");
                    return NGX_ERROR;
                }

                if (ngx_strcmp(ngx_signal, "stop") == 0
                    || ngx_strcmp(ngx_signal, "quit") == 0
                    || ngx_strcmp(ngx_signal, "reopen") == 0
      /* 
         reload      reload nginx    master+worker  master    reload  , master   ,    worker  ,    worker
             quit  ,              ,  ,       worker    。 ngx_signal_handler
      */
                    || ngx_strcmp(ngx_signal, "reload") == 0)
                {
                    ngx_process = NGX_PROCESS_SIGNALLER;
                    goto next;
                }
/*
     :
  ngx_core_module       ngx_core_conf_t;
               , "/usr/local/nginx/logs/nginx.pid"(     nginx  ID, pid);
     ,  pid;
  ngx_os_signal_process()    ;
*/
ngx_int_t ngx_signal_process(ngx_cycle_t *cycle, char *sig)
{
    ...
    //    master     NGX_PID_PATH
    file.name = ccf->pid;
    file.log = cycle->log;

    file.fd = ngx_open_file(file.name.data, NGX_FILE_RDONLY,
                            NGX_FILE_OPEN, NGX_FILE_DEFAULT_ACCESS);

    if (file.fd == NGX_INVALID_FILE) {
        ngx_log_error(NGX_LOG_ERR, cycle->log, ngx_errno,
                      ngx_open_file_n " \"%s\" failed", file.name.data);
        return 1;
    }

    n = ngx_read_file(&file, buf, NGX_INT64_LEN + 2, 0);

    if (ngx_close_file(file.fd) == NGX_FILE_ERROR) {
        ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
                      ngx_close_file_n " \"%s\" failed", file.name.data);
    }

    if (n == NGX_ERROR) {
        return 1;
    }

    while (n-- && (buf[n] == CR || buf[n] == LF)) { /* void */ }

    pid = ngx_atoi(buf, ++n); //master  id

    if (pid == NGX_ERROR) {
        ngx_log_error(NGX_LOG_ERR, cycle->log, 0,
                      "invalid PID number \"%*s\" in \"%s\"",
                      n, buf, file.name.data);
        return 1;
    }

    return ngx_os_signal_process(cycle, sig, pid);
}

Channel
Nginx 에 서 는 socketpair () 함 수 를 이용 하여 서로 연 결 된 socket 을 만 들 고 부자 프로 세 스 의 통신 을 실현 합 니 다. 즉, Master 프로 세 스 와 Worker 프로 세 스 의 통신 을 실현 합 니 다. Nginx 에 서 는 이러한 통신 을 채널 - channel 로 정의 합 니 다.
1. channel 정의
typedef struct { 
     ngx_uint_t  command; //             NGX_CMD_OPEN_CHANNEL 
     ngx_pid_t   pid;  //      id     ID,           ID
     ngx_int_t   slot; //                      ngx_processes        
     ngx_fd_t    fd; //   fd           
} ngx_channel_t;

2. channel 등록
Master 프로 세 스 는 fork () 함 수 를 통 해 하위 프로 세 스 를 만 듭 니 다. fork 전에 socketpair () 를 사용 하여 연 결 된 소켓 을 만 듭 니 다. 부자 프로 세 스 간 통신 에 사용 되 며, 하위 프로 세 스 도 이 소켓 을 얻 을 수 있 습 니 다. 하위 프로 세 스 가 초기 화 될 때 소켓 을 epoll 에 추가 하여 부모 프로 세 스 의 메 시 지 를 기다 리 고 메시지 처리 함 수 를 등록 합 니 다.부모 프로 세 스 통과 ngxwrite_channel () 메 시 지 를 보 내 고 하위 프로 세 스 는 ngxread_channel () 에서 메 시 지 를 읽 습 니 다.
ngx_pid_t ngx_spawn_process(ngx_cycle_t *cycle, ngx_spawn_proc_pt proc, void *data,
    char *name, ngx_int_t respawn) //respawn   NGX_PROCESS_RESPAWN ,      ngx_processes[]    
{
    ...
        if (socketpair(AF_UNIX, SOCK_STREAM, 0, ngx_processes[s].channel) == -1) // ngx_worker_process_init       
        {
            ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
                          "socketpair() failed while spawning \"%s\"", name);
            return NGX_INVALID_PID;
        }

        /*   master channel[0](    ),channel[1](    )        */  
        if (ngx_nonblocking(ngx_processes[s].channel[0]) == -1) {
            ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
                          ngx_nonblocking_n " failed while spawning \"%s\"",
                          name);
            ngx_close_channel(ngx_processes[s].channel, cycle->log);
            return NGX_INVALID_PID;
        }

        if (ngx_nonblocking(ngx_processes[s].channel[1]) == -1) {
            ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
                          ngx_nonblocking_n " failed while spawning \"%s\"",
                          name);
            ngx_close_channel(ngx_processes[s].channel, cycle->log);
            return NGX_INVALID_PID;
        }
    ...

    pid = fork();
}
static void ngx_worker_process_init(ngx_cycle_t *cycle, ngx_int_t worker)
{ 
    //  epoll add  ngx_chanel   epoll    
    if (ngx_add_channel_event(cycle, ngx_channel, NGX_READ_EVENT,
                              ngx_channel_handler) // ngx_spawn_process   
        == NGX_ERROR)
    {
        /* fatal */
        exit(2);
    }
}

공유 메모리
Nginx 에서 각 Worker 프로 세 스 는 공유 메모 리 를 통 해 통신 합 니 다. 공유 메모 리 는 Linux 에서 제공 하 는 가장 기본 적 인 프로 세 스 간 통신 방식 입 니 다. mmap 와 shmget 시스템 호출 을 통 해 메모리 에 연속 적 인 선형 주소 공간 을 만 들 었 고 munmap 또는 shmdt 시스템 호출 을 통 해 이 메모 리 를 방출 할 수 있 습 니 다.공유 메모 리 를 사용 하 는 장점 은 여러 프로 세 스 가 같은 공유 메모 리 를 사용 할 때 모든 프로 세 스 가 공유 메모리 의 내용 을 수정 한 후에 다른 프로 세 스 가 이 공유 메모리 에 접근 하면 수 정 된 내용 을 얻 을 수 있다 는 것 이다.
Nginx 는 ngx 를 정의 합 니 다.shm_t 구조 체, 공유 메모리 설명 에 사용
typedef struct {
    u_char      *addr; //          
    size_t       size; //        
    ngx_str_t    name; //         
    ngx_log_t   *log;  //shm.log = cycle->log;      ngx_log_t  
    ngx_uint_t   exists;   /* unsigned  exists:1;  */ //                 , 1       
} ngx_shm_t;

조작 ngxshm_t 구조 체 의 방법 은 두 가지 가 있다. ngxshm_alloc (mmap 기반 구현) 는 새로운 공유 메모리 할당 에 사용 되 며, ngxshm_free (munmap 기반) 는 이미 존재 하 는 공유 메모 리 를 방출 하 는 데 사 용 됩 니 다.공유 메모 리 는 Master 프로 세 스 가 만 들 고 Worker 프로 세 스 가 공유 합 니 다.Nginx 놀 라 운 문 제 를 해결 하 는 것 은 상호 배척 자 물 쇠 를 설정 함으로써 상호 배척 자 물 쇠 를 가 진 작업 프로 세 스 만 이 고객 과 연결 하 는 임 무 를 맡 을 수 있 고 이 상호 배척 자 물 쇠 는 공유 메모리 에 넣 습 니 다.또한 ngin 은 연결 수 를 집계 하고 이 전역 변 수 는 공유 메모리 에 도 넣 습 니 다.

좋은 웹페이지 즐겨찾기