Spring Boot 기반 트레이딩 교육 플랫폼 백엔드 API — 가입자 642명+, 피드백 요청 5,300건+ 처리 (2025.12~)
기간: 2025.08 ~ 진행중 | 역할: 백엔드 개발 (BE 2명, FE 1명) | 문서: tradingpt-docs
20개 도메인을 DDD + CQRS 패턴으로 설계하고, NicePay 빌링키 기반 정기결제, OAuth2 이중 인증(카카오/네이버), AWS Multi-AZ 고가용성 인프라를 구축했습니다. k6 부하 테스트 기반 3-Layer 병목 분석과 JPA 최적화로 실서비스 운영 품질을 확보했습니다.
| 지표 | Before | After | 개선율 |
|---|---|---|---|
| 실서비스 운영 | — | 642명+ 가입, 피드백 요청 5,300건+ | 2025.12 오픈 |
| SQL 쿼리 수 | 101개 | 4개 | 96% 감소 |
| p95 응답시간 | 40.7초 | 800ms | 97% 개선 |
| 정기결제 안정성 | — | 100% | 엣지케이스 4개 방어 |
Java 17 Spring Boot 3.3 Spring Security 6 JPA/Hibernate QueryDSL MySQL 8.0 Redis OAuth2 AWS Docker GitHub Actions ShedLock DDD CQRS
1. N+1 쿼리 & HikariCP 커넥션 풀 고갈 — 쿼리 96% 감소 (101→4)
- 문제: 관리자 대시보드 API 1건에 101개 SQL 쿼리 발생, HikariCP 커넥션 풀(max 10) 고갈로 3일간 서비스 불가
- 원인: Customer(1-side) 기준 쿼리 → 모든 연관관계 ToMany → Fetch Join 불가, 루프 내 5개 Repository 호출 (N+1 폭발)
- 해결: N-side(Subscription)에서 시작 → 모든 관계 ToOne 전환, JPQL Fetch Join + IN절 배치 쿼리 + 메모리 조립, 스케줄러 cron 5분 간격 분산
- 성과: 쿼리 101→4 (96%↓), 응답 20s→2s (90%↓), 커넥션 풀 100%→50%
2. REQUIRES_NEW + REPEATABLE_READ 트랜잭션 격리 충돌 — 결제 성공률 0%→100%
- 문제: NicePay 빌링키 등록 성공 후 구독 생성 100% 실패, 특이하게 0원 프로모션은 성공하고 유료 결제만 실패
- 원인: REQUIRES_NEW 자식 TX가 PaymentMethod 커밋 후, 부모 TX의 REPEATABLE_READ 스냅샷에서 재조회 시 stale 데이터 읽음 (MVCC 가시성 문제)
- 해결: PaymentMethod ID 재조회 대신 엔티티 객체를 직접 전달하여 DB 재조회를 근본적으로 우회
- 성과: 결제 성공률 0%→100%, DB 쿼리 25% 감소, 에러 정확도 100%
3. k6 1000 VU 부하 테스트 — 3-Layer 병목 분석 — p95 40.7s→800ms (97%↓)
- 문제: 1000 VU 부하 테스트에서 p95 40.7초, CPU 96%, t3.medium burstable 인스턴스 CPU 크레딧 즉시 소진
- 원인: Layer 1 — BCrypt CPU-bound (60-70%), Layer 2 — HikariCP 커넥션 풀 부족 (20-25%), Layer 3 — RDS IOPS 제한 (10-15%)
- 해결: EC2 t3.medium→c6i.xlarge(compute-optimized), RDS db.t3.micro→db.r6g.large(Graviton2), HikariCP (cores×2)+1 재계산
- 성과: p95 40.7s→800ms (97%↓), TPS 41.7→150-200 (4-5x↑), CPU 96%→40-60%
4. CSRF Cross-Origin Cookie/Header 불일치 — Decorator 패턴으로 에러율 100%→0%
- 문제: SPA(localhost:3000)에서 API(dev.tradingpt.kr)로 모든 POST/PUT/DELETE 요청 403 에러
- 원인: Spring Security 6 기본 CookieCsrfTokenRepository는 Cookie만 전달, SPA는 Response Header에서 토큰을 읽어야 하는데 기본 구현은 미지원
- 해결: Wrapper(Decorator) 패턴으로 HeaderAndCookieCsrfTokenRepository 구현, Cookie + Header 양쪽에 CSRF 토큰 전달
- 성과: CSRF 에러율 100%→0%, 기존 코드 변경 0줄 (Decorator), SPA 완전 호환
주요 아키텍처 의사결정 — 7개 기술 선택과 근거
| 항목 | 선택 | 핵심 근거 |
|---|---|---|
| 인프라 | Multi-AZ | 99.95% SLA, Public/Private Subnet 분리, 장애 격리 |
| 배포 | Blue/Green | 다운타임 0, 롤백 5분, 배포시간 67% 단축 (GitHub Actions + CodeDeploy) |
| 컨테이너 | EC2+ASG | YAGNI 원칙, 연 $1,236 절감 (vs EKS $345/월), Docker 패키징으로 ECS 마이그레이션 경로 확보 |
| 인증 | Redis Session | JWT Blacklist 역설 해결 (토큰 무효화에 결국 Redis 필요 → Stateless 장점 상실), 동시접속 제어 네이티브 지원 |
| 스케줄링 | ShedLock | 테이블 1개 (vs Spring Batch 6개, Quartz 11개), @SchedulerLock 어노테이션 1줄 추가 |
| 모니터링 | CloudWatch | AWS 네이티브 통합, EC2/ALB/RDS/ElastiCache 메트릭 통합 |
| DDD Aggregate | Shared Kernel | 독립 Aggregate, customer_id + 기간축 복합 키로 논리적 연결 |
| 프로젝트 | 설명 | 기술 |
|---|---|---|
| Indayvidual | 맞춤형 일정 관리 솔루션 | Spring Boot |
| Momento | 가족 대화 플랫폼 · 99.985% 성능 개선 (60s→9ms) | Spring Boot, Kotlin, OpenAI GPT-4, Redis |
| Love Keeper | 커플 소통 플랫폼 · AWS ECS Fargate MSA | Spring Boot, Flutter, AWS ECS |
| Mody | 맞춤형 스타일 서비스 | Spring Boot |
| nugget | 시각장애인 보행 보조 · Google Solution Challenge Top 100 | Flutter, TensorFlow Lite |
| chalim | 메뉴판 번역 서비스 | Flutter |



