콘텐츠로 건너뛰기

NginX

면접관 – “흠… 애송이군…”

면접관이 묻는다.

면접관: “프로젝트에 Nginx를 쓰셨는데, Nginx가 뭔지 알고 쓰셨나요?

우리는 뭐라고 답해야 할까?

나: “Nginx는 웹서버입니다. 리버스 프록시, 로드 밸런서, 그리고 http 캐시로도 쓰일 수 있는 소프트웨어입니다. 요청에 응답하기 위해 이벤트 기반 구조를 채택했고, 덕분에 현재 웹 서버 분야에서 1등을 하고 있습니다.

보기엔 완벽한 답변이다.
그러나 면접관이 이렇게 묻는다면 뭐라고 대답하겠는가?

면접관: “이벤트 기반 구조요? 이벤트 기반 구조가 어떤 점이 좋아서 Nginx를 썼는데요? 웹서버 분야에서 제일 잘나가는게 Apache 서버 아닌가요? 그것과 차이점이 뭐죠?

나: “어…Nginx가 벤치마크 테스트를 했을때 가볍고 성능이 좋기도 하고요… 아파치 서버보다 최신 기술이에요…

오늘은 Nginx에 대해 완전정복하는 시간을 가져보자.

탄생배경

웹서버 역사의 흐름

1995년 이전에는 UNIX 기반 최초 웹서버 NCSA HTTPd가 있었다.
그러나 이 프로그램은 버그가 많아서 개발자들이 불편함을 호소했다.
이 버그들을 수정하면서, 구조를 변경하고 기능을 추가해서 만든 것이 지금의 Apache 서버인 것이다.

Apache는 당시로선 혁신이었다.
요청이 들어오면 프로세스나 스레드를 하나씩 만들어서 처리하는 방식이었고, 이게 굉장히 직관적이고 안정적이었다.
그래서 한동안 Apache가 웹서버의 표준이나 다름없었다.

Apache의 Prefork방식

그런데 2000년대 초반, 문제가 생기기 시작했다.

C10K 문제 — Apache의 한계

1999년 Dan Kegel이라는 엔지니어가 하나의 논문을 발표한다.

“동시에 1만 명의 클라이언트를 어떻게 처리할 것인가?”

이게 바로 유명한 C10K(Concurrent 10,000 connections) 문제다.

인터넷이 폭발적으로 성장하면서 서버 하나가 처리해야 하는 동시 접속자 수가 수천, 수만 명으로 늘어났다.
그런데 Apache는 구조적으로 한계가 있었다.

Apache의 방식을 그림으로 그려보면 이렇다.

요청 1 → 프로세스/스레드 1 생성 → 처리
요청 2 → 프로세스/스레드 2 생성 → 처리
요청 3 → 프로세스/스레드 3 생성 → 처리
...
요청 10,000 → 프로세스/스레드 10,000 생성 → ???

10,000개의 요청이 들어오면 10,000개의 프로세스(또는 스레드)를 만들어야 한다.
각각의 프로세스는 메모리를 차지하고, CPU는 이걸 번갈아가며 처리한다.
동시 접속자가 늘어날수록 메모리는 폭발하고, CPU는 프로세스를 전환하는 것만으로도 지쳐버린다.

이 현상을 컨텍스트 스위칭 오버헤드라고 부른다.

모바일 시대가 열리고 트래픽이 폭발적으로 증가하자, 이 문제는 현실이 되었다.

  • 커넥션이 연결될 때마다 프로세스를 생성하는 방식 -> 메모리 부족 현상으로 이어짐
  • 확장성 -> 프로세스가 차지하는 리소스의 양이 늘어남.
  • 많은 커넥션 요청이 올때마다 굉장히 많은 컨텍스트 스위칭을 하여 CPU에 무리를 줌.

Nginx의 탄생

2004년, 러시아의 개발자 *gor Sysoev가 C10K 문제를 해결하기 위해 Nginx를 만들었다.

핵심 아이디어는 단순했다.

“요청마다 스레드를 만들지 말고, 하나의 스레드가 여러 요청을 동시에 처리하게 하자.”

이것이 이벤트 기반 비동기(Event-Driven, Non-Blocking) 구조다.

Apache vs Nginx — 구조 비교

Apache: 프로세스/스레드 기반

Apache는 MPM(Multi-Processing Module) 방식으로 동작한다.
대표적인 두 가지가 있다.

  • Prefork 방식: 요청마다 독립적인 프로세스를 생성한다. 안정적이지만 메모리를 많이 먹는다.
  • Worker 방식: 프로세스 안에 여러 스레드를 만들어 처리한다. Prefork보다는 효율적이지만 여전히 한계가 있다.

어떤 방식이든 핵심은 같다.
요청 하나당 처리 단위(프로세스 or 스레드)가 하나 필요하다.
그리고 그 처리 단위가 응답을 완료할 때까지 점유된다.

Nginx: 이벤트 기반 비동기

Nginx는 구조 자체가 다르다.

마스터 프로세스 (Master Process)
└── 워커 프로세스 1 (Worker Process)
└── 워커 프로세스 2
└── 워커 프로세스 3
└── 워커 프로세스 4
  • 마스터 프로세스는 설정 파일을 읽고 워커 프로세스들을 관리하는 관리자 역할이다.
    실제 요청을 처리하는 건 워커 프로세스다.

중요한 건 여기서부터다.
워커 프로세스 하나가 수천 개의 연결을 동시에 처리한다.
어떻게 가능한 것일까?

이벤트 기반 구조, 제대로 이해하기

