도입
개발자들이 흔히 말하는 WAS는 보통 Web Application Server를 뜻합니다. 특히 Java/Jakarta 진영에서는 톰캣(Tomcat) 같은 서블릿 컨테이너부터 WebLogic, Liberty 같은 풀스택 애플리케이션 서버까지 넓게 묶어 말하는 경우가 많습니다.
중요한 점은 WAS가 단순한 “웹페이지 제공기”가 아니라는 것입니다. 정적 파일만 빠르게 보내는 웹 서버와 달리, WAS는 요청을 애플리케이션 코드까지 전달하고, 비즈니스 로직을 수행하고, 데이터베이스나 메시징 같은 외부 자원과 연결하며, 결과를 동적으로 만들어 응답합니다. 그래서 WAS를 이해하면 웹 서버와의 차이, 톰캣과 엔터프라이즈 애플리케이션 서버의 차이, 그리고 실무 배치 구조가 한꺼번에 정리됩니다.
필요성
웹 서비스는 결국 요청을 받아 애플리케이션 코드를 실행하고 결과를 돌려주는 구조입니다. 그런데 이 과정에서 정적 파일 제공, TLS 종료, 압축, 리버스 프록시, 비즈니스 로직 실행, 세션 관리, DB 연결 관리 같은 역할이 모두 섞여 버리면 구조가 금방 흐려집니다.
WAS를 이해하면 “무엇을 앞단 웹 서버가 맡고, 무엇을 애플리케이션 실행 환경이 맡는가”를 나눠 볼 수 있습니다. 이 구분이 되어야 톰캣만 단독으로 쓸지, NGINX를 앞단에 둘지, 세션을 어디에 둘지, 멀티 인스턴스 운영을 어떻게 할지 같은 실무 결정이 쉬워집니다.
- 정적 파일과 동적 요청 처리를 분리하고 싶을 때
- Servlet/JSP 기반 애플리케이션이 어떻게 실행되는지 이해해야 할 때
- 세션, 스레드, DB 커넥션 풀, 배포 방식까지 함께 봐야 할 때
- Tomcat, WebLogic, Liberty 같은 제품군 차이를 정리해야 할 때
- NGINX + WAS + DB 구조를 운영 관점에서 이해해야 할 때
정의
WAS를 가장 단순하게 말하면, 웹 요청을 애플리케이션 코드까지 전달하고 그 결과를 응답으로 만드는 서버 실행 계층입니다. 웹 서버가 정적 콘텐츠 제공에 강하다면, WAS는 요청 해석과 비즈니스 로직 수행에 강하다고 볼 수 있습니다.
특히 자바 웹 환경에서는 서블릿 컨테이너가 WAS의 핵심 실행 엔진처럼 보이는 경우가 많습니다. 서블릿 컨테이너는 요청/응답 객체를 만들고, 적절한 서블릿에 매핑하고, 생명주기를 관리하고, 응답을 flush하는 역할을 맡습니다. 풀스택 애플리케이션 서버는 여기서 더 나아가 더 넓은 엔터프라이즈 기능을 포함합니다.
핵심 원리
애플리케이션은 단지 비즈니스 로직만 작성하고 싶어 합니다. 하지만 실제 런타임은 요청 파싱, 요청-응답 객체 생성, URL 매핑, 스레드 할당, 세션 연결, 출력 스트림 flush, 종료 시 자원 정리 같은 부수 작업이 훨씬 많습니다.
WAS는 바로 이 공통 런타임 책임을 애플리케이션 대신 맡는 계층입니다. 개발자는 서블릿이나 프레임워크 코드로 로직을 작성하고, WAS는 그 로직이 안전하게 실행되도록 요청 흐름과 실행 환경을 관리합니다.
기본 구조
| 구성 요소 | 역할 | 실무 포인트 |
|---|---|---|
| Connector / Listener | HTTP 연결을 받고 내부 처리 엔진으로 넘김 | 포트, 프로토콜, HTTPS, keep-alive 설정과 연결됨 |
| Servlet Container | 요청을 서블릿에 매핑하고 생명주기를 관리 | init / service / destroy 흐름의 중심 |
| Application Deployment | 웹 애플리케이션을 서버에 배치 | WAR 파일, exploded directory, hot deploy와 연결 |
| Thread Model | 요청을 어떤 스레드가 처리할지 관리 | 서블릿 인스턴스 필드 사용 시 동시성 문제가 생길 수 있음 |
| Session Management | 같은 사용자의 여러 요청을 연결 | 멀티 인스턴스에서는 외부 저장소나 세션 전략이 중요 |
| External Resource Access | DB, 메시징, 외부 API 같은 자원과 연결 | 커넥션 풀, 타임아웃, 장애 전파와 연결 |
대표적인 배치 흐름
브라우저
↓
NGINX / Apache HTTP Server
↓
WAS (Tomcat / WebLogic / Liberty)
↓
Application Code
↓
DB / MQ / External API
패턴 1. 웹 서버와 WAS 역할 분리
웹 서버는 이미지, CSS, JS, 정적 HTML 같은 파일을 빠르게 내려주는 데 강합니다. 반면 WAS는 사용자의 요청을 받아 코드 실행을 통해 응답을 동적으로 만듭니다. 그래서 전통적인 구조에서는 웹 서버가 앞단에서 요청을 받고, 동적 요청만 WAS로 넘깁니다.
다만 오늘날은 경계가 예전처럼 절대적이지 않습니다. Tomcat도 HTTP Connector를 통해 단독으로 웹 서버처럼 동작할 수 있고, 반대로 NGINX도 리버스 프록시와 로드 밸런싱을 통해 애플리케이션 트래픽 제어에 깊게 개입합니다. 그래서 요즘은 “웹 서버냐 WAS냐”보다 어느 계층이 어떤 책임을 맡는가로 이해하는 편이 더 맞습니다.
패턴 2. 서블릿 컨테이너와 요청 처리 흐름
서블릿 컨테이너는 요청을 전달만 하지 않습니다. 서블릿이 아직 없으면 클래스를 로드하고 인스턴스를 만들고 init을 호출한 뒤, 요청마다 service를 호출하고, 서비스에서 제거할 때는 destroy를 호출합니다.
또한 컨테이너는 일반적으로 요청당 스레드를 할당하는 방향으로 동작합니다. 그래서 서블릿 인스턴스 필드에 요청별 상태를 담거나, 공유 자원을 아무 보호 없이 건드리면 동시성 문제가 생길 수 있습니다. WAS를 이해할 때 스레드 모델을 같이 봐야 하는 이유가 여기 있습니다.
서블릿 기반 요청 처리 흐름
1) 클라이언트가 HTTP 요청을 보낸다
2) WAS가 요청을 적절한 서블릿으로 매핑한다
3) 필요하면 서블릿 클래스를 로드하고 init 한다
4) service / doGet / doPost 같은 메서드가 실행된다
5) 응답이 생성되고 flush 된다
6) 서비스 종료 시 destroy 로 정리한다
세션도 이 계층에서 중요한 역할을 합니다. HTTP는 stateless이기 때문에 같은 사용자의 연속된 요청을 하나의 흐름으로 묶으려면 세션 관리가 필요하고, 서블릿 API는 HttpSession을 통해 이를 지원합니다.
패턴 3. 배포와 운영 구조
전통적인 자바 웹 애플리케이션은 WAR 형태로 패키징되어 WAS에 배포되는 경우가 많습니다. 톰캣은 WAR 배포를 정식으로 지원하고, Manager 웹 애플리케이션이나 자동 배포 기능 등을 통해 운영할 수 있습니다.
운영 관점에서는 스레드, 세션, DB 커넥션, 로그, 리버스 프록시 배치가 중요합니다. 세션을 WAS 로컬 메모리에만 두면 멀티 인스턴스에서 sticky session 또는 외부 세션 저장소가 필요해지고, DB 연결은 매 요청마다 새로 열지 않고 커넥션 풀을 통해 관리하는 편이 일반적입니다. 앞단 NGINX 같은 리버스 프록시는 정적 파일 제공, 헤더 조정, 프록시 패스, 버퍼링, 로드 밸런싱 같은 역할을 수행하며 WAS 앞에 많이 배치됩니다.
배포와 운영에서 주로 보는 것
- WAR 배포 / 롤링 배포
- 스레드 풀과 요청 처리량
- 세션 저장 위치
- DB 커넥션 풀
- 리버스 프록시와 로드 밸런서
- 로그와 메트릭
- graceful shutdown
대표 제품과 구분
| 제품 | 성격 | 핵심 포인트 |
|---|---|---|
| Apache Tomcat | 오픈소스 서블릿/JSP 중심 런타임 | 가볍고 널리 쓰이며, 많은 Java 웹앱의 기본 실행 환경 |
| Oracle WebLogic Server | 엔터프라이즈 Jakarta EE 애플리케이션 서버 | 확장성, 관리 기능, 클라우드·쿠버네티스 운영 지원 |
| IBM WebSphere Liberty / Open Liberty | 경량 런타임 기반 애플리케이션 서버 | Jakarta EE 및 MicroProfile 친화적 |
실무 감각으로 정리하면, 톰캣은 “서블릿 컨테이너 중심의 가벼운 WAS”로, WebLogic과 Liberty는 “더 넓은 엔터프라이즈 런타임 기능까지 포함한 애플리케이션 서버”로 보는 편이 이해가 쉽습니다. 다만 현대 환경에서는 경계가 완전히 고정돼 있지 않고, 제품마다 제공 범위와 운영 철학이 조금씩 다릅니다.
한계와 주의점
WAS는 많은 편의를 주지만, 동시에 복잡성을 함께 가져옵니다. 스레드가 부족하면 요청이 밀리고, 세션을 잘못 관리하면 멀티 인스턴스에서 로그인 상태가 흔들리고, DB 연결을 무제한처럼 다루면 오히려 외부 자원이 먼저 무너질 수 있습니다.
또한 오늘날에는 스프링 부트처럼 애플리케이션 내부에 톰캣을 내장하는 방식도 흔하기 때문에, 과거처럼 “별도 WAS 서버에 WAR를 올린다”만이 정답은 아닙니다. 따라서 WAS는 제품 이름보다 실행 책임과 운영 모델의 관점으로 이해하는 편이 더 실전적입니다.
- 세션을 로컬 메모리에만 두고 멀티 인스턴스로 확장하지 않기
- 서블릿 인스턴스 필드에 요청 상태를 넣지 않기
- 리버스 프록시와 WAS의 책임을 뒤섞지 않기
- WAS를 만능 솔루션처럼 보고 DB 병목이나 네트워크 병목을 무시하지 않기
자주 하는 실수
- 웹 서버 = WAS라고 단순화함
- Tomcat = 풀 Jakarta EE 애플리케이션 서버라고 착각함
- WAS가 동적 요청을 처리한다는 점보다 단순 “포트 열고 받는 서버”로만 이해함
- 서블릿 동시성 모델을 무시하고 인스턴스 필드를 함부로 사용함
- 세션을 로컬에만 두고 멀티 서버 운영 문제를 나중에 생각함
- NGINX 같은 리버스 프록시를 앞단에 두는 이유를 성능 하나로만 이해함
- WAR 배포와 내장 서버 실행 모델 차이를 구분하지 않음
실무 루틴
- 먼저 정적 처리와 동적 처리를 어디서 나눌지 결정한다.
- 세션을 로컬에 둘지 외부 저장소에 둘지 정한다.
- 요청 동시성 모델과 스레드 안전성을 먼저 점검한다.
- WAR 배포형인지 내장 서버형인지 배포 모델을 정한다.
- 앞단 리버스 프록시가 필요한지, 로드 밸런싱이 필요한지 판단한다.
- DB 커넥션, 타임아웃, 로그, 메트릭, graceful shutdown까지 함께 본다.
- 그다음에야 Tomcat, WebLogic, Liberty 같은 구체 제품을 선택한다.
디버깅
WAS 장애를 볼 때 먼저 나눌 질문
- 요청이 앞단 프록시에서 막히는가?
- WAS까지 도달하는가?
- 매핑과 실행이 정상인가?
- 세션/스레드/커넥션 풀이 병목인가?
- 외부 자원(DB, MQ, API)이 느린가?
- 배포 단위(WAR, 설정, 버전)가 꼬였는가?
요약
- ✅ WAS는 웹 요청을 받아 애플리케이션 코드를 실행하고 동적 응답을 생성하는 실행 환경이다.
- ✅ 웹 서버는 정적 처리와 프록시에 강하고, WAS는 동적 처리와 애플리케이션 실행에 강하다.
- ✅ 자바 웹 환경에서는 서블릿 컨테이너가 WAS의 핵심 실행 엔진처럼 동작한다.
- ✅ 요청 흐름은 보통 init / service / destroy 같은 생명주기 안에서 관리된다.
- ✅ 세션, 스레드, 커넥션 풀, WAR 배포는 WAS 운영의 핵심 주제다.
- ✅ 톰캣은 경량 런타임, WebLogic과 Liberty는 더 넓은 엔터프라이즈 런타임 관점으로 볼 수 있다.
- ✅ 앞단 NGINX 같은 리버스 프록시와 함께 배치되는 경우가 매우 흔하다.
- ✅ WAS는 단순 “포트 열고 요청 받는 서버”가 아니라 애플리케이션 실행 책임을 묶는 런타임 계층이다.