웹서버·WAS·DB 서버를 분리하는 이유 – 면접 대비·아키텍처 정리


웹서버 – WAS – DB 분리는 백엔드 개발자·인프라 엔지니어 면접에서 빠지지 않는 단골 질문입니다. “왜 하나의 서버에 다 올리면 안 되나요?”, “웹서버와 WAS의 차이가 뭔가요?”, “Nginx는 왜 Tomcat 앞에 두는 건가요?” — 이 질문들은 서버 아키텍처 설계의 기본 철학을 이해하는지 측정하는 지표입니다. 단순히 “역할이 달라서”라는 한 줄 답변으로는 시니어 개발자 평가를 통과할 수 없습니다. 정적·동적 콘텐츠의 처리 방식 차이, 보안 계층화, 독립적 확장성, 장애 격리까지 각 계층을 분리하는 이유는 하나의 거대한 설계 원칙에서 출발합니다. 이 글에서는 분리의 이유를 구조적으로 해부하고 실무 설계까지 연결합니다.


목차

  1. 기초 개념 – 웹서버·WAS·DB 각각의 역할과 차이
  2. 단일 서버 구성의 문제점 – 왜 하나에 다 올리면 안 되는가
  3. 분리 이유 ① 역할 분담과 처리 효율 최적화
  4. 분리 이유 ② 보안 계층화와 공격 표면 최소화
  5. 분리 이유 ③ 독립적 확장과 장애 격리
  6. 실전 아키텍처 – Nginx·Tomcat·DB 실제 구성법

1. 기초 개념 – 웹서버·WAS·DB 각각의 역할과 차이

웹서버 – WAS – DB 분리의 이유를 이해하려면 먼저 각 컴포넌트가 무엇을 하는지 정확히 알아야 합니다. 역할이 다르기 때문에 분리하는 것이기 때문입니다.

웹서버(Web Server) – 정적 콘텐츠 전문가

웹서버는 클라이언트(브라우저)의 HTTP 요청을 받아 정적 콘텐츠를 응답하는 서버입니다. 정적 콘텐츠란 서버에 파일 형태로 저장되어 있고, 요청마다 동일한 내용을 반환하는 리소스입니다.

정적 콘텐츠 예시:
- HTML 파일       → index.html
- CSS 스타일시트  → style.css
- JavaScript 파일 → app.js
- 이미지           → logo.png, banner.jpg
- 폰트 파일        → font.woff2
- 동영상·PDF       → video.mp4, manual.pdf

대표적인 웹서버는 Nginx와 Apache HTTP Server입니다. 이들은 정적 파일 응답에 최적화된 구조를 가지며, 수만 개의 동시 연결을 적은 메모리로 처리할 수 있습니다. Nginx는 이벤트 기반 비동기 모델을 사용해 동시 접속이 많아도 메모리 사용량이 거의 늘어나지 않습니다.

웹서버는 동적 콘텐츠를 직접 생성하지 못합니다. 로그인한 사용자에게 맞춤화된 페이지를 만들거나, 데이터베이스에서 데이터를 조회해 HTML을 구성하는 작업은 웹서버의 영역이 아닙니다.

WAS(Web Application Server) – 동적 콘텐츠 생성 엔진

WAS는 비즈니스 로직을 실행하고 동적 콘텐츠를 생성하는 애플리케이션 실행 환경입니다. 동적 콘텐츠란 요청하는 사람·시간·상황에 따라 내용이 달라지는 응답입니다.

동적 콘텐츠 예시:
- 로그인 후 개인화된 메인 페이지
- 실시간 검색 결과
- 장바구니 상품 목록
- 주문 내역 조회
- 결제 처리
- 추천 알고리즘 실행 결과

대표적인 WAS는 Apache TomcatJBoss/WildFlyWebLogicWebSphere이며, Java 기반 애플리케이션에서는 Tomcat이 가장 널리 사용됩니다. Node.js·Python(Django/Flask)·Ruby on Rails 환경에서는 해당 언어의 애플리케이션 서버가 WAS 역할을 수행합니다.

WAS는 DB에서 데이터를 조회하고, 비즈니스 규칙을 적용하고, 결과를 JSON 또는 HTML로 변환해 응답합니다. 이 과정은 CPU와 메모리를 많이 소비하며, 처리 시간도 정적 콘텐츠 응답보다 훨씬 깁니다.

