Development guide

dandb3·2024년 1월 2일
0

webserv

목록 보기
3/6

Introduction

리턴 코드

  • NGX_OK — Operation succeeded.
  • NGX_ERROR — Operation failed.
  • NGX_AGAIN — Operation incomplete; call the function again.
  • NGX_DECLINED — Operation rejected, for example, because it is disabled in the configuration. This is never an error.
  • NGX_BUSY — Resource is not available.
  • NGX_DONE — Operation complete or continued elsewhere. Also used as an alternative success code.
  • NGX_ABORT — Function was aborted. Also used as an alternative error code.

Memory management

Cycle

  • 특정 configuration으로 부터 만들어진 nginx runtime context를 저장한다.
  • type은 ngx_cycle_t이다.
  • nginx configuration이 reload될 때 마다, 새로운 cycle이 만들어지는데, 성공적으로 생성된 후 기존 cycle은 삭제된다.

cycle의 멤버들 (중요한 것들만 정리)

  • connections, connection_n
    • type ngx_connection_t들의 array에 해당한다.
  • conf_ctx
    • core module configuration 들의 array에 해당한다.
    • configuration들은 nginx configuration files를 읽으면서 만들어지고 채워진다.
  • modules, modules_n
    • type ngx_module_t 들의 array에 해당한다.
  • listening
    • type ngx_listening_t 들의 array에 해당한다.
    • 보통 서로 다른 module들의 listen directive를 통해 ngx_create_listening()를 호출해서 객체가 생성된다.
    • listen 소켓은 listening object를 기반으로 생성된다.

Networking

Connection

  • connection type ngx_connection_t는 소켓 디스크립터의 wrapper에 해당한다.

멤버 변수들

  • fd
    • 소켓 디스크립터
  • data
    • Arbitrary connection context.
    • 보통 connection의 top에서 만들어진 HTTP request나 Stream session과 같은 higher-level 객체에 대한 포인터이다.
  • read, write
    • connection을 위한 read와 write 이벤트
  • recv, send, recv_chain, send_chain
    • connection을 위한 I/O 작업
  • sockaddr, socklen, addr_text
    • 원격 소켓 주소 in binary and text forms
  • local_sockaddr, local_socklen
    • 로컬 소켓 주소 in binary form
    • 처음에는 비어있지만, ngx_connection_local_sockaddr() 함수를 통해 local socket address를 알 수 있다.

Events

Event

  • 이벤트 객체인 ngx_event_t는 특정 이벤트가 발생했을 때 처리하는 메커니즘을 제공한다.

멤버 변수

  • data
    • event handler에서 사용하는 arbitrary event context가 저장된다.
    • 보통 event와 관련된 connection 포인터가 저장됨.
  • handler
    • event 발생 시 호출되는 함수.
  • write
    • write event임을 의미하는 플래그.
    • 플래그가 세워져 있지 않다면, read event임을 의미함.
  • active
    • event가 I/O notification을 수신하기 위해 register 되었는지 알려주는 플래그
  • ready
    • event가 I/O notification을 수신했는지 나타내는 플래그
  • eof
    • 데이터를 읽는 중 EOF가 발생했음을 의미하는 플래그
  • error
    • reading 혹은 writing 도중 에러가 발생했음을 알려주는 플래그
  • posted
    • 이벤트가 queue에 posted되었는지 의미하는 플래그
  • queue
    • 이벤트를 queue에 post하기 위한 queue node

I/O events

  • ngx_get_connection()으로 얻어진 connection은 c->read와 c->write의 두 개의 attached event가 있는데, 이들은 각각 read와 write 이벤트가 발생했을 때 사용된다.
  • 모든 이벤트들은 Edge-Triggered mode에서만 동작한다.
    • Edge-Triggered?
      • “소켓의 상태가 바뀌었을 때” 만을 의미한다.
      • 예를들면, 부분적인 read가 발생했을 경우, 읽을 데이터가 남아있음에도 불구하고 event가 발생하지 않는 경우이다.
      • 반대는 Level-Triggered로, 읽을 데이터가 남아 있을 경우 event가 발생한다.

Posted events

  • event가 posted된다? → 지금은 아니지만 현재 event loop iteration 안에 언젠가 handler가 호출될 경우를 의미한다.
  • 즉, posted events는 post queue를 통해서 저장된다.
  • ngx_post_event(ev, q) 매크로는 event ev를 post queue q에다가 넣는 역할을 한다.
  • ngx_delete_posted_event(ev) 매크로는 event ev를 queue의 현재 posted된 위치에서 제거하는 역할을 한다.
  • 일반적으로 이벤트들은 ngx_posted_events queue에 post되고, 나중에 event들이 다 handled되고 나서 처리된다.
  • ngx_event_process_posted()를 통해 event queue가 처리되는데, queue가 비어있을 때 까지 계속 event handler를 호출한다.
  • posted event handler는 더 많은 이벤트들을 post할 수 있다.

Event loop

  • nginx master process를 제외하고 모든 nginx process들은 I/O를 수행하고, event loop을 가지고 있다.
  • ngx_process_events_and_timers()를 통해서 nginx event loop이 수행된다.
  • 프로세스가 exit되기 전 까지 위 함수가 수행된다.

event loop 내부 과정 (timer 배제)

  • nginx configuration에 의해 선택된 event notification mechanism에 따라 handler를 호출하여 I/O event를 처리한다.
    • 이 때 handler는 적어도 하나의 I/O event가 발생하기를 기다린다.
    • read / write event 발생 시, ready 플래그가 set 되고, event handler가 호출된다.
    • 리눅스의 경우 ngx_epoll_process_events()가 보통 사용된다.
    • 물론 macOS X의 경우 ngx_kqueue_process_events()가 사용된다.
  • ngx_event_process_posted() 함수를 통해서 posted event를 처리한다.
    • 위 함수는 queue가 빌 때 까지, posted event queue로부터 첫 번째 원소를 지우고 원소의 handler를 호출하는 것을 반복한다.

