Skip to content

Latest commit

ย 

History

History
818 lines (627 loc) ยท 39 KB

File metadata and controls

818 lines (627 loc) ยท 39 KB

FairTicket-BE ๋ถ€ํ•˜ ํ…Œ์ŠคํŠธ (k6)

k6 ๊ธฐ๋ฐ˜ ๋ถ€ํ•˜ ํ…Œ์ŠคํŠธ ๋ฐ์ดํ„ฐ, ์‹œ๋‚˜๋ฆฌ์˜ค, ์Šคํฌ๋ฆฝํŠธ ๋ชจ์Œ์ž…๋‹ˆ๋‹ค. ๋Œ€๊ธฐ์—ด(Queue) ํญ์ฃผ ์‹œ๋‚˜๋ฆฌ์˜ค๋ฅผ ๋‹ค๋ฃน๋‹ˆ๋‹ค.

๋ชฉ์ฐจ

01. ๊ฐœ์š” ๋ฐ ๋ชฉ์ 

์ด ๋ฌธ์„œ๋Š” FairTicket-BE์˜ ๋Œ€๊ธฐ์—ด(Queue) ์‹œ์Šคํ…œ์— ๋Œ€ํ•œ ๋ถ€ํ•˜ ํ…Œ์ŠคํŠธ ๊ฐ€์ด๋“œ์ž…๋‹ˆ๋‹ค. k6๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์˜คํ”ˆ ์งํ›„ ๋™์‹œ ์ ‘์†์ด ๋ชฐ๋ฆด ๋•Œ ๋Œ€๊ธฐ์—ด์ด ๊ฒฌ๋””๋Š”์ง€ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค.

์ฃผ์š” ๋ชฉ์ :

  • ๋Œ€๊ธฐ์—ด ์‹œ์Šคํ…œ์˜ ์„ฑ๋Šฅ ํ•œ๊ณ„ ํŒŒ์•…
  • Redis Sorted Set/ํ† ํฐ ๋ฐœ๊ธ‰ ์ง€์—ฐ ์ธก์ •
  • Rate Limit(429) ๋ฐœ์ƒ ๊ตฌ๊ฐ„ ํ™•์ธ
  • ํƒ€์ž„์•„์›ƒ/์—๋Ÿฌ์œจ ๋ชจ๋‹ˆํ„ฐ๋ง
  • Spring JVM ๋ฉ”ํŠธ๋ฆญ(CPU, Heap Memory, Garbage Collection) ๋ชจ๋‹ˆํ„ฐ๋ง
  • TPS๋ณ„ ์„ฑ๋Šฅ ํŠน์„ฑ ๋ถ„์„

02. ์•„ํ‚คํ…์ฒ˜

๋ถ€ํ•˜ ํ…Œ์ŠคํŠธ๋Š” 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
Loading
  • ํ˜ธ์ŠคํŠธ: 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์„ ์ ์šฉํ•ฉ๋‹ˆ๋‹ค.

03. ํ…Œ์ŠคํŠธ ํˆด ์„ ์ •

์ด ํ”„๋กœ์ ํŠธ๋Š” ์ดˆ๊ธฐ์— wrk ๊ธฐ๋ฐ˜์œผ๋กœ ์‹œ์ž‘๋˜์—ˆ์œผ๋‚˜, k6๋กœ ์ „ํ™˜๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ์ „ํ™˜ ์ด์œ ์™€ ๊ณผ์ •์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

์ „ํ™˜ ์ด์œ 