DB 서버(Database Server) – 데이터 영속성 담당

DB 서버는 애플리케이션의 데이터를 저장·조회·수정·삭제하는 전용 서버입니다.

DB 서버 역할:
- 데이터 영속성 보장 (Persistence)
- 트랜잭션 처리 (ACID 보장)
- 동시성 제어 (여러 요청의 데이터 무결성 유지)
- 인덱스·쿼리 최적화
- 백업·복구

대표적인 RDBMS는 MySQL, PostgreSQL, Oracle이며, NoSQL로는 MongoDB, Redis, Cassandra가 있습니다. DB 서버는 디스크 I/O와 메모리가 핵심 자원이며, 구성 특성이 웹서버·WAS와 완전히 다릅니다.

세 컴포넌트의 핵심 차이 한눈에 비교

구분웹서버WASDB 서버
주요 역할정적 콘텐츠 응답동적 콘텐츠 생성데이터 저장·조회
처리 방식파일 읽기·HTTP 응답비즈니스 로직 실행쿼리 실행·트랜잭션
병목 자원네트워크·I/OCPU·메모리디스크 I/O·메모리
대표 소프트웨어Nginx, ApacheTomcat, Node.jsMySQL, PostgreSQL
확장 방법수평 확장 용이수평 확장 용이수직 확장·샤딩

2. 단일 서버 구성의 문제점 – 왜 하나에 다 올리면 안 되는가

분리의 이유를 이해하는 가장 빠른 방법은 분리하지 않았을 때 무슨 일이 벌어지는지를 보는 것입니다.

단일 서버 구성의 현실

[클라이언트]
     ↓ HTTP 요청
[단일 서버]
  ├── 웹서버 (Nginx/Apache)
  ├── WAS (Tomcat/Node.js)
  └── DB (MySQL)
     ↓
[클라이언트에게 응답]

소규모 프로젝트나 개발 환경에서는 이 구성도 충분합니다. 문제는 트래픽이 늘고 서비스가 커질 때 나타납니다.

문제 ① 자원 경합(Resource Contention)

웹서버·WAS·DB는 각각 다른 자원을 집중적으로 사용합니다. 하나의 서버에 모두 올리면 자원을 서로 빼앗습니다.

예시 시나리오:
- DB가 대용량 쿼리 실행 → CPU·메모리 집중 사용
- 동시에 WAS가 비즈니스 로직 실행 → CPU 부족
- 웹서버의 네트워크 I/O도 처리해야 함

결과: 모든 응답이 느려짐 (DB 때문에 정적 파일 하나 받는 것도 느려짐)

각 컴포넌트는 서로 다른 최적화가 필요한데, 한 서버에서는 그 어느 것도 최적화할 수 없습니다.

문제 ② 확장의 불가능

트래픽이 늘어날 때 서버를 추가(Scale Out)하려 하면, 웹서버·WAS·DB가 모두 묶여 있어 필요한 부분만 선택적으로 늘릴 수 없습니다. WAS만 부하가 걸려도 DB까지 함께 복제해야 합니다. DB를 여러 개 복제하면 데이터 일관성 문제가 생깁니다.

단일 서버 확장의 딜레마:
WAS 부하 증가 → 서버 추가 → DB도 같이 복제 → 데이터 불일치 위험
                              ↗ 아니면 수직 확장(더 좋은 서버로 교체)
                                → 비용 급증, 한계 존재

문제 ③ 보안 취약점 전파

단일 서버에서 웹서버 취약점이 공격당하면, 같은 서버에 있는 DB에 직접 접근할 수 있게 됩니다. 외부 요청을 처리하는 웹서버와 민감한 데이터가 담긴 DB가 같은 물리적 공간에 있다는 것 자체가 치명적인 보안 위험입니다.

문제 ④ 장애 전파(Cascading Failure)

WAS에서 메모리 누수가 발생해 서버가 다운되면, 웹서버와 DB까지 모두 같이 죽습니다. 하나의 컴포넌트 장애가 전체 서비스 장애로 직결됩니다.


3. 분리 이유 ① 역할 분담과 처리 효율 최적화

