Nginx 소스 코드 연구 2: NGINX 의 사건 처리 개론

15829 단어 nginx
NGINX 는 서버 의 응용 프로그램 으로서 클 라 이언 트 가 데 이 터 를 보 낸 후에 서버 에서 이런 처 리 를 하고 있다. 데 이 터 는 먼저 네트워크 카드 를 거 쳐 네트워크 카드 는 운영 체제 와 상호작용 을 하고 운영 체제 의 협의 스 택 처 리 를 거 친 다음 에 서로 다른 응용 프로그램 과 상호작용 을 한다.
이 안에서 두 가지 개념 과 관련 되 는데 하 나 는 사용자 상태 이 고 하 나 는 커 널 상태 이다.응용 프로그램 은 시스템 호출 함 수 를 통 해 커 널 공간 에 들 어가 고 커 널 운행 은 데이터 준비 와 데이터 복사 등 작업 을 한다.NGINX 에 있어 그 는 응용 프로그램 과 운영 체제 의 상호작용, 즉 사용자 상태 와 커 널 상태 간 의 상호작용 이다. NGINX 와 커 널 의 상호작용 방식 이 매우 많다. 예 를 들 어 open (), read () 등 은 모두 커 널 과 상호작용 을 하고 있다. 인터넷 IO 에 있어 우 리 는 Liux 에서 의 네트워크 IO 가 주로 다섯 가지 가 있다 는 것 을 알 고 있다.
첫째, IO 를 막 고 응용 프로그램 은 커 널 함 수 를 호출 하여 커 널 이 데이터 준비 와 데이터 복사 전 과정 을 막 습 니 다.
둘째, 비 차단 IO 입 니 다. 응용 프로그램 은 커 널 함 수 를 호출 하여 커 널 데이터 가 준비 되 어 있 는 지, 커 널 데이터 가 준비 되 어 있 을 때 까지 계속 확인 하고 커 널 이 데이터 복사 가 완 료 될 때 까지 차단 합 니 다.
세 번 째 는 I / O 재 활용 입 니 다. 응용 프로그램 은 커 널 파 라 메 터 를 호출 하여 커 널 의 관심 사 를 알 립 니 다. 커 널 은 이 사건 에 준 비 된 데 이 터 를 받 은 후에 응용 프로그램 에 알 립 니 다. 응용 프로그램 은 커 널 의 데이터 복사 가 완 료 될 때 까지 막 습 니 다. 일반 웹 서버 는 이러한 IO 모델 을 사용 합 니 다. 예 를 들 어 Apache 가 사용 하 는 select / poll, 물론 nginx 도 select / poll 을 지원 하지만 Liux 2.6 이후 에...NGINX 는 보통 epoll 을 선택한다.
네 번 째 는 신호 입 니 다. 응용 프로그램 은 신호 처리 함 수 를 설치 하고 운행 과정 이 막 히 지 않 습 니 다. 운영 시스템 은 데 이 터 를 준비 한 후에 응용 프로그램 에 신 호 를 보 냅 니 다. 응용 프로그램의 신호 처리 함 수 는 IO 처 리 를 할 수 있 습 니 다.
다섯 번 째 비동기, 응용 프로그램 은 운영 체제 에서 제공 하 는 비동기 IO 함수, 예 를 들 어 ao 를 호출 합 니 다.read。
운영 체제 가 보 낸 요청 은 즉시 되 돌아 갈 필요 가 없 음 을 알 리 고 운영 체제 가 데이터 준비 와 데이터 복사 가 끝 난 후에 응용 프로그램 이 시스템 호출 함수 로 지정 한 신 호 를 알 립 니 다.
실제 네트워크 I / O 모델 에서 앞의 네 가 지 는 모두 동기 모델 이 고 다섯 번 째 는 비동기 모델 이다.
NGINX 의 module 에서 지원 하 는 IO 모델 부터 살 펴 보 겠 습 니 다.
|-- event

|   |-- modules

|   |   |-- ngx_aio_module.c

|   |   |-- ngx_devpoll_module.c

|   |   |-- ngx_epoll_module.c

|   |   |-- ngx_eventport_module.c

|   |   |-- ngx_kqueue_module.c

|   |   |-- ngx_poll_module.c

|   |   |-- ngx_rtsig_module.c

|   |   |-- ngx_select_module.c

|   |   `-- ngx_win32_select_module.c

이 장 에 서 는 NGINX 가 epoll 을 인터넷 IO 로 사용 하 는 것 을 중점적으로 연구 할 것 이다.
 
NGINX 는 네트워크 IO 를 하 는데 세 개의 모듈 과 관련된다.
모듈 이름
유형
소재 파일
ngx_events_module
NGX_CORE_MODULE
ngx_event.c
ngx_event_core_module
NGX_EVENT_MODULE
ngx_event.c
ngx_epoll_module
NGX_EVENT_MODULE
module/ngx_epoll_module.c
 
지난 장 에 서 는 module 의 시작 과정 을 언급 하 였 으 며, initcycle 함수, 대 ngxevents_module 의 설정 정보 가 생 성 되 었 습 니 다. 설정 파일 을 분석 하여 ngx 를 호출 합 니 다.events_commands 대 NGXEVENT_MODULE 은 설정 정보의 생 성, 분석, 초기 화 를 했다.
 
1. master - work 작업 모델 의 처리 과정
설정 정 보 를 처리 한 후에 프로 세 스 의 처리 과정 을 살 펴 보 겠 습 니 다.
1、  저 희 는 master - work 작업 모드 를 선택 하 겠 습 니 다.
ngx_master_process_cycle(ngx_cycle_t *cycle)

{

        ......

    

    ngx_start_worker_processes(cycle, ccf->worker_processes,

                               NGX_PROCESS_RESPAWN);

    ngx_start_cache_manager_processes(cycle, 0);

    

    ......

}

 
2、
static void

ngx_start_worker_processes(ngx_cycle_t *cycle, ngx_int_t n, ngx_int_t type)

{

    ngx_int_t      i;

    ngx_channel_t  ch;



    ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "start worker processes");



    ch.command = NGX_CMD_OPEN_CHANNEL;



    for (i = 0; i < n; i++) {



        ngx_spawn_process(cycle, ngx_worker_process_cycle,

                          (void *) (intptr_t) i, "worker process", type);



        ch.pid = ngx_processes[ngx_process_slot].pid; //      

        ch.slot = ngx_process_slot;

        ch.fd = ngx_processes[ngx_process_slot].channel[0];



        ngx_pass_open_channel(cycle, &ch);

    }

}

 
3、
//    

ngx_pid_t

ngx_spawn_process(ngx_cycle_t *cycle, ngx_spawn_proc_pt proc, void *data,

    char *name, ngx_int_t respawn)

{

   ……



    pid = fork();



    switch (pid) {



    case -1:

        ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,

                      "fork() failed while spawning \"%s\"", name);

        ngx_close_channel(ngx_processes[s].channel, cycle->log);

        return NGX_INVALID_PID;



    case 0: //      proc

        ngx_pid = ngx_getpid();

        proc(cycle, data);

        break;



    default: //     

        break;

    }

     

    ……



    return pid;

}

 
4、
static void

ngx_worker_process_cycle(ngx_cycle_t *cycle, void *data)

{

……



    ngx_worker_process_init(cycle, worker);



    ngx_setproctitle("worker process");



……



    for ( ;; ) {

……

        ngx_process_events_and_timers(cycle);

        ……

    }

}

 
5、
static void

ngx_worker_process_init(ngx_cycle_t *cycle, ngx_int_t worker)

{

    ……



    for (i = 0; ngx_modules[i]; i++) {

        if (ngx_modules[i]->init_process) {

            if (ngx_modules[i]->init_process(cycle) == NGX_ERROR) {

                /* fatal */

                exit(2);

            }

        }

    }



 ……



    if (ngx_add_channel_event(cycle, ngx_channel, NGX_READ_EVENT,

                              ngx_channel_handler)

        == NGX_ERROR)

    {

        /* fatal */

        exit(2);

    }

}

 
6、
static ngx_int_t

ngx_event_process_init(ngx_cycle_t *cycle)

{

    ......



    //   module action





    ......

    cycle->connections =

        ngx_alloc(sizeof(ngx_connection_t) * cycle->connection_n, cycle->log);

    if (cycle->connections == NULL) {

        return NGX_ERROR;

    }



    c = cycle->connections;



    cycle->read_events = ngx_alloc(sizeof(ngx_event_t) * cycle->connection_n,

                                   cycle->log);

    if (cycle->read_events == NULL) {

        return NGX_ERROR;

    }



    rev = cycle->read_events;

    for (i = 0; i < cycle->connection_n; i++) {

        rev[i].closed = 1;

        rev[i].instance = 1;

#if (NGX_THREADS)

        rev[i].lock = &c[i].lock;

        rev[i].own_lock = &c[i].lock;

#endif

    }



    cycle->write_events = ngx_alloc(sizeof(ngx_event_t) * cycle->connection_n,

                                    cycle->log);

    if (cycle->write_events == NULL) {

        return NGX_ERROR;

    }



    wev = cycle->write_events;

    for (i = 0; i < cycle->connection_n; i++) {

        wev[i].closed = 1;

#if (NGX_THREADS)

        wev[i].lock = &c[i].lock;

        wev[i].own_lock = &c[i].lock;

#endif

    }



    i = cycle->connection_n;

    next = NULL;



    do {

        i--;



        c[i].data = next;

        c[i].read = &cycle->read_events[i];

        c[i].write = &cycle->write_events[i];

        c[i].fd = (ngx_socket_t) -1;



        next = &c[i];



#if (NGX_THREADS)

        c[i].lock = 0;

#endif

    } while (i);



    cycle->free_connections = next;

    cycle->free_connection_n = cycle->connection_n;



    /* for each listening socket */



    ls = cycle->listening.elts;

    for (i = 0; i < cycle->listening.nelts; i++) {



        ......



        rev->handler = ngx_event_accept;



        if (ngx_use_accept_mutex) {

            continue;

        }



        if (ngx_event_flags & NGX_USE_RTSIG_EVENT) {

            if (ngx_add_conn(c) == NGX_ERROR) {

                return NGX_ERROR;

            }



        } else {

            if (ngx_add_event(rev, NGX_READ_EVENT, 0) == NGX_ERROR) {

                return NGX_ERROR;

            }

        }



#endif



    }



    return NGX_OK;

}

좋은 웹페이지 즐겨찾기