Skip to content

About

An e-commerce platform for premium groceries and fresh food.

Resources

Stars

1 star

Watchers

0 watching

Forks

 
 

Repository files navigation

BeGroom

성능 목표

예상 트래픽 기준: DAU 100K, Peak CCU 30K, Peak 1.5K TPS
인프라 설계: 비즈니스 로직 및 DB 처리용 r6i.large (2 Core, 16GB RAM), 알림 로직 처리용 m7g.medium (1 Core, 4GB RAM) x 2.


대표 문제 해결 사례

1. [실시간 알림] 커널 튜닝 & 선언적 직렬화를 통한 SSE 커넥션 메모리 최적화

전체적인 아키텍처

flowchart LR
    Client["Client"] -->|SSE Keep-Alive| App["Notification Server"]
    App --> Emitter["SseEmitter"]
    Emitter --> Socket["TCP Socket"]
    Socket --> Kernel["OS Kernel<br/>tcp_rmem / tcp_wmem"]
    App --> Serialize["@JsonSerialize<br/>응답 최소화"]
Loading

문제 원인

  • C20K 동시 SSE 커넥션 환경에서 힙·네이티브 메모리가 선형 증가하며 OOM이 발생함.
  • OS 기본 소켓 버퍼(tcp_rmem/tcp_wmem ≈ 128KB)가 커넥션당 과도하게 할당되어 메모리 상한이 빨리 소진됨.
  • Spring SseEmitter 기본 설정과 과도한 JSON 페이로드가 커넥션당 응답·버퍼 비용을 키움.

해결 과정

  • Linux tcp_rmem / tcp_wmem을 SSE Keep-Alive 트래픽 특성에 맞게 하향 튜닝해 커넥션당 커널 버퍼 점유를 줄임.
  • 알림 DTO에 @JsonSerialize 기반 선언적 직렬화를 적용해 필드·중첩 객체를 최소화한 경량 이벤트로 송출함.
  • SseEmitter 타임아웃·재연결(Last-Event-ID) 정책을 명시해 유휴 커넥션 누수와 재전송 비용을 통제함.
  • Emitter 저장소를 멤버 단위 ConcurrentHashMap으로 구성해 브로드캐스트 시 O(1) 조회·정리 경로를 확보함.

결과

  • 커넥션당 메모리 사용량 약 40KB 감소.
  • 동일 리소스 기준 최대 동시 SSE 커넥션 수 3.1배 증가.
  • C20K 부하 테스트에서 OOM 0건, 안정적인 Keep-Alive 유지율 확보.

2. [주문 및 상품] 톰캣 튜닝과 커넥션 풀 최적화

전체적인 아키텍처

flowchart TB
    Clients["Clients<br/>C10K Traffic"] --> Tomcat["Tomcat<br/>max-connections"]
    Tomcat --> Threads["Worker Threads"]
    Threads --> App["Order / Product API"]
    App --> Pool["HikariCP<br/>maximumPoolSize"]
    Pool --> DB["MySQL"]
Loading

문제 원인

  • C10K 트래픽 급증 시 P99 응답이 timeout 상한(약 30s)까지 밀리며 사용자 체감 지연이 커짐.
  • Tomcat 기본 max-connections(8192)이 동시 수용량을 넘지 못해 요청이 대기열에 적체됨.
  • HikariCP 풀 경합으로 DB 커넥션 대기 Pending thread가 폭증하고 dial tcp: i/o timeout이 발생함.

해결 과정

  • Tomcat max-connections를 15000으로 상향해 급증 트래픽의 동시 수용 한계를 확장함.
  • HikariCP maximumPoolSize를 CPU 코어 수 기반 공식으로 재산정해 풀 과다·과소로 인한 경합을 줄임.
  • 주문·상품 API의 트랜잭션 범위를 점검해 커넥션 점유 시간을 줄이고 풀 반환 지연을 완화함.
  • 스레드·풀 지표를 모니터링하며 Pending thread와 timeout 비율이 안정화될 때까지 재조정함.

결과

  • P99 응답시간 30s → 1.2s.
  • 부하 테스트에서 dial tcp: i/o timeout 에러율 0%.
  • C10K 동시 요청 환경에서도 Pending thread 폭증 없이 안정적 처리량 유지.

3. [시스템 인프라] 기능 기반 서버 분리로 MSA 아키텍처 구축

전체적인 아키텍처

flowchart LR
    Client["Client"] --> ALB["ALB<br/>API Gateway"]
    ALB -->|"구독 / SSE"| Noti["Notification WAS x2"]
    ALB -->|"주문·결제 등"| Main["Main WAS"]
    Main -->|"publish"| Redis["Redis Pub/Sub"]
    Redis -->|"broadcast"| Noti
    Main --> DB["MySQL"]
    Noti --> Emitter["SseEmitter<br/>로컬 커넥션"]
Loading

문제 원인

  • SSE 커넥션이 메모리를 독점해 알림 발생 시 주문·결제 등 핵심 기능 성능에 악영향이 생김.
  • 모놀리스 구조에서 부가 기능(알림)이 메인 기능에 필요한 RAM까지 점유하는 주객전도 상황이 발생함.
  • OS Send buffer 처리 속도와 단일 인스턴스 커넥션 수용 한계로 C50K 확장에 병목이 생김.

해결 과정

  • TCP 소켓·FD는 특정 WAS 커널에만 존재 가능함을 확인하고, Emitter를 외부 저장소에 공유하는 구조를 배제함.
  • 알림 WAS를 독립 분리하고 Spring Profile(main / notification)로 Publisher·Subscriber 빈을 분기함.
  • Main WAS는 DB 반영 후 Redis notification-topic에 publish하고, 알림 WAS는 Pub/Sub으로 수신해 로컬 Emitter에 전송함.
  • AWS ALB로 API Gateway를 구성해 SSE 구독은 알림 서버, 그 외 API는 Main WAS로 라우팅하고 Mesh·Cascading Failure를 완화함.

결과

  • 알림 서버 대당 약 15,000 커넥션, 합산 약 30,000 동시 SSE 구독 유지에 성공함.
  • Main WAS 메모리를 주문·결제 등 비즈니스 로직에 확보하고, SSE 메모리 독점에 의한 상호 간섭을 제거함.
  • OS Send buffer 부하를 인스턴스 단위로 분산해 커넥션 생성 지연을 완화하고, 단일 장애 지점 없는 고가용성 구조를 확보함.

About

An e-commerce platform for premium groceries and fresh food.

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages