k6 ๊ธฐ๋ฐ ๋ถํ ํ ์คํธ ๋ฐ์ดํฐ, ์๋๋ฆฌ์ค, ์คํฌ๋ฆฝํธ ๋ชจ์์ ๋๋ค. ๋๊ธฐ์ด(Queue) ํญ์ฃผ ์๋๋ฆฌ์ค๋ฅผ ๋ค๋ฃน๋๋ค.
- 01. ๊ฐ์ ๋ฐ ๋ชฉ์
- 02. ์ํคํ ์ฒ
- 03. ํ ์คํธ ํด ์ ์
- 04. ๋น ๋ฅธ ์์ ๋ฐ ๋๋ ํ ๋ฆฌ ๊ตฌ์กฐ
- 05. ์๊ตฌ ์ฌํญ ๋ฐ ์ฃผ์์
- 06. ๋ถํ ์๋๋ฆฌ์ค
- 07. TPS๋ณ ๋ถํ ์งํ
- 08. ๊ฒฐ๋ก ๋ฐ ํ๋ํฌ์ธํธ
์ด ๋ฌธ์๋ FairTicket-BE์ ๋๊ธฐ์ด(Queue) ์์คํ ์ ๋ํ ๋ถํ ํ ์คํธ ๊ฐ์ด๋์ ๋๋ค. k6๋ฅผ ์ฌ์ฉํ์ฌ ์คํ ์งํ ๋์ ์ ์์ด ๋ชฐ๋ฆด ๋ ๋๊ธฐ์ด์ด ๊ฒฌ๋๋์ง ํ์ธํฉ๋๋ค.
์ฃผ์ ๋ชฉ์ :
- ๋๊ธฐ์ด ์์คํ ์ ์ฑ๋ฅ ํ๊ณ ํ์
- Redis Sorted Set/ํ ํฐ ๋ฐ๊ธ ์ง์ฐ ์ธก์
- Rate Limit(429) ๋ฐ์ ๊ตฌ๊ฐ ํ์ธ
- ํ์์์/์๋ฌ์จ ๋ชจ๋ํฐ๋ง
- Spring JVM ๋ฉํธ๋ฆญ(CPU, Heap Memory, Garbage Collection) ๋ชจ๋ํฐ๋ง
- TPS๋ณ ์ฑ๋ฅ ํน์ฑ ๋ถ์
๋ถํ ํ ์คํธ๋ Docker Compose๋ก ๋์ด FairTicket-BE ์คํ์ ๋ํด, ๋ก์ปฌ ํธ์คํธ์์ k6/์คํฌ๋ฆฝํธ๋ก ์์ฒญ์ ๋ณด๋ด๋ ๊ตฌ์กฐ์ ๋๋ค. ๋ฉํธ๋ฆญ์ Prometheus / Grafana๋ก ์์งยท์กฐํํฉ๋๋ค.
flowchart LR
subgraph host["๋ก์ปฌ ํธ์คํธ"]
direction TB
scripts["load-test/scripts<br/>(seed-db, prepare-tokens,<br/>verify-env, run-queue)"]
k6["k6<br/>queue-flow.js"]
data["data/queue<br/>(tokens, config.env)"]
scripts --> data
data --> k6
end
subgraph compose["Docker Compose (FairTicket-BE)"]
direction TB
subgraph app["์ ํ๋ฆฌ์ผ์ด์
"]
be["fairticket-be<br/>:8080"]
pg["PostgreSQL<br/>fairticket-postgres"]
redis["Redis<br/>fairticket-redis"]
be --> pg
be --> redis
end
subgraph monitoring["๋ชจ๋ํฐ๋ง"]
prometheus["Prometheus<br/>:9090"]
grafana["Grafana<br/>:3000"]
prometheus -->|scrape| be
grafana -->|์ฟผ๋ฆฌ| prometheus
end
end
scripts -->|"curl (signup/login)"| be
scripts -->|"docker exec psql<br/>(seed-schedule.sql)"| pg
k6 -->|"HTTP ๋ถํ<br/>(enter/status/heartbeat)"| be
- ํธ์คํธ:
load-test/์คํฌ๋ฆฝํธ๋ก ํ ํฐ ์์ฑยทDB ์๋ยทํ๊ฒฝ ๊ฒ์ฆ ํ, k6๊ฐ ๋๊ธฐ์ด API์ ๋ถํ๋ฅผ ๊ฑธ์ต๋๋ค. - ์ ํ๋ฆฌ์ผ์ด์ : API ์๋ฒ(fairticket-be), PostgreSQL, Redis. BE๊ฐ DB/Redis์ ํต์ ํฉ๋๋ค.
- ๋ชจ๋ํฐ๋ง: Prometheus๊ฐ BE์
/actuator/prometheus๋ฉํธ๋ฆญ์ ์์งํฉ๋๋ค. Grafana(localhost:3000)์์ ๋ฉํธ๋ฆญ ๋์๋ณด๋๋ฅผ ์กฐํํ ์ ์์ต๋๋ค. - ์ ์: k6ยทcurl์
BASE_URL(๊ธฐ๋ณธhttp://localhost:8080)๋ก ์์ฒญํ๋ฉฐ, seed-db๋docker exec๋ก ์ปจํ ์ด๋ ๋ด๋ถ Postgres์ SQL์ ์ ์ฉํฉ๋๋ค.
์ด ํ๋ก์ ํธ๋ ์ด๊ธฐ์ wrk ๊ธฐ๋ฐ์ผ๋ก ์์๋์์ผ๋, k6๋ก ์ ํ๋์์ต๋๋ค. ์ ํ ์ด์ ์ ๊ณผ์ ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
-
์๋ต ๋ณธ๋ฌธ ์ฒ๋ฆฌ ๋ถ์์
- wrk๋ ์ฑ๋ฅ ์ต์ ํ๋ก
init()ํธ์ถ ํresponseํจ์๊ฐ ์ ์๋์ง ์์ผ๋ฉด body๋ฅผ ํ์ฑํ์ง ์์ต๋๋ค. responseํจ์๊ฐ ์ ์๋์ด ์์ด๋ wrk ๋ฒ์ /์ค์ ์ ๋ฐ๋ผ ํธ์ถ๋์ง ์์ ์ ์์ต๋๋ค.body๊ฐnil์ด๊ฑฐ๋ ๋น ๊ฐ์ผ ์ ์์ด READY ์ํ ๊ฐ์ง๊ฐ ๋ถ์์ ํฉ๋๋ค.
- wrk๋ ์ฑ๋ฅ ์ต์ ํ๋ก
-
์ค๋ ๋๋ณ ๋ณ์ ๋๊ธฐํ ๋ฌธ์
- wrk๋ ๋ฉํฐ์ค๋ ๋ ๊ธฐ๋ฐ์ผ๋ก ๋์ํ๋ฉฐ, ์ค๋ ๋๋ณ๋ก ๋ ๋ฆฝ์ ์ธ Lua ์ํ๋ฅผ ์ฌ์ฉํฉ๋๋ค.
- ์ ์ญ ๋ณ์ ๋๊ธฐํ๊ฐ ์ด๋ ค์ ์ ํํ ๋ฉํธ๋ฆญ ์ง๊ณ๊ฐ ์ด๋ ต์ต๋๋ค.
-
๋๋ฒ๊น ๋ฐ ์ ์ง๋ณด์ ์ด๋ ค์
- Lua ์คํฌ๋ฆฝํธ๋ ๋๋ฒ๊น ์ด ์ด๋ ต๊ณ , ๋ก๊น ๊ธฐ๋ฅ์ด ์ ํ์ ์ ๋๋ค.
- ๋ณต์กํ ๋ก์ง ๊ตฌํ์ด ์ด๋ ต๊ณ ์ฝ๋ ๊ฐ๋ ์ฑ์ด ๋จ์ด์ง๋๋ค.
-
์๋ต ๋ณธ๋ฌธ ์ฒ๋ฆฌ ์์ ์ฑ
- JavaScript ๊ธฐ๋ฐ์ผ๋ก ์๋ต ๋ณธ๋ฌธ ํ์ฑ๊ณผ ๊ฒ์ฆ์ด ์์ ์ ์ ๋๋ค.
JSON.parse()๋ฅผ ์ฌ์ฉํ์ฌ ์ ํํ READY ์ํ ๊ฐ์ง๊ฐ ๊ฐ๋ฅํฉ๋๋ค.
-
๊ฐ๋ ฅํ ๋ฉํธ๋ฆญ ์์ง
- ์ปค์คํ
๋ฉํธ๋ฆญ(
Counter,Trend,Gauge)์ ์ฝ๊ฒ ์ ์ํ ์ ์์ต๋๋ค. - ์ฒดํฌ(
check)์ ์๊ณ๊ฐ(thresholds) ์ค์ ์ผ๋ก ์๋ ๊ฒ์ฆ์ด ๊ฐ๋ฅํฉ๋๋ค. - ์์ธํ ๋ฉํธ๋ฆญ์ ๊ธฐ๋ณธ ์ ๊ณตํฉ๋๋ค (p50, p95, p99 ๋ฑ).
- ์ปค์คํ
๋ฉํธ๋ฆญ(
-
๋๋ฒ๊น ๋ฐ ์ ์ง๋ณด์ ์ฉ์ด
- JavaScript๋ก ์์ฑ๋์ด ๊ฐ๋ฐ์์๊ฒ ์น์ํฉ๋๋ค.
console.log()๋ก ์ฌ์ด ๋ก๊น ์ด ๊ฐ๋ฅํฉ๋๋ค.- ์ฝ๋ ๊ฐ๋ ์ฑ๊ณผ ์ ์ง๋ณด์์ฑ์ด ๋ฐ์ด๋ฉ๋๋ค.
-
ํ์ฅ์ฑ
- Cloud ์คํ ์ง์ (k6 Cloud)
- ๊ณ ๊ธ ์๋๋ฆฌ์ค ์ง์ (scenarios, executors)
- ํฅํ ํ์ฅ์ ์ ๋ฆฌํฉ๋๋ค.
Lua โ JavaScript ๋ณํ:
queue-flow.luaโqueue-flow.jsqueue-enter.luaโqueue-enter.jsqueue-status.luaโqueue-status.jsqueue-heartbeat.luaโqueue-heartbeat.js
์ฃผ์ ๋ณ๊ฒฝ์ฌํญ:
- wrk์
wrk.format()โ k6์http.get(),http.post() - wrk์
response()ํจ์ โ k6์check()ํจ์์ ์๋ต ๋ณธ๋ฌธ ์ง์ ํ์ฑ - wrk์
delay()ํจ์ โ k6์sleep()ํจ์ - wrk์ ์ค๋ ๋/์ฐ๊ฒฐ ๊ฐ๋ โ k6์ Virtual Users (VUs) ๊ฐ๋
ํ๊ฒฝ ๋ณ์ ๋ณ๊ฒฝ:
WRK_THREADS,WRK_CONNECTIONS,WRK_DURATION์ ๊ฑฐK6_VUS,K6_DURATION์ถ๊ฐ
ํ ํฐ ํ์ผ ํ์ ๋ณ๊ฒฝ:
- Lua ํ์(
tokens_generated.lua) ์ ๊ฑฐ - JSON ํ์(
tokens.json) ์ถ๊ฐ (k6์open()ํจ์ ์ฌ์ฉ)
Bash ์คํฌ๋ฆฝํธ ๋ณ๊ฒฝ:
04-run-queue-{100|500|1000|2000}.sh: wrk ๋ช ๋ น์ด๋ฅผ k6 ๋ช ๋ น์ด๋ก ๋ณ๊ฒฝ- ํ๊ฒฝ ๋ณ์ ์ ๋ฌ ๋ฐฉ์ ๋ณ๊ฒฝ (
--envํ๋๊ทธ ์ฌ์ฉ)
ํ ํฐ ์ค๋น ์คํฌ๋ฆฝํธ ์ ๋ฐ์ดํธ:
02-prepare-tokens.sh: JSON ํ์ ํ ํฐ ํ์ผ ์์ฑ ์ถ๊ฐ
- README.md: wrk ์ธ๊ธ์ ๋ชจ๋ k6๋ก ๋ณ๊ฒฝ
- ๋๋ ํ ๋ฆฌ ๊ตฌ์กฐ์์
.luaํ์ผ ์ ๊ฑฐ - k6 ๋ช ๋ น์ด ์์๋ก ์ ๋ฐ์ดํธ
- โ ์๋ต ๋ณธ๋ฌธ ์ฒ๋ฆฌ ์์ ์ฑ ํฅ์
- โ READY ์ํ ๊ฐ์ง ์ ํ๋ ๊ฐ์
- โ ์ปค์คํ ๋ฉํธ๋ฆญ์ผ๋ก ์์ธํ ๋ถ์ ๊ฐ๋ฅ
- โ ์ฝ๋ ๊ฐ๋ ์ฑ ๋ฐ ์ ์ง๋ณด์์ฑ ํฅ์
- โ ํฅํ ํ์ฅ์ฑ ํ๋ณด
cd load-test
# 1) ์ค์ ๋ก๋ (์ ํ์ฌํญ, ์คํฌ๋ฆฝํธ ๋ด๋ถ์์ ์๋ ๋ก๋๋จ)
source data/config.env
# 2) DB ์๋ โ ์ค์ผ์ค์ "์ด๋ฏธ ์คํ" ์ํ๋ก (2xx ์๋ต์ ์ํด)
# Docker ๋๋ ๋ก์ปฌ psql์ ์๋์ผ๋ก ๊ฐ์งํ์ฌ ์ ์ฉ
./scripts/01-seed-db.sh
# 3) ํ
์คํธ ์ ์ ๋ฐ JWT ํ ํฐ ์์ฑ
# ๊ธฐ์กด ํ ํฐ์ ์ ํจ์ฑ์ ๊ฒ์ฆํ๊ณ , ์ ํจํ ํ ํฐ์ ์ ์งํ๋ฉฐ ๋ถ์กฑํ ๊ฐ์๋ง ์๋ก ๋ฐ๊ธ
# tokens.txt์ tokens.json(k6์ฉ)์ ์์ฑ
./scripts/02-prepare-tokens.sh
# 4) ๋๊ธฐ์ด ์๋๋ฆฌ์ค ์คํ (์๋์ผ๋ก ํ๊ฒฝ ๊ฒ์ฆ ํฌํจ)
# ๊ฐ ์คํฌ๋ฆฝํธ๋ ๋ค์์ ์๋์ผ๋ก ์ํํฉ๋๋ค:
# - ์ค์ผ์ค ์คํ ์ํ ํ์ธ (๋ฏธ์คํ ์ 01-seed-db.sh ์๋ ์คํ)
# - ํ ํฐ ํ์ธ ๋ฐ ํ์์ ๋ฐ๊ธ (์ ํจํ ํ ํฐ์ ์ ์งํ๊ณ ๋ถ์กฑํ ๊ฐ์๋ง ๋ฐ๊ธ)
# - ํ๊ฒฝ ๊ฒ์ฆ (03-verify-env.sh: ์๋ฒ ์ฐ๊ฒฐ, ์ค์ผ์ค ์คํ, ํ ํฐ ์ ํจ์ฑ)
# - k6 ์คํ (queue-flow.js)
# TPS๋ณ ์คํฌ๋ฆฝํธ ์ ํ:
./scripts/04-run-queue-100.sh # TPS 100 (๊ธฐ๋ณธ)
./scripts/04-run-queue-500.sh # TPS 500
./scripts/04-run-queue-1000.sh # TPS 1000
./scripts/04-run-queue-2000.sh # TPS 2000์ฐธ๊ณ : 04-run-queue-*.sh ์คํฌ๋ฆฝํธ๋ 02-prepare-tokens.sh๋ฅผ ํธ์ถํ์ฌ ๊ธฐ์กด ํ ํฐ์ ์ ํจ์ฑ์ ๊ฒ์ฆํ๊ณ , ์ ํจํ ํ ํฐ์ ์ ์งํ๋ฉฐ ๋ถ์กฑํ ๊ฐ์๋ง ์๋ก ๋ฐ๊ธํฉ๋๋ค. ๋ฐ๋ผ์ ํ ํฐ ๋ง๋ฃ ๊ฑฑ์ ์์ด ๋ฐ๋ณต ์คํํ ์ ์์ต๋๋ค.
load-test/
โโโ README.md # ์ด ํ์ผ
โโโ data/
โ โโโ config.env # ๊ณตํต ์ค์ (BASE_URL, SCHEDULE_ID ๋ฑ)
โ โโโ tokens.txt.example # tokens.txt ํ์ ์์
โ โโโ seed-schedule.sql # DB ์๋ (์ค์ผ์ค ์คํ)
โ โโโ queue/ # ๋๊ธฐ์ด ์๋๋ฆฌ์ค
โ โโโ tokens.txt # prepare-tokens.sh ๋ก ์์ฑ
โ โโโ tokens.json # k6์ฉ JSON ํ์ ํ ํฐ ํ์ผ
โโโ scripts/
โ โโโ 01-seed-db.sh # DB ์๋ ์ ์ฉ (Docker ๋๋ ๋ก์ปฌ psql ์ง์)
โ โโโ 02-prepare-tokens.sh # N๋ช
signup+login โ tokens.txt โ tokens.json (ํ ํฐ ์ ํจ์ฑ ๊ฒ์ฆ ํฌํจ)
โ โโโ 03-verify-env.sh # ์ค์ผ์ค ์คํยทํ ํฐ 1๊ฑด curl๋ก 200 ์ฌ๋ถ ๊ฒ์ฆ (3๋จ๊ณ ๊ฒ์ฆ)
โ โโโ 04-run-queue-100.sh # ๋๊ธฐ์ด ์๋๋ฆฌ์ค ์คํ (TPS 100)
โ โโโ 04-run-queue-500.sh # ๋๊ธฐ์ด ์๋๋ฆฌ์ค ์คํ (TPS 500)
โ โโโ 04-run-queue-1000.sh # ๋๊ธฐ์ด ์๋๋ฆฌ์ค ์คํ (TPS 1000)
โ โโโ 04-run-queue-2000.sh # ๋๊ธฐ์ด ์๋๋ฆฌ์ค ์คํ (TPS 2000)
โ โโโ queue-flow.js # ํตํฉ ํ๋ฆ (enter โ heartbeat + status ๋ฐ๋ณต until READY)
โ โโโ queue-enter.js, queue-status.js, queue-heartbeat.js # ๊ฐ๋ณ API ๋ถํ ํ
์คํธ
โโโ results/ # ํ
์คํธ ๊ฒฐ๊ณผ ๋ก๊ทธ
โโโ 100-tps-log.txt
โโโ 500-tps-log.txt
โโโ 1000-tps-log.txt
์ค์ผ์ค์ "์ด๋ฏธ ์คํ" ์ํ๋ก ๋ณ๊ฒฝํ์ฌ ๋ถํ ํ ์คํธ์์ 2xx ์๋ต์ ๋ฐ์ ์ ์๋๋ก ํฉ๋๋ค.
์ง์ ํ๊ฒฝ:
- Docker:
fairticket-postgres์ปจํ ์ด๋๊ฐ ์คํ ์ค์ด๋ฉดdocker exec๋ก SQL์ ์ ์ฉํฉ๋๋ค. - ๋ก์ปฌ psql: Docker๊ฐ ์์ผ๋ฉด ๋ก์ปฌ
psql์ ์ฌ์ฉํฉ๋๋ค (๊ธฐ๋ณธ:localhost:5433, ์ฌ์ฉ์:fairticket, ๋น๋ฐ๋ฒํธ:fairticket123).
์ฌ์ฉ๋ฒ:
./scripts/01-seed-db.sh์ฃผ์ ๊ธฐ๋ฅ:
- ํ ํฐ ์ ํจ์ฑ ๊ฒ์ฆ: ๊ธฐ์กด ํ ํฐ ํ์ผ์ด ์์ผ๋ฉด ๊ฐ ํ ํฐ์ ์ ํจ์ฑ์ ๊ฒ์ฆํฉ๋๋ค (401์ด ์๋๋ฉด ์ ํจ). ์ ํจํ ํ ํฐ์ ์ ์งํ๊ณ ๋ถ์กฑํ ๊ฐ์๋ง ์๋ก ๋ฐ๊ธํฉ๋๋ค.
- ์๋ ๋ฒํธ ๊ด๋ฆฌ: ๊ธฐ์กด ํ ํฐ ํ์ผ์ ๋ผ์ธ ์๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ์์ ๋ฒํธ๋ฅผ ๊ฒฐ์ ํ์ฌ ์ค๋ณต์ ๋ฐฉ์งํฉ๋๋ค.
- JSON ๋ณํ: k6์์ ์ฌ์ฉํ ์ ์๋๋ก
tokens.txt๋ฅผtokens.jsonํ์์ผ๋ก ๋ณํํฉ๋๋ค. - ์ต์
์ง์:
--skip-gen์ต์ ์ผ๋ก ํ ํฐ ์์ฑ ์์ด JSON ๋ณํ๋ง ์ํํ ์ ์์ต๋๋ค.
์ฌ์ฉ๋ฒ:
./scripts/02-prepare-tokens.sh # ํ ํฐ ์์ฑ + JSON ๋ณํ
./scripts/02-prepare-tokens.sh --skip-gen # JSON ๋ณํ๋ง ์ํ๋ถํ ํ ์คํธ ์คํ ์ ํ๊ฒฝ์ ๊ฒ์ฆํฉ๋๋ค. 3๋จ๊ณ ๊ฒ์ฆ์ ์ํํฉ๋๋ค:
- ์๋ฒ ์ฐ๊ฒฐ ํ์ธ:
BASE_URL/actuator/health๋ก ์๋ฒ ์ฐ๊ฒฐ ์ฌ๋ถ ํ์ธ - ์ค์ผ์ค ์คํ ์ฌ๋ถ ํ์ธ:
GET /api/v1/concerts/{CONCERT_ID}์dates[].available๋ก ํด๋น ์ค์ผ์ค์ด ์คํ ์ํ์ธ์ง ํ์ธ - ํ ํฐ ์ ํจ์ฑ ํ์ธ:
tokens.txt์ ์ฒซ ๋ฒ์งธ ํ ํฐ์ผ๋กPOST /api/v1/queue/{SCHEDULE_ID}/enter๋ฅผ ์ค์ ํธ์ถํ์ฌ HTTP ์ํ ์ฝ๋ ํ์ธ
์๋ฌ ์ฒ๋ฆฌ:
- 401: ํ ํฐ ๋ง๋ฃ ๋๋ JWT secret ๋ถ์ผ์น โ
02-prepare-tokens.sh์ฌ์คํ ํ์ - 429: Rate Limit โ ์๋ฒ ์ค์ ํ์ธ ๋๋ ์ ์ ํ ์ฌ์๋
- ๊ธฐํ 4xx/5xx: ์ค์ผ์ค/์ฝ์ํธ ID ๋๋ ์๋ฒ ๋ก์ง ํ์ธ ํ์
์๋ํ ๊ธฐ๋ฅ:
- ์ค์ผ์ค ์คํ ์ํ ํ์ธ:
check_schedule_open()ํจ์๋ก ์ค์ผ์ค์ด ์คํ ์ํ์ธ์ง ํ์ธํฉ๋๋ค. ๋ฏธ์คํ ์01-seed-db.sh๋ฅผ ์๋ ์คํํฉ๋๋ค. - ํ ํฐ ํ์ธ ๋ฐ ํ์์ ๋ฐ๊ธ:
02-prepare-tokens.sh๋ฅผ ํธ์ถํ์ฌ ๊ธฐ์กด ํ ํฐ์ ์ ํจ์ฑ์ ๊ฒ์ฆํ๊ณ , ์ ํจํ ํ ํฐ์ ์ ์งํ๋ฉฐ ๋ถ์กฑํ ๊ฐ์๋ง ์๋ก ๋ฐ๊ธํฉ๋๋ค (NUM_USERS=$K6_VUS_*). - ํ๊ฒฝ ๊ฒ์ฆ:
03-verify-env.sh๋ฅผ ์๋ ์คํํ์ฌ ์๋ฒ ์ฐ๊ฒฐ, ์ค์ผ์ค ์คํ, ํ ํฐ ์ ํจ์ฑ์ ํ์ธํฉ๋๋ค. - ์ ๋ ๊ฒฝ๋ก ์ ๋ฌ:
TOKEN_JSON_PATH๋ฅผ ์ ๋ ๊ฒฝ๋ก๋ก ์ ๋ฌํ์ฌ k6์open()ํจ์์์ ์ ํํ ๋ก๋๋๋๋ก ํฉ๋๋ค.
- k6 ์ค์น
- FairTicket-BE ์๋ฒ ์คํ ์ค (๊ธฐ๋ณธ
http://localhost:8080) - (์ ํ)
data/config.env์์BASE_URL,SCHEDULE_ID๋ฑ ์ค์
๋ก์ปฌ ํ
์คํธ ํ๊ฒฝ์์๋ Rate Limit์ด ๋นํ์ฑํ๋์ด ์์ต๋๋ค (RATE_LIMIT_ENABLED = false).
๋ฐ๋ผ์ ๋ชจ๋ TPS ์๋๋ฆฌ์ค(100, 500, 1000, 2000)๊ฐ ๋จ์ผ IP์์๋ 429 ์๋ฌ ์์ด ๋์ํ๋๋ก ์ค๊ณ๋์ด ์์ต๋๋ค.
- ํ์ผ:
src/main/java/com/fairticket/global/security/RateLimitFilter.java - ์ค์ :
RATE_LIMIT_ENABLED = falseโ Rate Limit ๋ฏธ์ ์ฉ(๋ฌด์ ํ)
์ด์/์คํ
์ด์ง ํ๊ฒฝ์์๋ ๋ณด์์ ์ํด RATE_LIMIT_ENABLED = true๋ก ์ค์ ํ๊ณ MAX_REQUESTS_PER_MINUTE๋ฅผ ์ ์ ํ ์กฐ์ ํ์ธ์.
๋ถํ ํ ์คํธ์์ ๋ชจ๋ ์๋ต์ด Non-2xx์ด๋ฉด ๋ค์์ ํ์ธํ์ธ์.
| ์์ธ | ํ์ธ ๋ฐฉ๋ฒ | ์กฐ์น |
|---|---|---|
| ํ ํฐ ๋ง๋ฃ(401) | ./scripts/03-verify-env.sh ์คํ |
ํ ํฐ์ ์๋ฒ jwt.expiration(๊ธฐ๋ณธ 1์๊ฐ)๋ง ์ ํจํฉ๋๋ค. ํ
์คํธํ ์๋ฒ(BASE_URL)๊ฐ ๋ ์๋ ์ํ์์ ./scripts/02-prepare-tokens.sh ๋ค์ ์คํ. |
| JWT secret ๋ถ์ผ์น | ์๋ฒ ์ฌ๊ธฐ๋ ํ ํ ํฐ ๋ฏธ์ฌ๋ฐ๊ธ | ๊ฐ์ ์๋ฒ์์ 02-prepare-tokens.sh๋ก ๋ฐ๊ธํ ํ ํฐ๋ง ์ ํจ. ์ด๋ฏธ์ง/์ค์ ๋ณ๊ฒฝ ํ ์ฌ๊ธฐ๋ํ๋ค๋ฉด ํ ํฐ ๋ค์ ์์ฑ. |
| ์ค์ผ์ค ๋ฏธ์คํ | 03-verify-env.sh 2๋จ๊ณ ์คํจ | ./scripts/01-seed-db.sh ์คํ ํ ์ฌํ์ธ. |
| Rate Limit(429) | 03-verify-env.sh 3๋จ๊ณ์์ 429 | ๋ก์ปฌ ํ
์คํธ ํ๊ฒฝ์์๋ ๋ฐ์ํ์ง ์์์ผ ํจ. ์ด์ ํ๊ฒฝ์์ ๋ฐ์ ์ ์๋ฒ RATE_LIMIT_ENABLED ๋๋ MAX_REQUESTS_PER_MINUTE ํ์ธ. |
์ค์ HTTP ์ํ ์ฝ๋๋ k6 ๊ฒฐ๊ณผ์ HTTP status breakdown์ ํ์๋ฉ๋๋ค.
์คํ ์งํ ๋์ ์ ์์ด ๋ชฐ๋ฆด ๋ ๋๊ธฐ์ด์ด ๊ฒฌ๋๋์ง ํ์ธํ๋ค.
Redis Sorted Set/ํ ํฐ ๋ฐ๊ธ ์ง์ฐ, 429(Rate Limit) ๋ฐ์ ๊ตฌ๊ฐ, ํ์์์/์๋ฌ์จ, Spring JVM ๋ฉํธ๋ฆญ(CPU, Heap Memory, Garbage Collection)์ ๋ณธ๋ค.
์๋ฏธ: ์คํ ์งํ ๋์ ์ ์์ด ๋ชฐ๋ฆด ๋ ๋๊ธฐ์ด์ด ๊ฒฌ๋๋์ง ํ์ธ
์๋๋ฆฌ์ค:
- ๋์ ์ง์
: ํ ์ค์ผ์ค์ N๋ช
(์: 1,000~5,000)์ด ๋์์
POST /api/v1/queue/{scheduleId}/enter - ์ํ ํด๋ง: ์ง์
ํ ์ ์ ๋ค์ด ์ฃผ๊ธฐ์ ์ผ๋ก
GET /api/v1/queue/{scheduleId}/statusํธ์ถ (READY ์ ๋ฆฌ๋ค์ด๋ ํธ๊น์ง ๊ฒ์ฆ) - Heartbeat:
POST /api/v1/queue/{scheduleId}/heartbeat๋์/๋ฐ๋ณต ํธ์ถ
ํ์ธ ํฌ์ธํธ: Redis Sorted Set/ํ ํฐ ๋ฐ๊ธ ์ง์ฐ, 429(Rate Limit) ๋ฐ์ ๊ตฌ๊ฐ, ํ์์์/์๋ฌ์จ, Spring JVM ๋ฉํธ๋ฆญ(CPU, Heap Memory, Garbage Collection)
ํ ์ฌ์ฉ์๋น ํ๋์ ํ๋ฆ: enter 1ํ โ heartbeat + status ๋ฐ๋ณต(WAITING ๋๊ธฐ) โ READY ์์ .
| ๊ตฌ๋ถ | ์ค๋ช | ์คํฌ๋ฆฝํธ |
|---|---|---|
| ํตํฉ ํ๋ฆ | enter ํ heartbeat + status ํด๋ง until READY (๊ถ์ฅ) | queue-flow.js |
| ๊ฐ๋ณ API ๋ถํ | enter / status / heartbeat ๊ฐ๊ฐ ๋จ๋ ๋ถํ | queue-enter.js, queue-status.js, queue-heartbeat.js |
04-run-queue-{100|500|1000|2000}.sh ์คํ ์ ๋ค์์ ์๋์ผ๋ก ์ํํฉ๋๋ค:
- ์ค์ผ์ค ์คํ ์ํ ํ์ธ (๋ฏธ์คํ ์ 01-seed-db.sh ์๋ ์คํ)
- ํ ํฐ ํ์ธ ๋ฐ ํ์์ ๋ฐ๊ธ (02-prepare-tokens.sh: ์ ํจํ ํ ํฐ์ ์ ์งํ๊ณ ๋ถ์กฑํ ๊ฐ์๋ง ๋ฐ๊ธ)
- ํ๊ฒฝ ๊ฒ์ฆ (03-verify-env.sh: ์๋ฒ ์ฐ๊ฒฐ, ์ค์ผ์ค ์คํ, ํ ํฐ ์ ํจ์ฑ ํ์ธ)
- ํตํฉ ํ๋ฆ(queue-flow.js) ์คํ
๊ฐ ๊ฐ์ ์ฌ์ฉ์(ํ ํฐ)๋ ์ฒซ ์์ฒญ์์ enter, ์ดํ ์์ฒญ์์ **ํํธ๋นํธ(HEARTBEAT_INTERVAL_MS ๊ฐ๊ฒฉ)**์ **status(STATUS_POLL_MS ๊ฐ๊ฒฉ)**๋ฅผ ๋ฒ๊ฐ์๊ฐ๋ฉฐ ๋ณด๋ด๋ฉฐ WAITING โ READY๋ฅผ ๊ธฐ๋ค๋ฆฌ๋ ๊ตฌ์กฐ์ ๋๋ค. ํํธ๋นํธ๋ heartbeat TTL(30์ด)๋ณด๋ค ์งง์ ๊ฐ๊ฒฉ(๊ธฐ๋ณธ 20์ด)์ผ๋ก ์ ์กํ์ฌ ์ฌ์ฉ์๊ฐ ํ์์ ์ ๊ฑฐ๋์ง ์๋๋ก ํฉ๋๋ค.
Executor ํ์
: constant-arrival-rate
์ ํํ TPS๋ฅผ ์ ์งํ๊ธฐ ์ํด arrival rate executor๋ฅผ ์ฌ์ฉํฉ๋๋ค. ํ๊ฒฝ ๋ณํ์ ๊ด๊ณ์์ด ์ค์ ํ TPS๋ฅผ ์ผ์ ํ๊ฒ ์ ์งํฉ๋๋ค.
์ฃผ์ ๊ธฐ๋ฅ:
- ํ ํฐ ๋ก๋: k6์
open()ํจ์๋ก JSON ํ์ ํ ํฐ ํ์ผ(data/queue/tokens.json)์ ๋ก๋ํฉ๋๋ค. VU ID ๊ธฐ๋ฐ์ผ๋ก ํ ํฐ์ ์ํ ์ฌ์ฉํฉ๋๋ค. - ํํธ๋นํธ ๊ด๋ฆฌ:
HEARTBEAT_INTERVAL_MS(๊ธฐ๋ณธ 20์ด) ๊ฐ๊ฒฉ์ผ๋ก ํํธ๋นํธ๋ฅผ ์ ์กํ์ฌ ์ฌ์ฉ์๊ฐ ํ์์ ์ ๊ฑฐ๋์ง ์๋๋ก ํฉ๋๋ค. - Status ํด๋ง:
STATUS_POLL_MS๊ฐ๊ฒฉ์ผ๋ก status๋ฅผ ์กฐํํ๋ฉฐ, READY ์ํ๋ฅผ ์์ ํ ๋๊น์ง ๋ฐ๋ณตํฉ๋๋ค. - ๋ฌดํ ๋ฃจํ ๋ฐฉ์ง: ์ต๋ ๋ฐ๋ณต ํ์(1000ํ) ์ ํ์ ๋์ด ๋ฌดํ ๋๊ธฐ๋ฅผ ๋ฐฉ์งํฉ๋๋ค.
์ปค์คํ ๋ฉํธ๋ฆญ:
enter_requests: ๋๊ธฐ์ด ์ง์ ์์ฒญ ์ (Counter)status_requests: ์ํ ์กฐํ ์์ฒญ ์ (Counter)heartbeat_requests: ํํธ๋นํธ ์ ์ก ์์ฒญ ์ (Counter)ready_received: READY ์ํ ์์ ํ์ (Counter)enter_duration: Enter API ์ง์ฐ์๊ฐ (Trend)status_duration: Status API ์ง์ฐ์๊ฐ (Trend)heartbeat_duration: Heartbeat API ์ง์ฐ์๊ฐ (Trend)ready_time: Enter๋ถํฐ READY๊น์ง ์์ ์๊ฐ (Trend)- ์คํจ ๋ถ์์ฉ ๋ฉํธ๋ฆญ:
enter_failures: Enter ์์ฒญ ์คํจ ์ (Counter)status_failures: Status ์์ฒญ ์คํจ ์ (Counter)heartbeat_failures: Heartbeat ์์ฒญ ์คํจ ์ (Counter)status_404: Status 404 (NOT_IN_QUEUE) ๋ฐ์ ์ (Counter)status_500: ์๋ฒ ์๋ฌ(500) ๋ฐ์ ์ (Counter)timeout_errors: ํ์์์/์ฐ๊ฒฐ ์คํจ ์ (Counter)
ํ๊ฒฝ ๋ณ์ ์ฒ๋ฆฌ:
VUS์DURATIONํ๊ฒฝ ๋ณ์๋ฅผ ์ฐ์ ์ฌ์ฉํฉ๋๋ค.VUS๊ฐ ์์ผ๋ฉดK6_VUS๋ฅผ,DURATION์ด ์์ผ๋ฉดK6_DURATION์ ์ฌ์ฉํฉ๋๋ค (ํ์ ํธํ์ฑ).TARGET_TPS๊ฐ ์ ํจํ์ง ์์ผ๋ฉด ๊ธฐ๋ณธ๊ฐ 100์ ์ฌ์ฉํฉ๋๋ค.preAllocatedVUs์maxVUs๋ ์๋ ๊ณ์ฐ๋ฉ๋๋ค:preAllocatedVUs = Math.max(VUS || 100, targetRate)maxVUs = Math.max((VUS || 100) * 2, targetRate * 2)
๊ฒฐ๊ณผ ์์ฝ (handleSummary): ํ ์คํธ ์ข ๋ฃ ์ ๋ค์ ์ ๋ณด๋ฅผ ์ถ๋ ฅํฉ๋๋ค:
- ์์ฒญ ํต๊ณ: Enter/Status/Heartbeat ์์ฒญ ์, READY ์์ ํ์, ์ ์ฒด ์์ฒญ ์, ์คํจ์จ
- ์คํจ ๋ถ์: Enter/Status/Heartbeat ์คํจ ์, Status 404/500 ๋ฐ์ ์, ํ์์์/์ฐ๊ฒฐ ์คํจ ์, Status 404 ๋น์จ
- ์ง์ฐ์๊ฐ: ์ ์ฒด HTTP ์์ฒญ, Enter API, Status API, Heartbeat API์ min/avg/max/p50/p90/p95/p99
- Enter โ READY ์์ ์๊ฐ: min/avg/max/p50/p90/p95/p99
- ์ฒ๋ฆฌ๋: ํ ์คํธ ์ง์ ์๊ฐ, ์ ์ฒด ํ๊ท RPS, Enter RPS, Status RPS, Heartbeat RPS, ์ค์ TPS, TPS ๋ฌ์ฑ๋ฅ
๋๊ธฐ์ด ๋ถํ๋ฅผ ์ด๋น ์ง์ (enter) ์์ ๋ฐ๋ผ 100, 500, 1000, 2000 TPS๋ก ๊ตฌ๋ถํ์ฌ ํ ์คํธํ ์ ์์ต๋๋ค. ๊ฐ TPS๋ณ๋ก ๋ ๋ฆฝ์ ์ธ ์ค์ ๋ณ์๋ฅผ ์ฌ์ฉํ๋ฏ๋ก ์๋ก ์ํฅ์ ์ฃผ์ง ์์ต๋๋ค.
- ์๋ฒ Rate Limit: ๋ก์ปฌ ํ
์คํธ ํ๊ฒฝ์์๋
RATE_LIMIT_ENABLED = false๋ก ์ค์ ๋์ด ์์ด Rate Limit์ด ์ ์ฉ๋์ง ์์ต๋๋ค. ๋ชจ๋ ์๋๋ฆฌ์ค๊ฐ ๋จ์ผ IP์์๋ 429 ์๋ฌ ์์ด ๋์ํฉ๋๋ค. - TPS๋ณ ์คํฌ๋ฆฝํธ:
04-run-queue-{100|500|1000|2000}.sh๊ฐ๊ฐ ํด๋น TPS ์ ์ฉ ๋ณ์๋ฅผ ์ฌ์ฉํฉ๋๋ค.
๋ก์ปฌ ํ ์คํธ ํ๊ฒฝ์์๋ Rate Limit์ด ๋นํ์ฑํ๋์ด ์์ด ๋จ์ผ IP์์๋ 429 ์์ด ๋์ํฉ๋๋ค.
- ๋ชฉํ TPS: ์ด๋น ๋๊ธฐ์ด ์ง์
(enter) ์.
TARGET_TPS_100=100์ผ๋ก 100 TPS ๊ณ ์ . - status ํด๋ง ๊ฐ๊ฒฉ: ์ง์
ํ ์ฌ์ฉ์๊ฐ status๋ฅผ ํธ์ถํ๋ ์ฃผ๊ธฐ.
STATUS_POLL_MS_100=1000(1์ด)์ผ๋ก ์ค์ . - ํํธ๋นํธ ๊ฐ๊ฒฉ: ์ง์
ํ ์ฌ์ฉ์๊ฐ ํํธ๋นํธ๋ฅผ ์ ์กํ๋ ์ฃผ๊ธฐ.
HEARTBEAT_INTERVAL_MS=20000(20์ด)์ผ๋ก ์ค์ ํด, heartbeat TTL(30์ด)๋ณด๋ค ์งง๊ฒ ์ ์งํ์ฌ ์ฌ์ฉ์๊ฐ ํ์์ ์ ๊ฑฐ๋์ง ์๋๋ก ํจ. - ์ฆ, "์ด๋น 100๋ช ์ง์ + ์ด๋ฏธ ๋๊ธฐ ์ค์ธ ์ฌ์ฉ์๋ค์ 1์ด๋ง๋ค status ํด๋ง + 20์ด๋ง๋ค ํํธ๋นํธ ์ ์ก" ๊ตฌ์กฐ.
| ๋ชฉํ | ์ค์ |
|---|---|
| Enter TPS | TARGET_TPS_100=100 โ k6๊ฐ VU๋น ๊ฐ๊ฒฉ์ผ๋ก ์ด๋น 100๊ฑด enter ๋ฐ์ |
| Status ํด๋ง | STATUS_POLL_MS_100=1000 โ ์ง์
ํ ์ฌ์ฉ์๋น 1์ด๋ง๋ค status 1ํ |
| k6 | K6_VUS_100=100 (config.env์ ์คํฌ๋ฆฝํธ ๊ธฐ๋ณธ๊ฐ ๋์ผ), K6_DURATION_100=60s โ ๋์ ์ ์ 100๋ช
์๋ฎฌ๋ ์ด์
|
์คํ: ./scripts/04-run-queue-100.sh
์ต๊ณ ๋ถํ ํ ์คํธ๋ฅผ ์ํ ์ค์ ์ ๋๋ค.
- ๋ชฉํ TPS: ์ด๋น ๋๊ธฐ์ด ์ง์
(enter) ์.
TARGET_TPS_500=500์ผ๋ก 500 TPS ๊ณ ์ . - status ํด๋ง ๊ฐ๊ฒฉ:
STATUS_POLL_MS_500=1000(1์ด) ๊ธฐ๋ณธ๊ฐ. ํ์ ์ ์กฐ์ ๊ฐ๋ฅ. - ํํธ๋นํธ ๊ฐ๊ฒฉ:
HEARTBEAT_INTERVAL_MS=20000(20์ด) ๊ณตํต ์ค์ ์ฌ์ฉ.
| ๋ชฉํ | ์ค์ |
|---|---|
| Enter TPS | TARGET_TPS_500=500 โ k6๊ฐ VU๋น ๊ฐ๊ฒฉ์ผ๋ก ์ด๋น 500๊ฑด enter ๋ฐ์ |
| Status ํด๋ง | STATUS_POLL_MS_500=1000 โ ์ง์
ํ ์ฌ์ฉ์๋น 1์ด๋ง๋ค status 1ํ |
| k6 | K6_VUS_500=500 (config.env์ ์คํฌ๋ฆฝํธ ๊ธฐ๋ณธ๊ฐ ๋์ผ), K6_DURATION_500=60s โ ๋์ ์ ์ 500๋ช
์๋ฎฌ๋ ์ด์
|
์คํ: ./scripts/04-run-queue-500.sh
๊ณ ๋ถํ ํ ์คํธ๋ฅผ ์ํ ์ค์ ์ ๋๋ค.
- ๋ชฉํ TPS: ์ด๋น ๋๊ธฐ์ด ์ง์
(enter) ์.
TARGET_TPS_1000=1000์ผ๋ก 1000 TPS ๊ณ ์ . - status ํด๋ง ๊ฐ๊ฒฉ:
STATUS_POLL_MS_1000=1000(1์ด) ๊ธฐ๋ณธ๊ฐ. ํ์ ์ ์กฐ์ ๊ฐ๋ฅ. - ํํธ๋นํธ ๊ฐ๊ฒฉ:
HEARTBEAT_INTERVAL_MS=20000(20์ด) ๊ณตํต ์ค์ ์ฌ์ฉ.
| ๋ชฉํ | ์ค์ |
|---|---|
| Enter TPS | TARGET_TPS_1000=1000 โ k6๊ฐ VU๋น ๊ฐ๊ฒฉ์ผ๋ก ์ด๋น 1000๊ฑด enter ๋ฐ์ |
| Status ํด๋ง | STATUS_POLL_MS_1000=1000 โ ์ง์
ํ ์ฌ์ฉ์๋น 1์ด๋ง๋ค status 1ํ |
| k6 | K6_VUS_1000=1000 (config.env์ ์คํฌ๋ฆฝํธ ๊ธฐ๋ณธ๊ฐ ๋์ผ), K6_DURATION_1000=60s โ ๋์ ์ ์ 1000๋ช
์๋ฎฌ๋ ์ด์
|
์คํ: ./scripts/04-run-queue-1000.sh
์ด๊ณ ๋ถํ ํ ์คํธ๋ฅผ ์ํ ์ค์ ์ ๋๋ค.
- ๋ชฉํ TPS: ์ด๋น ๋๊ธฐ์ด ์ง์
(enter) ์.
TARGET_TPS_2000=2000์ผ๋ก 2000 TPS ๊ณ ์ . - status ํด๋ง ๊ฐ๊ฒฉ:
STATUS_POLL_MS_2000=1000(1์ด) ๊ธฐ๋ณธ๊ฐ. ํ์ ์ ์กฐ์ ๊ฐ๋ฅ. - ํํธ๋นํธ ๊ฐ๊ฒฉ:
HEARTBEAT_INTERVAL_MS=20000(20์ด) ๊ณตํต ์ค์ ์ฌ์ฉ.
| ๋ชฉํ | ์ค์ |
|---|---|
| Enter TPS | TARGET_TPS_2000=2000 โ k6๊ฐ VU๋น ๊ฐ๊ฒฉ์ผ๋ก ์ด๋น 2000๊ฑด enter ๋ฐ์ |
| Status ํด๋ง | STATUS_POLL_MS_2000=1000 โ ์ง์
ํ ์ฌ์ฉ์๋น 1์ด๋ง๋ค status 1ํ |
| k6 | K6_VUS_2000=2000 (config.env ๊ธฐ๋ณธ๊ฐ) / 2000 (์คํฌ๋ฆฝํธ ๊ธฐ๋ณธ๊ฐ), K6_DURATION_2000=60s โ ๋์ ์ ์ 2000๋ช
์๋ฎฌ๋ ์ด์
|
์คํ: ./scripts/04-run-queue-2000.sh
๊ฐ TPS๋ณ๋ก ๋ ๋ฆฝ์ ์ธ ๋ณ์๋ฅผ ์ฌ์ฉํ๋ฏ๋ก ์๋ก ์ํฅ์ ์ฃผ์ง ์์ต๋๋ค.
์ฐธ๊ณ : queue-flow.js๋ VUS์ DURATION ํ๊ฒฝ ๋ณ์๋ฅผ ์ฐ์ ์ฌ์ฉํฉ๋๋ค. 04-run-queue-*.sh ์คํฌ๋ฆฝํธ๋ K6_VUS_*์ K6_DURATION_*๋ฅผ VUS์ DURATION์ผ๋ก ๋งคํํ์ฌ ์ ๋ฌํฉ๋๋ค. queue-flow.js๋ VUS๊ฐ ์์ผ๋ฉด K6_VUS๋ฅผ, DURATION์ด ์์ผ๋ฉด K6_DURATION์ ์ฌ์ฉํฉ๋๋ค (ํ์ ํธํ์ฑ). TARGET_TPS๊ฐ ์ ํจํ์ง ์์ผ๋ฉด ๊ธฐ๋ณธ๊ฐ 100์ ์ฌ์ฉํฉ๋๋ค.
| ๋ณ์ | ์ค๋ช | ๊ธฐ๋ณธ๊ฐ | ๋น๊ณ |
|---|---|---|---|
| ๊ณตํต ์ค์ | |||
| BASE_URL | API ์๋ฒ | http://localhost:8080 | - |
| SCHEDULE_ID | ํ์ฐจ ID | 1 | - |
| CONCERT_ID | ๊ณต์ฐ ID | 1 | - |
| GRADE | ์ข์ ๋ฑ๊ธ | VIP | - |
| ZONE | ์ข์ ๊ตฌ์ญ | A | - |
| NUM_USERS | ํ ํฐ ์์ฑ ์ธ์ ์ | 1000 | - |
| HEARTBEAT_INTERVAL_MS | ํํธ๋นํธ ์ ์ก ๊ฐ๊ฒฉ(ms) | 20000 | ๊ณตํต ์ฌ์ฉ |
| TOKEN_JSON_PATH | k6์ฉ ํ ํฐ JSON ํ์ผ ๊ฒฝ๋ก | data/queue/tokens.json | k6 ์คํฌ๋ฆฝํธ์์ ์ฌ์ฉ |
| 100 TPS ์ ์ฉ ๋ณ์ | |||
| TARGET_TPS_100 | ์ด๋น ๋๊ธฐ์ด ์ง์ (enter) ์ | 100 | 04-run-queue-100.sh ์ฌ์ฉ |
| K6_VUS_100 | k6 Virtual Users ์ | 100 | config.env์ ์คํฌ๋ฆฝํธ ๊ธฐ๋ณธ๊ฐ ๋์ผ |
| K6_DURATION_100 | ํ ์คํธ ์๊ฐ | 60s | 04-run-queue-100.sh ์ฌ์ฉ |
| STATUS_POLL_MS_100 | status ํด๋ง ๊ฐ๊ฒฉ(ms) | 1000 | 04-run-queue-100.sh ์ฌ์ฉ |
| 500 TPS ์ ์ฉ ๋ณ์ | |||
| TARGET_TPS_500 | ์ด๋น ๋๊ธฐ์ด ์ง์ (enter) ์ | 500 | 04-run-queue-500.sh ์ฌ์ฉ |
| K6_VUS_500 | k6 Virtual Users ์ | 500 | config.env์ ์คํฌ๋ฆฝํธ ๊ธฐ๋ณธ๊ฐ ๋์ผ |
| K6_DURATION_500 | ํ ์คํธ ์๊ฐ | 60s | 04-run-queue-500.sh ์ฌ์ฉ |
| STATUS_POLL_MS_500 | status ํด๋ง ๊ฐ๊ฒฉ(ms) | 1000 | 04-run-queue-500.sh ์ฌ์ฉ |
| 1000 TPS ์ ์ฉ ๋ณ์ | |||
| TARGET_TPS_1000 | ์ด๋น ๋๊ธฐ์ด ์ง์ (enter) ์ | 1000 | 04-run-queue-1000.sh ์ฌ์ฉ |
| K6_VUS_1000 | k6 Virtual Users ์ | 1000 | config.env์ ์คํฌ๋ฆฝํธ ๊ธฐ๋ณธ๊ฐ ๋์ผ |
| K6_DURATION_1000 | ํ ์คํธ ์๊ฐ | 60s | 04-run-queue-1000.sh ์ฌ์ฉ |
| STATUS_POLL_MS_1000 | status ํด๋ง ๊ฐ๊ฒฉ(ms) | 1000 | 04-run-queue-1000.sh ์ฌ์ฉ |
| 2000 TPS ์ ์ฉ ๋ณ์ | |||
| TARGET_TPS_2000 | ์ด๋น ๋๊ธฐ์ด ์ง์ (enter) ์ | 2000 | 04-run-queue-2000.sh ์ฌ์ฉ |
| K6_VUS_2000 | k6 Virtual Users ์ | 2000 | config.env์ ์คํฌ๋ฆฝํธ ๊ธฐ๋ณธ๊ฐ ๋์ผ |
| K6_DURATION_2000 | ํ ์คํธ ์๊ฐ | 60s | 04-run-queue-2000.sh ์ฌ์ฉ |
| STATUS_POLL_MS_2000 | status ํด๋ง ๊ฐ๊ฒฉ(ms) | 1000 | 04-run-queue-2000.sh ์ฌ์ฉ |
- ๋ชฉํ TPS: 100
- VUs: 100
- Duration: 60์ด
- Status ํด๋ง ๊ฐ๊ฒฉ: 1000ms (1์ด)
- Heartbeat ๊ฐ๊ฒฉ: 20000ms (20์ด)
์์ฒญ ํต๊ณ:
- Enter requests: 6,000
- Status requests: 6,000
- Heartbeat requests: 0
- READY received: 6,000
- Total requests: 12,000
- Failed requests rate: 0.00%
์ง์ฐ์๊ฐ (ms):
| ๋ฉํธ๋ฆญ | ์ ์ฒด HTTP ์์ฒญ | Enter API | Status API |
|---|---|---|---|
| min | 0.69 | 0.80 | 0.69 |
| avg | 2.15 | 2.43 | 1.87 |
| max | 78.64 | 78.64 | 64.38 |
| p50 | 1.46 | 1.54 | 1.36 |
| p90 | 2.84 | 3.13 | 2.52 |
| p95 | 4.54 | 5.33 | 4.02 |
| p99 | 0.00 | 0.00 | 0.00 |
Enter โ READY ์์ ์๊ฐ (ms):
- min: 1.00
- avg: 4.56
- max: 127.00
- p50: 3.00
- p90: 6.00
- p95: 10.00
- p99: 0.00
์ฒ๋ฆฌ๋:
- ํ ์คํธ ์ง์ ์๊ฐ: 60.00์ด
- ์ ์ฒด ํ๊ท RPS: 200.00 (Enter + Status + Heartbeat ํฉ๊ณ)
- Enter RPS: 100.00
- Status RPS: 100.00
- ์ค์ TPS (Enter/์ด): 100.00
JVM ๋ฉํธ๋ฆญ:
| ๋ฉํธ๋ฆญ | ๊ฐ | ์ค๋ช |
|---|---|---|
| CPU utilization (JVM CPU) | ์ต๋ 8-9% (ํผํฌ), ์ดํ 2% ๋ฏธ๋ง์ผ๋ก ์์ ํ | ํ ์คํธ ์ด๋ฐ(19:49:00-19:50:30) ์ฝ 8-9% ๋ถ๊ทผ์์ ๋ ๋ฒ์ ํผํฌ๋ฅผ ๋ณด์์ผ๋ฉฐ, ์ดํ 2% ๋ฏธ๋ง์ผ๋ก ํฌ๊ฒ ๊ฐ์ํ์ฌ ๋ฎ์ ์์ค์ ์ ์ง |
| Heap Memory utilization | 2-3.5% ๋ฒ์ ๋ณ๋, ์ดํ 2% ์์ค์ผ๋ก ์์ ํ | ํ ์คํธ ๊ธฐ๊ฐ ๋์ 2%์์ 3.5% ์ฌ์ด๋ฅผ ์ค๋ฅด๋ด๋ฆฌ๋ฉฐ ๋ณ๋ํ๋ค๊ฐ, ํ ์คํธ ์ข ๋ฃ ํ 2% ์์ค์ผ๋ก ์์ ํ |
| Garbage Collection | ์ต๋ 0.35% (ํผํฌ), ์ดํ 0%๋ก ๊ฐ์ | ํ ์คํธ ์์(19:49:00)๋ถํฐ ์ฆ๊ฐํ๊ธฐ ์์ํ์ฌ 19:50:30๊ฒฝ ์ฝ 0.35%์์ ํผํฌ๋ฅผ ์ฐ์ ํ, 19:51:30๊น์ง 0%๋ก ๊ฐ์ |
์๋น์ค ๋ฉํธ๋ฆญ (Grafana ๋์๋ณด๋):
- Rate: ์ ์ฒด ์์ฒญ ์ฒ๋ฆฌ์จ์ด 19:49:00๋ถํฐ ์ ์ง์ ์ผ๋ก ์ฆ๊ฐํ์ฌ 19:50:15๊ฒฝ ์ฝ 180 req/s์์ ์ต๊ณ ์ ์ ๋๋ฌํ ํ, 19:51:00๊น์ง 0 req/s๋ก ๊ธ๊ฐ
- Request Per Sec:
/api/v1/queue/{scheduleId}/enter์/api/v1/queue/{scheduleId}/status์๋ํฌ์ธํธ๊ฐ 19:50:15๊ฒฝ ์ฝ 90-100 req/s์์ ์ต๊ณ ์ ์ ๊ธฐ๋ก - Percent of 2xx Requests: ๋ชจ๋ API ์๋ํฌ์ธํธ์ ๋ํด 2xx ์๋ต์ด ์ง์์ ์ผ๋ก 100%๋ฅผ ์ ์ง
- Percent of 5xx Requests: "No data"๋ก ํ์๋์ด, ํด๋น ๊ธฐ๊ฐ ๋์ 5xx ์๋ฌ๋ ๋ฐ์ํ์ง ์์
- โ ์๋ฒฝํ ์ฑ๋ฅ: ์คํจ์จ 0%, ๋ชฉํ TPS 100% ๋ฌ์ฑ
- โ ๋ฎ์ ์ง์ฐ์๊ฐ: ํ๊ท ์๋ต ์๊ฐ 2.15ms, p95๊ฐ 4.54ms๋ก ๋งค์ฐ ์ฐ์
- โ ์์ ์ ์ธ ์ฒ๋ฆฌ: Enter โ READY ์์ ์๊ฐ ํ๊ท 4.56ms๋ก ์ฆ์ ์ฒ๋ฆฌ๋จ
- โ Rate Limit ๋ฏธ๋ฐ์: ๋ก์ปฌ ํ ์คํธ ํ๊ฒฝ์์๋ Rate Limit์ด ๋นํ์ฑํ๋์ด ์์ด 429 ์๋ฌ ์์ด ์์ ์ ์ผ๋ก ๋์
- ๋ชฉํ TPS: 500
- VUs: 500
- Duration: 60์ด
- Status ํด๋ง ๊ฐ๊ฒฉ: 1000ms (1์ด)
- Heartbeat ๊ฐ๊ฒฉ: 20000ms (20์ด)
์์ฒญ ํต๊ณ:
- Enter requests: 30,001
- Status requests: 30,089
- Heartbeat requests: 4
- READY received: 30,000
- Total requests: 60,094
- Failed requests rate: 0.12%
์ง์ฐ์๊ฐ (ms):
| ๋ฉํธ๋ฆญ | ์ ์ฒด HTTP ์์ฒญ | Enter API | Status API | Heartbeat API |
|---|---|---|---|---|
| min | 0.50 | 0.55 | 0.50 | 1.47 |
| avg | 1.44 | 1.62 | 1.26 | 5.74 |
| max | 122.37 | 122.37 | 93.68 | 9.15 |
| p50 | 0.74 | 0.76 | 0.72 | 6.18 |
| p90 | 1.22 | 1.26 | 1.18 | 8.35 |
| p95 | 2.81 | 3.04 | 2.60 | 8.75 |
| p99 | 0.00 | 0.00 | 0.00 | 0.00 |
Enter โ READY ์์ ์๊ฐ (ms):
- min: 1.00
- avg: 2.68
- max: 144.00
- p50: 1.00
- p90: 3.00
- p95: 6.00
- p99: 0.00
์ฒ๋ฆฌ๋:
- ์ค์ ๋ ํ ์คํธ ์๊ฐ: 60.00์ด
- ์ค์ ์คํ ์๊ฐ: 90.00์ด (graceful stop ํฌํจ)
- RPS ๊ณ์ฐ ๊ธฐ์ค ์๊ฐ: 60.00์ด
- ์ ์ฒด ํ๊ท RPS: 1,001.57 (Enter + Status + Heartbeat ํฉ๊ณ)
- Enter RPS: 500.02
- Status RPS: 501.48
- Heartbeat RPS: 0.07
- ์ค์ TPS (Enter/์ด): 500.02
- ๋ชฉํ TPS: 500
- TPS ๋ฌ์ฑ๋ฅ : 100.00%
JVM ๋ฉํธ๋ฆญ:
| ๋ฉํธ๋ฆญ | ๊ฐ | ์ค๋ช |
|---|---|---|
| CPU utilization (JVM CPU) | ์ต๋ ์ฝ 17-18% (ํผํฌ), ์ดํ 0%์ ๊ฐ๊น์ด ์์ค์ผ๋ก ๊ฐ์ | ํ ์คํธ ์์ ์ 0%์ ๊ฐ๊น์ด ์์ค์ผ๋ก ์์ํ์ฌ ์ฝ 17-18%๊น์ง ๊ธ๊ฒฉํ ์์น, ์ดํ ์ ์ฐจ ์ฝ 10%๋ก ๊ฐ์ํ๋ค๊ฐ ํ ์คํธ ์ข ๋ฃ ํ 0%์ ๊ฐ๊น์ด ์์ค์ผ๋ก ๊ฐ์ |
| Heap Memory utilization | 2-6% ๋ฒ์ ๋ณ๋, ์ฝ 5% ์์ค์ผ๋ก ์์ํ ์ฆ๊ฐ | ์ฌ์ฉ๋ฅ ์ 2%์์ 6% ์ฌ์ด๋ฅผ ์ค๊ฐ๋ฉฐ ์ฝ 5.5%๋ก ์ ์ ์ ์ฐ์๋ค๊ฐ ์ ์ ๊ฐ์ํ ํ, ์ฝ 5% ์์ค์ผ๋ก ์์ํ ์ฆ๊ฐํ๋ ์ถ์ธ |
| Garbage Collection | ์ต๋ ์ฝ 0.5% (ํผํฌ), ์ดํ 0%๋ก ๊ฐ์ | ํ ์คํธ ์ค๋ฐ์ ์ฝ 0.5%๋ก ์ต๋์น๋ฅผ ๊ธฐ๋กํ ํ ๋ค์ 0%๋ก ๋จ์ด์ง๋ ์ข ๋ชจ์์ ๊ณก์ ์ ๋ณด์ |
์๋น์ค ๋ฉํธ๋ฆญ (Grafana ๋์๋ณด๋):
- Rate: ์ ์ฒด ์์ฒญ ์ฒ๋ฆฌ์จ์ด ํ ์คํธ ์์ ํ ์ฝ 800-900 req/s๊น์ง ๊ธ์ฆํ ํ ๋ค์ ๊ฐ์ (500 TPS ๊ตฌ๊ฐ๊ณผ ์ผ์น)
- Request Per Sec:
/api/v1/queue/{scheduleId}/enter์/api/v1/queue/{scheduleId}/heartbeat์๋ํฌ์ธํธ๊ฐ ์ฝ 400-450 req/s ์ด์์ผ๋ก ๊ฐ์ฅ ๋ง์ ์์ฒญ ์๋ฅผ ๊ธฐ๋ก/api/v1/queue/{scheduleId}/status๋ ๋์ ์์ฒญ ์๋ฅผ ๋ณด์
- Percent of 2xx Requests: ๊ฑฐ์ ๋ชจ๋ ์์ฒญ์์ 100%์ 2xx (์ฑ๊ณต) ์๋ต ์ฝ๋๋ฅผ ๋ณด์ฌ์ค
- Percent of 5xx Requests: "No data"๋ก ํ์๋์ด ํด๋น ๊ธฐ๊ฐ ๋์ ์๋ฒ ์๋ฌ (5xx)๋ ๋ฐ์ํ์ง ์์
- Total Requests: ์ด ์ฝ 61.5K (60,094์ ๋์ผ ๊ตฌ๊ฐ) ๊ท๋ชจ์ ์์ฒญ์ด ์ฒ๋ฆฌ๋จ
- Requests Average Duration:
/api/v1/queue/{scheduleId}/enter: 980 ยตs (๋ง์ดํฌ๋ก์ด)/api/v1/queue/{scheduleId}/status: 824 ยตs (๋ง์ดํฌ๋ก์ด)/api/v1/queue/{scheduleId}/heartbeat: 3.83 ms
- โ ๋ชฉํ ๋ฌ์ฑ: TPS ๋ฌ์ฑ๋ฅ 100%, ์คํจ์จ 0.12%๋ก ๋งค์ฐ ๋ฎ์
- โ ์ฐ์ํ ์ฑ๋ฅ: ํ๊ท ์๋ต ์๊ฐ 1.44ms, p95๊ฐ 2.81ms๋ก ์ฌ์ ํ ์ฐ์
- โ ๋น ๋ฅธ ์ฒ๋ฆฌ: Enter โ READY ์์ ์๊ฐ ํ๊ท 2.68ms๋ก ๋งค์ฐ ๋น ๋ฆ
โ ๏ธ ์คํ ์๊ฐ ์ฐ์ฅ: graceful stop์ผ๋ก ์ธํด ์ค์ ์คํ ์๊ฐ์ด 90์ด๋ก ์ฐ์ฅ๋จ (์ ์ ๋์)
- ๋ชฉํ TPS: 1000
- VUs: 1000
- Duration: 60์ด
- Status ํด๋ง ๊ฐ๊ฒฉ: 1000ms (1์ด)
- Heartbeat ๊ฐ๊ฒฉ: 20000ms (20์ด)
์์ฒญ ํต๊ณ:
- Enter requests: 57,198
- Status requests: 107,169
- Heartbeat requests: 2,318
- READY received: 56,660
- Total requests: 166,685
- Failed requests rate: 0.00%
์คํจ ๋ถ์:
- Enter ์คํจ: 0๊ฑด
- Status ์คํจ: 0๊ฑด
- Heartbeat ์คํจ: 0๊ฑด
- Status 404 (NOT_IN_QUEUE): 0๊ฑด
- Status 500 (์๋ฒ ์๋ฌ): 0๊ฑด
- ํ์์์/์ฐ๊ฒฐ ์คํจ: 0๊ฑด
์ง์ฐ์๊ฐ (ms):
| ๋ฉํธ๋ฆญ | ์ ์ฒด HTTP ์์ฒญ | Enter API | Status API | Heartbeat API |
|---|---|---|---|---|
| min | 0.51 | 0.53 | 0.51 | 0.70 |
| avg | 56.46 | 65.02 | 52.53 | 26.80 |
| max | 2325.06 | 2309.89 | 2325.06 | 409.09 |
| p50 | 3.40 | 2.50 | 3.77 | 4.97 |
| p90 | 164.11 | 212.56 | 138.18 | 97.45 |
| p95 | 290.38 | 345.54 | 261.04 | 132.42 |
| p99 | 0.00 | 0.00 | 0.00 | 0.00 |
Enter โ READY ์์ ์๊ฐ (ms):
- min: 1.00
- avg: 212.01
- max: 39,801.00
- p50: 5.00
- p90: 339.00
- p95: 566.00
- p99: 0.00
์ฒ๋ฆฌ๋:
- ์ค์ ๋ ํ ์คํธ ์๊ฐ: 60.00์ด
- ์ค์ ์คํ ์๊ฐ: 90.93์ด (graceful stop ํฌํจ)
- RPS ๊ณ์ฐ ๊ธฐ์ค ์๊ฐ: 60.00์ด
- ์ ์ฒด ํ๊ท RPS: 2,778.08 (Enter + Status + Heartbeat ํฉ๊ณ)
- Enter RPS: 953.30
- Status RPS: 1,786.15
- Heartbeat RPS: 38.63
- ์ค์ TPS (Enter/์ด): 953.30
- ๋ชฉํ TPS: 1000
- TPS ๋ฌ์ฑ๋ฅ : 95.33%
JVM ๋ฉํธ๋ฆญ:
| ๋ฉํธ๋ฆญ | ๊ฐ | ์ค๋ช |
|---|---|---|
| CPU utilization (JVM CPU) | ์ต๋ ์ฝ 70% (ํผํฌ), ์ดํ 5% ๋ฏธ๋ง์ผ๋ก ์์ ํ | ํ ์คํธ ์ด๋ฐ ์ฝ 70%๋ก ์ต๊ณ ์น๋ฅผ ๊ธฐ๋กํ ํ ์ ์ฐจ ๊ฐ์ํ์ฌ ํ ์คํธ ์ข ๋ฃ ํ์๋ 5% ๋ฏธ๋ง์ผ๋ก ์์ ํ |
| Heap Memory utilization | ์ต๋ ์ฝ 15% (ํผํฌ), ์ดํ ์ฝ 5% ์์ค์ผ๋ก ์ ์ง | ๋ ์ฐจ๋ก์ ๊ฑธ์ณ ์ฝ 15%๋ก ํผํฌ๋ฅผ ์ฐ์ ํ ์ฝ 5% ์์ค์ผ๋ก ์ ์ง |
| Garbage Collection | ์ต๋ ์ฝ 2.5% (ํผํฌ), ์ดํ ๊ฑฐ์ 0%๋ก ๊ฐ์ | ํ ์คํธ ์ด๋ฐ์ ์ฝ 2.5%๋ก ๊ฐ์ฅ ๋์ ํ๋์ ๋ณด์์ผ๋ฉฐ, ์ดํ ์ ์ฐจ ๊ฐ์ํ์ฌ ๊ฑฐ์ 0%์ ๊ฐ๊น๊ฒ ๋จ์ด์ง |
์๋น์ค ๋ฉํธ๋ฆญ (Grafana ๋์๋ณด๋):
- Rate: ์ ์ฒด ์์ฒญ ์ฒ๋ฆฌ์จ์ด ์ฝ 2.5K req/s (2,500 ์์ฒญ/์ด)๋ก ์ต๊ณ ์น๋ฅผ ๊ธฐ๋กํ ํ ๋น ๋ฅด๊ฒ ๊ฐ์ (1000 TPS ๊ตฌ๊ฐ๊ณผ ์ผ์น)
- Request Per Sec:
/api/v1/queue/{scheduleId}/enter๊ฐ ์ฝ 1.3K req/s๋ก ๊ฐ์ฅ ๋์ ์์ฒญ ์๋ฅผ ๋ณด์/api/v1/queue/{scheduleId}/heartbeat๋ ์ฝ 750 req/s๋ก ๋ ๋ฒ์งธ๋ก ๋์ ์์ฒญ ์๋ฅผ ๊ธฐ๋ก
- Percent of 2xx Requests: ๋ชจ๋ ์๋ํฌ์ธํธ์์ 100%์ 2xx ์๋ต๋ฅ ์ ๋ณด์ฌ, ๋ชจ๋ ์์ฒญ์ด ์ฑ๊ณต์ ์ผ๋ก ์ฒ๋ฆฌ๋จ
- Percent of 5xx Requests: "No data"๋ก ํ์๋์ด 5xx ์๋ฌ๋ ๋ฐ์ํ์ง ์์
- Total Requests: ์ด 168K (166,685์ ๋์ผ ๊ตฌ๊ฐ) ๊ท๋ชจ์ ์์ฒญ์ด ๋ฐ์
- Requests Average Duration:
/api/v1/queue/{scheduleId}/enter: 41.6 ms/api/v1/queue/{scheduleId}/status: 37.9 ms/api/v1/queue/{scheduleId}/heartbeat: 16.4 ms
๊ฒฝ๊ณ :
- User 538, 1079, 679, 658, 843, 581์ด 1000ํ ๋ฐ๋ณต ๋ด์ READY ์ํ๋ฅผ ๋ฐ์ง ๋ชปํจ
โ ๏ธ TPS ๋ฏธ๋ฌ์ฑ: ๋ชฉํ 1000 TPS ๋๋น 95.33% ๋ฌ์ฑ (953.30 TPS)โ ๏ธ ์ง์ฐ์๊ฐ ์ฆ๊ฐ: ํ๊ท ์๋ต ์๊ฐ์ด 56.46ms๋ก ์ฆ๊ฐ, p95๊ฐ 290.38ms๋ก ์์นโ ๏ธ Enter โ READY ์ง์ฐ: ํ๊ท 212.01ms, p95๊ฐ 566ms๋ก ์ฆ๊ฐํ์ฌ ๋๊ธฐ ์๊ฐ์ด ๊ธธ์ด์งโ ๏ธ ์ผ๋ถ ์ฌ์ฉ์ ํ์์์: 6๋ช ์ ์ฌ์ฉ์๊ฐ 1000ํ ๋ฐ๋ณต ๋ด์ READY๋ฅผ ๋ฐ์ง ๋ชปํจ- โ ์๋ฌ ์์: ์คํจ์จ 0%, ์๋ฒ ์๋ฌ ์์
| TPS | ๋ฌ์ฑ๋ฅ | ํ๊ท ์ง์ฐ์๊ฐ | p95 ์ง์ฐ์๊ฐ | EnterโREADY ํ๊ท | ์คํจ์จ | ์ํ |
|---|---|---|---|---|---|---|
| 100 | 100% | 2.15ms | 4.54ms | 4.56ms | 0.00% | โ ์ต์ |
| 500 | 100% | 1.44ms | 2.81ms | 2.68ms | 0.12% | โ ์ฐ์ |
| 1000 | 95.33% | 56.46ms | 290.38ms | 212.01ms | 0.00% |
-
100-500 TPS ๊ตฌ๊ฐ: ๋งค์ฐ ์์ ์ ์ด๊ณ ์ฐ์ํ ์ฑ๋ฅ์ ๋ณด์
- ์คํจ์จ ๊ฑฐ์ ์์
- ์ง์ฐ์๊ฐ ๋งค์ฐ ๋ฎ์
- ๋ชฉํ TPS ์๋ฒฝ ๋ฌ์ฑ
-
1000 TPS ๊ตฌ๊ฐ: ์ฑ๋ฅ ์ ํ ์์
- ํ๊ท ์ง์ฐ์๊ฐ์ด 56ms๋ก ์ฆ๊ฐ
- p95 ์ง์ฐ์๊ฐ์ด 290ms๋ก ์์น
- ์ผ๋ถ ์ฌ์ฉ์๊ฐ READY๋ฅผ ๋ฐ์ง ๋ชปํ๋ ๊ฒฝ์ฐ ๋ฐ์
- TPS ๋ฌ์ฑ๋ฅ 95.33%๋ก ์ฝ๊ฐ ๋ฏธ๋ฌ
- ๋๊ธฐ์ด ์์คํ
ํ๋ผ๋ฏธํฐ ํ๋: ๋ถํ ํ
์คํธ ๊ฒฐ๊ณผ๋ฅผ ๋ฐํ์ผ๋ก ๋ค์ ์ค์ ๊ฐ ์กฐ์ ๊ณ ๋ ค
batch-size: ๋ฐฐ์น ์ ์ฅ ์ฒ๋ฆฌ ํฌ๊ธฐ (๊ธฐ๋ณธ๊ฐ: 100) - TPS์ ๋ฐ๋ผ ์ฆ๊ฐ ๊ฐ๋ฅmax-active-users: ๋์ ํ์ฑ ์ฌ์ฉ์ ์ (๊ธฐ๋ณธ๊ฐ: 500) - ์๋ฒ ๋ฆฌ์์ค์ ๋ฐ๋ผ ์กฐ์ scheduler-interval-ms: ๋ฐฐ์น ์ ์ฅ ์ฒ๋ฆฌ ์ฃผ๊ธฐ (๊ธฐ๋ณธ๊ฐ: 5000ms) - ์ฒ๋ฆฌ๋์ ๋ฐ๋ผ ๋จ์ถ ๊ฐ๋ฅ
- Sorted Set ์ฐ์ฐ ์ต์ ํ: ๋๊ธฐ์ด ์์ ์กฐํ ์
ZRANK๋์ ๋ ํจ์จ์ ์ธ ๋ฐฉ๋ฒ ๊ณ ๋ ค - Connection Pool ํฌ๊ธฐ ์กฐ์ : ๋์ ์ฐ๊ฒฐ ์์ ๋ง๊ฒ Redis ์ฐ๊ฒฐ ํ ํฌ๊ธฐ ์ฆ๊ฐ
- Connection Pool ์กฐ์ : ๋์ ์์ฒญ ์์ ๋ง๊ฒ DB ์ฐ๊ฒฐ ํ ํฌ๊ธฐ ์ฆ๊ฐ
- ์ฟผ๋ฆฌ ์ต์ ํ: N+1 ์ฟผ๋ฆฌ ๋ฌธ์ ํ์ธ ๋ฐ ํด๊ฒฐ
- ์บ์ฑ ์ ๋ต: ์์ฃผ ์กฐํ๋๋ ๋ฐ์ดํฐ(์ค์ผ์ค ์ ๋ณด ๋ฑ) ์บ์ฑ
- Rate Limiting ์ค์ : ์ด์ ํ๊ฒฝ์์๋
RATE_LIMIT_ENABLED = true๋ก ์ค์ ํ๊ณMAX_REQUESTS_PER_MINUTE๋ฅผ ์ ์ ํ ์กฐ์
- ๋ก๋ ๋ฐธ๋ฐ์ฑ: ์ฌ๋ฌ ์๋ฒ ์ธ์คํด์ค๋ก ๋ถ์ฐ ์ฒ๋ฆฌ
- Redis ํด๋ฌ์คํฐ๋ง: Redis ์ฑ๋ฅ ํฅ์์ ์ํ ํด๋ฌ์คํฐ ๊ตฌ์ฑ
- ๋ก์ปฌ ํ ์คํธ: 1000 TPS ์ดํ ๊ถ์ฅ
- ์คํธ๋ ์ค ํ ์คํธ: 1100-1200 TPS (ํ๊ณ ํ์ธ)
- ์ด์ ํ๊ฒฝ: ๋ถ์ฐ ์ํคํ ์ฒ ๋๋ ์๋ฒ ์ค์ผ์ผ ์์ ํ์
- Heartbeat ์ต์ ํ: ๋ถํ์ํ Heartbeat ์์ฒญ ๊ฐ์
- Status ํด๋ง ์ต์ ํ: ํด๋ง ๊ฐ๊ฒฉ์ ๋์ ์ผ๋ก ์กฐ์ ํ์ฌ ๋ถํ ๊ฐ์
- ์๋ฌ ์ฒ๋ฆฌ ๊ฐํ: ํ์์์ ๋ฐ์ ์ ์ฌ์๋ ๋ก์ง ์ถ๊ฐ
ํ์ฌ ์์คํ ์ 500 TPS๊น์ง๋ ๋งค์ฐ ์์ ์ ์ผ๋ก ๋์ํ๋ฉฐ, 1000 TPS์์๋ 95% ์ด์์ ์ฑ๋ฅ์ ๋ณด์ฌ์ฃผ๊ณ ์์ต๋๋ค. ๋ค๋ง, 1000 TPS ์ด์์์๋ ์ง์ฐ์๊ฐ ์ฆ๊ฐ์ ์ผ๋ถ ์ฌ์ฉ์์ ํ์์์์ด ๋ฐ์ํ๋ฏ๋ก, ์ด์ ํ๊ฒฝ์์๋ ๋ถ์ฐ ์ํคํ ์ฒ์ ์ธํ๋ผ ์ต์ ํ๊ฐ ํ์ํฉ๋๋ค.




