infra
Platform

모듈 맵

[Infra Ops] Tomcat 세션 클러스터링과 Redis 세션 외부화

0 / 52 완료

펼치기
0 / 52 완료0%

Infra-ops · 17 / 52

[Infra Ops] Tomcat 세션 클러스터링과 Redis 세션 외부화

DeltaManager 클러스터, Nginx sticky session, Redis spring-session까지 — Tomcat 2대 이상 운영 시 세션 유지 문제를 해결하는 실무 패턴

🚨INCIDENT ALERT
HIGH

쇼핑몰 운영팀 슬랙에 메시지가 올라왔습니다. "오늘 오전부터 장바구니가 자꾸 비워진다는 고객 문의가 10건 넘게 들어왔어요. 로그인도 풀리는 경우가 있고요." 전날 밤 WAS 서버를 1대에서 2대로 늘리는 작업을 했습니다. 트래픽은 잘 분산되고 있는데 이 민원은 뭔가요?

원인은 세션입니다. 로그인 후 장바구니를 담은 세션이 Tomcat1 메모리에 있는데, 다음 요청은 Nginx가 Tomcat2로 보냈습니다. Tomcat2는 그 세션을 모릅니다. 로그인이 풀리고, 장바구니가 비워집니다.

WAS를 이중화할 때 반드시 세션 문제를 함께 해결해야 합니다.

이번 챕터에서 배울 것
  • 1WAS 이중화 시 세션 소실이 발생하는 구조적 원인을 설명할 수 있다
  • 2Tomcat DeltaManager 클러스터를 server.xml에 설정하고 멤버십을 확인할 수 있다
  • 3Nginx ip_hash로 sticky session을 구성하고 jvmRoute와 연동할 수 있다
  • 4spring-session-data-redis로 세션을 Redis에 외부화하고 WAS 재기동 후 세션 유지를 확인할 수 있다
  • 5세션 전략 3가지의 트레이드오프를 근거로 환경에 맞는 방법을 선택할 수 있다
실습 환경 준비
Tomcat 버전 확인
catalina.sh version 2>/dev/null || /opt/tomcat/bin/catalina.sh version
Redis 실행 확인
redis-cli ping
Nginx upstream 설정 확인
nginx -T 2>/dev/null | grep -A 5 upstream
멀티캐스트 인터페이스 확인
ip route show | grep -E 'dev|multicast'

WAS 이중화 시 세션 문제

💡개념

세션 소실이 발생하는 구조적 원인

WAS를 이중화하면 트래픽 분산이라는 목적은 달성하지만, 세션이라는 새로운 문제가 즉시 발생합니다. 각 WAS 인스턴스는 자신의 JVM 메모리에 세션을 독립적으로 관리하기 때문에, 로드밸런서가 요청을 다른 WAS로 보내는 순간 그 사용자의 로그인 상태는 사라집니다. 이 문제를 해결하지 않고 WAS 이중화를 운영하면 사용자에게는 "자꾸 로그아웃된다"는 민원이 반복됩니다.

WAS 이중화 세션 소실 — 로드밸런서가 다른 WAS로 요청을 보내면 세션이 없다

HTTP는 상태가 없는(stateless) 프로토콜입니다. 로그인 정보, 장바구니처럼 사용자별로 유지해야 하는 데이터는 서버 쪽에서 세션이라는 형태로 보관합니다. 각 WAS는 세션을 자신의 JVM 힙(메모리)에 저장합니다.

WAS가 1대일 때는 문제가 없습니다. 모든 요청이 같은 JVM으로 들어오므로 세션을 찾을 수 있습니다. WAS를 2대로 늘리면 달라집니다. 로드밸런서는 요청마다 Tomcat1과 Tomcat2 중 하나를 고릅니다. 세션이 Tomcat1 메모리에 있는데 Tomcat2가 요청을 받으면, Tomcat2는 세션을 모르므로 "인증되지 않은 사용자"로 취급합니다.