wrk์˜ ๋ฌธ์ œ์ 

  1. ์‘๋‹ต ๋ณธ๋ฌธ ์ฒ˜๋ฆฌ ๋ถˆ์•ˆ์ •

    • wrk๋Š” ์„ฑ๋Šฅ ์ตœ์ ํ™”๋กœ init() ํ˜ธ์ถœ ํ›„ response ํ•จ์ˆ˜๊ฐ€ ์ •์˜๋˜์ง€ ์•Š์œผ๋ฉด body๋ฅผ ํŒŒ์‹ฑํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
    • response ํ•จ์ˆ˜๊ฐ€ ์ •์˜๋˜์–ด ์žˆ์–ด๋„ wrk ๋ฒ„์ „/์„ค์ •์— ๋”ฐ๋ผ ํ˜ธ์ถœ๋˜์ง€ ์•Š์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
    • body๊ฐ€ nil์ด๊ฑฐ๋‚˜ ๋นˆ ๊ฐ’์ผ ์ˆ˜ ์žˆ์–ด READY ์ƒํƒœ ๊ฐ์ง€๊ฐ€ ๋ถˆ์•ˆ์ •ํ•ฉ๋‹ˆ๋‹ค.
  2. ์Šค๋ ˆ๋“œ๋ณ„ ๋ณ€์ˆ˜ ๋™๊ธฐํ™” ๋ฌธ์ œ

    • wrk๋Š” ๋ฉ€ํ‹ฐ์Šค๋ ˆ๋“œ ๊ธฐ๋ฐ˜์œผ๋กœ ๋™์ž‘ํ•˜๋ฉฐ, ์Šค๋ ˆ๋“œ๋ณ„๋กœ ๋…๋ฆฝ์ ์ธ Lua ์ƒํƒœ๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.
    • ์ „์—ญ ๋ณ€์ˆ˜ ๋™๊ธฐํ™”๊ฐ€ ์–ด๋ ค์›Œ ์ •ํ™•ํ•œ ๋ฉ”ํŠธ๋ฆญ ์ง‘๊ณ„๊ฐ€ ์–ด๋ ต์Šต๋‹ˆ๋‹ค.
  3. ๋””๋ฒ„๊น… ๋ฐ ์œ ์ง€๋ณด์ˆ˜ ์–ด๋ ค์›€

    • Lua ์Šคํฌ๋ฆฝํŠธ๋Š” ๋””๋ฒ„๊น…์ด ์–ด๋ ต๊ณ , ๋กœ๊น… ๊ธฐ๋Šฅ์ด ์ œํ•œ์ ์ž…๋‹ˆ๋‹ค.
    • ๋ณต์žกํ•œ ๋กœ์ง ๊ตฌํ˜„์ด ์–ด๋ ต๊ณ  ์ฝ”๋“œ ๊ฐ€๋…์„ฑ์ด ๋–จ์–ด์ง‘๋‹ˆ๋‹ค.

k6์˜ ์žฅ์ 

  1. ์‘๋‹ต ๋ณธ๋ฌธ ์ฒ˜๋ฆฌ ์•ˆ์ •์„ฑ

    • JavaScript ๊ธฐ๋ฐ˜์œผ๋กœ ์‘๋‹ต ๋ณธ๋ฌธ ํŒŒ์‹ฑ๊ณผ ๊ฒ€์ฆ์ด ์•ˆ์ •์ ์ž…๋‹ˆ๋‹ค.
    • JSON.parse()๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ •ํ™•ํ•œ READY ์ƒํƒœ ๊ฐ์ง€๊ฐ€ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.
  2. ๊ฐ•๋ ฅํ•œ ๋ฉ”ํŠธ๋ฆญ ์ˆ˜์ง‘

    • ์ปค์Šคํ…€ ๋ฉ”ํŠธ๋ฆญ(Counter, Trend, Gauge)์„ ์‰ฝ๊ฒŒ ์ •์˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
    • ์ฒดํฌ(check)์™€ ์ž„๊ณ„๊ฐ’(thresholds) ์„ค์ •์œผ๋กœ ์ž๋™ ๊ฒ€์ฆ์ด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.
    • ์ƒ์„ธํ•œ ๋ฉ”ํŠธ๋ฆญ์„ ๊ธฐ๋ณธ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค (p50, p95, p99 ๋“ฑ).
  3. ๋””๋ฒ„๊น… ๋ฐ ์œ ์ง€๋ณด์ˆ˜ ์šฉ์ด

    • JavaScript๋กœ ์ž‘์„ฑ๋˜์–ด ๊ฐœ๋ฐœ์ž์—๊ฒŒ ์นœ์ˆ™ํ•ฉ๋‹ˆ๋‹ค.
    • console.log()๋กœ ์‰ฌ์šด ๋กœ๊น…์ด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.
    • ์ฝ”๋“œ ๊ฐ€๋…์„ฑ๊ณผ ์œ ์ง€๋ณด์ˆ˜์„ฑ์ด ๋›ฐ์–ด๋‚ฉ๋‹ˆ๋‹ค.
  4. ํ™•์žฅ์„ฑ

    • Cloud ์‹คํ–‰ ์ง€์› (k6 Cloud)
    • ๊ณ ๊ธ‰ ์‹œ๋‚˜๋ฆฌ์˜ค ์ง€์› (scenarios, executors)
    • ํ–ฅํ›„ ํ™•์žฅ์— ์œ ๋ฆฌํ•ฉ๋‹ˆ๋‹ค.

์ „ํ™˜ ๊ณผ์ •

1. ์Šคํฌ๋ฆฝํŠธ ๋ณ€ํ™˜

Lua โ†’ JavaScript ๋ณ€ํ™˜:

  • queue-flow.lua โ†’ queue-flow.js
  • queue-enter.lua โ†’ queue-enter.js
  • queue-status.lua โ†’ queue-status.js
  • queue-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) ๊ฐœ๋…

2. ์„ค์ • ๋ณ€๊ฒฝ

ํ™˜๊ฒฝ ๋ณ€์ˆ˜ ๋ณ€๊ฒฝ:

  • WRK_THREADS, WRK_CONNECTIONS, WRK_DURATION ์ œ๊ฑฐ
  • K6_VUS, K6_DURATION ์ถ”๊ฐ€

