nginx
글
-
nginx 소스 파헤치기 1: AI와 함께 소스를 읽는 방법과 분석 지도
nginx가 무엇이고 어떻게 동작하며 어디에 쓰는지를 그림과 3분 실습으로 먼저 보고 시작하는, nginx 소스 읽기 연재의 첫 글입니다. 어떤 판(mainline 1.31.9 개발판)을 읽는지와 stable 1.30.x와의 차이, 같은 소스를 받아 도커에서 auto/configure와 make로 빌드하는 법, 26만 줄짜리 소스의 폴더 지도, 요청 하나가 accept에서 sendfile까지 지나는 큰 길을 gdb와 strace로 확인한 결과, 그리고 AI가 쓴 노트를 소스로 다시 확인하며 읽는 방법을 정리합니다.
-
nginx 소스 파헤치기 2: 전체 지도 — 마스터와 워커, 모듈, cycle, 설정 문맥
nginx 소스를 처음 여는 중급 프로그래머를 위한 연재 전체의 지도입니다. 마스터 하나와 워커 여럿이 각각 어디서 기다리는지, 모든 기능이 ngx_module_t 하나로 꽂히는 모듈 구조와 "CORE"·"HTTP" 글자로 된 모듈 종류, 실행 중인 nginx의 전부를 담은 ngx_cycle_t와 conf_ctx, nginx.conf의 main·events·http·server·location 문맥이 비트 플래그로 검사되는 방법, 한 워커의 이벤트 루프가 수백 개의 연결을 도는 모습을 실제 소스와 ps·gdb 예제로 확인합니다.
-
nginx 소스 파헤치기 3: 메모리 풀과 기본 자료구조 — ngx_pool_t, ngx_str_t, ngx_buf_t와 ngx_chain_t
nginx 의 C 코드에도 free() 는 거의 없습니다. 요청 하나, 연결 하나처럼 수명이 같은 메모리를 풀에 모아 한꺼번에 버리기 때문입니다. ngx_pool_t 의 블록 사슬과 failed 카운트, 큰 할당을 따로 다루는 large 목록, cleanup, NUL 로 끝나지 않는 ngx_str_t, 배열·리스트·큐·해시, 그리고 응답을 담는 ngx_buf_t 와 ngx_chain_t 를 실제 소스와 디버그 로그·gdb 로 확인합니다.
-
nginx 소스 파헤치기 4: 기동과 설정 읽기 — main()에서 ngx_init_cycle까지
nginx 를 켜면 main() 이 명령줄을 읽고, ngx_init_cycle() 이 nginx.conf 를 읽어 cycle 이라는 설정 한 벌을 만든 뒤에야 마스터 프로세스가 돌기 시작합니다. 설정 파서가 파일·블록·명령줄(-g) 세 경우를 한 함수로 처리하는 법, 한 글자씩 읽어 낱말로 나누는 ngx_conf_read_token(), 오류 메시지가 찍히는 자리, reload 가 같은 ngx_init_cycle() 을 다시 부르며 옛 cycle 에서 듣기 소켓과 공유 메모리를 물려받는 과정을 nginx 1.31.9 소스와 gdb·strace 예제로 따라갑니다.
-
nginx 소스 파헤치기 5: 모듈과 디렉티브 — nginx.conf 한 줄이 모듈의 설정 구조체가 되기까지
nginx 의 모듈은 ngx_module_t 구조체 하나이고, 디렉티브는 그 구조체가 가리키는 ngx_command_t 표의 한 줄입니다. configure 가 만드는 모듈 배열, load_module 로 읽는 동적 모듈, 디렉티브 이름으로 함수를 찾는 ngx_conf_handler(), http·server·location 마다 모듈별 설정 구조체를 만드는 ngx_http_block(), 그리고 설정 때 한 번에 끝나는 병합(merge)을 소스로 따라갑니다. 디렉티브 넷을 가진 동적 모듈을 직접 만들어 콜백 순서와 병합 결과, 오류 메시지를 확인합니다.
-
nginx 소스 파헤치기 6: 마스터와 워커 — 프로세스, 시그널, 무중단 reload
nginx -s reload 한 줄이 어떻게 마스터의 sigsuspend() 루프를 깨우고, 새 설정으로 새 워커를 띄운 뒤 옛 워커를 하던 일을 마치게 하고 내보내는지 src/os/unix/ngx_process_cycle.c 를 따라 읽습니다. 시그널 핸들러가 플래그만 세우는 이유, 마스터와 워커를 잇는 socketpair 채널, ngx_processes[] 표의 respawn·just_spawn·exiting 비트, kill -9 당한 워커를 다시 띄우는 길, USR2 바이너리 교체까지 strace·디버그 로그·ps 로 확인합니다.
-
nginx 소스 파헤치기 7: 이벤트 루프 — epoll, 타이머, posted 이벤트, accept
워커 하나가 스레드 하나로 수천 연결을 돌리는 ngx_process_events_and_timers() 한 바퀴를 소스로 따라갑니다. epoll 을 함수 포인터 표(ngx_event_actions)로 끼우는 법, worker_connections 만큼 미리 만든 연결 배열과 빈 목록, EPOLLET 와 낡은 이벤트를 거르는 instance 비트, 레드블랙 트리 타이머가 epoll_wait 의 타임아웃이 되는 길, posted 큐, 그리고 accept_mutex(기본 off)·EPOLLEXCLUSIVE·reuseport 가운데 누가 새 연결을 받는지를 strace·gdb·디버그 로그로 확인합니다.
-
nginx 소스 파헤치기 8: HTTP 요청 읽기 — 연결이 ngx_http_request_t가 되기까지
accept한 소켓 하나가 nginx 안에서 ngx_http_request_t가 되기까지를 소스로 따라갑니다. 데이터가 올 때까지 요청 구조체를 만들지 않는 이유, switch 상태 기계로 된 요청 줄·헤더 파서, client_header_buffer_size와 large_client_header_buffers가 쓰이는 자리, Host 헤더로 server 블록을 고르는 순서, keep-alive와 파이프라인을 디버그 로그·gdb·nc로 직접 확인합니다.
-
nginx 소스 파헤치기 9: 11단계 phase와 location 찾기 — 요청은 어떤 순서로 처리되나
헤더를 다 읽은 요청은 nginx 안에서 11개의 phase를 차례로 지납니다. 모듈들이 등록한 핸들러가 설정 때 한 줄짜리 ph[] 배열로 펴지고, ngx_http_core_run_phases()가 그 배열을 checker 함수로 돌리는 구조를 소스에서 확인합니다. location 블록이 접두사 트리로 바뀌어 =, ^~, 정규식, 1.31.x의 predicate location 순서로 골라지는 과정과 rewrite last·break, 내부 리다이렉트, named location이 배열의 어느 칸으로 되돌아가는지도 디버그 로그와 gdb로 직접 봅니다.
-
nginx 소스 파헤치기 10: 필터와 정적 파일 — 응답은 어떻게 흘러 나가나
정적 파일 하나가 응답이 되어 소켓까지 가는 길을 nginx 1.31.9 소스로 따라갑니다. 파일 내용을 읽지 않고 ngx_buf_t 에 "파일의 몇 번째부터 몇 번째"만 적는 static 핸들러, 함수 포인터 두 개로 이어 붙인 헤더·본문 필터 사슬과 그 순서를 정하는 ngx_modules.c, 파일을 메모리로 읽을지 정하는 copy 필터와 ngx_output_chain, 모아 두었다 보내는 write 필터와 writev + sendfile 까지 gdb·strace·디버그 로그로 확인합니다.
-
nginx 소스 파헤치기 11: upstream과 proxy — 리버스 프록시의 한 요청
proxy_pass 한 줄이 location 에 콘텐츠 핸들러를 걸고, proxy 모듈이 ngx_http_upstream_t 의 콜백을 채우면 upstream 이 논블로킹 connect·요청 보내기·응답 헤더 읽기·본문 흘려보내기를 맡는 과정을 소스로 따라갑니다. 백엔드로 실제 나가는 요청(이 판의 기본값 HTTP/1.1, 보내지 않는 Connection 헤더), 502·504 가 정해지는 자리와 proxy_next_upstream, proxy_buffering on/off 와 임시 파일을 디버그 로그·gdb·작은 백엔드로 확인합니다.
-
nginx 소스 파헤치기 12: 부하 분산, upstream keepalive, stream 모듈 — 그리고 연재를 마치며
upstream {} 에 서버를 여러 대 적으면 nginx는 요청마다 어느 서버로 보낼지를 어떻게 고를까요. peer.init·get·free 세 함수 포인터로 짜인 부하 분산의 틀, 가중치 5:1:1을 a a b a c a a로 고르게 펴는 smooth weighted round robin, max_fails와 fail_timeout, 그 get/free를 감싸 연결을 캐시에 넣었다 꺼내는 keepalive 모듈(이 판에서는 적지 않아도 켜집니다), 그리고 같은 바닥을 TCP에 쓴 stream 모듈을 소스와 도커 예제로 확인하고 연재를 마무리합니다.