해결 방법은 세 가지입니다. 각각 구현 복잡도와 장애 허용 범위가 다릅니다.

방법원리장점단점
Sticky Session로드밸런서가 같은 클라이언트를 항상 같은 WAS로 보냄구현 단순, 추가 인프라 불필요WAS 장애 시 세션 소실, NAT 환경 집중
Session ReplicationWAS 간에 세션 데이터를 복제해 동기화WAS 어디에 요청이 가도 세션 유지노드 증가 시 복제 트래픽 급증
Session 외부화WAS 밖의 저장소(Redis)에 세션 보관WAS 재기동에도 세션 유지, 수평 확장 용이Redis 추가 운영 필요

Tomcat DeltaManager 클러스터 설정

💡개념

DeltaManager — All-to-All 세션 복제

Tomcat 클러스터는 추가 인프라 없이 WAS 노드끼리 세션을 동기화하는 방법입니다. 멀티캐스트로 클러스터 멤버를 발견하고, 세션 변경이 생길 때마다 그 차이(delta)를 전체 노드에 전파하는 방식이라 어느 WAS로 요청이 가도 동일한 세션을 읽을 수 있습니다. 단, 이 방식은 노드 수가 늘어날수록 복제 트래픽이 N-1배로 늘어나는 구조적 한계가 있어, 소규모 클러스터(2~3대)에 적합합니다.

Tomcat DeltaManager All-to-All 복제 — 모든 노드에 세션 변경분을 브로드캐스트

서버를 2대로 늘린 직후부터 장바구니가 비워진다는 민원이 쏟아집니다. Nginx 로그에는 이상이 없고, 두 Tomcat 모두 정상 동작 중입니다. 문제는 세션이 각자의 메모리에만 있다는 것입니다. 이 문제를 Tomcat 레벨에서 해결하는 방법이 DeltaManager 클러스터입니다. 세션이 변경될 때마다 변경분을 클러스터 전체로 전파해, 어떤 WAS로 요청이 가도 동일한 세션 데이터를 읽게 합니다.

Tomcat 내장 클러스터 기능을 사용하는 방법입니다. 세션이 변경될 때마다 그 차이(delta)를 클러스터 내 모든 노드에 멀티캐스트로 전파합니다. 어떤 WAS로 요청이 가도 최신 세션을 찾을 수 있습니다.

DeltaManager와 BackupManager의 차이는 복제 범위입니다. DeltaManager는 All-to-All — 클러스터 전체에 뿌립니다. 노드가 2~4대일 때 단순하고 효과적입니다. BackupManager는 Primary-Backup — 지정된 백업 노드 1개에만 복제해 트래픽을 아낍니다. 노드가 많을수록 BackupManager가 유리합니다.

server.xml<Cluster> 블록을 추가합니다. 두 Tomcat 서버 모두 동일하게 설정하되, jvmRoute 값만 다르게 줍니다.

XML
<!-- /opt/tomcat/conf/server.xml — Tomcat1 -->
<Server port="8005" shutdown="SHUTDOWN">
  <Service name="Catalina">
    <Engine name="Catalina" defaultHost="localhost" jvmRoute="tomcat1">

      <Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"
               channelSendOptions="8">

        <Manager className="org.apache.catalina.ha.session.DeltaManager"
                 expireSessionsOnShutdown="false"
                 notifyListenersOnReplication="true"/>

        <Channel className="org.apache.catalina.tribes.group.GroupChannel">

          <!-- 멀티캐스트로 클러스터 멤버 발견 -->
          <Membership className="org.apache.catalina.tribes.membership.McastService"
                      address="228.0.0.4"
                      port="45564"
                      frequency="500"
                      dropTime="3000"/>

          <!-- 세션 복제 수신 포트 -->
          <Receiver className="org.apache.catalina.tribes.transport.nio.NioReceiver"
                    address="auto"
                    port="4000"
                    autoBind="100"
                    selectorTimeout="5000"
                    maxThreads="6"/>

          <Sender className="org.apache.catalina.tribes.transport.ReplicationTransmitter">
            <Transport className="org.apache.catalina.tribes.transport.nio.PooledParallelSender"/>
          </Sender>

          <Interceptor className="org.apache.catalina.tribes.group.interceptors.TcpFailureDetector"/>
          <Interceptor className="org.apache.catalina.tribes.group.interceptors.MessageDispatchInterceptor"/>
        </Channel>

        <Valve className="org.apache.catalina.ha.tcp.ReplicationValve" filter=""/>
        <Valve className="org.apache.catalina.ha.session.JvmRouteBinderValve"/>
      </Cluster>

      <Host name="localhost" appBase="webapps">
        <!-- ... -->
      </Host>

    </Engine>
  </Service>