ํ† ํฐ ํŒŒ์ผ ํ˜•์‹ ๋ณ€๊ฒฝ:

  • Lua ํ˜•์‹(tokens_generated.lua) ์ œ๊ฑฐ
  • JSON ํ˜•์‹(tokens.json) ์ถ”๊ฐ€ (k6์˜ open() ํ•จ์ˆ˜ ์‚ฌ์šฉ)

3. ์‹คํ–‰ ์Šคํฌ๋ฆฝํŠธ ์—…๋ฐ์ดํŠธ

Bash ์Šคํฌ๋ฆฝํŠธ ๋ณ€๊ฒฝ:

  • 04-run-queue-{100|500|1000|2000}.sh: wrk ๋ช…๋ น์–ด๋ฅผ k6 ๋ช…๋ น์–ด๋กœ ๋ณ€๊ฒฝ
  • ํ™˜๊ฒฝ ๋ณ€์ˆ˜ ์ „๋‹ฌ ๋ฐฉ์‹ ๋ณ€๊ฒฝ (--env ํ”Œ๋ž˜๊ทธ ์‚ฌ์šฉ)

ํ† ํฐ ์ค€๋น„ ์Šคํฌ๋ฆฝํŠธ ์—…๋ฐ์ดํŠธ:

  • 02-prepare-tokens.sh: JSON ํ˜•์‹ ํ† ํฐ ํŒŒ์ผ ์ƒ์„ฑ ์ถ”๊ฐ€

4. ๋ฌธ์„œ ์—…๋ฐ์ดํŠธ

  • README.md: wrk ์–ธ๊ธ‰์„ ๋ชจ๋‘ k6๋กœ ๋ณ€๊ฒฝ
  • ๋””๋ ‰ํ† ๋ฆฌ ๊ตฌ์กฐ์—์„œ .lua ํŒŒ์ผ ์ œ๊ฑฐ
  • k6 ๋ช…๋ น์–ด ์˜ˆ์‹œ๋กœ ์—…๋ฐ์ดํŠธ

์ „ํ™˜ ๊ฒฐ๊ณผ

  • โœ… ์‘๋‹ต ๋ณธ๋ฌธ ์ฒ˜๋ฆฌ ์•ˆ์ •์„ฑ ํ–ฅ์ƒ
  • โœ… READY ์ƒํƒœ ๊ฐ์ง€ ์ •ํ™•๋„ ๊ฐœ์„ 
  • โœ… ์ปค์Šคํ…€ ๋ฉ”ํŠธ๋ฆญ์œผ๋กœ ์ƒ์„ธํ•œ ๋ถ„์„ ๊ฐ€๋Šฅ
  • โœ… ์ฝ”๋“œ ๊ฐ€๋…์„ฑ ๋ฐ ์œ ์ง€๋ณด์ˆ˜์„ฑ ํ–ฅ์ƒ
  • โœ… ํ–ฅํ›„ ํ™•์žฅ์„ฑ ํ™•๋ณด

04. ๋น ๋ฅธ ์‹œ์ž‘ ๋ฐ ๋””๋ ‰ํ† ๋ฆฌ ๊ตฌ์กฐ

๋น ๋ฅธ ์‹œ์ž‘

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

์Šคํฌ๋ฆฝํŠธ ์ƒ์„ธ ์„ค๋ช…

01-seed-db.sh (DB ์‹œ๋“œ ์ ์šฉ)

์Šค์ผ€์ค„์„ "์ด๋ฏธ ์˜คํ”ˆ" ์ƒํƒœ๋กœ ๋ณ€๊ฒฝํ•˜์—ฌ ๋ถ€ํ•˜ ํ…Œ์ŠคํŠธ์—์„œ 2xx ์‘๋‹ต์„ ๋ฐ›์„ ์ˆ˜ ์žˆ๋„๋ก ํ•ฉ๋‹ˆ๋‹ค.

์ง€์› ํ™˜๊ฒฝ:

  • Docker: fairticket-postgres ์ปจํ…Œ์ด๋„ˆ๊ฐ€ ์‹คํ–‰ ์ค‘์ด๋ฉด docker exec๋กœ SQL์„ ์ ์šฉํ•ฉ๋‹ˆ๋‹ค.
  • ๋กœ์ปฌ psql: Docker๊ฐ€ ์—†์œผ๋ฉด ๋กœ์ปฌ psql์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค (๊ธฐ๋ณธ: localhost:5433, ์‚ฌ์šฉ์ž: fairticket, ๋น„๋ฐ€๋ฒˆํ˜ธ: fairticket123).

์‚ฌ์šฉ๋ฒ•:

./scripts/01-seed-db.sh

02-prepare-tokens.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 ๋ณ€ํ™˜๋งŒ ์ˆ˜ํ–‰

