Skip to content

TEAM-RediClaim/coupon-backend

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

128 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

🎟️ Coupon Backend System

λŒ€κ·œλͺ¨ νŠΈλž˜ν”½ μƒν™©μ—μ„œλ„ μ•ˆμ •μ μœΌλ‘œ μ„ μ°©μˆœ 쿠폰을 λ°œκΈ‰ν•˜κΈ° μœ„ν•œ λ°±μ—”λ“œ μ‹œμŠ€ν…œμž…λ‹ˆλ‹€. **MSA(Microservices Architecture)**λ₯Ό 기반으둜 ν•˜λ©°, νŠΈλž˜ν”½ 폭주둜 μΈν•œ μ„œλ²„ μž₯μ• λ₯Ό λ°©μ§€ν•˜κΈ° μœ„ν•΄ **λŒ€κΈ°μ—΄ μ‹œμŠ€ν…œ(Traffic Shaping)**이 μ μš©λ˜μ–΄ μžˆμŠ΅λ‹ˆλ‹€.

πŸ—οΈ μ•„ν‚€ν…μ²˜ 및 λͺ¨λ“ˆ ꡬ성 (Architecture)

이 ν”„λ‘œμ νŠΈλŠ” λŒ€κ·œλͺ¨ νŠΈλž˜ν”½μ„ μ•ˆμ •μ μœΌλ‘œ μ²˜λ¦¬ν•˜λŠ” 것을 μ‹œμž‘μœΌλ‘œ, ν–₯ν›„ ν™•μž₯ κ°€λŠ₯ν•œ 쿠폰 ν”Œλž«νΌμœΌλ‘œ λ°œμ „μ‹œν‚€λŠ” 것을 λͺ©ν‘œλ‘œ ν•©λ‹ˆλ‹€. 각 λͺ¨λ“ˆμ€ MSA(Microservices Architecture) 원칙에 따라 μ² μ €νžˆ 역할이 λΆ„λ¦¬λ˜μ–΄ μžˆμŠ΅λ‹ˆλ‹€.

λͺ¨λ“ˆλͺ… μ—­ν•  및 μ±…μž„ (Role & Responsibility) 기술 μŠ€νƒ
gate-app [Traffic Shaping & Flow Control]
- λŒ€κ·œλͺ¨ μ§„μž… νŠΈλž˜ν”½μ˜ 버퍼링 및 μœ λŸ‰ μ œμ–΄
- Redis ZSet 기반의 λŒ€κΈ°μ—΄ μ‹œμŠ€ν…œ κ΅¬ν˜„
- Downstream μ„œλΉ„μŠ€ 보호λ₯Ό μœ„ν•œ Throttling
Redis, Kafka Producer
Spring Boot
issuer-app [Coupon Issuance Processor]
- λŒ€κΈ°μ—΄μ„ ν†΅κ³Όν•œ μš”μ²­μ— λŒ€ν•œ μ‹€μ§ˆμ  λ°œκΈ‰ νŠΈλžœμž­μ…˜ 처리
- λ™μ‹œμ„± μ œμ–΄ 및 데이터 무결성 보μž₯
- (ν–₯ν›„) 이쒅 μ„œλΉ„μŠ€ κ°„ λΆ„μ‚° νŠΈλžœμž­μ…˜ μ£Όκ΄€
Kafka Consumer, MySQL (JPA)
Spring Boot
core [Domain Core & Shared Kernel]
- 쿠폰 λ„λ©”μΈμ˜ 핡심 λΉ„μ¦ˆλ‹ˆμŠ€ 둜직 및 μ •μ±… μ •μ˜
- λͺ¨λ“ˆ κ°„ κ³΅μœ λ˜λŠ” DTO, Event 객체, 곡톡 μœ ν‹Έλ¦¬ν‹°
- ν”Œλž«νΌ ν™•μž₯을 μœ„ν•œ 곡톡 κ·œμ•½ 관리
Java 17 (Library)

