[Spring Boot] Embedded Web Server 설정과 튜닝
정의
Spring Boot 의 starter 가 내장 서버를 함께 번들. 별도 WAR 배포 / 외부 Tomcat 불필요.
기본 매핑:
spring-boot-starter-web→ Tomcat (기본)spring-boot-starter-webflux→ Nettyspring-boot-starter-jetty→ Jettyspring-boot-starter-undertow→ Undertow
같은 starter 안에서 교체:
implementation("org.springframework.boot:spring-boot-starter-web") {
exclude(module = "spring-boot-starter-tomcat")
}
implementation("org.springframework.boot:spring-boot-starter-jetty")
기본 설정
server:
port: 8080
servlet:
context-path: /api # 모든 경로 prefix
forward-headers-strategy: native # reverse proxy 뒤 X-Forwarded-* 처리
compression:
enabled: true
mime-types: text/html, application/json
min-response-size: 1024
http2:
enabled: true
error:
whitelabel:
enabled: false
server.port=0 면 random port (테스트에서 흔히 사용).
Tomcat 튜닝
server:
tomcat:
threads:
max: 200 # 동시 처리 thread
min-spare: 10
accept-count: 100 # 큐
max-connections: 8192 # 동시 연결
connection-timeout: 20s
keep-alive-timeout: 60s
max-keep-alive-requests: 100
max-http-form-post-size: 2MB
max-swallow-size: 2MB # 거부 요청의 본문 읽기 제한
uri-encoding: UTF-8
accesslog:
enabled: true
pattern: "%t %a \"%r\" %s %b"
directory: /var/log/tomcat
threads.max 의미
worker thread 수. 요청마다 1 thread 점유. Tomcat 의 blocking 모델이므로:
- low-traffic, 빠른 응답: 50~200
- high-traffic, DB call 느림: 500~1000
- virtual thread 활성화 시 (Spring Boot 3.2+): 의미 사라짐
max-connections vs threads.max
max-connections > threads.max 가 정상. 연결은 keep-alive 로 유지되지만 worker 가 부족하면 큐잉. accept-count 만큼 큐.
virtual thread (Spring Boot 3.2+)
spring:
threads:
virtual:
enabled: true
Tomcat worker pool 이 virtual thread 사용. threads.max 영향 없음. spring-virtual-threads 참고.
Netty 튜닝 (WebFlux)
server:
netty:
connection-timeout: 20s
idle-timeout: 60s
max-keep-alive-requests: 1000
spring:
reactor:
netty:
pool:
max-connections: 10000
max-idle-time: 30s
Netty 는 이벤트 루프 기반. thread 수 적음 (보통 CPU core × 2). 동시 처리는 connection 수가 결정.
WebFlux + Netty 가 reactive non-blocking 시 가장 자연스러움. spring-webflux 참고.
Jetty / Undertow
server:
jetty:
threads:
max: 200
min: 8
accesslog:
enabled: true
undertow:
threads:
io: 4
worker: 64
buffer-size: 16384
Undertow 는 XNIO 기반. Tomcat 보다 메모리 효율적, throughput 우수.
다이나믹 customization
application.yml 로 안 되는 세밀 조정:
@Component
public class TomcatCustomizer implements WebServerFactoryCustomizer<TomcatServletWebServerFactory> {
@Override
public void customize(TomcatServletWebServerFactory factory) {
factory.addConnectorCustomizers(connector -> {
connector.setProperty("relaxedQueryChars", "[]|"); // 특수문자 허용
connector.setProperty("disableUploadTimeout", "false");
connector.setProperty("connectionUploadTimeout", "120000");
});
factory.addContextCustomizers(context -> {
context.setCookieProcessor(new Rfc6265CookieProcessor());
});
factory.setProtocol("org.apache.coyote.http11.Http11AprProtocol"); // APR
}
}
WebServerFactoryCustomizer<T> Bean 으로 등록. 시작 시 자동 적용.
동적 port
@SpringBootApplication
class App {
public static void main(String[] args) {
ConfigurableApplicationContext ctx = SpringApplication.run(App.class, args);
int port = ctx.getWebServer().getPort();
System.out.println("Started on port " + port);
}
}
테스트:
@SpringBootTest(webEnvironment = RANDOM_PORT)
class IntegrationTest {
@LocalServerPort int port; // 자동 주입
}
Graceful Shutdown
server:
shutdown: graceful
spring:
lifecycle:
timeout-per-shutdown-phase: 30s
- 신규 연결 거부
- 진행 중 요청 완료 대기 (최대 30s)
- 이후 강제 종료
K8s terminationGracePeriodSeconds 와 맞춤. preStop hook 도 활용.
HTTP/2
server:
http2:
enabled: true
ssl:
enabled: true
key-store: classpath:keystore.p12
key-store-password: ${KEYSTORE_PASSWORD}
HTTP/2 는 보통 SSL 필요 (h2). plaintext HTTP/2 (h2c) 는 reverse proxy 뒤.
Compression
server:
compression:
enabled: true
mime-types:
- text/html
- text/xml
- text/plain
- text/css
- text/javascript
- application/javascript
- application/json
min-response-size: 1024
응답 크기 > 1KB 이면 gzip. JSON / HTML / CSS 압축으로 대역폭 절약.
CDN / reverse proxy 가 압축한다면 끄기.
CORS (전역)
@Configuration
class WebConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/api/**")
.allowedOrigins("https://app.example.com")
.allowedMethods("GET", "POST", "PUT", "DELETE")
.allowedHeaders("*")
.allowCredentials(true)
.maxAge(3600);
}
}
Spring Security 도 함께 사용 시 SecurityFilterChain 에 cors 활성화 필요:
.cors(c -> c.configurationSource(corsSource))
Static resources
spring:
web:
resources:
static-locations: classpath:/static/, classpath:/public/
cache:
period: 30d
cachecontrol:
max-age: 30d
must-revalidate: true
add-mappings: true
mvc:
static-path-pattern: /static/**
production: long cache + content hash (Vite / webpack [name].[hash].js).
Error pages
server:
error:
whitelabel:
enabled: false
include-message: always
include-binding-errors: always
include-stacktrace: on-param # ?trace=true 일 때만
include-exception: false
전역 @ControllerAdvice 또는 ErrorController 로 custom.
모니터링
management:
endpoints:
web:
exposure:
include: health, metrics, info, threaddump
metrics:
enable:
tomcat: true
jvm: true
Tomcat 의 thread pool / connection 상태 → Prometheus / Grafana.
함정과 베스트 프랙티스
- production: graceful shutdown + 적절한 timeout
- Tomcat threads.max 는 DB connection pool size 와 균형 (worker > pool)
- CDN / reverse proxy 뒤 면
forward-headers-strategy: native필수 - HTTPS terminate 위치: 보통 reverse proxy. Spring 은 plain HTTP 받음
- virtual thread 활성화 시 worker pool 튜닝 무의미해짐
- embedded server 선택: 대부분 기본 Tomcat 으로 충분. 특수 요구 (메모리 ↓, 비동기 ↑) 시만 교체
- Netty 와 WebFlux 페어: blocking 코드 섞으면 의미 없음. 모든 단계 reactive 여야
관련 위키
이 글의 용어 (6개)
- [Spring Boot] 자동 구성과 @SpringBootApplicationspring
- 정의 Spring Boot의 핵심 가치 = 자동 구성(autoconfiguration). classpath의 라이브러리를 보고 합리적 기본 설정으로 Bean 등록. Tomcat이…
- [Spring Boot] SSL/HTTPS 설정spring
- 정의 Spring Boot 에서 HTTPS / TLS 설정 방법. JKS (legacy), PKCS12, PEM (modern), SSL Bundles (Spring Boot 3…
- [Spring] Actuator: health, metrics, infospring
- 정의 Spring Boot Actuator는 프로덕션용 monitoring/management endpoint 자동 제공. health check, metrics, env, be…
- [Spring] Spring MVC: @RestController, @RequestMappingspring
- 정의 Spring MVC는 Servlet 기반 동기 웹 프레임워크. 이 요청을 받아 핸들러(컨트롤러 메서드)에 라우팅. REST API와 전통 MVC(HTML) 모두 지원. We…
- [Spring] Virtual Threads (Project Loom): Spring 6.1+spring
- 정의 Virtual Thread 는 JDK 21+ 에서 GA 된 경량 thread. JVM 이 OS thread (carrier) 위에 가상 thread 를 M:N 매핑. 수백만…
- [Spring] WebFlux: Reactive, Mono, Fluxspring
- 정의 Spring WebFlux는 Project Reactor 기반의 비동기·non-blocking 웹 프레임워크. Spring MVC와 별개. Netty 기본 (Tomcat도 …
💬 댓글