프로젝트 목록
Backend & Infra · 2026.04 - 2026.05 · 팀 프로젝트

First Ticket - MSA 티켓 예매 플랫폼

Tech Stack

Java 21 Spring Boot Spring Cloud Gateway Keycloak PostgreSQL Redis Kafka QueryDSL AWS ECS Fargate Docker Grafana GitHub Actions

주요 기능

  • Keycloak ROPC 기반 회원가입 · 로그인 · 토큰 재발급
  • Redis JTI 블랙리스트 + Refresh Token Rotation
  • Gateway 인증 필터 - 헤더 위조 차단 후 사용자 컨텍스트 주입
  • L1 Caffeine + L2 Redis 2단 블랙리스트 캐시
  • Eureka 서비스 디스커버리 · Config Server 설정 관리
  • HOST 권한 신청 · 승인 (HostRequest Aggregate)
  • QueryDSL 기반 관리자 전용 사용자 검색 API
  • Resilience4j Circuit Breaker · Bulkhead · Zipkin 분산 추적

성과

  • 블랙리스트 조회 스파이크 24회 → 1회 (-95.8%)
  • GET /users/me TPS 1,720 — Little's Law 예측 대비 오차 1%, 응답 37ms → 11ms (-70%)
  • 로그인 TPS 175 → 1,568 (+796%), 응답 135ms → 63ms (-53%)
  • BulkheadFullException 4,917건 → 0건, Circuit Breaker CLOSED 유지
  • 비밀번호 변경 후 남는 고아 세션 0건 (RFC 7009 즉시 revoke)

상세내용

대기열로 트래픽을 흡수하고, 분산락으로 선점 좌석을 직렬화하고, Kafka Saga 로 결제 실패를 보상하는 구조입니다. 6개 서비스가 Spring Cloud Gateway · Eureka · Config Server 위에 올라가고, 모든 요청의 진입점인 Gateway 에서 인증·인가·보안을 단일 흐름으로 처리합니다. 배포는 AWS ECS Fargate 에 GitHub Actions CI/CD 로 이어집니다.

Keycloak 이 발급한 JWT 는 만료 전 강제 무효화가 불가능합니다. 로그아웃·비밀번호 변경 후에도 탈취된 토큰이 유효한 문제를 Redis JTI 블랙리스트로, 탈취된 Refresh Token 재사용을 Rotation 으로 해결했습니다. 짧은 AT TTL 만 쓰는 안과 서버 세션 안은 각각 UX 저하와 Stateless 이점 상실로 기각했고, 로그아웃 후 최대 5초(L1 TTL) 지연을 감수하는 쪽을 택했습니다.

트러블슈팅

요청 1건마다 Redis 조회 - vuser 70 구간에서 1,400 TPS 스파이크

원인
모든 요청이 Gateway 에서 Redis 내 blacklist:{jti} 를 조회하다 보니, 초당 처리량이 그대로 Redis 호출량이 됐습니다. 실제로 블랙리스트에 걸리는 토큰은 1% 미만임에도 전량을 조회하고 있었습니다.
해결
Caffeine L1 캐시(TTL 5s)를 우선 조회하고 Cache Miss 일 때만 Redis 로 내려가게 바꿔 조회 24회 → 1회 (-95.8%). 로그아웃 후 최대 5초 지연은 AT TTL(15분) 대비 0.3% 라 수용했습니다.

vuser 50 구간에서 503 에러 및 TPS 가 0 으로 떨어지는 현상

원인
Resilience4j Bulkhead 의 maxConcurrentCalls 가 25 로 묶여 있었습니다. 동시 호출이 한도를 넘자 BulkheadFullException 이 즉시(elapsed 0ms) 발생했고, 이 예외를 Circuit Breaker 가 실패로 집계해 sliding window 실패율이 50% 를 넘겨 OPEN 으로 전환됐습니다.
해결
한도를 200 으로 올려 BulkheadFullException 4,917건 → 0건, Circuit Breaker 는 CLOSED 를 유지했습니다.

로그인 TPS 175 에서 정체, 응답 135ms

원인
부하테스트 분석 결과 지연의 97% 가 Keycloak ROPC 호출이었습니다. Gateway 1ms 미만, User Service 5ms 미만인데 Keycloak 왕복만 약 130ms 였습니다.
해결
at-cache:{SHA-256(lower(email))} 키로 Redis AT 캐시를 도입해 TPS 175 → 1,568 (+796%), 응답 135ms → 63ms (-53%). 이메일을 해시로 써서 PII 평문 저장을 피했습니다.

DB 커넥션 대기로 응답이 지연되는 현상

원인
HikariCP 풀 기본값 10 인데 vuser 는 50 이라서 구조적으로 부족했습니다. 게다가 connection-timeout 이 30초라 대기가 그대로 응답 지연으로 쌓였습니다.
해결
Little's Law(L = λ × W)로 필요 커넥션을 산정해 풀을 50 으로, timeout 은 3초 fast-fail 로 조정했습니다. GET /users/me TPS 1,720 으로 예측 대비 오차 1%, 응답 37ms → 11ms (-70%).
AWS 배포 아키텍처 — ALB 를 거쳐 Gateway 가 6개 마이크로서비스로 라우팅하고, Eureka·Config Server 가 서비스 디스커버리와 설정을 담당합니다. RDS 는 서비스별 스키마로 분리했고 Keycloak·Redis·Kafka·Prometheus·Grafana·Zipkin 은 EC2 컨테이너로 운영합니다.

기여도 · 6인 백엔드 팀 - User/Auth 도메인 · API Gateway · Eureka 설계 및 구현

“AI시대, AI가 대체할 수 없는 책임질 수 있는 개발자가 되겠습니다.”