웹 서버 (Web Server)
1. 개념
웹 서버는 HTTP/1.1, HTTP/2, HTTP/3 (QUIC) 등 표준 웹 프로토콜을 구현한 네트워크 애플리케이션으로, OSI 7 계층 모델의 애플리케이션 계층에서 동작하며, 클라이언트(주로 웹 브라우저 또는 다른 HTTP 클라이언트)의 요청을 처리하여 **정적 컨텐츠(Static Content)**를 효율적으로 제공하는 데 최적화되어 있습니다. 여기서 정적 리소스란, 서버 사이드 로직의 개입 없이 파일 시스템에서 직접 읽어와 클라이언트에게 반환할 수 있는 데이터를 의미합니다.
- 정적 리소스의 예시:
- HTML, CSS, JavaScript 파일 (프론트엔드 빌드 아티팩트 포함)
- 이미지 파일 (JPG, PNG, GIF, SVG, WebP 등)
- 폰트 파일 (TTF, OTF, WOFF 등)
- 영상, 오디오, PDF 등 바이너리 리소스
- 핵심 기능:
- HTTP 프로토콜 처리: 클라이언트로부터의 HTTP 요청을 파싱하고, 유효성을 검사하며, 적절한 HTTP 응답 코드를 포함하여 리소스를 반환합니다.
- 정적 파일 서빙: 파일 시스템에 저장된 정적 파일을 고성능으로 제공합니다. 이는 주로 비동기 Non-blocking I/O 모델을 통해 구현되어 다수의 동시 연결을 효율적으로 처리합니다.
- 리버스 프록시(Reverse Proxy): 클라이언트와 백엔드 서버(WAS) 사이에 위치하여 클라이언트의 요청을 대신 받아 WAS로 전달하고, WAS의 응답을 받아 클라이언트에 전달하는 역할을 수행합니다. 이를 통해 WAS의 IP 주소를 숨기고, 보안 및 로드 밸런싱 기능을 추가할 수 있습니다.
- 로드 밸런서(Load Balancer): 다수의 WAS 인스턴스에 대한 요청을 분산하여 시스템의 가용성과 성능을 향상시킵니다. Round Robin, Least Connections, IP Hash 등 다양한 로드 밸런싱 알고리즘을 지원합니다.
- TLS 종단점(Termination Proxy): HTTPS 통신을 위한 TLS/SSL 핸드쉐이크를 수행하고, 암복호화 작업을 담당하여 WAS의 부하를 줄입니다. 이는 SSL Offloading이라고도 불립니다.
- 캐싱 프록시(Caching Proxy): 자주 요청되는 정적 리소스를 캐싱하여 동일한 요청에 대해 WAS를 거치지 않고 웹 서버가 직접 응답하게 함으로써 응답 시간을 단축하고 WAS의 부하를 줄입니다.
2. 동작 구조
웹 서버의 동작 과정은 다음과 같은 흐름을 따릅니다.
- 연결 수립: 클라이언트(브라우저)가 웹 서버의 Well-Known TCP 포트(HTTP: 80, HTTPS: 443)로 TCP 연결을 수립합니다.
- HTTP 요청 수신: 클라이언트가 HTTP 요청 메시지(예: GET /index.html HTTP/1.1, Host: example.com)를 웹 서버로 전송합니다.
- 요청 파싱 및 라우팅: 웹 서버는 수신된 HTTP 요청을 파싱하여 요청된 URI와 HTTP 메서드를 식별합니다.
- 정적 리소스 요청: 요청된 URI가 /static/image.jpg와 같이 정적 리소스에 해당하면, 웹 서버는 내부 파일 시스템에서 해당 파일을 찾아 읽어들입니다.
- 동적 리소스 요청 (프록시): 요청된 URI가 /api/users와 같이 동적 리소스에 해당하거나, 특정 패턴에 매칭되면, 웹 서버는 설정된 리버스 프록시 규칙에 따라 요청을 하나 이상의 백엔드 WAS로 전달합니다. 이 때, 요청 헤더(예: X-Forwarded-For, X-Forwarded-Proto)를 추가하여 원래 클라이언트의 정보나 프로토콜 정보를 WAS에 전달할 수 있습니다.
- 응답 생성 및 전송:
- 정적 리소스 응답: 찾은 정적 파일의 MIME 타입(예: Content-Type: text/html 또는 image/jpeg)을 결정하고, Content-Length, ETag, Cache-Control 등 적절한 HTTP 응답 헤더와 함께 파일 데이터를 클라이언트에 전송합니다. 파일 전송 시 Zero-copy 기술을 활용하여 커널 공간에서 사용자 공간으로의 데이터 복사를 최소화하여 성능을 최적화하기도 합니다.
- 프록시 응답: WAS로부터 응답을 받으면, 웹 서버는 해당 응답을 그대로 클라이언트에게 포워딩하거나, 추가적인 헤더 조작, 압축(Gzip/Brotli) 등의 처리를 거쳐 전송합니다.
- 연결 종료 또는 유지: Keep-Alive 설정에 따라 TCP 연결을 유지하여 다음 요청에 재사용하거나, 요청 처리가 완료되면 연결을 종료합니다.
3. 예시 소프트웨어
다양한 웹 서버 소프트웨어가 존재하며, 각각의 설계 철학과 강점이 다릅니다.
- Nginx:
- 특징: 이벤트 기반(event-driven), 비동기(asynchronous), 논블로킹(non-blocking) I/O 모델을 채택하여 적은 메모리로 높은 동시성을 처리할 수 있습니다. 경량성과 고성능으로 정적 파일 서빙, 리버스 프록시, 로드 밸런싱에 매우 강력합니다. C10K problem 해결의 대표적인 사례로 꼽힙니다.
- 주요 사용처: 고성능 웹 서비스의 프론트엔드 게이트웨이, 마이크로서비스 아키텍처의 API Gateway.
- Apache HTTP Server (httpd):
- 특징: 모듈 기반 아키텍처로, 다양한 기능을 모듈 형태로 쉽게 추가하고 확장할 수 있습니다. MPM(Multi-Processing Modules)을 통해 프로세스 기반(prefork), 스레드 기반(worker), 이벤트 기반(event) 등 다양한 동시성 처리 모델을 지원합니다. 오랜 역사와 광범위한 커뮤니티 지원을 자랑합니다.
- 주요 사용처: 전통적인 웹 호스팅 환경, 복잡한 설정과 다양한 모듈이 필요한 환경.
- Caddy:
- 특징: Go 언어로 개발되었으며, 자동 HTTPS(Let's Encrypt를 통한 무료 TLS 인증서 발급 및 갱신)를 기본으로 제공하여 설정이 매우 간편합니다. Nginx와 유사하게 리버스 프록시, 로드 밸런싱 등의 기능을 지원합니다.
- 주요 사용처: 개발 환경, 소규모 프로젝트, 간편한 HTTPS 설정이 필요한 경우.
- Microsoft IIS (Internet Information Services):
- 특징: Windows 운영체제에 내장된 웹 서버로, .NET 애플리케이션 호스팅에 최적화되어 있습니다. GUI 기반의 관리 도구를 제공하여 설정 및 관리가 용이합니다.
- 주요 사용처: Windows 서버 환경, ASP.NET 기반의 웹 애플리케이션.
4. 기술적 특징
| I/O 모델 | Nginx는 epoll (Linux), kqueue (FreeBSD), IOCP (Windows) 등 OS 비동기 I/O 메커니즘을 활용하는 비동기 논블로킹(Asynchronous Non-blocking) I/O 모델을 사용하여 적은 수의 워커 프로세스로 다수의 동시 연결을 효율적으로 처리합니다. Apache HTTP Server는 MPM(Multi-Processing Modules) 설정에 따라 프로세스 기반(prefork) 또는 **스레드 기반(worker)**의 블로킹 I/O 모델을 기본으로 사용하다가, 최근에는 event MPM을 통해 비동기 처리도 지원합니다. |
| 성능 최적화 | - Keep-Alive (HTTP persistent connections): 단일 TCP 연결을 통해 여러 HTTP 요청/응답을 처리하여 연결 수립 오버헤드를 줄입니다.<br>- 콘텐츠 압축: Gzip, Brotli 등 알고리즘을 사용하여 전송되는 데이터의 크기를 줄여 네트워크 대역폭 사용량을 최적화합니다.<br>- HTTP 캐싱: Cache-Control, Expires, ETag, Last-Modified 등의 HTTP 헤더를 활용하여 클라이언트나 프록시 서버에 리소스를 캐싱하게 하여 재요청 시 서버 부하를 줄입니다.<br>- Zero-copy I/O: 커널 공간에서 직접 데이터를 소켓으로 전송하여 CPU 오버헤드를 줄입니다. |
| 보안 기능 | - TLS/SSL 핸드쉐이크 및 암복호화: HTTPS 통신을 위한 TLS(Transport Layer Security) 프로토콜을 구현하여 데이터 암호화 및 무결성을 보장합니다.<br>- 접근 제어 (Access Control): IP 주소, HTTP Basic 인증 등을 기반으로 특정 리소스에 대한 접근을 제한합니다.<br>- Rate Limiting: 특정 IP 주소나 사용자로부터의 요청 빈도를 제한하여 DoS(Denial of Service) 공격을 방어합니다.<br>- 웹 방화벽(WAF) 연동: ModSecurity와 같은 WAF 모듈 또는 외부 WAF 솔루션과의 연동을 통해 SQL Injection, XSS 등의 웹 공격을 탐지하고 차단합니다. |
| 확장성 | 단순히 정적 컨텐츠를 제공하는 것을 넘어, 리버스 프록시, 로드 밸런싱, 캐싱 프록시, URL Rewriting, CORS(Cross-Origin Resource Sharing) 처리 등 다양한 네트워크 및 웹 애플리케이션 계층의 기능을 수행할 수 있도록 설계되었습니다. 이를 통해 복잡한 시스템 아키텍처의 최전선에서 트래픽을 효율적으로 관리합니다. |
WAS (Web Application Server)
1. 개념 (전공자 기준)
**WAS(Web Application Server)**는 웹 서버와 달리, 동적 비즈니스 로직을 처리하고 동적으로 데이터를 생성하는 서버 측 애플리케이션 플랫폼입니다. 클라이언트의 요청에 따라 데이터베이스 조회, 비즈니스 규칙 적용, 다른 시스템과의 연동 등을 수행하여 맞춤형 응답을 생성합니다. WAS는 웹 기반 서비스의 **백엔드 애플리케이션 계층(Logic Layer)**을 담당하는 핵심 컴포넌트이며, 일반적으로 특정 프로그래밍 언어 및 프레임워크의 런타임 환경을 제공합니다.
- 전통적인 WAS: 과거에는 Java EE(Enterprise Edition) 표준을 기반으로 하는 Tomcat, JBoss(WildFly), WebLogic, WebSphere 등과 같은 컨테이너를 지칭했습니다. 이들은 서블릿(Servlet), JSP(JavaServer Pages), EJB(Enterprise JavaBeans) 등의 기술 스택을 포함하여 엔터프라이즈급 애플리케이션 개발을 위한 풍부한 기능을 제공했습니다.
- 현대적인 WAS의 확장된 개념: 오늘날에는 특정 Java EE 컨테이너에 국한되지 않고, Node.js의 Express/NestJS, Python의 Django/Flask/FastAPI, Spring Boot (Java), PHP의 Laravel, Go의 Gin/Fiber 등 모든 서버 사이드 프레임워크 기반의 백엔드 런타임 환경을 포괄적으로 WAS로 간주합니다. 이들은 HTTP 요청을 처리하고, 비즈니스 로직을 실행하며, 데이터베이스와 상호작용하여 동적인 응답을 생성하는 역할을 수행합니다.
2. 동작 구조
WAS의 동작 구조는 웹 서버로부터 요청을 전달받아 비즈니스 로직을 처리하는 과정에 중점을 둡니다.
- HTTP 요청 수신 (주로 웹 서버로부터): 웹 서버로부터 GET /api/users, POST /login 등 동적 처리가 필요한 HTTP 요청을 전달받습니다. 이는 주로 프록시를 통해 전달됩니다.
- 요청 처리 및 라우팅:
- WAS 내부의 웹 컨테이너(Web Container) 또는 프레임워크의 라우터는 수신된 요청의 URL 패턴을 분석하여 해당 요청을 처리할 적절한 컨트롤러(Controller) 또는 **핸들러(Handler)**를 매핑합니다.
- 요청 파라미터, 헤더, 바디 등의 데이터를 파싱하여 컨트롤러의 메서드에 전달할 수 있는 형태로 변환합니다 (예: JSON 데이터를 객체로 매핑).
- 비즈니스 로직 실행:
- 컨트롤러는 요청을 바탕으로 **서비스 계층(Service Layer)**의 메서드를 호출하여 핵심 비즈니스 로직을 수행합니다.
- 서비스 계층은 필요한 경우 **데이터 접근 계층(DAO: Data Access Object 또는 Repository)**을 통해 관계형 데이터베이스(RDBMS), NoSQL 데이터베이스, 캐시 서버(Redis, Memcached), 메시지 큐(Kafka, RabbitMQ) 등 외부 데이터 소스와 연동하여 데이터를 조회, 저장, 수정, 삭제합니다. 이 과정에서 ORM(Object-Relational Mapping) 프레임워크나 JDBC/ODBC 드라이버가 사용될 수 있습니다.
- 트랜잭션 관리, 예외 처리, 로깅 등 다양한 비즈니스 규칙과 시스템 로직이 이 계층에서 처리됩니다.
- 응답 생성:
- 비즈니스 로직의 처리 결과를 바탕으로 WAS는 클라이언트에 응답할 데이터를 생성합니다. 이는 주로 JSON (REST API), XML, 또는 HTML (서버 사이드 렌더링) 형태가 됩니다.
- 서버 사이드 렌더링(SSR): WAS가 HTML 템플릿 엔진(예: Thymeleaf, JSP, EJS, Pug, Jinja2)을 사용하여 동적으로 HTML 페이지를 생성하고 클라이언트에 전송합니다.
- API 응답: 데이터를 JSON/XML 형태로 직렬화하여 클라이언트에 전송합니다.
- 응답 전송: 생성된 응답 데이터와 함께 적절한 HTTP 응답 헤더(예: Content-Type, Status Code)를 포함하여 웹 서버 또는 클라이언트에 응답을 전송합니다.
3. 예시 소프트웨어
WAS는 다양한 프로그래밍 언어와 프레임워크 생태계에서 구현됩니다.
- Java 기반:
- Apache Tomcat: 경량형 오픈소스 서블릿 컨테이너로, Spring Boot와 같은 프레임워크의 내장 WAS로 많이 사용됩니다.
- JBoss (WildFly): Java EE 스펙을 완전히 구현한 엔터프라이즈급 WAS입니다.
- WebLogic (Oracle), WebSphere (IBM): 상용 엔터프라이즈 WAS로, 대규모 시스템 및 레거시 시스템에서 주로 사용됩니다.
- JavaScript 기반 (Node.js 런타임):
- Express.js: Node.js의 가장 인기 있는 웹 프레임워크로, 미들웨어 기반의 유연한 구조를 제공합니다.
- NestJS: TypeScript 기반의 Node.js 프레임워크로, Angular와 유사한 모듈/컴포넌트 기반 아키텍처를 제공하며 엔터프라이즈 애플리케이션 개발에 적합합니다.
- Python 기반:
- Django: 풀 스택(Full-stack) 웹 프레임워크로, ORM, 관리자 페이지, 인증 시스템 등 다양한 기능을 내장하고 있어 신속한 개발에 용이합니다.
- Flask: 경량 웹 마이크로프레임워크로, 최소한의 기능만을 제공하여 개발자가 유연하게 확장할 수 있습니다.
- FastAPI: 고성능 비동기 웹 프레임워크로, Python 타입 힌트를 활용하여 자동 문서화 및 데이터 유효성 검사를 지원합니다.
- PHP 기반:
- Laravel: MVC 패턴을 따르는 인기 있는 PHP 웹 프레임워크로, 개발 생산성이 높고 풍부한 기능을 제공합니다.
- Symfony: Laravel의 기반이 되는 컴포넌트 지향 프레임워크로, 유연성과 확장성이 뛰어납니다.
- Go 기반:
- Gin: Go 언어의 고성능 웹 프레임워크로, 라우팅, 미들웨어 처리 등에 최적화되어 있습니다.
- Fiber: Express.js와 유사한 API를 제공하며, Go의 fasthttp 라이브러리를 기반으로 하여 매우 빠른 성능을 자랑합니다.
4. 기술적 특징
| 언어 런타임 | WAS는 특정 프로그래밍 언어의 코드를 실행하기 위한 런타임 환경을 제공합니다.<br>- JVM (Java Virtual Machine): Java 기반 WAS (Tomcat, JBoss)는 JVM 위에서 동작하며, 플랫폼 독립성과 가비지 컬렉션, JIT 컴파일 등의 이점을 가집니다.<br>- V8 Engine (Node.js): Node.js 기반 WAS는 Google Chrome의 V8 JavaScript 엔진을 사용하여 JavaScript 코드를 실행합니다. 이벤트 루프 기반의 단일 스레드 비동기 I/O 모델이 특징입니다.<br>- CPython (Python): Python 기반 WAS는 CPython 인터프리터를 통해 Python 코드를 실행하며, GIL(Global Interpreter Lock)로 인해 멀티코어 활용에 제약이 있을 수 있습니다. |
| 스레드 모델 | WAS의 동시성 처리 모델은 언어 및 프레임워크에 따라 다릅니다.<br>- Java 기반 (Tomcat, Spring Boot): 일반적으로 요청당 스레드를 할당하는 멀티스레드 기반 모델을 사용합니다. 각 요청은 별도의 스레드에서 처리되어 블로킹 I/O 작업이 발생해도 다른 요청을 처리할 수 있습니다. 최근에는 Spring WebFlux와 같은 비동기/논블로킹 프레임워크도 등장하고 있습니다.<br>- Node.js 기반 (Express, NestJS): 이벤트 루프 기반의 단일 스레드 비동기 I/O 모델을 사용합니다. I/O 작업(DB 쿼리, 파일 시스템 접근 등)은 백그라운드에서 비동기적으로 처리되며, 메인 스레드는 블로킹 없이 논블로킹 I/O 작업의 완료를 기다립니다. --- |
웹 개발에서 동적인 컨텐츠와 복잡한 비즈니스 로직을 효율적으로 처리하기 위해, 기능적 분리 및 확장성을 고려한 아키텍처는 필수적입니다. 이 중심에 **웹 서버(Web Server)**와 **웹 애플리케이션 서버(WAS: Web Application Server)**가 있으며, 각자의 특화된 역할을 통해 시스템 전체의 성능, 안정성, 보안을 향상시킵니다. 이 두 컴포넌트의 심층적인 이해는 분산 시스템 설계와 최적화의 기반이 됩니다.
웹 서버 (Web Server)
1. 개념 (전공자 기준)
웹 서버는 애플리케이션 계층(Application Layer) 프로토콜인 HTTP(Hypertext Transfer Protocol)의 명세를 구현한 소프트웨어 에이전트입니다. 클라이언트(주로 웹 브라우저, REST 클라이언트 또는 다른 HTTP 에이전트)로부터 HTTP 요청을 수신하고, 주로 **정적 컨텐츠(Static Content)**를 제공하거나, 동적 컨텐츠 요청을 **프록시(Proxy)**하는 역할을 수행합니다.
정적 컨텐츠는 서버 사이드에서 어떠한 연산이나 데이터베이스 조회 없이 파일 시스템에서 직접 읽어와 반환 가능한 리소스를 의미하며, 이는 **멱등성(Idempotence)**을 가지는 GET 요청에 최적화될 수 있습니다. 예시로는 HTML, CSS, JavaScript 파일, 이미지(JPG, PNG, SVG), 폰트, 비디오, PDF 등의 바이너리 리소스가 있습니다.
웹 서버의 기능은 단순히 파일 서빙에 그치지 않고, 다음과 같은 핵심적인 네트워크 및 보안 인프라 기능을 수행합니다.
- 리버스 프록시(Reverse Proxy): 클라이언트와 하나 이상의 백엔드 서버(주로 WAS) 사이에 위치하여 클라이언트의 요청을 받아 WAS로 전달하고, WAS의 응답을 클라이언트에 전달합니다. 이를 통해 백엔드 서버의 IP 주소 및 내부 구조를 숨기고, 보안을 강화하며, 트래픽을 효율적으로 분산할 수 있습니다.
- 로드 밸런서(Load Balancer): 여러 WAS 인스턴스에 대한 요청을 분산하여 특정 서버에 부하가 집중되는 것을 방지하고, 시스템의 가용성과 확장성을 높입니다. Round Robin, Least Connections, IP Hash 등 다양한 로드 밸런싱 알고리즘을 지원합니다.
- TLS/SSL 종단점(Termination Proxy): HTTPS 통신에서 발생하는 TLS/SSL 암복호화 연산을 웹 서버에서 처리하여, 백엔드 WAS의 CPU 부하를 줄이는 SSL Offloading 기능을 제공합니다. 이는 성능 최적화 및 보안 정책 중앙화에 기여합니다.
- 캐싱 프록시(Caching Proxy): 자주 요청되는 정적 또는 캐시 가능한 동적 리소스를 메모리나 디스크에 저장하여, 동일한 요청이 다시 들어왔을 때 WAS를 거치지 않고 웹 서버가 직접 응답하게 함으로써 응답 시간을 단축하고 백엔드 부하를 줄입니다. HTTP Cache-Control 헤더를 준수합니다.
- 접근 제어 및 보안: IP 주소 기반 접근 제어, 기본 인증(Basic Authentication), rate limiting(API 호출 속도 제한) 등을 통해 악의적인 요청이나 과도한 트래픽으로부터 시스템을 보호합니다.
- URL Rewriting: 요청된 URL을 내부적으로 다른 URL로 변환하여 리소스의 실제 위치를 숨기거나, SEO(Search Engine Optimization) 친화적인 URL을 제공하는 데 사용됩니다.
2. 동작 구조 (네트워크 및 OS 관점)
웹 서버의 동작 구조는 주로 높은 동시성과 효율적인 I/O 처리에 초점을 맞춥니다.
- 리스닝 소켓(Listening Socket) 및 바인딩: 웹 서버는 초기화 시 특정 IP 주소와 포트(예: IPv4 0.0.0.0:80, IPv6 [::]:443)에 대한 리스닝 소켓을 생성하고 운영체제에 바인딩합니다. 이는 클라이언트 연결 요청을 대기하는 진입점 역할을 합니다.
- 연결 수립 (TCP 3-Way Handshake): 클라이언트가 웹 서버의 포트로 TCP SYN 패킷을 전송하여 연결을 요청하면, 웹 서버는 SYN-ACK로 응답하고, 클라이언트는 ACK로 최종 응답하여 TCP 연결이 수립됩니다. HTTPS의 경우, TCP 연결 수립 후 TLS 핸드쉐이크 과정을 거쳐 암호화된 통신 채널이 생성됩니다.
- 이벤트 처리 및 요청 수신: 웹 서버는 수립된 연결로부터 클라이언트의 HTTP 요청 스트림을 비동기적으로 읽어들입니다.
- 비동기 논블로킹 I/O 모델 (Nginx, Caddy): epoll (Linux), kqueue (FreeBSD/macOS), IOCP (Windows)와 같은 OS 커널 레벨의 비동기 I/O 이벤트 처리 메커니즘을 사용합니다. 웹 서버의 워커 프로세스는 단일 스레드 내에서 다수의 연결을 동시에 관리하며, I/O 작업(소켓 읽기/쓰기, 파일 읽기)이 완료되기를 기다리는 동안 다른 연결의 이벤트를 처리하여 높은 동시성을 달성합니다.
- 멀티프로세스/멀티스레드 블로킹 I/O 모델 (Apache Prefork/Worker MPM): 전통적인 Apache HTTP Server는 각 클라이언트 요청에 대해 별도의 프로세스(prefork MPM) 또는 스레드(worker MPM)를 할당합니다. 이 모델에서는 I/O 작업이 블로킹 방식으로 이루어져 해당 프로세스/스레드가 I/O 완료를 기다리는 동안 다른 요청을 처리할 수 없습니다. 그러나 event MPM은 Keep-Alive 연결을 위한 스레드를 분리하여 일부 비동기성을 도입했습니다.
- HTTP 요청 파싱 및 자원 매핑: 수신된 바이트 스트림을 HTTP 메시지로 파싱하여 요청 라인(메서드, URI, 프로토콜 버전), 헤더 필드, 메시지 바디를 추출합니다. 파싱된 URI를 기반으로 다음과 같이 자원을 매핑합니다.
- 정적 파일 시스템 매핑: Document Root (웹 서버의 최상위 디렉터리) 기준으로 요청된 URI에 해당하는 파일을 로컬 파일 시스템에서 찾아 mmap() (메모리 맵 파일) 또는 sendfile() (Zero-copy I/O)과 같은 시스템 호출을 통해 효율적으로 읽어들입니다.
- 리버스 프록시 규칙 매핑: URI 패턴(예: /api/*)이 프록시 규칙과 일치하면, 내부적으로 WAS로 요청을 전달하기 위해 새로운 HTTP 요청을 생성하고, WAS와의 TCP 연결을 수립합니다. 이 과정에서 X-Forwarded-For, X-Forwarded-Proto, X-Forwarded-Host 등의 헤더를 추가하여 원본 요청 정보를 전달합니다.
- HTTP 응답 생성 및 전송:
- 정적 응답: 찾은 파일의 MIME Type(예: Content-Type: text/html), Content-Length, Last-Modified, ETag, Cache-Control 등 적절한 응답 헤더와 함께 파일 데이터를 TCP 소켓을 통해 클라이언트에 전송합니다.
- 프록시 응답: WAS로부터 전달받은 HTTP 응답(상태 코드, 헤더, 바디)을 클라이언트에 그대로 전달하거나, 웹 서버 설정에 따라 추가적인 헤더 조작, 응답 압축(Gzip/Brotli 인코딩), 캐싱 등을 수행한 후 전송합니다.
- 연결 관리: Connection 헤더(예: Keep-Alive, close)에 따라 TCP 연결을 유지하거나 종료합니다. Keep-Alive는 여러 요청-응답 쌍을 단일 TCP 연결을 통해 처리하여 연결 수립 및 해제 오버헤드를 줄입니다.
3. 예시 소프트웨어 (아키텍처 및 구현 특징)
- Nginx (엔진엑스):
- 설계 철학: 경량성, 고성능, 높은 동시성에 중점을 둔 이벤트 기반(event-driven) 아키텍처.
- 구현: C 언어로 작성되었으며, OS의 비동기 I/O 이벤트 처리 메커니즘(epoll, kqueue)을 적극 활용합니다. 마스터 프로세스(Master Process)가 워커 프로세스(Worker Processes)를 관리하고, 각 워커 프로세스는 단일 스레드 내에서 수천 개의 동시 연결을 논블로킹 방식으로 처리합니다.
- 특징: 정적 파일 서빙 성능이 매우 뛰어나며, 리버스 프록시, 로드 밸런서, HTTP 캐시 서버로서의 기능이 강력하여 현대 웹 아키텍처의 게이트웨이 역할을 주로 담당합니다.
- Apache HTTP Server (httpd):
- 설계 철학: 모듈성, 확장성, 유연성에 중점을 둔 프로세스/스레드 기반 아키텍처 (MPM).
- 구현: C 언어로 작성되었으며, MPM(Multi-Processing Modules)을 통해 다양한 동시성 모델을 지원합니다.
- prefork MPM: 각 요청에 대해 별도의 프로세스를 생성하며, 안정적이지만 메모리 사용량이 많습니다.
- worker MPM: 멀티스레드 기반으로, 각 요청을 스레드로 처리하여 prefork보다 메모리 효율적입니다.
- event MPM: Keep-Alive 연결을 위한 스레드를 분리하여 일부 논블로킹 I/O를 지원하며, 더 높은 동시성을 제공합니다.
- 특징: 다양한 플랫폼과 운영체제에서 광범위하게 사용되며, mod_php, mod_python 등 언어 인터프리터 모듈을 직접 로드하여 동적 컨텐츠를 자체적으로 처리할 수 있는 유연성을 제공합니다.
- Caddy:
- 설계 철학: 단순성, 자동화된 HTTPS, 현대적인 웹 기능 통합.
- 구현: Go 언어로 작성되었으며, Go의 동시성 모델(Goroutines, Channels)과 표준 라이브러리를 활용하여 효율적인 비동기 처리를 수행합니다.
- 특징: Let's Encrypt를 통한 자동 HTTPS 인증서 발급 및 갱신 기능을 내장하여 개발자의 설정 부담을 크게 줄였습니다. Nginx와 유사하게 리버스 프록시, 로드 밸런싱, 정적 파일 서빙 등을 지원하며 설정 파일이 직관적입니다.
4. 기술적 특징 (심층 분석)
| I/O 모델 | - Nginx (Event-Driven, Asynchronous Non-blocking I/O): 운영체제의 epoll (Linux), kqueue (FreeBSD/macOS), IOCP (Windows)와 같은 커널 레벨 비동기 이벤트 통지 메커니즘을 활용합니다. 단일 스레드 또는 소수의 워커 스레드가 수많은 소켓 디스크립터(File Descriptor)를 select(), poll(), epoll_wait() 등으로 모니터링하며, I/O 작업이 준비될 때마다 콜백 함수를 실행하는 방식으로 동작합니다. 이는 C10K 문제(하나의 서버에서 10,000개 이상의 동시 연결 처리) 해결의 핵심입니다.<br>- Apache HTTP Server (MPM 기반):<br> - prefork MPM: 각 클라이언트 연결에 대해 새로운 프로세스를 포크(fork)합니다. 프로세스 간 격리가 강하지만, 프로세스 생성/관리 오버헤드가 크고 메모리 사용량이 많습니다.<br> - worker MPM: 각 클라이언트 연결에 대해 스레드를 사용합니다. 프로세스 내 스레드 풀을 관리하여 prefork보다 효율적이지만, 스레드 간 컨텍스트 스위칭 오버헤드와 공유 자원 접근에 대한 동기화 문제가 발생할 수 있습니다.<br> - event MPM: Keep-Alive 연결 처리를 위한 별도의 스레드를 사용하여 블로킹 I/O의 한계를 일부 극복합니다. |
| DB 연동 | - ORM (Object-Relational Mapping): Java의 JPA(Hibernate), Python의 Django ORM, Node.js의 TypeORM/Sequelize 등 ORM 프레임워크를 통해 객체 지향적으로 데이터베이스를 조작합니다. 이는 SQL 쿼리를 직접 작성하는 부담을 줄이고 개발 생산성을 높입니다.<br>- Connection Pool: 데이터베이스 연결을 미리 생성하여 풀(pool)에 저장해두고, 필요할 때 재사용함으로써 연결 생성 및 해제에 따른 오버헤드를 줄여 WAS의 성능을 향상시킵니다.<br>- 트랜잭션 관리: 데이터베이스 작업의 원자성(Atomicity), 일관성(Consistency), 고립성(Isolation), 지속성(Durability)을 보장하기 위한 트랜잭션 경계를 설정하고 관리합니다. |
| 데이터베이스 연동 | WAS는 데이터베이스와의 효율적인 상호작작용을 위해 다양한 기술 스택을 활용합니다.<br>- ORM (Object-Relational Mapping): Java의 JPA(Hibernate), Python의 Django ORM, Node.js의 TypeORM/Sequelize 등 ORM 프레임워크는 객체 지향적인 방식으로 관계형 데이터베이스를 조작할 수 있게 하여 개발 생산성을 높이고 SQL 종속성을 줄입니다.<br>- Connection Pool: 데이터베이스 연결을 미리 생성하여 풀(pool)에 보관하고, 필요할 때 재사용함으로써 연결 생성 및 해제에 따른 오버헤드를 최소화하고 데이터베이스 부하를 줄여 WAS의 처리량을 향상시킵니다.<br>- 트랜잭션 관리: ACID(Atomicity, Consistency, Isolation, Durability) 특성을 보장하는 데이터베이스 트랜잭션 경계를 설정하고 관리합니다. 이는 여러 데이터베이스 연산이 하나의 논리적 단위로 성공 또는 실패하도록 하여 데이터의 무결성을 유지합니다. |
| 아키텍처 | WAS는 주로 MVC (Model-View-Controller) 또는 헥사고날 아키텍처(Hexagonal Architecture/Ports and Adapters)와 같은 계층적 아키텍처 패턴을 따릅니다. 이는 관심사의 분리(Separation of Concerns)를 통해 코드의 응집도(Cohesion)를 높이고 결합도(Coupling)를 낮춰, 유지보수성과 테스트 용이성을 향상시킵니다.<br>- MVC: Model(데이터 및 비즈니스 로직), View(사용자 인터페이스), Controller(요청 처리 및 Model-View 상호작용)로 구성됩니다.<br>- Hexagonal Architecture: 핵심 비즈니스 로직(Domain Layer)을 외부 시스템(데이터베이스, UI 등)으로부터 격리시키고, Port와 Adapter를 통해 외부와 상호작용합니다. |
웹 서버 vs. WAS: 기술적 차이 요약
| 주 역할 | 정적 자원 처리, 요청 라우팅, 리버스 프록시, 로드 밸런싱. | 동적 로직 실행, 데이터 처리, 비즈니스 로직 구현, 웹 애플리케이션 런타임 환경 제공. |
| 처리 리소스 | HTML/CSS/JS, 이미지, 폰트, 동영상 등 파일 시스템 기반의 정적 자원. | DB 쿼리 결과, 세션 처리, 사용자별 맞춤 데이터, 서버 사이드 렌더링 결과 등 동적 생성 데이터. |
| 응답 생성 방식 | 파일 시스템에서 직접 읽어오거나 캐시된 데이터를 기반으로 응답. | 비즈니스 로직을 실행하여 데이터베이스, 외부 시스템 등과 연동 후 동적으로 응답 생성. |
| 성능 특징 | I/O 중심, 비동기 논블로킹 I/O로 고성능 및 높은 동시성 처리. 캐싱 용이. | CPU/메모리 소비가 상대적으로 높음 (비즈니스 로직 연산, DB 연동). |
| 확장성 | 수평 확장이 용이하며, 로드 밸런싱 및 리버스 프록시를 통해 여러 WAS 인스턴스 앞에 배치됨. | 수평 확장 필요 (마이크로서비스, 클러스터링)하며, 주로 웹 서버 뒤에 배치되어 병렬 처리. |
| 기술 예시 | Nginx, Apache HTTP Server, Caddy, Lighttpd, IIS. | Apache Tomcat, JBoss, Spring Boot, Node.js + Express, Django, Flask, Laravel, Gin. |
실제 시스템 아키텍처에서의 협업 구조 (Three-Tier & MSA)
현대 웹 서비스 아키텍처는 대부분 웹 서버와 WAS를 분리하여 운용하며, 이는 Three-Tier Architecture의 핵심적인 패턴이자 **클라우드 마이크로서비스 아키텍처(MSA)**에서도 동일하게 적용됩니다.
[ Client (Web Browser, Mobile App) ]
↓ (HTTP/HTTPS Request)
[ Web Server (Nginx, Apache HTTP Server) ]
├─── 정적 자원 처리 ──────────────→ [ 파일 시스템, CDN ]
│ (Static Content)
│ (Dynamic Request Proxy: /api/*, /login)
└─── 리버스 프록시 & 로드 밸런싱 ─→ [ WAS Cluster / Instances ]
(Spring Boot, Node.js, Django)
↓ (DB Connection, API Call)
[ Data Layer ]
(DB, Cache, Message Queue, External Services)
- 클라이언트(Client): 웹 브라우저나 모바일 앱과 같은 HTTP 클라이언트가 사용자 요청을 시작합니다.
- 웹 서버(Web Server - Gateway / Edge Layer):
- 시스템의 **최전선(Edge Layer)**에 위치하여 클라이언트의 모든 요청을 가장 먼저 받습니다.
- 정적 요청(Static Content): /css/style.css, /images/logo.png 등 정적 리소스에 대한 요청은 웹 서버가 자체적으로 캐싱된 데이터나 파일 시스템에서 직접 찾아 고성능으로 제공합니다. 이는 WAS의 부하를 줄이고, 응답 시간을 단축합니다.
- 동적 요청(Dynamic Content): /api/users, /login 등 서버 사이드 로직 처리가 필요한 동적 요청은 리버스 프록시 설정에 따라 WAS 클러스터 또는 특정 WAS 인스턴스로 요청을 포워딩합니다. 이 과정에서 로드 밸런싱을 통해 트래픽을 효율적으로 분산하고, TLS Offloading을 통해 암호화 부담을 줄입니다.
- WAS (Web Application Server - Application Layer):
- 웹 서버로부터 전달받은 동적 요청을 처리하는 **비즈니스 로직 계층(Business Logic Layer)**입니다.
- 요청된 URL에 해당하는 비즈니스 로직을 실행하고, 필요에 따라 **데이터 계층(Data Layer)**과 상호작용합니다 (데이터베이스 조회/저장, 캐시 접근, 메시지 발행 등).
- 처리 결과를 기반으로 동적인 컨텐츠(JSON, XML, 동적 HTML)를 생성하여 웹 서버로 다시 응답을 보냅니다.
- 데이터 계층 (Data Layer):
- WAS에 의해 접근되는 데이터 저장소 및 외부 서비스입니다.
- 데이터베이스 (DB): 관계형 데이터베이스(MySQL, PostgreSQL, Oracle), NoSQL 데이터베이스(MongoDB, Cassandra, Redis) 등이 포함됩니다.
- 캐시 (Cache): Redis, Memcached와 같이 WAS가 자주 사용하는 데이터를 빠르게 접근하기 위한 인메모리 캐시 시스템입니다.
- 메시지 큐 (MQ): Kafka, RabbitMQ와 같이 비동기 통신 및 이벤트 기반 아키텍처를 위한 메시지 브로커입니다.
- 외부 서비스 / 마이크로서비스: WAS가 내부적으로 호출하는 다른 API 서비스 또는 마이크로서비스들이 이 계층에 포함될 수 있습니다.
결론: 협업과 분리의 중요성
웹 서버와 WAS를 분리하는 아키텍처는 여러 가지 기술적 이점을 제공하며, 이는 현대의 대규모 분산 시스템 및 클라우드 환경에서 표준적인 접근 방식입니다.
- 역할 분리 및 전문화:
- 웹 서버: I/O 집약적이며, 고성능의 정적 파일 서빙, 네트워크 트래픽 관리(프록시, 로드 밸런싱)에 특화됩니다.
- WAS: CPU 및 메모리 집약적이며, 복잡한 비즈니스 로직 연산, 데이터베이스 연동, 동적 컨텐츠 생성에 특화됩니다.
- 각 컴포넌트가 자신의 핵심 역할에 집중함으로써, 시스템 전체의 효율성을 극대화할 수 있습니다.
- 성능 최적화:
- 정적 컨텐츠를 웹 서버에서 직접 처리하여 WAS의 불필요한 부하를 줄입니다. 이는 WAS가 오직 비즈니스 로직 처리에만 집중할 수 있게 하여 처리량을 높입니다.
- 웹 서버의 캐싱 기능을 통해 반복되는 정적 요청에 대한 응답 시간을 단축하고, 백엔드 트래픽을 감소시킵니다.
- 확장성 (Scalability):
- 수평 확장이 용이합니다. 웹 서버는 트래픽 증가 시 로드 밸런서로서 WAS 인스턴스를 동적으로 추가하여 트래픽을 분산할 수 있습니다.
- 각 계층(웹 서버, WAS, DB)을 독립적으로 확장할 수 있어, 특정 계층의 병목 현상이 발생했을 때 해당 계층만 증설하여 전체 시스템의 가용성과 성능을 유지할 수 있습니다.
- 보안 강화:
- 웹 서버가 외부 네트워크로부터 WAS를 보호하는 방화벽(Firewall) 역할을 수행합니다. WAS의 직접적인 노출을 막고, DDoS 공격 방어, SSL/TLS 처리, 접근 제어 등 웹 서버의 보안 기능을 활용할 수 있습니다.
- 웹 서버의 TLS Offloading은 민감한 SSL 키 관리를 웹 서버에서 중앙 집중화할 수 있게 합니다.
- 고가용성 (High Availability) 및 장애 격리:
- 웹 서버가 여러 WAS 인스턴스에 대한 로드 밸런싱을 수행하므로, 특정 WAS 인스턴스에 장애가 발생하더라도 웹 서버는 해당 인스턴스를 트래픽 분배에서 제외하고 다른 정상적인 WAS로 요청을 전달하여 서비스 중단을 최소화합니다.
- 각 계층의 장애가 다른 계층으로 전파되는 것을 완화하여 전체 시스템의 안정성을 높입니다.
이러한 분리 원칙은 Three-Tier Architecture에서 Presentation Layer (웹 서버), Application Layer (WAS), Data Layer (DB)로 명확히 나뉘어 적용되며, 이는 **마이크로서비스 아키텍처(MSA)**에서 각 마이크로서비스가 독립적인 WAS 역할을 하고 그 앞에 API Gateway (웹 서버의 확장된 형태)가 위치하는 형태로 발전합니다. 결과적으로 웹 서버와 WAS의 협업은 고성능, 고확장성, 고가용성을 지닌 현대 웹 서비스 시스템을 구축하는 데 필수적인 전략입니다.
'코드의 해부학' 카테고리의 다른 글
| React 라이프사이클 : React는 어떻게 컴포넌트를 살리고 죽이는가? (2) | 2025.06.07 |
|---|---|
| Jenkins: 개발자에게 자유를! 자동화가 선사하는 여유로운 삶. (4) | 2025.06.05 |
| Monitoring & Logging : 시스템은 거짓말하지 않는다 (2) | 2025.06.04 |
| MSA(마이크로서비스 아키텍처) : 개발팀의 꿈인가? 아니면 PM의 악몽인가? (0) | 2025.06.04 |
| IaC(Infrastructure as Code) : 코드로 빚어내는 '운영의 연금술' (0) | 2025.06.04 |