Modules

Core Modules

  • nginx의 대부분의 기능은 모듈로써 구현된다.

  • 모듈 소스파일은 ngx_module_t type의 전역변수를 포함하고 있어야 하고, 그 구조는 아래와 같다.

    struct ngx_module_s {
    
        /* private part is omitted */
    
        void                 *ctx;
        ngx_command_t        *commands;
        ngx_uint_t            type;
    
        ngx_int_t           (*init_master)(ngx_log_t *log);
    
        ngx_int_t           (*init_module)(ngx_cycle_t *cycle);
    
        ngx_int_t           (*init_process)(ngx_cycle_t *cycle);
        ngx_int_t           (*init_thread)(ngx_cycle_t *cycle);
        void                (*exit_thread)(ngx_cycle_t *cycle);
        void                (*exit_process)(ngx_cycle_t *cycle);
    
        void                (*exit_master)(ngx_cycle_t *cycle);
    
        /* stubs for future extensions are omitted */
    };
    
    typedef struct ngx_module_s ngx_module_t
  • ctx field에는 private data가 저장된다.

  • commands array에는 configuration directives가 저장된다.

    module lifecycle

    • master process의 context에서, configuration file에 configuration directive가 나타나면 configuration directive handler가 호출된다.
    • configuration이 성공적으로 파싱이 완료되면, master process의 context에서 init_module handler가 호출된다. init_module handler는 configuration이 load될 때 마다 master process에서 호출된다.
    • master process가 하나 이상의 worker process를 만들고, init_process handler가 각각 호출된다.
    • worker process가 master로 부터 shutdown / terminate를 수신하면, exit_process handler를 호출한다.
    • master process는 exit하기 전에 exit_master handler를 호출한다.
  • typectx field에 어떤 것이 저장되어 있는지 정의한다. 아래는 type의 가능한 값들이다.

    • NGX_CORE_MODULE
    • NGX_EVENT_MODULE
    • NGX_HTTP_MODULE
    • NGX_MAIL_MODULE
    • NGX_STREAM_MODULE

생략…

HTTP

Connection

각각의 HTTP client connection은 아래 순서를 따른다:

  • ngx_event_accept()
    • client TCP 연결을 accept한다.
    • listen 소켓의 read notification이 발생했을 때 호출되는 handler이다.
    • 새롭게 accept된 client 소켓을 wrap하는 ngx_connection_t 객체가 생성된다.
    • nginx listener는 새로 만들어진 connection 객체를 인자로 하는 handler를 제공한다.
    • HTTP connection의 경우 ngx_http_init_connection(c) 이다.
  • ngx_http_init_connection()
    • HTTP connection의 early initialization를 수행한다.
    • ngx_http_connection_t 객체가 새로 만들어지고, reference가 connection의 data field에 저장된다.
    • 나중에 HTTP request 객체로 바뀔 예정임.
    • PROXY 프로토콜 파서와 SSL handshake도 이 단계에서 시작된다.
  • ngx_http_wait_request_handler()
    • read event handler이다.
    • client socket에 data가 available한 경우 호출된다.
    • 이 단계에서 HTTP request 객체인 ngx_http_request_t가 만들어지고, connection의 data field에 위치하게 된다.
  • ngx_http_process_request_line()
    • read event handler이다.
    • client request line을 읽어들인다.
    • 이 handler는 ngx_http_wait_request_handler()에 의해 set 된다.
    • connection의 buffer 로 데이터가 read된다.
    • 버퍼의 크기?
      • client_header_buffer_size directive에 의해 버퍼의 크기가 결정된다.
      • entire client header가 버퍼 안에 들어가는 것이 예상된다.
      • 만약 초기 크기가 충분하지 않다면, 더 큰 buffer가 할당되고, 크기는 large_client_header_buffers directive에 의해 결정된다.
  • ngx_http_process_request_headers()
    • read event handler이다.
    • client request header를 읽기 위한 함수.
    • ngx_http_process_request_line() 함수 후에 handler로 set된다.
  • ngx_http_core_run_phases()
    • request header가 완전히 읽어지고 파싱이 완료되면 호출된다.
    • request의 phase를 NGX_HTTP_POST_READ_PHASE 부터 NGX_HTTP_CONTENT_PHASE 까지 변화시키면서 동작한다.
    • The last phase is intended to generate a response and pass it along the filter chain.
    • response는 이 phase에서 client에게 보내지지 않고, buffered 후에 finalization stage에 보내진다.
  • ngx_http_finalize_request()
    • request가 모든 output을 생성하거나 error가 발생했을 경우 호출된다.
    • error가 발생한 경우, 적절한 error page가 response로 사용된다.
    • 이 시점에 response가 완전히 client에게 전달되지 않았다면, HTTP writer ngx_http_writer()가 activate되어서 보내지지 않은 데이터를 마저 보내게 된다.
  • ngx_http_finalize_connection()
    • 완전한 response가 client에게 보내졌고, request가 destroy될 수 있을 때 호출된다.
    • 만약 client connection keepalive가 enable되어 있었다면, ngx_http_set_keepalive()가 호출되어 현재 request를 destroy하고 동일한 connection에서 다음 request를 기다린다.
    • 그렇지 않다면, ngx_http_close_request()가 request와 connection를 모두 destroy한다.
profile
공부 내용 저장소

0개의 댓글