λκ·λͺ¨ νΈλν½μ μμ μ μΌλ‘ μ²λ¦¬νλ 리μ‘ν°λΈ λκΈ°μ΄ μμ€ν
Flowλ ν°μΌν , μκ°μ μ² λ± μκ°μ μΌλ‘ λͺ°λ¦¬λ λκ·λͺ¨ νΈλν½μ ν¨μ¨μ μΌλ‘ μ²λ¦¬νκΈ° μν μ€μκ° λκΈ°μ΄ μμ€ν μ λλ€.
λ¬Έμ : ν°μΌν
μκ°μ μλ§ λͺ
μ΄ λμμ μ μ β μλ² λ€μ΄ π₯
ν΄κ²°: λκΈ°μ΄λ‘ μ μ
μ μ μ΄ β μμ μ μΈ μλΉμ€ μ΄μ β
- π λ ΌλΈλ‘νΉ λ¦¬μ‘ν°λΈ μν€ν μ² - Spring WebFlux κΈ°λ° κ³ μ±λ₯ μ²λ¦¬
- β‘ Redis Sorted Set νμ© - μμ κ΄λ¦¬ λ° λΉ λ₯Έ μ‘°ν (O(log N))
- π VIP μ°μ μμ μ²λ¦¬ - μ°μ μμλ³ μ°¨λ± μ§μ νμ©
- π μ€μκ° ν΅κ³ λ° λͺ¨λν°λ§ - λκΈ° μΈμ, μ²λ¦¬μ¨ μ€μκ° μΆμ
- π μ΄λ ₯ κ΄λ¦¬ - λͺ¨λ λκΈ°μ΄ μ΄λ²€νΈ μΆμ λ° κ°μ¬
- π Redis Pub/Sub μλ¦Ό - μ€μκ° μν λ³κ²½ μλ¦Ό
- β° μλ μ€μΌμ€λ§ - μ£ΌκΈ°μ μΌλ‘ μ¬μ©μ μ§μ νμ©
- π¨ λκΈ°μ€ μΉ UI - μ¬μ©μ μΉνμ μΈ λκΈ° νλ©΄
- Java 21 - μ΅μ LTS, Virtual Thread μ§μ
- Spring Boot 3.4.4 - μ΅μ μμ ν λ²μ
- Spring WebFlux - 리μ‘ν°λΈ λ ΌλΈλ‘νΉ μΉ νλ μμν¬
- Project Reactor - 리μ‘ν°λΈ μ€νΈλ¦Ό ꡬν
- Redis 7.0 - In-Memory λ°μ΄ν° μ μ₯μ
- Sorted Set: μμ κ΄λ¦¬
- Pub/Sub: μ€μκ° μλ¦Ό
- List: μ΄λ ₯ κ΄λ¦¬
- Embedded Redis - ν μ€νΈ νκ²½
- JUnit 5 - λ¨μ ν μ€νΈ νλ μμν¬
- Reactor Test - 리μ‘ν°λΈ μ€νΈλ¦Ό ν μ€νΈ
- StepVerifier - λΉλκΈ° κ²μ¦
- TDD - ν μ€νΈ μ£Όλ κ°λ° λ°©λ²λ‘
Java 21
Redis 7.0+# macOS (Homebrew)
brew install redis
redis-server
# Docker
docker run -d -p 6379:6379 redis:7-alpine# νλ‘μ νΈ ν΄λ‘
git clone https://github.com/your-username/flow.git
cd flow
# λΉλ λ° μ€ν
./gradlew bootRun# λκΈ°μ€ μ μ
open http://localhost:9010/waiting-room?queue=default&user_id=1
# API ν
μ€νΈ
curl "http://localhost:9010/api/v1/queue?user_id=1&queue=default"# μΌλ° μ¬μ©μ λ±λ‘
POST /api/v1/queue?user_id=100&queue=default
# VIP μ¬μ©μ λ±λ‘ (μ°μ μμ)
POST /api/v1/queue?user_id=101&queue=default&is_vip=trueGET /api/v1/queue/rank?user_id=100&queue=defaultPOST /api/v1/queue/allow?queue=default&count=10GET /api/v1/queue/statistics?queue=default# νΉμ μ¬μ©μ μ΄λ ₯
GET /api/v1/queue/history?user_id=100&queue=default
# μ 체 λκΈ°μ΄ μ΄λ ₯
GET /api/v1/queue/history/all?queue=default&count=50- μ²λ¦¬λ: 30 TPS
- νκ· μλ΅ μκ°: 52ms
- μ±κ³΅λ₯ : 100%
μμΈν μ±λ₯ ν μ€νΈ κ²°κ³Όλ PERFORMANCE.mdλ₯Ό μ°Έκ³ νμΈμ.
- λ ΌλΈλ‘νΉ I/Oλ‘ μμ² κ°μ λμ μ°κ²° μ²λ¦¬
- μ μ μ€λ λλ‘ λμ μ²λ¦¬λ λ¬μ±
- λ°±νλ μ λ₯Ό ν΅ν μμ μ μΈ μ€νΈλ¦Ό μ²λ¦¬
- Redis Sorted Set: O(log N) μμ μ‘°ν
- νμμ€ν¬ν κΈ°λ° μ€μ½μ΄: 곡μ ν λκΈ° μμ 보μ₯
- VIP μ€νμ : μ°μ μμ μ²λ¦¬ ꡬν
- ν μ΄λ¦μΌλ‘ λ©ν°ν λμ μ§μ
- μν νμ₯ κ°λ₯ν 무μν μ€κ³
- μ΄λ²€νΈ κΈ°λ° λμ¨ν κ²°ν©
- λκΈ°μ΄ μ©λ μ ν - 무ν λκΈ° λ°©μ§
- TTL μ€μ - μλ λ§λ£λ‘ λ©λͺ¨λ¦¬ κ΄λ¦¬
- μ΄λ ₯ κ΄λ¦¬ - κ°μ¬ λ° λ¬Έμ μΆμ
- ν΅κ³ API - μ΄μ λͺ¨λν°λ§
- π ν¬νΈν΄λ¦¬μ€ - νλ‘μ νΈ μμΈ μκ° (μ·¨μ μ©)
- ποΈ μν€ν μ² - μμ€ν μ€κ³ λ° κ΅¬μ‘°
- π‘ API λͺ μΈμ - μ 체 API λ¬Έμ
- π€ κΈ°μ μ μμ¬κ²°μ - κΈ°μ μ ν λ°°κ²½
- β‘ μ±λ₯ ν μ€νΈ - λΆν ν μ€νΈ κ²°κ³Ό
./gradlew test# κΈ°λ³Έ λΆν ν
μ€νΈ
./scripts/load-test.sh
# μ€νΈλ μ€ ν
μ€νΈ
./scripts/stress-test.sh
# VIP μ°μ μμ ν
μ€νΈ
./scripts/vip-test.shscheduler:
enable: true # μλ μ§μ
νμ© νμ±ν
max-allow-user-count: 3 # ν λ²μ μ§μ
νμ©ν μ΅λ μ¬μ©μ μ
queue:
max-capacity: 100 # λκΈ°μ΄ μ΅λ μ©λ (0=무μ ν)
ttl-seconds: 600 # λκΈ°μ΄ μλ λ§λ£ μκ° (μ΄)
token:
max-age-seconds: 300 # ν ν° μ ν¨ μκ°flow/
βββ src/
β βββ main/
β β βββ java/com/nhn/flow/
β β β βββ controller/ # REST API 컨νΈλ‘€λ¬
β β β βββ service/ # λΉμ¦λμ€ λ‘μ§
β β β βββ dto/ # μμ²/μλ΅ κ°μ²΄
β β β βββ exception/ # μμΈ μ²λ¦¬
β β βββ resources/
β β βββ application.yml # μ€μ νμΌ
β β βββ templates/ # Thymeleaf ν
νλ¦Ώ
β βββ test/ # ν
μ€νΈ μ½λ
βββ scripts/ # λΆν ν
μ€νΈ μ€ν¬λ¦½νΈ
βββ docs/ # νλ‘μ νΈ λ¬Έμ
μ΄ νλ‘μ νΈλ₯Ό ν΅ν΄ λ€μμ νμ΅νμ΅λλ€:
- β Spring WebFluxλ₯Ό νμ©ν 리μ‘ν°λΈ νλ‘κ·Έλλ°
- β Redisμ λ€μν μλ£κ΅¬μ‘° νμ© (Sorted Set, List, Pub/Sub)
- β λκ·λͺ¨ λμμ± μ²λ¦¬ λ° μ±λ₯ μ΅μ ν
- β TDD κΈ°λ° κ°λ° λ° ν μ€νΈ μλν
- β μ€λ¬΄ μ€μ¬μ μλ¬ νΈλ€λ§ λ° κ²μ¦
- β RESTful API μ€κ³ λ° λ¬Έμν
νλ‘μ νΈμ λν μ§λ¬Έμ΄λ μ μμ¬νμ΄ μμΌμλ©΄ μ΄μλ₯Ό λ±λ‘ν΄μ£ΌμΈμ.
This project is licensed under the MIT License.
λ§λ μ¬λ | ν¬νΈν΄λ¦¬μ€
β μ΄ νλ‘μ νΈκ° λμμ΄ λμλ€λ©΄ Starλ₯Ό λλ¬μ£ΌμΈμ!