03-verify-env.sh (ํ™˜๊ฒฝ ๊ฒ€์ฆ)

๋ถ€ํ•˜ ํ…Œ์ŠคํŠธ ์‹คํ–‰ ์ „ ํ™˜๊ฒฝ์„ ๊ฒ€์ฆํ•ฉ๋‹ˆ๋‹ค. 3๋‹จ๊ณ„ ๊ฒ€์ฆ์„ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค:

  1. ์„œ๋ฒ„ ์—ฐ๊ฒฐ ํ™•์ธ: BASE_URL/actuator/health๋กœ ์„œ๋ฒ„ ์—ฐ๊ฒฐ ์—ฌ๋ถ€ ํ™•์ธ
  2. ์Šค์ผ€์ค„ ์˜คํ”ˆ ์—ฌ๋ถ€ ํ™•์ธ: GET /api/v1/concerts/{CONCERT_ID}์˜ dates[].available๋กœ ํ•ด๋‹น ์Šค์ผ€์ค„์ด ์˜คํ”ˆ ์ƒํƒœ์ธ์ง€ ํ™•์ธ
  3. ํ† ํฐ ์œ ํšจ์„ฑ ํ™•์ธ: tokens.txt์˜ ์ฒซ ๋ฒˆ์งธ ํ† ํฐ์œผ๋กœ POST /api/v1/queue/{SCHEDULE_ID}/enter๋ฅผ ์‹ค์ œ ํ˜ธ์ถœํ•˜์—ฌ HTTP ์ƒํƒœ ์ฝ”๋“œ ํ™•์ธ

์—๋Ÿฌ ์ฒ˜๋ฆฌ:

  • 401: ํ† ํฐ ๋งŒ๋ฃŒ ๋˜๋Š” JWT secret ๋ถˆ์ผ์น˜ โ†’ 02-prepare-tokens.sh ์žฌ์‹คํ–‰ ํ•„์š”
  • 429: Rate Limit โ†’ ์„œ๋ฒ„ ์„ค์ • ํ™•์ธ ๋˜๋Š” ์ž ์‹œ ํ›„ ์žฌ์‹œ๋„
  • ๊ธฐํƒ€ 4xx/5xx: ์Šค์ผ€์ค„/์ฝ˜์„œํŠธ ID ๋˜๋Š” ์„œ๋ฒ„ ๋กœ์ง ํ™•์ธ ํ•„์š”

04-run-queue-*.sh (TPS๋ณ„ ์‹คํ–‰ ์Šคํฌ๋ฆฝํŠธ)

์ž๋™ํ™” ๊ธฐ๋Šฅ:

  • ์Šค์ผ€์ค„ ์˜คํ”ˆ ์ƒํƒœ ํ™•์ธ: check_schedule_open() ํ•จ์ˆ˜๋กœ ์Šค์ผ€์ค„์ด ์˜คํ”ˆ ์ƒํƒœ์ธ์ง€ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค. ๋ฏธ์˜คํ”ˆ ์‹œ 01-seed-db.sh๋ฅผ ์ž๋™ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค.
  • ํ† ํฐ ํ™•์ธ ๋ฐ ํ•„์š”์‹œ ๋ฐœ๊ธ‰: 02-prepare-tokens.sh๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ๊ธฐ์กด ํ† ํฐ์˜ ์œ ํšจ์„ฑ์„ ๊ฒ€์ฆํ•˜๊ณ , ์œ ํšจํ•œ ํ† ํฐ์€ ์œ ์ง€ํ•˜๋ฉฐ ๋ถ€์กฑํ•œ ๊ฐœ์ˆ˜๋งŒ ์ƒˆ๋กœ ๋ฐœ๊ธ‰ํ•ฉ๋‹ˆ๋‹ค (NUM_USERS=$K6_VUS_*).
  • ํ™˜๊ฒฝ ๊ฒ€์ฆ: 03-verify-env.sh๋ฅผ ์ž๋™ ์‹คํ–‰ํ•˜์—ฌ ์„œ๋ฒ„ ์—ฐ๊ฒฐ, ์Šค์ผ€์ค„ ์˜คํ”ˆ, ํ† ํฐ ์œ ํšจ์„ฑ์„ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค.
  • ์ ˆ๋Œ€ ๊ฒฝ๋กœ ์ „๋‹ฌ: TOKEN_JSON_PATH๋ฅผ ์ ˆ๋Œ€ ๊ฒฝ๋กœ๋กœ ์ „๋‹ฌํ•˜์—ฌ k6์˜ open() ํ•จ์ˆ˜์—์„œ ์ •ํ™•ํžˆ ๋กœ๋“œ๋˜๋„๋ก ํ•ฉ๋‹ˆ๋‹ค.

05. ์š”๊ตฌ ์‚ฌํ•ญ ๋ฐ ์ฃผ์˜์ 

์š”๊ตฌ ์‚ฌํ•ญ

  • k6 ์„ค์น˜
  • FairTicket-BE ์„œ๋ฒ„ ์‹คํ–‰ ์ค‘ (๊ธฐ๋ณธ http://localhost:8080)
  • (์„ ํƒ) data/config.env ์—์„œ BASE_URL, SCHEDULE_ID ๋“ฑ ์„ค์ •

๋กœ์ปฌ ํ…Œ์ŠคํŠธ ์‹œ Rate Limit

๋กœ์ปฌ ํ…Œ์ŠคํŠธ ํ™˜๊ฒฝ์—์„œ๋Š” 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๋ฅผ ์ ์ ˆํžˆ ์กฐ์ •ํ•˜์„ธ์š”.

ํ† ํฐยท์Šค์ผ€์ค„ ๊ฒ€์ฆ (2xx๊ฐ€ 0๊ฐœ์ผ ๋•Œ)

๋ถ€ํ•˜ ํ…Œ์ŠคํŠธ์—์„œ ๋ชจ๋“  ์‘๋‹ต์ด 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์— ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค.

06. ๋ถ€ํ•˜ ์‹œ๋‚˜๋ฆฌ์˜ค

๋ชฉ์ 

์˜คํ”ˆ ์งํ›„ ๋™์‹œ ์ ‘์†์ด ๋ชฐ๋ฆด ๋•Œ ๋Œ€๊ธฐ์—ด์ด ๊ฒฌ๋””๋Š”์ง€ ํ™•์ธํ•œ๋‹ค.
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 ์‹คํ–‰ ์‹œ ๋‹ค์Œ์„ ์ž๋™์œผ๋กœ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค:

  1. ์Šค์ผ€์ค„ ์˜คํ”ˆ ์ƒํƒœ ํ™•์ธ (๋ฏธ์˜คํ”ˆ ์‹œ 01-seed-db.sh ์ž๋™ ์‹คํ–‰)
  2. ํ† ํฐ ํ™•์ธ ๋ฐ ํ•„์š”์‹œ ๋ฐœ๊ธ‰ (02-prepare-tokens.sh: ์œ ํšจํ•œ ํ† ํฐ์€ ์œ ์ง€ํ•˜๊ณ  ๋ถ€์กฑํ•œ ๊ฐœ์ˆ˜๋งŒ ๋ฐœ๊ธ‰)
  3. ํ™˜๊ฒฝ ๊ฒ€์ฆ (03-verify-env.sh: ์„œ๋ฒ„ ์—ฐ๊ฒฐ, ์Šค์ผ€์ค„ ์˜คํ”ˆ, ํ† ํฐ ์œ ํšจ์„ฑ ํ™•์ธ)
  4. ํ†ตํ•ฉ ํ๋ฆ„(queue-flow.js) ์‹คํ–‰

๊ฐ ๊ฐ€์ƒ ์‚ฌ์šฉ์ž(ํ† ํฐ)๋Š” ์ฒซ ์š”์ฒญ์—์„œ enter, ์ดํ›„ ์š”์ฒญ์—์„œ **ํ•˜ํŠธ๋น„ํŠธ(HEARTBEAT_INTERVAL_MS ๊ฐ„๊ฒฉ)**์™€ **status(STATUS_POLL_MS ๊ฐ„๊ฒฉ)**๋ฅผ ๋ฒˆ๊ฐˆ์•„๊ฐ€๋ฉฐ ๋ณด๋‚ด๋ฉฐ WAITING โ†’ READY๋ฅผ ๊ธฐ๋‹ค๋ฆฌ๋Š” ๊ตฌ์กฐ์ž…๋‹ˆ๋‹ค. ํ•˜ํŠธ๋น„ํŠธ๋Š” heartbeat TTL(30์ดˆ)๋ณด๋‹ค ์งง์€ ๊ฐ„๊ฒฉ(๊ธฐ๋ณธ 20์ดˆ)์œผ๋กœ ์ „์†กํ•˜์—ฌ ์‚ฌ์šฉ์ž๊ฐ€ ํ์—์„œ ์ œ๊ฑฐ๋˜์ง€ ์•Š๋„๋ก ํ•ฉ๋‹ˆ๋‹ค.

์Šคํฌ๋ฆฝํŠธ ๊ตฌํ˜„ ์ƒ์„ธ

queue-flow.js (ํ†ตํ•ฉ ํ๋ฆ„)

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 ๋‹ฌ์„ฑ๋ฅ 

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 ์ „์šฉ ๋ณ€์ˆ˜๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

100 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

500 TPS ์‹œ๋‚˜๋ฆฌ์˜ค

์ตœ๊ณ  ๋ถ€ํ•˜ ํ…Œ์ŠคํŠธ๋ฅผ ์œ„ํ•œ ์„ค์ •์ž…๋‹ˆ๋‹ค.

  • ๋ชฉํ‘œ 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

1000 TPS ์‹œ๋‚˜๋ฆฌ์˜ค

๊ณ ๋ถ€ํ•˜ ํ…Œ์ŠคํŠธ๋ฅผ ์œ„ํ•œ ์„ค์ •์ž…๋‹ˆ๋‹ค.

  • ๋ชฉํ‘œ 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

2000 TPS ์‹œ๋‚˜๋ฆฌ์˜ค

์ดˆ๊ณ ๋ถ€ํ•˜ ํ…Œ์ŠคํŠธ๋ฅผ ์œ„ํ•œ ์„ค์ •์ž…๋‹ˆ๋‹ค.

  • ๋ชฉํ‘œ 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

ํ™˜๊ฒฝ ๋ณ€์ˆ˜ (config.env / ์‹คํ–‰ ์‹œ)

๊ฐ 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 ์‚ฌ์šฉ

07. TPS๋ณ„ ๋ถ€ํ•˜ ์ง„ํ–‰

07-1. 100TPS์ธ ๊ฒฝ์šฐ

ํ…Œ์ŠคํŠธ ์„ค์ •

  • ๋ชฉํ‘œ 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%๋กœ ๊ฐ์†Œ

JVM ๋ฉ”ํŠธ๋ฆญ - 100TPS

์„œ๋น„์Šค ๋ฉ”ํŠธ๋ฆญ (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 ์—๋Ÿฌ๋Š” ๋ฐœ์ƒํ•˜์ง€ ์•Š์Œ

์„œ๋น„์Šค ๋ฉ”ํŠธ๋ฆญ - 100TPS

๋ถ„์„

  • โœ… ์™„๋ฒฝํ•œ ์„ฑ๋Šฅ: ์‹คํŒจ์œจ 0%, ๋ชฉํ‘œ TPS 100% ๋‹ฌ์„ฑ
  • โœ… ๋‚ฎ์€ ์ง€์—ฐ์‹œ๊ฐ„: ํ‰๊ท  ์‘๋‹ต ์‹œ๊ฐ„ 2.15ms, p95๊ฐ€ 4.54ms๋กœ ๋งค์šฐ ์šฐ์ˆ˜
  • โœ… ์•ˆ์ •์ ์ธ ์ฒ˜๋ฆฌ: Enter โ†’ READY ์†Œ์š” ์‹œ๊ฐ„ ํ‰๊ท  4.56ms๋กœ ์ฆ‰์‹œ ์ฒ˜๋ฆฌ๋จ
  • โœ… Rate Limit ๋ฏธ๋ฐœ์ƒ: ๋กœ์ปฌ ํ…Œ์ŠคํŠธ ํ™˜๊ฒฝ์—์„œ๋Š” Rate Limit์ด ๋น„ํ™œ์„ฑํ™”๋˜์–ด ์žˆ์–ด 429 ์—๋Ÿฌ ์—†์ด ์•ˆ์ •์ ์œผ๋กœ ๋™์ž‘

07-2. 500TPS์ธ ๊ฒฝ์šฐ

ํ…Œ์ŠคํŠธ ์„ค์ •

  • ๋ชฉํ‘œ 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%๋กœ ๋–จ์–ด์ง€๋Š” ์ข… ๋ชจ์–‘์˜ ๊ณก์„ ์„ ๋ณด์ž„

JVM ๋ฉ”ํŠธ๋ฆญ - 500TPS

์„œ๋น„์Šค ๋ฉ”ํŠธ๋ฆญ (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

์„œ๋น„์Šค ๋ฉ”ํŠธ๋ฆญ - 500TPS

๋ถ„์„

  • โœ… ๋ชฉํ‘œ ๋‹ฌ์„ฑ: TPS ๋‹ฌ์„ฑ๋ฅ  100%, ์‹คํŒจ์œจ 0.12%๋กœ ๋งค์šฐ ๋‚ฎ์Œ
  • โœ… ์šฐ์ˆ˜ํ•œ ์„ฑ๋Šฅ: ํ‰๊ท  ์‘๋‹ต ์‹œ๊ฐ„ 1.44ms, p95๊ฐ€ 2.81ms๋กœ ์—ฌ์ „ํžˆ ์šฐ์ˆ˜
  • โœ… ๋น ๋ฅธ ์ฒ˜๋ฆฌ: Enter โ†’ READY ์†Œ์š” ์‹œ๊ฐ„ ํ‰๊ท  2.68ms๋กœ ๋งค์šฐ ๋น ๋ฆ„
  • โš ๏ธ ์‹คํ–‰ ์‹œ๊ฐ„ ์—ฐ์žฅ: graceful stop์œผ๋กœ ์ธํ•ด ์‹ค์ œ ์‹คํ–‰ ์‹œ๊ฐ„์ด 90์ดˆ๋กœ ์—ฐ์žฅ๋จ (์ •์ƒ ๋™์ž‘)

07-3. 1000TPS์ธ ๊ฒฝ์šฐ

ํ…Œ์ŠคํŠธ ์„ค์ •

  • ๋ชฉํ‘œ 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%์— ๊ฐ€๊น๊ฒŒ ๋–จ์–ด์ง

JVM ๋ฉ”ํŠธ๋ฆญ - 1000TPS

์„œ๋น„์Šค ๋ฉ”ํŠธ๋ฆญ (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

์„œ๋น„์Šค ๋ฉ”ํŠธ๋ฆญ - 1000TPS

๊ฒฝ๊ณ :

  • 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%, ์„œ๋ฒ„ ์—๋Ÿฌ ์—†์Œ

08. ๊ฒฐ๋ก  ๋ฐ ํŠœ๋‹ํฌ์ธํŠธ

์„ฑ๋Šฅ ์š”์•ฝ

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% โš ๏ธ ๊ฒฝ๊ณ 

์ฃผ์š” ๋ฐœ๊ฒฌ์‚ฌํ•ญ

  1. 100-500 TPS ๊ตฌ๊ฐ„: ๋งค์šฐ ์•ˆ์ •์ ์ด๊ณ  ์šฐ์ˆ˜ํ•œ ์„ฑ๋Šฅ์„ ๋ณด์ž„

    • ์‹คํŒจ์œจ ๊ฑฐ์˜ ์—†์Œ
    • ์ง€์—ฐ์‹œ๊ฐ„ ๋งค์šฐ ๋‚ฎ์Œ
    • ๋ชฉํ‘œ TPS ์™„๋ฒฝ ๋‹ฌ์„ฑ
  2. 1000 TPS ๊ตฌ๊ฐ„: ์„ฑ๋Šฅ ์ €ํ•˜ ์‹œ์ž‘

    • ํ‰๊ท  ์ง€์—ฐ์‹œ๊ฐ„์ด 56ms๋กœ ์ฆ๊ฐ€
    • p95 ์ง€์—ฐ์‹œ๊ฐ„์ด 290ms๋กœ ์ƒ์Šน
    • ์ผ๋ถ€ ์‚ฌ์šฉ์ž๊ฐ€ READY๋ฅผ ๋ฐ›์ง€ ๋ชปํ•˜๋Š” ๊ฒฝ์šฐ ๋ฐœ์ƒ
    • TPS ๋‹ฌ์„ฑ๋ฅ  95.33%๋กœ ์•ฝ๊ฐ„ ๋ฏธ๋‹ฌ

ํŠœ๋‹ ํฌ์ธํŠธ

1. Redis ์ตœ์ ํ™”

  • ๋Œ€๊ธฐ์—ด ์‹œ์Šคํ…œ ํŒŒ๋ผ๋ฏธํ„ฐ ํŠœ๋‹: ๋ถ€ํ•˜ ํ…Œ์ŠคํŠธ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ”ํƒ•์œผ๋กœ ๋‹ค์Œ ์„ค์ •๊ฐ’ ์กฐ์ • ๊ณ ๋ ค
    • batch-size: ๋ฐฐ์น˜ ์ž…์žฅ ์ฒ˜๋ฆฌ ํฌ๊ธฐ (๊ธฐ๋ณธ๊ฐ’: 100) - TPS์— ๋”ฐ๋ผ ์ฆ๊ฐ€ ๊ฐ€๋Šฅ
    • max-active-users: ๋™์‹œ ํ™œ์„ฑ ์‚ฌ์šฉ์ž ์ˆ˜ (๊ธฐ๋ณธ๊ฐ’: 500) - ์„œ๋ฒ„ ๋ฆฌ์†Œ์Šค์— ๋”ฐ๋ผ ์กฐ์ •
    • scheduler-interval-ms: ๋ฐฐ์น˜ ์ž…์žฅ ์ฒ˜๋ฆฌ ์ฃผ๊ธฐ (๊ธฐ๋ณธ๊ฐ’: 5000ms) - ์ฒ˜๋ฆฌ๋Ÿ‰์— ๋”ฐ๋ผ ๋‹จ์ถ• ๊ฐ€๋Šฅ
  • Sorted Set ์—ฐ์‚ฐ ์ตœ์ ํ™”: ๋Œ€๊ธฐ์—ด ์ˆœ์œ„ ์กฐํšŒ ์‹œ ZRANK ๋Œ€์‹  ๋” ํšจ์œจ์ ์ธ ๋ฐฉ๋ฒ• ๊ณ ๋ ค
  • Connection Pool ํฌ๊ธฐ ์กฐ์ •: ๋™์‹œ ์—ฐ๊ฒฐ ์ˆ˜์— ๋งž๊ฒŒ Redis ์—ฐ๊ฒฐ ํ’€ ํฌ๊ธฐ ์ฆ๊ฐ€

2. ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ตœ์ ํ™”

  • Connection Pool ์กฐ์ •: ๋™์‹œ ์š”์ฒญ ์ˆ˜์— ๋งž๊ฒŒ DB ์—ฐ๊ฒฐ ํ’€ ํฌ๊ธฐ ์ฆ๊ฐ€
  • ์ฟผ๋ฆฌ ์ตœ์ ํ™”: N+1 ์ฟผ๋ฆฌ ๋ฌธ์ œ ํ™•์ธ ๋ฐ ํ•ด๊ฒฐ

3. ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋ ˆ๋ฒจ

  • ์บ์‹ฑ ์ „๋žต: ์ž์ฃผ ์กฐํšŒ๋˜๋Š” ๋ฐ์ดํ„ฐ(์Šค์ผ€์ค„ ์ •๋ณด ๋“ฑ) ์บ์‹ฑ
  • Rate Limiting ์„ค์ •: ์šด์˜ ํ™˜๊ฒฝ์—์„œ๋Š” RATE_LIMIT_ENABLED = true๋กœ ์„ค์ •ํ•˜๊ณ  MAX_REQUESTS_PER_MINUTE๋ฅผ ์ ์ ˆํžˆ ์กฐ์ •

4. ์ธํ”„๋ผ ๋ ˆ๋ฒจ

  • ๋กœ๋“œ ๋ฐธ๋Ÿฐ์‹ฑ: ์—ฌ๋Ÿฌ ์„œ๋ฒ„ ์ธ์Šคํ„ด์Šค๋กœ ๋ถ„์‚ฐ ์ฒ˜๋ฆฌ
  • Redis ํด๋Ÿฌ์Šคํ„ฐ๋ง: Redis ์„ฑ๋Šฅ ํ–ฅ์ƒ์„ ์œ„ํ•œ ํด๋Ÿฌ์Šคํ„ฐ ๊ตฌ์„ฑ

5. ์‹œ๋‚˜๋ฆฌ์˜ค๋ณ„ ๊ถŒ์žฅ์‚ฌํ•ญ

  • ๋กœ์ปฌ ํ…Œ์ŠคํŠธ: 1000 TPS ์ดํ•˜ ๊ถŒ์žฅ
  • ์ŠคํŠธ๋ ˆ์Šค ํ…Œ์ŠคํŠธ: 1100-1200 TPS (ํ•œ๊ณ„ ํ™•์ธ)
  • ์šด์˜ ํ™˜๊ฒฝ: ๋ถ„์‚ฐ ์•„ํ‚คํ…์ฒ˜ ๋˜๋Š” ์„œ๋ฒ„ ์Šค์ผ€์ผ ์•„์›ƒ ํ•„์š”

ํ–ฅํ›„ ๊ฐœ์„  ๋ฐฉํ–ฅ

  1. Heartbeat ์ตœ์ ํ™”: ๋ถˆํ•„์š”ํ•œ Heartbeat ์š”์ฒญ ๊ฐ์†Œ
  2. Status ํด๋ง ์ตœ์ ํ™”: ํด๋ง ๊ฐ„๊ฒฉ์„ ๋™์ ์œผ๋กœ ์กฐ์ •ํ•˜์—ฌ ๋ถ€ํ•˜ ๊ฐ์†Œ
  3. ์—๋Ÿฌ ์ฒ˜๋ฆฌ ๊ฐ•ํ™”: ํƒ€์ž„์•„์›ƒ ๋ฐœ์ƒ ์‹œ ์žฌ์‹œ๋„ ๋กœ์ง ์ถ”๊ฐ€

๊ฒฐ๋ก 

ํ˜„์žฌ ์‹œ์Šคํ…œ์€ 500 TPS๊นŒ์ง€๋Š” ๋งค์šฐ ์•ˆ์ •์ ์œผ๋กœ ๋™์ž‘ํ•˜๋ฉฐ, 1000 TPS์—์„œ๋„ 95% ์ด์ƒ์˜ ์„ฑ๋Šฅ์„ ๋ณด์—ฌ์ฃผ๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ๋‹ค๋งŒ, 1000 TPS ์ด์ƒ์—์„œ๋Š” ์ง€์—ฐ์‹œ๊ฐ„ ์ฆ๊ฐ€์™€ ์ผ๋ถ€ ์‚ฌ์šฉ์ž์˜ ํƒ€์ž„์•„์›ƒ์ด ๋ฐœ์ƒํ•˜๋ฏ€๋กœ, ์šด์˜ ํ™˜๊ฒฝ์—์„œ๋Š” ๋ถ„์‚ฐ ์•„ํ‚คํ…์ฒ˜์™€ ์ธํ”„๋ผ ์ตœ์ ํ™”๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.