기간: 2024.12.09 ~ 2024.12.20
아키텍처
프로젝트 개요
주요 기능
선착순 쿠폰 발급 기능(시퀀스 다이어그램)
개발 목표
사용한 기술
ERD (Entity-Relationship Model)
Kafka 설정
패키지 구조
API 문서
성능 테스트 및 결과
시스템 포트 설정
프로젝트 관련 GitHub 리포지토리
목표 : 대규모 트래픽을 처리할 수 있는 쿠폰 시스템 설계 및 구현.
4. 선착순 쿠폰 발급 기능(시퀀스 다이어그램)
3. Produce 실패(쿠폰 발급 이벤트 전송 실패)
EDA 기반 시스템 설계
Kafka 와 Redis 를 활용하여 Event-Driven Architecture (EDA) 기반의 시스템 설계 및 구현 학습.
실시간 대규모 트래픽 처리
선착순 쿠폰 시스템을 통해 단시간 내 발생하는 대규모 트래픽을 효율적으로 처리 하고, 데이터 흐름과 분산 시스템의 특성을 이해.
실시간 모니터링 및 분석
Grafana 와 Pinpoint 를 적용하여 애플리케이션 성능 모니터링 및 분산 시스템 트랜잭션 추적을 실습.
Prometheus 기반 메트릭 수집 과 APM 분석 도구 활용 능력 강화.
성능 테스트 및 최적화 학습
JMeter 를 활용한 부하 테스트 및 병목 구간 분석.
실시간 대규모 요청 처리에 대한 성능 최적화 방안 을 학습
분류
사용한 기술
Backend
Spring Boot 3.x, Java 17, Spring Data JPA, Lombok, Validation, REST API
Database
MySQL, Redis
Messaging & Streaming
Kafka 2.x, Zookeeper, Kafka-UI
Containerization
Docker
Build & Dependency Management
Gradle
Monitoring & Observability
Prometheus, Grafana, Prometheus Micrometer, Spring Boot Actuator
Exporters
mysql-exporter, redis-exporter, kafka-exporter
APM (Application Performance Management)
Pinpoint
Testing & API Documentation
JUnit, JMeter, Swagger (springdoc-openapi)
Logging
Logback (MDC 기반 traceId 설정, UUID를 사용한 요청별 고유 식별자 생성)
7. ERD (Entity-Relationship Model)
Coupon 테이블 : 쿠폰의 기본 정보를 저장.
ID: 쿠폰의 기본 키 (자동 증가).
TITLE: 쿠폰의 제목.
QUANTITY: 쿠폰의 총 수량.
START_DATE, END_DATE: 쿠폰 시작 및 종료일.
CREATED_AT: 쿠폰 생성일.
CouponAssignLog 테이블 : 쿠폰 발급 이력을 저장.
ID: 쿠폰 발급 기록의 기본 키 (자동 증가).
UUID: 중복 방지 키 , 쿠폰 발급 요청의 고유 식별자.
COUPON_ID: 쿠폰의 외래 키. (Coupon 테이블의 ID와 연결)
2. UUID를 unique key로 사용한 이유
Kafka Producer에서 enable.idempotence=true 옵션을 통해 멱등성을 활성화하더라도, 중복 요청 이 발생할 가능성이 존재합니다.
중복 발급 방지 를 위해, 쿠폰 발급 요청마다 고유한 UUID 를 생성하여 이를 unique key로 지정했습니다.
UUID를 사용함으로써, 동일한 요청이 여러 번 처리되는 경우에도 한 번만 발급 되도록 보장할 수 있습니다.
Kafka 브로커 서버 : 3대
min.insync.replicas=2(최소 2개의 복제본이 동기화된 상태에서만 메시지가 성공적으로 전송)
Coupon-Assign (쿠폰 발급 이벤트)
Coupon-Assign-DLT (쿠폰 발급 실패 이벤트)
Producer 설정
데이터 무결성 보장
enable.idempotence=true (멱등성 활성화)
acks=all (모든 복제본 동기화 완료 후 응답)
배치 및 전송 최적화
linger.ms=100ms (배치 처리 대기 시간)
batch.size=1MB (배치 처리 최대 크기)
재시도 및 타임아웃
최대 재시도 횟수: 5회
재시도 간격: 1초
요청 타임아웃: 10초
에러 처리
쿠폰 발급 실패 시 : 메시지는 Dead Letter Queue(Coupon-Assign-DLT)로 전송.
Coupon-Assign (배치 처리)
Batch Listener 활성화
동시 처리(Concurrency): 3
최대 폴링 레코드 수: 500
Offset 설정
auto.offset.reset=earliest (가장 오래된 메시지부터 소비)
에러 처리
Exponential Backoff (초기 간격 1초, 2배 증가, 최대 5회 재시도)
실패 메시지는 Dead Letter Queue(Coupon-Assign-DLT)로 전송
Coupon-Assign-DLT (개별 처리)
Batch Listener 비활성화
Offset 설정
auto.offset.reset=earliest (가장 오래된 메시지부터 소비)
CouponSystem
├── docker - compose # Docker Compose 관련 설정 디렉토리 .
│ ├── docker - compose - database . yml # 데이터베이스 관련 Docker Compose 설정 파일 .
│ ├── docker - compose - kafka . yml # Kafka 클러스터를 설정하기 위한 Docker Compose 파일 .
│ ├── docker - compose - kafka - ui . yml # Kafka UI를 설정하기 위한 Docker Compose 파일 .
│ ├── docker - compose - monitoring . yml # Prometheus와 Grafana 기반의 모니터링을 설정하기 위한 Docker Compose 파일 .
│ └── docker - compose - ngrinder . yml # 성능 테스트를 위한 nGrinder Docker Compose 파일 .
├── pinpoint - agent - 2.5 .4 # Pinpoint Agent 파일 .
├── pinpoint - docker - 2.5 .3 # Pinpoint 서버 설정 및 Docker 관련 파일이 포함된 디렉토리 .
└── src
├── main
│ ├── java
│ │ └── com
│ │ └── gio
│ │ └── couponsystem
│ │ │ CouponSystemApplication . java # 애플리케이션의 진입점으로 , Spring Boot 실행 클래스 .
│ │ │
│ │ ├── config
│ │ │ CouponConfig . java # 초기 Redis에 쿠폰 개수를 설정하는 클래스 .
│ │ │ JpaAuditingConfig . java # JPA의 감사 ( Auditing ) 기능 설정 클래스 ( 생성일 , 수정일 자동 관리 ) .
│ │ │ KafkaProducerConfig . java # Kafka 프로듀서의 설정을 정의한 클래스 .
│ │ │ KafkaTopicConfig . java # Kafka 토픽 설정을 정의한 클래스 .
│ │ │ MDCLoggingFilter . java # MDC를 사용하여 요청마다 고유 traceId를 생성하고 로그에 추가하는 필터 .
│ │ │ MetricConfig . java # Prometheus를 위한 메트릭 수집 설정 클래스 .
│ │ │ ProducerConfigDebug . java # Kafka 프로듀서 설정 디버깅을 위한 클래스 .
│ │ │ SwaggerConfig . java # Swagger API 문서화를 위한 설정 클래스 .
│ │ │
│ │ ├── conpon
│ │ │ ├── controller
│ │ │ │ CouponController . java # 쿠폰과 관련된 API 요청을 처리하는 컨트롤러 .
│ │ │ │ CouponSwaggerController . java # Swagger 설정을 분리하기 위한 인터페이스로 , 쿠폰 API 명세를 정의 .
│ │ │ │
│ │ │ ├── converter
│ │ │ │ ObjectToStringConverter . java # 객체를 문자열로 변환하는 유틸리티 클래스 .
│ │ │ │
│ │ │ ├── domain
│ │ │ │ Coupon . java # 쿠폰 엔티티 클래스 .
│ │ │ │ CouponAssignLog . java # 쿠폰 할당 로그 엔티티 클래스 .
│ │ │ │
│ │ │ ├── dto
│ │ │ │ CouponCreateRequest . java # 쿠폰 생성 요청 데이터를 담는 DTO .
│ │ │ │ CouponCreateResponse . java # 쿠폰 생성 응답 데이터를 담는 DTO .
│ │ │ │ CouponQueryResponse . java # 쿠폰 조회 응답 데이터를 담는 DTO .
│ │ │ │
│ │ │ ├── repository
│ │ │ │ CouponProducer . java # 쿠폰 발급 Kafka 프로듀서 클래스 .
│ │ │ │ CouponRepository . java # 쿠폰 데이터를 관리하는 JPA 레포지토리 .
│ │ │ │
│ │ │ ├── service
│ │ │ │ CouponService . java # 쿠폰 비즈니스 로직을 처리하는 서비스 클래스 .
│ │ │ │
│ │ │ └── validator
│ │ │ CouponValidator . java # 쿠폰 데이터 유효성 검증 로직 .
│ │ │ Validator . java # 유효성 검증 커스텀 어노테이션
│ │ │
│ │ ├── event
│ │ │ CouponAssignEvent . java # 쿠폰 할당 이벤트 클래스 .
│ │ │
│ │ ├── exception
│ │ │ CustomException . java # 사용자 정의 예외 클래스 .
│ │ │ ExceptionCode . java # 애플리케이션에서 사용하는 예외 코드 정의 .
│ │ │ GlobalExceptionHandler . java # 글로벌 예외 처리 핸들러 클래스 .
│ │ │ ServerExceptionResponse . java # 서버 예외 응답을 정의한 클래스 .
│ │ │ ValidationExceptionResponse . java # 유효성 검증 실패 응답을 정의한 클래스 .
│ │ │
│ │ └── redis
│ │ RedisRepository . java # Redis와 상호작용하는 클래스 .
│ │
│ └── resources
│ application . yml # 애플리케이션 설정 파일 .
│ data . sql # 초기 데이터를 삽입하는 SQL 파일 .
│ logback - spring . xml # Logback 로그 설정 파일 .
│ prometheus . yml # Prometheus 설정 파일 .
│
└── test
├── java
│ └── com
│ └── gio
│ └── couponsystem
│ └── conpon
│ ├── controller
│ │ CouponControllerTest . java # CouponController에 대한 통합 테스트 클래스 .
│ │
│ └── service
│ CouponServiceTest . java # CouponService에 대한 통합 테스트 클래스 .
│
└── resources
application . yml # 테스트 환경의 애플리케이션 설정 파일 .
테스트 구성 :
총 200개의 쓰레드(유저) : 각 유저가 100번의 요청 을 수행.
목표 : 20,000개의 쿠폰 발급 요청을 시뮬레이션하여 성능 측정.
테스트 결과 :
평균 응답 시간 : 102ms
에러율 : 0%
TPS (초당 트랜잭션 처리량) : 1712.0 TPS
최대 응답 시간 : 279ms
표준편차 : 57.89ms
CPU 사용량 :
System CPU Usage : 테스트 시 시스템 CPU 사용량 100%에 도달. 이는 로컬 환경에서 부하가 발생했기 때문이며, 성능적으로 정확한 측정은 어려운 부분이 있지만, 부하가 예상보다 잘 처리됨.
Spring CPU Usage : Spring 프로세스 CPU 사용량은 비교적 낮았으며, 예상보다 성능을 잘 유지함.
Consumer Group Lag :
Lag 현상 : 테스트 초기에는 일부 lag이 쌓였지만, Consumer 서버에서 정상적으로 처리 되어 lag 없이 완료됨.
MySQL QPS :
최대 QPS : 1.72k 로 MySQL에서의 쿼리 처리량을 안정적으로 처리함.
Spring API 요청 처리량 :
최대 요청 처리량 : 216 요청/초 를 처리함. 이는 대규모 트래픽 환경에서 Spring API가 잘 동작하고 있음을 확인.
쿠폰 발급 개수 :
Redis : coupon:1 키에서 20,000개의 쿠폰이 정상적으로 0으로 처리됨.
MySQL : Coupon_Assign_Log 테이블에 20,000개의 쿠폰이 정상적으로 저장됨.
메트릭 :
쿠폰 발급 개수 : Prometheus 메트릭을 통해 20,000개 의 쿠폰 발급 확인
MySQL Coupon_Assign_Log 테이블 쿠폰 발급 내역
서비스 이름
설명
주소
Kafka Broker 1
Kafka 첫 번째 브로커
localhost:9092
Kafka Broker 2
Kafka 두 번째 브로커
localhost:9093
Kafka Broker 3
Kafka 세 번째 브로커
localhost:9094
Zookeeper
Kafka Zookeeper 서비스
localhost:32181
서비스 이름
설명
주소
MySQL Container
MySQL 데이터베이스 서비스
localhost:3306
MySQL Test Container
MySQL 테스트 데이터베이스 서비스
localhost:3307
Redis Container
Redis 데이터베이스 서비스
localhost:6379