</Server>

Tomcat2는 jvmRoute="tomcat2"로만 바꾸면 됩니다. 나머지는 동일합니다.

클러스터가 동작하려면 애플리케이션의 web.xml<distributable/> 태그가 있어야 합니다. 이 태그가 없으면 Tomcat이 세션을 분산 가능한 형태로 관리하지 않습니다.

XML
<!-- WEB-INF/web.xml -->
<web-app>
  <distributable/>
  <!-- ... -->
</web-app>

멀티캐스트 포트(45564)와 복제 수신 포트(4000)는 방화벽에서 열어야 합니다.

로컬 터미널
# firewalld 환경
firewall-cmd --permanent --add-port=45564/udp
firewall-cmd --permanent --add-port=4000/tcp
firewall-cmd --reload

Nginx Sticky Session 설정

💡개념

ip_hash와 jvmRoute — 로드밸런서 레이어 세션 고정

세션 복제 없이 세션 소실 문제를 빠르게 막아야 할 때 Nginx ip_hash가 현실적인 첫 번째 선택지입니다. 코드나 애플리케이션 설정 변경 없이 Nginx 설정 파일 한 줄로 적용되기 때문에, 긴급 패치나 일정이 촉박한 상황에서도 즉시 투입할 수 있습니다. 다만 NAT 환경에서 트래픽 집중이나 WAS 장애 시 세션 전체 소실 같은 구조적 한계가 있으므로, 근본 해결책보다는 임시 대응으로 사용해야 합니다.

Nginx ip_hash sticky session — 클라이언트 IP 해시로 WAS 고정

DeltaManager를 설정하기엔 일정이 촉박하고, 당장 이번 주 배포에서 세션 소실 문제만 막아야 하는 상황이 있습니다. Nginx 설정 몇 줄로 같은 클라이언트를 항상 같은 WAS로 보내는 것이 ip_hash sticky session입니다. 코드 변경 없이 Nginx 레이어에서 처리하기 때문에 빠르게 적용할 수 있습니다.

세션 복제 없이 로드밸런서 레이어에서 세션 문제를 해결하는 방법입니다. Nginx가 동일한 클라이언트 IP를 항상 같은 Tomcat으로 보내면, 세션이 항상 같은 JVM에 있으므로 소실되지 않습니다.

ip_hash는 클라이언트 IP의 처음 세 옥텟(xxx.xxx.xxx)으로 해시를 계산합니다. upstream 서버 목록이 변경되지 않는 한 같은 클라이언트는 항상 같은 서버로 갑니다.

Nginx
# /etc/nginx/conf.d/tomcat-cluster.conf
upstream tomcat_cluster {
    ip_hash;
    server 10.0.0.1:8080;
    server 10.0.0.2:8080;
}

server {
    listen 80;
    server_name app.example.com;

    location / {
        proxy_pass http://tomcat_cluster;

        proxy_set_header Host              $host;
        proxy_set_header X-Real-IP         $remote_addr;
        proxy_set_header X-Forwarded-For   $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;

        proxy_http_version 1.1;
        proxy_connect_timeout 10s;
        proxy_read_timeout    60s;
    }
}

jvmRoute를 설정하면 JSESSIONID 쿠키가 ABC123XYZ.tomcat1처럼 노드 식별자를 포함합니다. Nginx는 쿠키의 .tomcat1 접미사를 파싱해 해당 노드로 정확히 라우팅할 수 있습니다. ip_hash보다 더 정확한 sticky session이 필요하다면 nginx-sticky-module(쿠키 기반)을 사용합니다.

ip_hash의 한계:

상황문제
사무실 NAT (수백 명이 공인 IP 1개 사용)모든 트래픽이 단일 Tomcat으로 집중
모바일 사용자 (WiFi ↔ LTE 전환)IP가 바뀌면서 다른 노드로 이동, 세션 소실
upstream 서버 추가/제거해시 재계산으로 일부 클라이언트가 다른 서버로 이동
Tomcat 장애해당 노드를 사용하던 세션 전부 소실

이런 한계 때문에 ip_hash는 보조 수단으로 쓰고, 근본 해결책으로 세션 외부화를 선택하는 경우가 많습니다.

Redis 세션 외부화 (spring-session)

💡개념

왜 세션 복제보다 외부화가 더 나은가

세션을 WAS 메모리에 두는 한, WAS 재시작이나 스케일 아웃은 항상 세션 소실 위험을 동반합니다. Redis 외부화는 세션의 소유권을 WAS에서 분리해 이 문제를 구조적으로 해결합니다. 어느 WAS로 요청이 가든 같은 Redis를 읽기 때문에 세션 복제 트래픽도 없고, WAS를 마음대로 재시작하거나 늘려도 사용자 세션이 유지됩니다. Auto Scaling 환경이라면 세션 외부화 없이는 WAS를 탄력적으로 운영하기가 사실상 불가능합니다.

Redis 세션 외부화 — WAS는 세션 ID만 갖고 실제 데이터는 Redis에 저장

세션 복제(DeltaManager)의 근본 문제는 노드가 늘어날수록 복제 트래픽도 늘어난다는 점입니다. 노드가 N개이면 세션 변경 1건당 N-1번 복제가 발생합니다. 또한 WAS 재시작 시 메모리가 초기화되므로 배포 시 세션 소실이 일어납니다.

Redis 외부화는 이 문제를 구조적으로 해결합니다. WAS는 세션 ID(쿠키)만 클라이언트에 보내고, 실제 세션 데이터는 Redis에 저장합니다. 어떤 WAS로 요청이 가도 동일한 Redis를 읽으므로 세션이 항상 일치합니다. WAS를 재시작해도 Redis 데이터는 그대로이므로 세션이 유지됩니다.

Spring Boot 프로젝트 기준 설정입니다.

XML
<!-- pom.xml -->
<dependency>
    <groupId>org.springframework.session</groupId>
    <artifactId>spring-session-data-redis</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
PROPERTIES
# application.properties
spring.session.store-type=redis
spring.redis.host=redis-server
spring.redis.port=6379

# 세션 만료 시간 (초) — 기본값 1800초 (30분)
spring.session.timeout=1800

# Redis 커넥션 풀 설정
spring.redis.lettuce.pool.max-active=8
spring.redis.lettuce.pool.max-idle=8
spring.redis.lettuce.pool.min-idle=2

@EnableRedisHttpSession 어노테이션을 구성 클래스에 추가하면 spring-session이 Tomcat 기본 세션 관리자를 대체합니다.

Java
// SessionConfig.java
@Configuration
@EnableRedisHttpSession(maxInactiveIntervalInSeconds = 1800)
public class SessionConfig {
    // Redis 연결은 application.properties 설정으로 자동 구성됨
}

Redis에 저장된 세션은 spring:session:sessions:SESSION_ID 키로 Hash 자료구조로 보관됩니다. spring:session:expirations:TIMESTAMP로 만료 인덱스도 관리됩니다.

실습 1: 세션 클러스터 구성 확인

1DeltaManager 클러스터 멤버십 로그 확인

Tomcat 시작 후 catalina.out에서 클러스터 관련 로그를 확인합니다. 두 노드가 서로를 발견했다면 Member added 메시지가 나타납니다.

OUTPUT
INFO: Cluster is about to start
INFO: Receiver Server at /10.0.0.1:4000
INFO: Setting cluster member  /10.0.0.2:4000
INFO: Member added:10.0.0.2:4000 to cluster
INFO: Replication member joined: /10.0.0.2:4000

멤버 추가 로그가 보이면 멀티캐스트 통신이 성공한 것입니다. 다음 명령으로 멀티캐스트 포트 수신 여부도 확인합니다.

로컬 터미널
# 멀티캐스트 포트(45564) 수신 확인
ss -ulnp | grep 45564

# 클러스터 복제 포트(4000) 수신 확인
ss -tlnp | grep 4000
grep -i 'cluster\|member\|replication' /opt/tomcat/logs/catalina.out | tail -30
🔍실행 후 확인할 것
  • catalina.out에 'Member added' 메시지가 있는지 확인 — 없으면 멀티캐스트 차단 또는 network 설정 오류
  • ss -ulnp | grep 45564 결과에 java 프로세스가 보이는지 확인
  • ss -tlnp | grep 4000 으로 복제 수신 포트가 열렸는지 확인
  • web.xml에 &lt;distributable/&gt; 태그가 있는지 grep으로 재확인: grep -r 'distributable' /opt/tomcat/webapps/
2Nginx ip_hash sticky session 설정 적용 및 검증

upstream 블록에 ip_hash가 설정됐는지 확인합니다. curl로 같은 IP에서 반복 요청 시 동일한 WAS로만 응답이 와야 합니다.

로컬 또는 서버
# 쿠키를 유지하며 반복 요청 — JSESSIONID 뒤 jvmRoute 확인
curl -v -c /tmp/sess.txt -b /tmp/sess.txt http://app.example.com/login 2>&1 | grep -i 'set-cookie\|jsessionid'

# 예상 출력: Set-Cookie: JSESSIONID=ABC123.tomcat1
# 이후 요청에서도 .tomcat1 이 유지되면 sticky session 동작 중
curl -s -c /tmp/sess.txt -b /tmp/sess.txt http://app.example.com/dashboard -I | grep -i 'server\|via'

Nginx 설정 변경 후에는 반드시 문법 검사 후 reload합니다.

로컬 터미널
nginx -t && systemctl reload nginx
nginx -T 2>/dev/null | grep -A 3 'upstream'
🔍실행 후 확인할 것
  • JSESSIONID 쿠키에 '.tomcat1' 또는 '.tomcat2' 접미사가 있는지 확인 — jvmRoute 설정 증거
  • 같은 쿠키 파일로 반복 요청 시 동일한 노드로만 응답이 오는지 WAS 로그에서 확인
  • nginx -T | grep ip_hash 로 upstream 블록에 ip_hash 지시자가 있는지 재확인
  • nginx -t 에 'syntax is ok', 'test is successful' 두 줄이 모두 나오는지 확인

실습 2: Redis 세션 확인

3Redis에 저장된 세션 목록 조회

애플리케이션에 로그인 후 Redis에 세션이 저장됐는지 확인합니다.

DB 클라이언트
# 저장된 세션 수 확인
redis-cli keys "spring:session:sessions:*" | wc -l

# 특정 세션 상세 확인 (SESSION_ID 자리에 실제 ID 입력)
redis-cli hgetall "spring:session:sessions:SESSION_ID"

# 세션 만료까지 남은 시간(초)
redis-cli ttl "spring:session:sessions:SESSION_ID"

WAS 재기동 전후 세션 유지 여부를 검증합니다.

로컬 또는 서버
# 1) 로그인하여 세션 ID 기록
curl -c /tmp/redis-sess.txt http://app.example.com/login -d "user=test&pass=1234"

# 2) Tomcat 재시작
systemctl restart tomcat

# 3) 같은 세션으로 요청 — 로그인 유지 확인
curl -b /tmp/redis-sess.txt http://app.example.com/dashboard -I | head -5
redis-cli keys 'spring:session:sessions:*' | wc -l
🔍실행 후 확인할 것
  • redis-cli keys 결과에 'spring:session:sessions:' 키가 나타나는지 확인
  • hgetall 출력에 creationTime, lastAccessedTime, sessionAttr 등 세션 필드가 보이는지 확인
  • ttl 값이 양수(>0)인지 확인 — -1이면 만료 설정 누락, -2이면 키가 없음
  • Tomcat 재시작 후 동일 쿠키로 요청 시 HTTP 200 응답이 오는지 확인 — 세션 외부화 성공 증거

트러블슈팅

Tomcat 클러스터 시작 시 멀티캐스트 소켓을 바인딩하지 못하는 오류입니다. address="auto" 설정이 잘못된 인터페이스를 잡았거나, 멀티캐스트를 지원하지 않는 인터페이스에 바인딩하려고 시도하는 경우 발생합니다.

로컬 터미널
# 현재 네트워크 인터페이스와 IP 확인
ip addr show

# 멀티캐스트를 지원하는 인터페이스 확인
ip link show | grep MULTICAST

# Tomcat 클러스터 오류 로그 확인
grep -i 'multicast\|McastService\|Can.t assign' /opt/tomcat/logs/catalina.out | tail -10

address="auto"를 실제 서버 IP로 교체합니다.

XML
<!-- 수정 전 -->
<Receiver address="auto" port="4000" ... />

<!-- 수정 후 — 실제 서버 IP 명시 -->
<Receiver address="10.0.0.1" port="4000" ... />

컨테이너나 가상 인터페이스(docker0, lo)가 여러 개 있을 때 address="auto"가 잘못된 인터페이스를 선택하는 것이 주요 원인입니다.

server.xml<Cluster> 설정을 완료했는데 세션이 복제되지 않는 경우입니다. 가장 흔한 원인은 애플리케이션 web.xml<distributable/> 태그가 없는 것입니다. Tomcat은 이 태그가 있는 애플리케이션만 분산 세션 관리 대상으로 취급합니다.

로컬 터미널
# web.xml에 distributable 태그 확인
find /opt/tomcat/webapps -name "web.xml" -exec grep -l "distributable" {} \;

# 태그가 없다면 수동으로 확인
cat /opt/tomcat/webapps/ROOT/WEB-INF/web.xml | grep -i distributable

# 세션 복제 실패 로그 확인
grep -i 'session\|replicate\|distribute' /opt/tomcat/logs/catalina.out | grep -i 'error\|fail\|warn' | tail -20

web.xml<web-app> 태그 안 어느 위치에든 <distributable/> 한 줄을 추가하고 Tomcat을 재시작합니다. Spring Boot 내장 Tomcat을 사용하면 SpringBootServletInitializer가 자동으로 처리하지만, 외장 Tomcat에 WAR 배포 시에는 수동으로 넣어야 합니다.

Redis 장애 시 spring-session이 세션을 읽지 못해 사용자가 로그아웃되는 증상입니다. 기본 spring-session 설정은 Redis 연결 실패 시 예외를 던지고 세션을 복구하지 않습니다.

DB 클라이언트
# Redis 연결 상태 확인
redis-cli ping

# Redis 연결 거부 로그 확인
grep -i 'redis\|lettuce\|connection refused\|timeout' /var/log/your-app/app.log | tail -20

# Redis 슬레이브 복제 상태 확인 (Sentinel 또는 Cluster 구성 시)
redis-cli info replication | grep -E 'role|connected_slaves|master_host'

단기 대응으로는 Redis Sentinel이나 Redis Cluster로 고가용성을 구성합니다.

PROPERTIES
# application.properties — Redis Sentinel 연결
spring.redis.sentinel.master=mymaster
spring.redis.sentinel.nodes=sentinel1:26379,sentinel2:26379,sentinel3:26379

# 연결 타임아웃과 재시도 설정
spring.redis.timeout=2000
spring.redis.lettuce.pool.max-active=8

운영 환경에서 Redis를 단일 노드로 구성하면 Redis 자체가 SPOF(Single Point of Failure)가 됩니다. WAS 세션을 Redis에 외부화했다면 Redis 고가용성 설계도 함께 완료해야 합니다.

실무 맥락

💼
실무 맥락
현업 패턴

세션 전략 선택 기준 — 트래픽 규모와 인프라 비용에 따른 판단

실제 쇼핑몰이나 금융 서비스에서 WAS 이중화 시 세션 전략을 결정할 때는 세 가지 기준을 봅니다.

1. 트래픽 규모와 노드 수

노드 2~3대, 세션 크기 작음  →  DeltaManager (All-to-All)로 시작
노드 4대 이상, 세션 크기 중간  →  BackupManager 또는 Redis 외부화 검토
노드 수시로 변동 (Auto Scaling)  →  Redis 외부화 필수

Auto Scaling 환경에서 DeltaManager를 사용하면 노드가 추가될 때마다 전체 세션을 새 노드로 복제해야 합니다. 트래픽 증가로 노드를 늘리는 시점에 역설적으로 세션 복제 트래픽이 더 몰리는 문제가 생깁니다. Redis 외부화는 이 문제에서 자유롭습니다.

2. 세션 크기

세션에 사용자 ID와 권한 정보만 담으면 수 KB 이하입니다. 장바구니 전체, 파일 업로드 임시 데이터처럼 수십 KB 이상이면 세션 복제 비용이 급격히 높아집니다. Redis는 In-Memory이므로 대용량 세션도 빠르게 처리하지만, 메모리 비용도 함께 늘어납니다.

3. 배포 전략과 다운타임

서버 터미널
# 무중단 배포(Rolling Deploy) 시나리오
# 1) Nginx upstream에서 tomcat1 제외
# upstream 블록에 'server 10.0.0.1:8080 down;' 추가 후 reload

# 2) tomcat1만 재시작 (세션은 Redis에 있으므로 유지됨)
systemctl restart tomcat1

# 3) tomcat1 복귀
# 'down' 제거 후 reload
nginx -t && systemctl reload nginx

Redis 외부화 없이 DeltaManager + ip_hash 방식에서 Rolling Deploy를 하면, tomcat1 재시작 시 해당 노드의 세션이 일시적으로 소실됩니다. Redis 외부화 후에는 WAS 재기동과 세션 유지가 완전히 분리됩니다.

다음 모듈에서는 Tomcat JVM 튜닝과 GC 로그 분석을 다룹니다.

지식 확인

퀴즈 — 4문제

Q1

Tomcat 클러스터에서 DeltaManager와 BackupManager의 차이로 올바른 것은?

Q2

Nginx ip_hash로 sticky session을 구성하는 이유와 한계로 옳은 것은?

Q3

Redis 세션 외부화의 장점 — WAS 재기동 시 세션이 유지되는 이유는?

Q4

세션 클러스터 구성 후 jvmRoute 설정이 필요한 이유는?

0 / 4 답변

🧪 실습으로 확인하기

Nginx 설치 및 기동

초급

Linux 서버에 Nginx를 설치하고 systemd 서비스로 등록하여 80포트에서 응답하는 상태까지 만든다.

30📋 3단계💻 직접 환경
실습 시작하기 →

이것도 배워보세요

infra-ops중급 · 60
[Infra Ops] SSL/TLS 인증서 형식 변환과 갱신 절차
인프라 서비스 운영 트랙 계속
linux입문 · 30
[Linux] 개발자가 왜 리눅스 서버와 커맨드라인을 반드시 배워야 하는가
Linux 트랙 시작점