새로운 내용을 공부할 때
새로운 내용의 공부를 시작할 때 용어의 정의를 이해하지 못하거나 정확하게 알지 못한다면 그 용어가 포함된 문장을 이해하지 못합니다.
작은 단어 하나가 내용을 이해하지 못하게 하기 때문에 용어를 정확하게 이해하는 것이 중요합니다.
2025-02-16 TIL 내장/외장 톰캣
📌 2025-02-16 TIL
1. 오늘의 학습 주제
- 스프링 부트는 내장 톰캣을 사용하게 되었을까?
- 내장 컨테이너와 외장 컨테이너는 어떤 트레이드 오프가 있을까?
- 우리 회사에 맞는 웹 컨테이너는 어떤 종류일까?
- 비슷한 주제로 이야기해볼만한 스프링 구조가 있을까?
2. 학습 내용
스프링 부트는 “convention over configuration” 원칙을 따르며 개발자가 비즈니스 로직에 집중할 수 있도록 기본적인 설정을 자동으로 제공해 줍니다. 내장 톰캣을 사용하여, 별도의 복잡한 서블릿 컨테이너 설정 없이도 바로 웹 어플리케이션을 실행할 수 있습니다.
또한, 내장 서버 덕분에 실행 가능한 JAR 파일로 패키징 할 수 있어, 배포와 실행이 매우 간편하게 되었습니다. 이로 인해 개발과 테스트 환경에서 일관되 동작을 보장하고, 클라우드와 같은 다양한 환경에서도 쉽게 배포가 가능합니다.
내장 톰캣
배포를 쉽게하고, 실행 환경을 일관되게 유지하며, 최신 배포 방식과 잘 맞습니다.
운영 환경에서 서버 자원을 효율적으로 사용해야 하는 경우, 여러 애플리케이션을 하나의 톰캣으로 돌려야하는 경우에는 외장 톰캣을 선택하는 것도 가능합니다.
제가 생각하는 큰 장점은 실행 환경을 일관되게 유지할 수 있다는 겁니다.
외장 톰캣을 사용하면 개발환경, 테스트 환경, 운영 환경에서 톰캣 설정이 다를 수 있는 것을 동일하게 보장하거나 쉽게 확인이 가능합니다.
세션 클러스터링 지원 부족
내장 톰캣은 개별 애플리케이션 인스턴스로 동작하여 여러 서버 간 세션 공유가 기본적으로 안 됨.
만약 세션을 여러 서버에서 공유해야 하면 레디스 같은 외부 세션 저장소를 추가해야 함.
특징 | 내장 톰캣 (애플리케이션 중심 관리, 개별 최적화) | 외장 톰캣 (인프라 중심 관리, 공통 최적화) |
---|---|---|
관리 방식 | - 애플리케이션마다 독립적 톰캣 인스턴스 실행 - 개발팀이 애플리케이션과 서버 환경을 함께 관리 |
- 하나의 톰캣 인스턴스에서 여러 애플리케이션 실행 - 운영팀이 통합 관리 |
장점 | - 컨테이너 친화적: Docker, Kubernetes와 궁합이 좋음 - 배포 단순성: 애플리케이션별로 JAR 하나만 배포하면 됨 - 개별 서비스 확장성: 독립적으로 스케일링 가능 - 운영 환경 일관성: 로컬, 테스트, 운영 환경이 거의 동일 |
- 자원 효율성: 여러 애플리케이션이 하나의 서버 자원을 공유하여 메모리/CPU 활용도가 높음 - 공통 설정 관리 용이: server.xml, context.xml 등으로 통합 설정 가능 - 세션 공유 용이: 동일 톰캣 내에서 실행되어 세션 공유가 쉬움 - 운영 안정성: 인프라 단위 튜닝으로 성능 최적화 가능 |
단점 | - 자원 사용 비효율: 애플리케이션 개수만큼 톰캣 인스턴스가 증가하여 메모리 사용량 증가 - 중앙화된 관리 어려움: 여러 인스턴스에 공통 설정 적용이나 튜닝이 어려움 - 세션 공유 문제: 별도 저장소(예: Redis) 필요 |
- 배포 복잡성: 톰캣 설정 관리 및 애플리케이션을 WAR로 패키징해야 함 - 애플리케이션 간 영향: 한 서비스의 부하가 다른 서비스에 영향 - 로드 밸런싱 필요: 다수의 톰캣 인스턴스 운영 시 부하 분산 필수 - 환경 불일치 문제: 운영과 개발 환경의 톰캣 설정 차이 발생 가능 |
적합한 환경 | - 마이크로서비스 아키텍처(MSA) 및 컨테이너 기반 배포에 유리 | - 엔터프라이즈 환경에서 대규모 WAS 운영, 여러 애플리케이션의 자원 최적화에 유리 |
무중단 배포 및 확장성
- 내장 톰캣: 블루-그린 배포, 롤링 업데이트 등 개별 서비스 단위 배포가 쉬움
- 외장 톰캣: 여러 애플리케이션이 하나의 서버를 공유하므로 배포 시 충돌 가능성이 있음
단일 애플리케이션 vs. 분산 애플리케이션
- 단일 애플리케이션: 하나의 거대한 인프라에서 전체 서비스를 운영(ex: 외부 톰캣)
- 마이크로서비스: 각 기능을 개별 애플리케이션으로 독립 운영(ex: 내장 톰캣 같은 구조)
단일의 장점은 효율이고 마이크로는 독립으로 서로 통신을 위한 기술이 필요하게 된다.
Monolith 단일 애플리케이션, 인프라 중심
✔ 장점:
- 단일 애플리케이션이므로 데이터 공유가 쉽고 비즈니스 로직을 한 곳에서 관리할 수 있음.
- 하나의 서버에서 실행되므로 통합적인 트랜잭션 관리가 쉬움.
- 배포가 단순하고 별도의 서비스 간 통신(API 호출, 메시지 큐 등)이 필요 없음.
❌ 단점:
- 애플리케이션이 커질수록 **코드 유지보수와 확장성이 어려워짐 (ex: 기능 추가할 때 기존 코드 수정이 많아짐).
- 특정 기능만 업데이트해도 전체 애플리케이션을 재배포해야 함.
- 규모가 커질수록 부하 분산과 확장이 어려움 (단일 서버 자원에 의존).
분산처리
💡 여러 개의 작은 서비스로 기능을 분리하여 독립적으로 배포하는 구조
✔ 장점:
- 각 서비스가 독립적으로 실행되므로 배포와 확장이 유연함 (ex: 일부 서비스만 업데이트 가능).
- 특정 서비스만 따로 확장할 수 있어서 트래픽이 몰리는 부분만 스케일링 가능.
- 각 서비스가 독립적이므로, 기술 스택을 자유롭게 선택 가능 (ex: 일부 서비스는 Kotlin, 일부는 Python 사용).
❌ 단점:
- 서비스 간 API 호출, 메시지 큐 등을 이용한 **통신 비용이 증가함.**
- 데이터 일관성 관리가 어려움 (각 서비스가 독립된 DB를 가질 경우 트랜잭션 관리가 복잡해짐).
- 운영 및 모니터링이 복잡해짐 (각 서비스의 로그, 장애 감지, 트래픽 관리가 필요).
스프링 MVC에서 레이어 구조 트레이드 오프
스프링 부트 MVC에서도 레이어를 어떻게 나누느냐에 따라 트레이드 오프가 발생함.
3-Tier 구조
✔ 장점:
- 직관적인 구조 : 요청이 컨트롤러 → 서비스 → 레포지토리로 가는 표준적인 흐름.
- 단일 애플리케이션에서 관리하기 쉬움 : 모든 로직이 한 애플리케이션 내부에서 동작하므로 데이터 일관성이 높음.
- 운영이 간단: 모든 로직이 같은 코드베이스에 있으므로 배포와 유지보수가 용이.
❌ 단점:
- 애플리케이션이 커질수록 모듈 분리가 어려워짐.
- 비즈니스 로직이 많아질 경우 서비스 레이어가 비대해짐.
- 마이크로서비스로 전환할 때 리팩토링이 필요.
CQRS
💡 읽기(Query)와 쓰기(Command) 로직을 분리하는 패턴
✔ 장점:
- 읽기와 쓰기 성능을 최적화할 수 있음 (ex: 조회는 캐시 활용, 쓰기는 트랜잭션 강화를 적용).
- 데이터베이스 확장성이 높아짐 (ex: 읽기 전용 DB와 쓰기 전용 DB를 분리 가능).
- 서비스 간 결합도를 낮출 수 있음 (ex: 마이크로서비스에 적합).
❌ 단점:
- 구현이 복잡 (읽기와 쓰기 로직을 분리해야 하므로 코드 구조가 복잡해질 수 있음).
- 데이터 일관성 문제가 발생할 수 있음 (ex: 읽기 모델이 쓰기 모델과 즉시 동기화되지 않을 가능성이 있음).
DDD
💡 도메인 중심 설계를 적용하여 비즈니스 로직을 명확하게 분리하는 방식
✔ 장점:
- 도메인별로 로직을 나눠 유지보수가 용이함.
- 비즈니스 로직이 명확하게 구분되므로 확장성이 높음.
- 마이크로서비스와 궁합이 좋음.
❌ 단점:
- 설계가 복잡해질 수 있음 (비즈니스 도메인을 잘 정의해야 함).
- 초기 개발 속도가 느릴 수 있음 (도메인 분석과 모델링이 필요).
정리
구분 | 인프라 단위 (Monolith) | 애플리케이션 단위 (Microservices) |
---|---|---|
운영 방식 | 하나의 거대한 애플리케이션 | 독립적인 작은 서비스들 |
배포 방식 | 전체 배포 필요 | 개별 배포 가능 |
트래픽 처리 | 단일 서버 확장 (Scale Up) | 개별 서비스 확장 (Scale Out) |
데이터 일관성 | 트랜잭션 관리 쉬움 | 분산 환경에서 데이터 동기화 필요 |
유지보수 | 코드가 많아질수록 복잡해짐 | 서비스 간 통신 및 운영 복잡성 증가 |
기술 스택 | 모든 기능이 같은 기술 사용 | 서비스마다 다른 기술 선택 가능 |
- 독립적 운영 vs. 중앙 관리
- 독립적 운영 (Microservices):
- 애플리케이션 각각이 독자적인 실행 환경(예: 내장 톰캣)을 갖고 독립적으로 배포, 확장, 관리됨.
- 이 방식은 마이크로서비스 아키텍처처럼 각 서비스가 자율적으로 운영되어 변경과 확장이 자유로움
- 단점은 여러 인스턴스를 관리해야 하므로, 모니터링, 로드 밸런싱 등 추가적인 관리가 필요하다는 점
- 중앙 관리 (Monolith):
- 하나의 통합된 인프라(예: 외장 톰캣)에서 여러 애플리케이션을 운영하여 중앙집중적인 관리가 가능함.
- 이 방식은 단일 애플리케이션 또는 모놀리식 아키텍처에서 볼 수 있는데, 공통 설정과 자원 활용 면에서는 효율적이지만, 개별 서비스의 확장이나 독립적인 업데이트가 어려움
- 독립적 운영 (Microservices):
- MVC 구조와 아키텍처 설계의 연관성
- Spring Boot에서 제공하는 MVC 레이어도 애플리케이션 전체를 단일 모듈로 구성할지, 아니면 각 서비스 별로 독립된 모듈로 구성할지에 따라 설계가 달라진다.
- 즉, 내장 톰캣(독립적 운영)을 선택하면 각 서비스가 자신만의 실행 환경과 생명주기를 가지게 되어 마이크로서비스 방식에 더 가깝게 설계할 수 있고,
외장 톰캣(중앙 관리)을 선택하면 공통의 인프라 내에서 모든 기능을 운영하는 모놀리식 방식에 가깝게 설계할 수 있다.
- 트레이드 오프의 발생
- 독립성:
각 애플리케이션이나 서비스가 독자적으로 운영되면, 개발 및 배포의 유연성이 높아지지만, 전체 시스템 관리와 인프라 설정(예: 로드 밸런싱, 모니터링)이 복잡해질 수 있음. - 자원 효율성 및 중앙 관리:
중앙에서 모든 애플리케이션을 관리하면 자원 활용이 최적화되고 공통 설정을 한 번에 적용할 수 있지만, 한 서비스의 문제나 부하가 다른 서비스에 영향을 줄 위험이 있음.
- 독립성:
결국, 내장 톰캣과 외장 톰캣 선택은 단순한 기술 선택이 아니라, 애플리케이션을 어떻게 운영하고자 하는지, 즉 마이크로서비스와 모놀리식 아키텍처 중 어느 쪽을 지향할지에 대한 전략적인 결정으로 이어지며, 이는 MVC 구조 설계에도 직접적인 영향을 미치게 된다.
스프링과 스프링 부트 차이
기존 스프링
- 톰캣 직접 설치 및 실행
- 라이브러리 의존성 관리 어려움 : 직접 의존성 추가 및 버전을 일치해야함
- 설정 파일 복잡함: applicationContext.xml 같은 설정이 많음
스프링 부트
- 내장 톰캣 기본 제공: 따로 설치하지 않고 자바 실행명령으로 가능함
java -jar myapp.jar
- 자동 라이브러리 관리:
starter
의존성을 추가하면 관련된 의존성과 기본 설정으로 빈 등록함 - 설정 간소화:
application.yaml
등 으로 단순하게 설정가능
댓글남기기