웹서버 WAS DB 분리의 첫 번째이자 가장 근본적인 이유는 각 컴포넌트를 그것이 잘하는 일에만 집중시키는 것입니다.

정적·동적 콘텐츠의 처리 경로 분리

웹서버와 WAS를 분리하면, 요청 유형에 따라 처리 경로가 달라집니다.

[클라이언트 요청]
       ↓
[웹서버 (Nginx)]
       ├── 정적 요청 (CSS/JS/이미지)
       │         ↓
       │   디스크에서 파일 읽어 즉시 응답 (WAS 거치지 않음)
       │
       └── 동적 요청 (API/JSP)
                 ↓
          [WAS (Tomcat)]
                 ↓
           비즈니스 로직 실행
                 ↓
            [DB 서버]
                 ↓
           데이터 조회·저장

정적 파일 요청이 WAS를 거치지 않는 것이 핵심입니다. Nginx는 정적 파일을 CPU 연산 없이 파일 시스템에서 직접 읽어 응답하므로, 수만 건의 정적 요청을 WAS 부하 없이 처리합니다. WAS는 진짜 비즈니스 로직이 필요한 요청에만 집중할 수 있습니다.

리버스 프록시로서의 웹서버

웹서버는 단순히 정적 파일을 제공하는 것 외에 리버스 프록시(Reverse Proxy) 역할을 수행합니다.

nginx

