본문
ECS Fargate Multi-Agent 환경에서 Auto Scaling 시 세션 유실 문제 해결기
ECS Fargate로 Multi-Agent 구조의 서비스를 운영하다 보면 예상치 못한 순간에 문제가 찾아옵니다.CPU 사용률이 80%를 넘으면서 Auto Scaling이 작동했는데, 정작 사용자들의 세션이 끊겨버리는 상황이 발생했습니다.
"분명 부하 분산을 위해 설정한 건데, 왜 세션이 날아가는 거지?" 원인을 파악하고 나니, 이건 단순히 설정 문제가 아니라 Stateful한 Multi-Agent 구조의 본질적인 한계였습니다. 문제를 어떻게 분석했고, 최종적으로 어떤 방향을 선택했는지 기록해 봅니다.
문제 상황: 스케일링이 되면 세션이 사라진다
실제로 일어난 일
- 특정 Task의 CPU가 80%를 넘어가면서 알람 발생
- Auto Scaling 정책이 정상 작동해 새 Task가 추가됨
- 그런데 기존에 연결되어 있던 사용자 세션이 유실됨
- Multi-Agent 특성상 대화 컨텍스트까지 같이 날아감
스케일링 자체는 제대로 동작했지만, 정작 사용자 경험은 좋지 않았습니다.
첫 번째 시도: 그냥 스펙을 올려보자
가장 먼저 떠오른 생각은 간단했습니다. "CPU가 부족하니까 Task 스펙을 올리면 되지 않을까?"
애초에 80% 임계치에 덜 도달하도록 만들면, 스케일링 자체를 줄일 수 있을 테니까요.
그런데 막상 스펙을 올리려고 하니 벽에 부딪혔습니다.
Fargate의 최대 제한
- CPU: 최대 16 vCPU
- Memory: 최대 120GB
제가 담당하던 서비스는 이미 이 한계에 가까운 스펙을 사용하고 있었습니다. 여러 AI Agent가 동시에 돌아가다 보니 리소스 소모가 상당했거든요. 더 이상 스펙 업그레이드로는 해결이 어렵다는 걸 알게 되었습니다.
두 번째 시도: ALB Sticky Session을 켜면 되지 않을까
그럼 세션을 특정 Task에 고정시키면 어떨까요? ALB에 Sticky Session 기능이 있으니, 이걸 활성화해 보기로 했습니다.
# ALB Target Group Stickiness 설정
stickiness {
type = "lb_cookie"
cookie_duration = 86400 # 24시간
enabled = true
}
사용자가 한 번 연결된 Task에 계속 붙어있으면 세션도 유지될 거라고 생각했습니다.
그런데 Multi-Agent 환경에서는 예상치 못한 문제가 생겼습니다
- 부하가 한쪽으로 쏠림: 특정 Task에만 사용자가 몰리면서 로드밸런싱이 제대로 안 됨
- Agent 협업이 어려움: 여러 Agent가 협력해서 작업하는 구조인데, 특정 Task에만 고정되니 비효율적
- 장애가 전파됨: 고정된 Task에 문제가 생기면 그 Task의 모든 사용자가 영향받음
- Scale-in 할 때 문제: Task를 줄이려고 하면 해당 Task의 세션이 다 날아감
Sticky Session은 일반적인 웹 서비스에는 괜찮지만, 제가 맡은 서비스처럼 분산된 Agent 구조에서는 적합하지 않았습니다.
그래서 찾아본 근본적인 해결책
방안 1: 그냥 ECS EC2로 갈아타기
이렇게 하면 좋은 점
- Fargate처럼 인스턴스 타입 제약이 적음 (r7i.24xlarge 같은 큰 인스턴스도 쓸 수 있음)
- CPU/메모리를 훨씬 더 많이 쓸 수 있음
- 인스턴스 단위로 관리하니 성능 예측이 더 쉬움
하지만 문제도 있음
- AMI 관리, 패치, 보안 설정 등 신경 쓸 게 많아짐
- Auto Scaling Group도 따로 관리해야 함
- EC2가 뜨는 시간 때문에 스케일링이 좀 느림
- 금융권이다 보니 EC2 보안 규정 맞추는 것도 일
고민되는 부분
Fargate를 쓰는 이유가 운영 편의성 때문인데, EC2로 가면 그걸 다 포기하는 셈입니다. 특히 금융권에서 EC2 직접 관리하려면 챙겨야 할 게 한두 가지가 아니거든요.