비유를 하나 들어보자.

  • Apache 방식 (동기/블로킹)
    • 카페에서 주문을 받는 직원이 있다. 손님 A가 주문을 하면, 그 직원은 A의 커피가 나올 때까지 그 자리에서 기다린다. 커피가 나오면 A에게 주고, 그 다음에야 손님 B를 받는다. 직원이 100명이 필요하면 100명을 고용해야 한다.
  • Nginx 방식 (비동기/논블로킹)
    • 카페 직원 한 명이 주문을 받는다. A가 주문하면 주방에 넘기고, 바로 B의 주문을 받는다. B 주문을 넘기고, C의 주문을 받는다. 그러다 주방에서 “A 커피 나왔어요”라는 이벤트가 오면, 그때 A에게 가져다준다.
    • 직원 한 명이 수백 명을 처리할 수 있다.

이게 바로 Nginx의 이벤트 드리븐(Event-Driven) 방식이다.
I/O 작업(네트워크, 파일 읽기 등)이 완료됐다는 이벤트를 기다리는 동안, 다른 요청들을 처리한다.
블로킹 없이 계속 돌아간다.

그래서 실제로 얼마나 차이나는가?

동시 접속 수가 늘어날수록 차이가 극명하게 드러난다.

동시 접속 수Apache 메모리 사용Nginx 메모리 사용
1,000높음낮음
10,000매우 높음 (한계 도달)여전히 낮음
50,000+사실상 불가처리 가능

단순히 메모리만의 문제가 아니다. 컨텍스트 스위칭이 줄어드니 CPU 효율도 올라간다.

Nginx가 하는 역할들

Nginx는 단순한 웹서버가 아니다.

1. 웹서버 (Web Server)

정적 파일(HTML, CSS, JS, 이미지 등)을 직접 클라이언트에게 전달한다.
이 부분은 Apache도 잘하지만, Nginx가 훨씬 빠르다.

2. 리버스 프록시 (Reverse Proxy)

클라이언트 ↔ Nginx ↔ 백엔드 서버 구조에서, Nginx가 중간에서 요청을 받아 내부 서버로 전달하는 역할이다.

클라이언트 
  → Nginx 
    → Node.js 서버
      → Django 서버
        → Spring 서버

클라이언트는 Nginx 하나만 바라본다.
내부 구조를 숨길 수 있고, 보안도 올라간다. (프록시 서버 주소만 노출, DB서버나 캐시서버의 해킹 방지)

3. 로드 밸런서 (Load Balancer)

여러 대의 백엔드 서버로 트래픽을 분산시킨다. 특정 서버에 부하가 몰리는 걸 막는다.

클라이언트 
  → Nginx → 서버 1 (33%)
            → 서버 2 (33%)
              → 서버 3 (33%)

4. HTTP 캐시 (HTTP Cache)

자주 요청되는 콘텐츠를 Nginx에 캐싱해두고, 백엔드 서버까지 가지 않고 바로 응답한다.
백엔드 부하를 크게 줄일 수 있다.

Apache가 여전히 쓰이는 이유

그렇다면 Apache는 죽은 기술인가? 아니다.

Apache는 .htaccess 파일을 통해 디렉토리 단위로 설정을 바꿀 수 있다. 웹호스팅 환경처럼 여러 사용자가 각자 자기 설정을 가져야 할 때 매우 유용하다.

또한 수십 년간 쌓인 모듈 생태계안정성은 Apache만의 강점이다. PHP를 직접 내장 모듈로 실행하는 방식 등, Apache가 더 자연스러운 환경이 있다.

비교 항목ApacheNginx
구조프로세스/스레드 기반이벤트 기반 비동기
동시 접속 성능불리유리
정적 파일 처리보통빠름
동적 콘텐츠 처리직접 처리 가능백엔드에 위임
설정 유연성 (.htaccess)강점제한적
메모리 사용많음적음
모듈 생태계풍부점점 성장 중

면접 답변, 다시 써보자

면접관: “프로젝트에 Nginx를 쓰셨는데, Nginx가 뭔지 알고 쓰셨나요?”

이제 이렇게 답할 수 있다.

나:
“Apache는 요청이 들어올 때마다 프로세스나 스레드를 생성해서 처리합니다.
동시 접속이 많아지면 그만큼 메모리와 CPU가 소모되고, 컨텍스트 스위칭 오버헤드도 커집니다.
반면 Nginx는 이벤트 기반 비동기 구조로, 워커 프로세스 하나가 수천 개의 연결을 논블로킹 방식으로 처리합니다.
I/O 대기 중에도 다른 요청을 계속 처리하기 때문에 메모리 사용이 적고 동시 처리 성능이 훨씬 뛰어납니다.
특히 저는 정적 파일 서빙과 리버스 프록시로 사용했는데, 이 두 가지 모두 Nginx가 강점을 보이는 영역이라 선택했습니다.”

면접관 – “너, 우리 회사의 포켓몬이 되어라!”

요약

  • Apache
    • 프로세스/스레드 기반, 안정적, .htaccess 유연, 동시 접속에 약함
    • 즉, 안정성확장성 덕분에 아직까지도 많이 사용됨.
  • Nginx
    • 이벤트 기반 비동기, 가볍고 빠름, 동시 접속에 강함, 리버스 프록시/로드밸런서에 탁월
    • 즉, 동시커넥션 문제를 해결한다는 강점이 있음.
  • C10K 문제가 Nginx 탄생의 직접적인 계기
  • 이벤트 기반 = I/O 대기 중 다른 요청 처리 → 스레드 하나로 수천 연결 처리
  • 무조건 Nginx가 좋은 게 아니라, 상황에 맞는 선택이 중요

[참고자료]

명강의 of 명강의
0 글이 마음에 드시면 하트를 눌러주세요! 행복한 고민이 됩니다!

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다

Exit mobile version