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
- 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
- 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 {
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);
};
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를 호출한다.
-
type
은 ctx
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한다.