방안 2: Redis로 세션 관리하기 (최종 선택)
구조를 이렇게 바꾸면
사용자 → ALB → ECS Task (아무거나) → Redis (ElastiCache)
↓
세션 데이터 저장소
실제로 구현할 내용
- ElastiCache Redis 셋업:
- Multi-AZ로 구성해서 한쪽 죽어도 괜찮게
- Cluster Mode 켜서 성능 확보
- 세션 데이터를 분리:
- 사용자 세션 → Redis
- Agent 컨텍스트 → Redis
- 대화 히스토리 → Redis + DB(RDS/DynamoDB)
- Connection Pooling 적용:
- Redis 연결 재사용해서 성능 올리기
- Timeout 적절하게 설정
이렇게 하면 좋은 점
- Stateless 구조: 어느 Task로 가든 세션 유지됨
- 확장이 자유로움: Task 개수 제약 없이 Auto Scaling 가능
- 장애가 격리됨: 한 Task 죽어도 다른 사용자한테 영향 없음
- Multi-Agent 친화적: Agent끼리 상태 공유하기 쉬움
- Fargate 장점 유지: 서버리스 편의성 그대로
코드로 보면 이런 느낌
import redis
import json
class SessionManager:
def __init__(self):
self.redis_client = redis.Redis(
host='your-elasticache-endpoint',
port=6379,
decode_responses=True,
socket_keepalive=True,
socket_connect_timeout=5,
max_connections=50
)
def save_session(self, session_id: str, data: dict):
"""세션 저장"""
self.redis_client.setex(
f"session:{session_id}",
86400, # 24시간 유지
json.dumps(data)
)
def get_session(self, session_id: str):
"""세션 가져오기"""
data = self.redis_client.get(f"session:{session_id}")
return json.loads(data) if data else None
def save_agent_context(self, session_id: str, agent_id: str, context: dict):
"""Agent 컨텍스트 저장"""
key = f"agent:{session_id}:{agent_id}"
self.redis_client.setex(key, 3600, json.dumps(context))
비용 측면에서도
- ElastiCache r7g.large: 월 약 156달러
- EC2 r7i.4xlarge로 전환: 월 약 730달러
- Fargate + Redis 조합이 더 저렴함
결론: Redis 기반 세션 관리로 결정
여러 가지를 검토해 본 결과, Redis로 세션을 중앙에서 관리하는 방식이 제가 맡은 서비스 상황에 잘 맞았습니다.
이 방식을 선택한 이유
- Fargate의 운영 편의성을 그대로 가져갈 수 있음
- Stateless 아키텍처 구현 가능
- Multi-Agent 구조에 적합함
- 비용도 합리적
- 금융권 보안 규정 맞추기도 상대적으로 수월
앞으로 할 일
- ElastiCache Redis Cluster 구성 (Multi-AZ)
- Session Manager 구현하고 테스트
- Connection Pool 튜닝
- CloudWatch + Redis metrics로 모니터링 설정
- Failover 상황 시뮬레이션
가끔은 단순히 스펙을 올리는 것보다, 구조를 바꾸는 게 더 나은 해결책일 때가 있습니다. 처음엔 "그냥 CPU 더 주면 되지 않나?" 싶었는데, 결과적으로는 아키텍처를 개선하는 방향으로 가게 되었네요.
댓글