# Nginx 리버스 프록시 설정 예시
server {
    listen 80;
    server_name example.com;

    # 정적 파일은 Nginx가 직접 처리
    location /static/ {
        root /var/www/html;
        expires 30d;              # 브라우저 캐시 설정
        add_header Cache-Control "public";
    }

    # 동적 요청은 WAS로 전달
    location /api/ {
        proxy_pass http://tomcat_server:8080;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }

    # JSP 요청도 WAS로
    location ~ \.jsp$ {
        proxy_pass http://tomcat_server:8080;
    }
}

이 구성에서 클라이언트는 항상 Nginx(80번 포트)와만 통신합니다. Tomcat의 존재와 포트(8080)는 클라이언트에게 완전히 숨겨집니다.

SSL/TLS 처리 집중화

HTTPS 암호화·복호화(SSL Termination)는 CPU를 소모하는 작업입니다. 이를 웹서버에서 한 번만 처리하면, 웹서버와 WAS 사이는 HTTP(평문)로 통신해 WAS의 CPU 부담을 줄일 수 있습니다.

외부: HTTPS (암호화) → [웹서버: SSL 복호화] → 내부: HTTP (평문) → [WAS]

4. 분리 이유 ② 보안 계층화와 공격 표면 최소화

웹서버 WAS DB 분리의 두 번째 핵심 이유는 보안입니다. 계층을 분리하면 각 계층이 방어선 역할을 하며, 한 계층이 뚫려도 다음 계층이 보호합니다.

DMZ(비무장지대) 구조 실현

보안 관점에서 이상적인 서버 구성은 군사적 개념인 DMZ를 차용합니다.

[인터넷 (신뢰 불가 영역)]
           ↓
    [방화벽 1 (외부)]
           ↓
[DMZ 영역 - 웹서버 위치]
    (80, 443 포트만 오픈)
           ↓
    [방화벽 2 (내부)]
           ↓
[내부망 - WAS 위치]
    (특정 포트만 웹서버→WAS 허용)
           ↓
    [방화벽 3 또는 보안 그룹]
           ↓
[DB 영역 - DB 서버 위치]
    (WAS→DB 포트만 허용, 외부 접근 불가)

이 구조에서 DB 서버는 외부 인터넷과 직접 연결되는 경로가 전혀 없습니다. 해커가 웹서버를 뚫어도 방화벽 2가 WAS로의 진입을 막고, WAS를 뚫어도 방화벽 3이 DB를 보호합니다.

각 서버의 최소 권한 원칙

분리된 구성에서는 각 서버에 필요한 최소한의 권한만 부여할 수 있습니다.

웹서버: 정적 파일 읽기 권한만 (DB 접근 정보 없음)
WAS:   DB 접근 정보 있음, 하지만 외부 직접 접근 불가
DB:    WAS에서 오는 특정 포트·IP만 허용

단일 서버에서는 웹서버 코드도 DB 접속 정보(비밀번호)를 알게 됩니다. 분리하면 웹서버는 DB 접속 정보 자체를 가지지 않습니다.

공격 표면(Attack Surface) 최소화

단일 서버 공격 표면:
- 웹서버 취약점 → DB까지 도달 가능
- WAS 취약점 → DB까지 도달 가능
- DB 취약점 → 직접 인터넷 노출

분리된 구성의 공격 표면:
- 웹서버 공격 → WAS까지 도달 불가 (방화벽)
- WAS 공격 → DB까지 도달하기 위해 추가 방화벽 우회 필요
- DB → 인터넷과 직접 연결 없음

5. 분리 이유 ③ 독립적 확장과 장애 격리

웹서버 WAS DB 분리의 세 번째 이유는 각 계층을 독립적으로 확장하고 장애를 격리할 수 있다는 것입니다.

병목 지점별 선택적 확장(Scale Out)

상황별 독립 확장 예시:

[상황 1] 정적 파일 요청 폭증
→ 웹서버만 추가 (WAS·DB 불변)
  [웹서버1] [웹서버2] [웹서버3]
            ↓
          [WAS]
            ↓
           [DB]

[상황 2] 비즈니스 로직 처리 부하 증가
→ WAS만 추가 (웹서버·DB 불변)
  [웹서버] + [로드밸런서]
      ↓
[WAS1] [WAS2] [WAS3]
      ↓
     [DB]

[상황 3] DB 읽기 부하 증가
→ DB Read Replica 추가 (웹서버·WAS 불변)
  [WAS]
    ↓
[DB Primary(쓰기)] + [DB Replica1(읽기)] [DB Replica2(읽기)]

단일 서버에서는 불가능한 이 선택적 확장이, 분리를 통해 비용 효율적으로 가능해집니다.

로드 밸런서를 통한 WAS 다중화

nginx

# Nginx upstream으로 WAS 로드밸런싱
upstream was_cluster {
    least_conn;                           # 최소 연결 수 기반 분배
    server was1.internal:8080 weight=3;   # WAS 서버 1 (가중치 3)
    server was2.internal:8080 weight=3;   # WAS 서버 2 (가중치 3)
    server was3.internal:8080 weight=1;   # WAS 서버 3 (가중치 1)
    keepalive 32;                         # 연결 재사용
}

server {
    location /api/ {
        proxy_pass http://was_cluster;
        proxy_next_upstream error timeout; # 장애 시 다음 서버로
    }
}

이 구성에서 WAS 서버 하나가 다운돼도, Nginx가 자동으로 다른 WAS로 요청을 전달합니다.

장애 격리(Fault Isolation)

분리된 구성에서는 장애가 계층을 넘어 전파되지 않습니다.

[장애 격리 시나리오]

WAS 한 대가 메모리 누수로 다운:
→ 웹서버는 정상 작동 (정적 파일 계속 서비스)
→ 로드밸런서가 다운된 WAS를 제외하고 다른 WAS로 분배
→ DB는 영향 없음

DB 슬로우 쿼리 발생:
→ WAS는 DB 응답을 기다리며 스레드 사용 증가
→ 웹서버는 여전히 정적 파일 즉시 응답
→ DB 슬로우 쿼리가 웹서버 장애로 이어지지 않음

단일 서버에서의 동일 상황:
→ DB 슬로우 쿼리 → 전체 서버 응답 지연 → 전체 서비스 중단

6. 실전 아키텍처 – Nginx·Tomcat·DB 실제 구성법

이론을 실제 구성으로 연결합니다. 프로덕션 환경에서 널리 사용되는 Nginx + Tomcat + MySQL 3계층 구성의 핵심을 정리합니다.

전체 요청 흐름

[클라이언트 (브라우저/모바일)]
        ↓ HTTPS (443)
[Nginx 웹서버]
  ├─ /static/* → 파일 시스템에서 직접 응답
  ├─ /api/*    → Tomcat으로 프록시
  └─ SSL Termination (HTTPS→HTTP 변환)
        ↓ HTTP (8080)
[Apache Tomcat WAS]
  ├─ Spring Boot 애플리케이션 실행
  ├─ 비즈니스 로직 처리
  └─ DB 커넥션 풀로 쿼리 요청
        ↓ JDBC (3306)
[MySQL DB 서버]
  ├─ Primary (읽기+쓰기)
  └─ Replica (읽기 전용)

DB 커넥션 풀 – WAS와 DB 사이의 핵심

WAS와 DB 사이에는 **커넥션 풀(Connection Pool)**이 필수입니다. DB 연결을 매 요청마다 새로 맺으면 오버헤드가 크기 때문에, 미리 연결을 맺어두고 재사용합니다.

java

// Spring Boot application.properties DB 커넥션 풀 설정
spring.datasource.url=jdbc:mysql://db-server:3306/mydb
spring.datasource.username=app_user
spring.datasource.password=secure_password

# HikariCP (Spring Boot 기본 커넥션 풀)
spring.datasource.hikari.maximum-pool-size=20    # 최대 연결 수
spring.datasource.hikari.minimum-idle=5          # 최소 유지 연결 수
spring.datasource.hikari.connection-timeout=3000 # 연결 대기 최대 시간(ms)
spring.datasource.hikari.idle-timeout=600000     # 유휴 연결 유지 시간(ms)

WAS는 DB 서버의 호스트명과 포트만 알며, DB 서버는 외부에 직접 노출되지 않습니다.

면접 모범 답변 – “웹서버와 WAS를 왜 분리하나요?”

“웹서버와 WAS를 분리하는 주된 이유는 세 가지입니다. 첫째, 역할 최적화입니다. Nginx 같은 웹서버는 정적 파일을 비동기 이벤트 방식으로 수만 개의 동시 요청을 처리하는 데 최적화되어 있고, Tomcat 같은 WAS는 비즈니스 로직 실행에 특화되어 있습니다. 정적 요청이 WAS를 거치지 않으면 WAS 부하가 크게 줄어듭니다. 둘째, 보안 계층화입니다. 웹서버를 DMZ에 두고 WAS와 DB를 내부망에 분리하면, 외부 공격이 DB까지 도달하기 어려워집니다. 셋째, 독립적 확장입니다. 트래픽 패턴에 따라 WAS만 늘리거나 웹서버만 늘리는 선택적 스케일 아웃이 가능합니다. DB를 분리하는 이유도 동일하게 보안 격리, 독립 확장, 그리고 DB 특화 최적화(디스크 I/O, 메모리) 적용 가능성 때문입니다.”

실무에서 자주 묻는 추가 질문

“WAS도 정적 파일 처리 가능한데 왜 굳이 웹서버를 앞에 두나요?”

Tomcat도 정적 파일 처리가 가능하지만 Nginx보다 훨씬 비효율적입니다. Tomcat은 요청마다 스레드를 생성하는 Thread-per-Request 모델이라, 정적 파일 요청에도 스레드를 소비합니다. 반면 Nginx는 이벤트 루프 기반이라 하나의 스레드로 수만 개의 동시 연결을 처리합니다. 동시 접속 1,000명이 정적 파일을 요청할 때 Nginx는 스레드 1개, Tomcat은 스레드 1,000개가 필요합니다.

“클라우드 환경에서도 이 분리가 의미 있나요?”

AWS 기준으로 보면, 웹서버 역할은 CloudFront(CDN)+S3로 대체하고, WAS는 ECS/EKS 컨테이너로, DB는 RDS로 분리하는 것이 권장 패턴입니다. 물리적 분리에서 서비스 분리로 형태가 바뀌었을 뿐, 계층 분리의 원칙은 동일합니다.


결론

웹서버 WAS DB 분리는 “그냥 관습”이 아니라 처리 효율 최적화·보안 계층화·독립 확장·장애 격리라는 명확한 공학적 이유에서 출발합니다. 각 컴포넌트를 그것이 가장 잘하는 일에만 집중시키고, 계층 사이에 방화벽과 접근 제어를 두어 보안을 강화하며, 병목 지점만 선택적으로 확장할 수 있는 유연한 구조가 3계층 분리의 핵심 가치입니다. 면접에서는 이 세 가지 이유를 논리적으로 연결해 설명하고, 실무에서는 Nginx의 upstream 설정·SSL Termination·로드밸런싱 구성을 직접 적용해보는 것이 이해를 완성하는 가장 빠른 방법입니다.

답글 남기기

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