πŸš€ ν–₯ν›„ λ‘œλ“œλ§΅ (Roadmap)

ν˜„μž¬λŠ” κ³ νŠΈλž˜ν”½ μ•ˆμ •μ„± 확보에 μ§‘μ€‘ν•˜κ³  있으며, μ μ§„μ μœΌλ‘œ μ•„λž˜ 기술적 κ³Όμ œλ“€μ„ μˆ˜ν–‰ν•˜μ—¬ ν”Œλž«νΌμ˜ 완성도λ₯Ό 높일 κ³„νšμž…λ‹ˆλ‹€.

  1. Phase 1: μ•ˆμ •μ„± 확보 (Current)

    • λŒ€κΈ°μ—΄ μ‹œμŠ€ν…œ(Gate)을 ν†΅ν•œ νŠΈλž˜ν”½ μ œμ–΄ 및 μ„œλ²„ 보호
    • Kafkaλ₯Ό ν™œμš©ν•œ 비동기 처리 및 데이터 μœ μ‹€ λ°©μ§€
  2. Phase 2: ν”Œλž«νΌ 고도화

    • λ‹€μ–‘ν•œ 쿠폰 μ •μ±…(ν• μΈμœ¨, μœ νš¨κΈ°κ°„, 쀑볡 λ°œκΈ‰ λ“±)을 Core λͺ¨λ“ˆμ— μ§‘μ•½
    • λ©€ν‹° ν…Œλ„ŒνŠΈ(Multi-tenant) ꡬ쑰 κ³ λ €
  3. Phase 3: MSA 심화 (Distributed System)

    • λΆ„μ‚° νŠΈλžœμž­μ…˜ 처리: Saga Pattern 등을 λ„μž…ν•˜μ—¬ 결제/포인트 λ“± 타 λ§ˆμ΄ν¬λ‘œμ„œλΉ„μŠ€μ™€μ˜ μ •ν•©μ„± 보μž₯
    • 데이터 일관성: CDC(Change Data Capture) 및 Outbox Pattern λ„μž… κ²€ν† 

πŸ”„ 데이터 흐름 (Data Flow)

  1. μœ μ € μ§„μž…: POST /enqueue β†’ Gate (Redis λŒ€κΈ°μ—΄ 적재)
  2. λŒ€κΈ° 및 폴링: μœ μ €λŠ” GET /rankλ₯Ό 톡해 본인의 순번 확인 (Waiting)
  3. μŠ€μΌ€μ€„λ§: Gate λ‚΄λΆ€ μŠ€μΌ€μ€„λŸ¬κ°€ μ„€μ •λœ 속도(TPS)에 맞좰 μœ μ €λ₯Ό Processing μƒνƒœλ‘œ λ³€κ²½ 및 Kafka둜 λ©”μ‹œμ§€ λ°œν–‰
  4. λ°œκΈ‰ 처리: Issuerκ°€ Kafka λ©”μ‹œμ§€λ₯Ό μ†ŒλΉ„(Consume)ν•˜μ—¬ MySQL에 쿠폰 λ°œκΈ‰ 기둝 μ €μž₯

βš™οΈ ν™˜κ²½ μ„€μ • (Configuration)

λ³΄μ•ˆμ„ μœ„ν•΄ application.yml νŒŒμΌμ€ Git에 ν¬ν•¨λ˜μ–΄ μžˆμ§€ μ•ŠμŠ΅λ‹ˆλ‹€. ν”„λ‘œμ νŠΈ 싀행을 μœ„ν•΄ 각 λͺ¨λ“ˆμ˜ src/main/resources κ²½λ‘œμ— application.yml을 직접 생성해야 ν•©λ‹ˆλ‹€.

1. gate-app μ„€μ • μ˜ˆμ‹œ

spring:
  data:
    redis:
      host: localhost # K8s 배포 μ‹œ μ„œλΉ„μŠ€λͺ… (예: redis.rediclaim.svc.cluster.local)
      port: 6379
  kafka:
    bootstrap-servers: localhost:9092 # K8s 배포 μ‹œ μ„œλΉ„μŠ€λͺ…
    producer:
      key-serializer: org.apache.kafka.common.serialization.StringSerializer
      value-serializer: org.springframework.kafka.support.serializer.JsonSerializer
  # Gate μ „μš© μ„€μ •
  gate:
    event-ids: 1001, 1002
    dispatch-mode: kafka
    dispatch-per-second: 100 # μ΄ˆλ‹Ή μ²˜λ¦¬λŸ‰ μ œν•œ

2. issuer-app μ„€μ • μ˜ˆμ‹œ

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/rediclaim_db # K8s 배포 μ‹œ μ„œλΉ„μŠ€λͺ…
    username: root
    password: root
    driver-class-name: com.mysql.cj.jdbc.Driver
  jpa:
    hibernate:
      ddl-auto: update
  kafka:
    bootstrap-servers: localhost:9092
    consumer:
      group-id: coupon-group

πŸš€ 개발 및 배포 μ›Œν¬ν”Œλ‘œμš° (Workflow)

CI/CD(GitHub Actions) 없이 둜컬 ν™˜κ²½μ—μ„œ 직접 λΉŒλ“œν•˜μ—¬ Kubernetes(Kind)에 λ°°ν¬ν•˜λŠ” μ ˆμ°¨μž…λ‹ˆλ‹€.

μ „μ œ 쑰건

  • Docker Desktop μ‹€ν–‰ 쀑
  • Docker Hub 둜그인 μ™„λ£Œ (docker login)
  • Kubernetes ν΄λŸ¬μŠ€ν„°(Kind) μ‹€ν–‰ 쀑

πŸ“¦ Step 1. 도컀 이미지 λΉŒλ“œ (Build)

Gradle의 bootBuildImageλ₯Ό μ‚¬μš©ν•˜μ—¬ 각 λͺ¨λ“ˆλ³„λ‘œ 이미지λ₯Ό λΉŒλ“œν•©λ‹ˆλ‹€. (Dockerfile λΆˆν•„μš”)

# Gate λͺ¨λ“ˆ λΉŒλ“œ (νƒœκ·Έλͺ…은 본인 ν™˜κ²½μ— 맞게 μˆ˜μ •)
./gradlew :gate-app:bootBuildImage --imageName=seongjunnoh/gate-app:latest

# Issuer λͺ¨λ“ˆ λΉŒλ“œ
./gradlew :issuer-app:bootBuildImage --imageName=seongjunnoh/issuer-app:latest

⬆️ Step 2. 도컀 ν—ˆλΈŒ ν‘Έμ‹œ (Push)

Kind ν΄λŸ¬μŠ€ν„°κ°€ 이미지λ₯Ό 내렀받을 수 μžˆλ„λ‘ 도컀 ν—ˆλΈŒμ— μ—…λ‘œλ“œν•©λ‹ˆλ‹€.

docker push seongjunnoh/gate-app:latest
docker push seongjunnoh/issuer-app:latest

πŸ”„ Step 3. μΏ λ²„λ„€ν‹°μŠ€ 배포 및 μž¬μ‹œμž‘ (Deploy)

μ΅œμ‹  이미지λ₯Ό λ°˜μ˜ν•˜κΈ° μœ„ν•΄ νŒŒλ“œλ₯Ό μž¬μ‹œμž‘ν•©λ‹ˆλ‹€. (imagePullPolicy: Always μ„€μ • ν•„μˆ˜)

# YAML μ„€μ • 적용 (졜초 1회 ν˜Ήμ€ λ³€κ²½ μ‹œ)
kubectl apply -f k8s/gate-app-deployment.yml
kubectl apply -f k8s/issuer-app-deployment.yml

# 둀아웃 μž¬μ‹œμž‘ (이미지 κ°±μ‹ )
kubectl rollout restart deployment/gate-app -n rediclaim
kubectl rollout restart deployment/issuer-app -n rediclaim

βœ… Step 4. 배포 확인

# 배포 μƒνƒœ λͺ¨λ‹ˆν„°λ§
kubectl rollout status deployment/gate-app -n rediclaim

# μ‹€μ‹œκ°„ 둜그 확인
kubectl logs -n rediclaim -l app=gate-app -f

πŸ—οΈ 인프라 ꡬ좕 (Infrastructure)

둜컬 Kind ν΄λŸ¬μŠ€ν„°μ— ν•„μš”ν•œ 미듀웨어λ₯Ό μ„€μΉ˜ν•©λ‹ˆλ‹€.

# 1. λ„€μž„μŠ€νŽ˜μ΄μŠ€ 생성
kubectl create namespace rediclaim

# 2. 인프라 배포 (Redis, Kafka, MySQL)
kubectl apply -f k8s/redis.yml
kubectl apply -f k8s/kafka.yml
kubectl apply -f k8s/mysql.yml

Note: RedisλŠ” μ„±λŠ₯ ν…ŒμŠ€νŠΈλ₯Ό μœ„ν•΄ appendonly no, save "" μ˜΅μ…˜μœΌλ‘œ 섀정될 수 μžˆμŠ΅λ‹ˆλ‹€. (운영 ν™˜κ²½μ—μ„œλŠ” Persistence μ„€μ • ν•„μš”)


πŸ§ͺ ν…ŒμŠ€νŠΈ (Load Testing)

K6λ₯Ό μ‚¬μš©ν•˜μ—¬ λŒ€κΈ°μ—΄ μ‹œμŠ€ν…œμ˜ μ„±λŠ₯κ³Ό μ•ˆμ •μ„±μ„ κ²€μ¦ν•©λ‹ˆλ‹€.

Gate λͺ¨λ“ˆ 톡합 ν…ŒμŠ€νŠΈ (k6-gate-polling.js)

μœ μ €κ°€ λŒ€κΈ°μ—΄ μ§„μž… -> 순번 λŒ€κΈ°(Polling) -> μ²˜λ¦¬μ—΄ 이동(Processing) ν•˜λŠ” 전체 과정을 κ²€μ¦ν•©λ‹ˆλ‹€.

# λŒ€μ‹œλ³΄λ“œμ™€ ν•¨κ»˜ μ‹€ν–‰
K6_WEB_DASHBOARD=true k6 run scripts/k6-gate-polling.js

μ£Όμš” 검증 ν•­λͺ©:

  • κΈ°λŠ₯ μ •ν•©μ„±: λͺ¨λ“  μœ μ €κ°€ μ—λŸ¬ 없이 Processing μƒνƒœλ‘œ μ „ν™˜λ˜λŠ”κ°€?
  • λŒ€κΈ° μ‹œκ°„(UX): μœ μ €κ°€ μ‹€μ œ μž…μž₯ν•˜κΈ°κΉŒμ§€ κ±Έλ¦¬λŠ” μ‹œκ°„ (waiting_time μ§€ν‘œ)
  • μ•ˆμ •μ„±: 슀파이크 νŠΈλž˜ν”½ λ°œμƒ μ‹œ μ„œλ²„κ°€ λ‹€μš΄λ˜μ§€ μ•ŠλŠ”κ°€?

πŸ› οΈ Tech Stack

  • Language: Java 17
  • Framework: Spring Boot 3.4.4
  • Database: MySQL 8.0, Redis 7.x
  • Message Queue: Apache Kafka 3.8
  • Build Tool: Gradle
  • Deployment: Docker, Kubernetes (Kind)
  • Testing: K6 (Load Testing), JUnit 5

About

Open-source One Click Rapid Coupon Issuance System

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors