403 V1 focused load test plan - 100-hours-a-week/KTB4-3rd-CLOUD GitHub Wiki
์ด ๋ฌธ์๋ ์๋ ๋ค ๊ฐ์ง ์ง๋ฌธ๋ง ์์น๋ก ๋ตํ๊ธฐ ์ํ ์คํ ๊ณํ์ด๋ค. RPS ์ฐ์ ๊ทผ๊ฑฐ์ ์ ์ฒด ๋ณ๋ชฉ ๋ชฉ๋ก์ 402 ์ค๊ณ, ๊ณตํต ํ ํด๋ก์งยท๊ด์ธกยท์ค๋จ ์กฐ๊ฑด์ 402 ์คํ์ ๊ทธ๋๋ก ๋ฐ๋ฅด๊ณ , ์ฌ๊ธฐ์๋ 402์ ๋ถ๋ถ์งํฉ์ ์ ๋น๊ต ์ถ๊ณผ ํ์ ์ฐ์๋ง ์ถ๊ฐํ๋ค.
| ์ง๋ฌธ | ์ด ๋ฌธ์ ๋จ๊ณ | 402 ๋งคํ | 402์ ์์ด์ ์๋ก ๋ฃ์ ๊ฒ |
|---|---|---|---|
| WS ๋์ ์ฐ๊ฒฐ ์ ์ฆ๊ฐ๊ฐ Spring ์์์ ์ผ๋ง๋ ์ ์ ํ๋๊ฐ | F1-a | T9 | ์ฐ๊ฒฐ๋น heapยทdirect ์ฐ์ถ์, WS_PER_CONNECTION_BYTES ์กฐ๊ฑด |
| WS ๋์ ์ฐ๊ฒฐ ์๋์จ ์ฆ๊ฐ๊ฐ ์์์ ์ผ๋ง๋ ์ ์ ํ๋๊ฐ | F1-b | T9์ ํผ์ฌ | ์ฐ๊ฒฐ ์ ๊ณ ์ ยท์ฐ๊ฒฐ๋ฅ ๋จ๋ ์ถ, Nginx ์ง์ ํ๊ณ ๋ถ๋ฆฌ |
| ๊ทธ ์ ์ ๊ฐ RESTยท๋ค๋ฅธ API ์๋น์ค์ ์ฅ์ ๋ฅผ ์ฃผ๋๊ฐ | F1-c | T11 | ์ปจํ ์ด๋ quota ๊ฒฉ๋ฆฌ ํ์ธ, CPU credit ๋ณด์ |
| ๋ฉ์์ง ์ ํ๋ณ(๊ธด ์ปจํ ์คํธยท์ ์ ์ฐ๊ฒฐ โ ์งง์ ๋ฉ์์งยท๋ง์ ์ฐ๊ฒฐ) CPUยท๋ฉ๋ชจ๋ฆฌ ๋น๊ต | F2 | T10 ์ผ๋ถ | 2ร2ร2 ์์ธ ์ค๊ณ, payload๋ณ DATA_FILE, ๊ฑด์ยท๋ฐ์ดํธ ๋น์ฉ ๋ถ๋ฆฌ |
| DB ์ ์ ์ ๋น๋๊ธฐยท์บ์ ์ฒ๋ฆฌ๊ฐ ํ์ํ๊ฐ | F3 | T10ยทT6 ์ผ๋ถ |
chat_hold_ms ์ถ, ํ ํฌ๊ธฐ ์ฐ์(Little) |
| ์ฌ์ฉ์ ์ฆ๊ฐ๋ก ์ธํ ์ธ๊ธฐ ํ ๊ฒฝํฉยทํ ์ ์ ๊ฐ ๋ค๋ฅธ API์ ์ฃผ๋ ์ํฅ | F4 | T8 | ํ timeout โ lock wait timeout ๋ถ๋ฆฌ, ๋ณํ REST |
| ๋จ์ ์กฐํ RPS ์ฆ๊ฐ์ ๋ฐ๋ฅธ ์ปจํ ์ด๋ ์ฑ๋ฅ ๋ณํ(t3.medium) | F5 | T2ยทT3 ์ผ๋ถ | RPS๋น CPU-ms, quota ์ด๋ก ์ํ, credit ๋ณด์ |
์ธก์ ๋์์ loadtest-target/compose.yaml์ ํฉ์ฑ ํฝ์ค์ฒ(perf/ws-lab/demo
๋น๋ ์ด๋ฏธ์ง)์ด๋ฉฐ, ๋ถํ ๋ฐ์๊ธฐ๋ loadtest-scenarios/์ k6 ์คํฌ๋ฆฝํธ๋ฅผ
loadtest-target/k6.sh๋ก ์คํํ๋ค. ์ ๋๊ฐ์ ์ค์ moyeota/be๊ฐ ์๋๋ฏ๋ก
๊ณก์ ์ ๋ชจ์๊ณผ ์ต์ด ํฌํ ์์์ ๊ฒฐ๋ก ์ผ๋ก ์ฌ์ฉํ๊ณ , ์ ๋ RPS๋ฅผ V1 ์ฉ๋
๋ณด์ฆ๊ฐ์ผ๋ก ์ฐ์ง ์๋๋ค.
t3.medium์ 2 vCPU ยท 4 GiB๋ค. ์ปจํ
์ด๋ ์์ฐ์ docs/103-V1-IaC-Input-Spec.md
4.1์ ๋ฐ๋ฅด๋ฉฐ ํฉ๊ณ๊ฐ ํธ์คํธ CPU๋ฅผ 100% ์์งํ๋๋ก ๋ฐฐ๋ถ๋์ด ์๋ค.
| ์ปจํ ์ด๋ | CPU | ๋ฉ๋ชจ๋ฆฌ | ๋น๊ณ |
|---|---|---|---|
| nginx | 0.25 | 128 MB |
worker_processes 1, worker_connections 16384, nofile 32768 |
| frontend(placeholder) | 0.50 | 512 MB | ์์ 384 MB ์ ์ |
| backend(Spring) | 0.75 | 768 MB |
-Xmx512m, nofile 16384, Tomcat threads 200 / max-connections 8192 |
| mysql | 0.50 | 768 MB | buffer pool 384 MB, max_connections 151 |
| ํฉ๊ณ | 2.00 | 2,176 MB |
์ด ๋ฐฐ๋ถ์์ ๋์ค๋ ๊ตฌ์กฐ์ ์ฌ์ค์ ํ์ ์ ๊ธฐ์ค์ ์ผ๋ก ์ผ๋๋ค.
- REST์ WebSocket์ ๊ฐ์ backend ์ปจํ ์ด๋์ 0.75 CPU ยท 512 MB heap ยท Hikari 10 ์ปค๋ฅ์ ์ ๊ณต์ ํ๋ค. ๋ฐ๋ผ์ "WS๊ฐ API ์๋น์ค์ ์ฅ์ ๋ฅผ ์ค๋ค"๋ 1์ฐจ์ ์ผ๋ก ์ปจํ ์ด๋ ๋ด๋ถ ๊ฒฝํฉ์ผ๋ก ๋ํ๋๋ค.
- frontendยทmysqlยทnginx๋ ๋ณ๋ quota์ด๋ฏ๋ก backend ํฌํ๋ง์ผ๋ก๋ ์ง์ ๋นผ์๊ธฐ์ง ์๋๋ค. ์ด๋ค๊น์ง ๋์์ ์ ํ๋๋ฉด ์์ธ์ ํธ์คํธ CPUยท๋คํธ์ํฌยท CPU credit ๋๋ ๋์คํฌ๋ค. F1-c์์ ์ด ๊ตฌ๋ถ์ ํ์ ์ ์ด๋ค.
- backend
mem_limit 768m๊ณผ-Xmx512m์ฌ์ด ์ฌ์ ๋ ์ฝ 256 MB๋ค. Metaspace, ์ค๋ ๋ ์คํ, Tomcat NIO์ direct ByteBuffer๊ฐ ์ด ์์์ ๋์ด๋๋ฏ๋ก heap OOM๋ณด๋ค ์ปจํ ์ด๋ OOM-kill์ด ๋จผ์ ์ฌ ์ ์๋ค. F1-a์์ NMT๋ก ํ์ธํ๋ค.
t3.medium์ baseline์ 20%(= 2 vCPU ์ค 0.4 vCPU, 24 credits/h)๋ค. backend ํ๋๋ง 0.75 CPU๋ฅผ ์ง์ ์ฌ์ฉํด๋ baseline์ ๋์ผ๋ฏ๋ก, 10๋ถ ์ด์ ์ธก์ ์ ํญ์ credit์ ์๋ชจํ๋ค.
- ๋งค ๋จ๊ณ ์ ํ๋ก
CPUCreditBalance,CPUSurplusCreditBalance, credit specification(standard/unlimited)์ ๊ธฐ๋กํ๋ค. - credit balance๊ฐ 0์ ๋ฟ์ ๊ตฌ๊ฐ์ ์ฑ๋ฅ ์ ํ๋ ์ฉ๋ ํ๊ณ๊ฐ ์๋๋ผ credit
๊ณ ๊ฐ์ด๋ค. ํด๋น ๊ตฌ๊ฐ์
C_knee์ฐ์ ์์ ์ ์ธํ๊ณ ์ฌ์ธก์ ํ๋ค. - ๋น๊ต ์คํ(F2 ์ ๊ฐ, F1-c control ๋๋น)์ credit ์ํ๊ฐ ์ ์ฌํ ๊ตฌ๊ฐ๋ผ๋ฆฌ๋ง ๋น๊ตํ๋ค. ๊ฐ๋ฅํ๋ฉด unlimited๋ก ๊ณ ์ ํ๊ณ ๊ทธ ์ฌ์ค์ ๊ฒฐ๊ณผ์ ๋จ๊ธด๋ค.
loadtest-target/.local/target.env ์ ์ฒด ๊ฐ์ ๋จ๊ณ๋ณ๋ก ๊ณ ์ ํ๊ณ , ๋ณ๊ฒฝ ์
RUN_ID์ ํจ๊ป ๊ธฐ๋กํ๋ค. ๊ธฐ๋ณธ๊ฐ์ ๋ค์๊ณผ ๊ฐ๋ค.
BACKEND_CPUS=0.75 BACKEND_MEMORY=768m JVM_XMX=512m
HIKARI_MAX_POOL_SIZE=10 HIKARI_CONNECTION_TIMEOUT_MS=1000
WS_PER_CONNECTION_BYTES=0
MYSQL_BUFFER_POOL=384M MYSQL_MAX_CONNECTIONS=151
FRONTEND_RESERVE_MB=384 FRONTEND_SSR_WORK_MS=5
์ถ๊ฐ๋ก BACKEND_IMAGE digest, ํฝ์ค์ฒ lab_run ์ค์ (chat_hold_ms,
lock_hold_ms, parties, seats), ๋ก์ปฌ ๋ฐ์๊ธฐ ์ฌ์ยทulimit -nยท์
๋ก๋
๋์ญํญ, ์๊ฐ๋, credit ์ํ๋ฅผ ๋งค ์คํ์ ๋จ๊ธด๋ค.
402์ ๋์ผํ๊ฒ C_knee(SLOยท์ ํฉ์ฑ์ด ์ฒ์ ๊นจ์ง๋ ์ง์ ๋ถํ), C_safe = C_knee ร 0.7์ ์ฌ์ฉํ๋ค. ๊ฐ ๋จ๊ณ๋ 5๋ถ warm-up โ 10๋ถ measure, ํ ๋ฒ์
ํ ์ถ๋ง ๋ณ๊ฒฝํ๊ณ , ์๊ณ ๊ทผ์ฒ ๋จ๊ณ๋ง 3ํ ๋ฐ๋ณตํด ์ค์๊ฐ๊ณผ ๋ณ๋ํญ์ ๋จ๊ธด๋ค.
๋ก์ปฌ ๋ฐ์๊ธฐ ์งํ(CPU 60% ๋ฏธ๋ง, swap 0, ์
๋ก๋ 70% ๋ฏธ๋ง, dropped iterations 0,
๋ชฉํ ์ ๋ฌ๋ฅ 95% ์ด์)๋ฅผ ๋ง์กฑํ์ง ๋ชปํ ์คํ์ ์๋ฒ ํ๊ณ๋ก ํด์ํ์ง ์๋๋ค.
REST ๋ฐฐ๊ฒฝ ๋ถํ๋ ๋ชจ๋ ๋ธ๋ก์ ๊ณ์ ๊น์ง ์๋๋ค. ํ ์คํธ ๋ชฉ์ ์ ๋ฐ๋ผ ๋ค์์ฒ๋ผ ๋ถ๋ฆฌํ๋ค.
| ๋จ๊ณ | REST ๋ฐฐ๊ฒฝ ๋ถํ | ์ด์ |
|---|---|---|
| F1-a ์ฐ๊ฒฐ๋น ์์ ๋จ๊ฐ | ์์ | WebSocket ์ฐ๊ฒฐ ์์ฒด์ heapยทdirectยทCPU ๋น์ฉ์ ์ธก์ |
| F1-b handshake ์๋์จ | ์์ | TLSยทNginxยท์ฐ๊ฒฐ ์๋ฆฝ ๋น์ฉ์ ์ธก์ |
| F1-c REST ๊ฐ์ญ | ํ์ | WS๊ฐ REST p95ยท์ค๋ฅ์จ์ ์ ํ์ํค๋์ง ์ธก์ |
| F2 echo ๋ฉ์์ง | ์์ | ์ฐ๊ฒฐ ์ยท๋ฉ์์ง ๊ฑด์ยทpayload ๋ฐ์ดํธ ๋น์ฉ์ ๋ถ๋ฆฌ |
| F3 DB ์ ์ฅ | ์ ํ์ ์ผ๋ก ํ์ | ์ ์ฅ ์์ฒด์ ๋ณํ REST ๊ฐ์ญ์ ๊ฐ๊ฐ ์ธก์ |
| F4 hot-row | ๊ฐ์ญ ์ธก์ ์ ํ์ | hot-row ์์ฒด์ ๋ค๋ฅธ API๋ก์ ์ ํ๋ฅผ ๋ถ๋ฆฌ |
| F5 ์กฐํ RPS | ์์ | ์กฐํ API ์์ฒด์ CPUยทDBยทquota ํ๊ณ๋ฅผ ์ธก์ |
http-mixed.js๋ฅผ ๋ชจ๋ ๋ธ๋ก์ ๊ณตํต ๋ฐฐ๊ฒฝ์ผ๋ก ์ฌ์ฉํ๋ฉด ๊ด์ธก๊ฐ์ ์์ํ
WebSocket ๋น์ฉ์ด ์๋๋ผ ๋ค์์ ํฉ์ด ๋๋ค.
๊ด์ธก ์์ = REST ๊ธฐ๋ณธ ๋น์ฉ + WebSocket ๋น์ฉ + ๋ ๋ถํ ์ฌ์ด์ ๊ฒฝํฉ ๋น์ฉ
๋ฐ๋ผ์ F1-aยทF1-bยทF2์ ํ๊ท์๋ REST๋ฅผ ๋ฃ์ง ์๋๋ค. F1-cยทF3ยทF4์์๋
control(REST๋ง)๊ณผ treatment(REST + WS ๋๋ hot-row)๋ฅผ ๊ฐ์ ์กฐ๊ฑด์ผ๋ก ๋น๊ตํ๋ค.
CPUยทthread ๊ฒฝํฉ์ REQUEST_GROUP=light, HikariยทDB ๊ฒฝํฉ์
REQUEST_GROUP=detail, ์ค์ ์ฌ์ฉ์ ํจํด์ http-mixed.js๋ก ๋ณ๋ ์ธก์ ํ๋ค.
๋ฐฐ๊ฒฝ REST๋ฅผ ๊ณ ์ ํ ๊ฒฐ๊ณผ๋ ์์ ๋จ๊ฐ๊ฐ ์๋๋ผ REST 50 RPS๊ฐ ์คํ ์ค์ผ ๋์
์กฐ๊ฑด๋ถ ์ถ๊ฐ ๋น์ฉ์ผ๋ก๋ง ํด์ํ๋ค.
management.server.port=8081(ํธ์คํธ 8080) โ /actuator/prometheus.
| ์งํ | PromQL ์ | ์ฐ์ด๋ ๋จ๊ณ |
|---|---|---|
| WS ๋์ ์ฐ๊ฒฐ | lab_ws_connections |
F1, F2 |
| WS ์ธ์ ์ํ ๋ฐ์ดํธ | lab_ws_connection_bytes |
F1-a |
| WS ๋ฉ์์ง ์ฒ๋ฆฌ์จ | rate(lab_ws_messages_total[1m]) |
F2, F3 |
| ์ฑํ ์ปค๋ฐ ์๊ฐ | histogram_quantile(0.95, sum by (le) (rate(lab_chat_commit_seconds_bucket[1m]))) |
F3 |
| ์ฑํ ์ปค๋ฐยท์ค๋ฅ ์ |
rate(lab_chat_committed_total[1m]), rate(lab_chat_errors_total[1m])
|
F3 |
| ์ข์ lock ์ ์ ์๊ฐ | histogram_quantile(0.95, sum by (le) (rate(lab_seat_lock_seconds_bucket[1m]))) |
F4 |
| ์ข์ ํธ๋์ญ์ ์๊ฐ | lab_seat_transaction_seconds_bucket |
F4 |
| ์ข์ ๊ฒฐ๊ณผ |
rate(lab_seat_approved_total[1m]), lab_seat_full_total, lab_seat_errors_total
|
F4 |
| ํ ๋๊ธฐ |
hikaricp_connections_pending, hikaricp_connections_active
|
F3, F4, F5 |
| ํ ํ๋ ์๊ฐ | histogram_quantile(0.95, sum by (le) (rate(hikaricp_connections_acquire_seconds_bucket[1m]))) |
F3, F4 |
| Tomcat |
tomcat_threads_busy_threads, tomcat_threads_config_max_threads
|
F1-c, F5 |
| JVM |
jvm_memory_used_bytes{area="heap"}, jvm_gc_pause_seconds_*, jvm_buffer_memory_used_bytes{id="direct"}
|
F1, F2 |
| HTTP |
histogram_quantile(0.95, sum by (le,uri) (rate(http_server_requests_seconds_bucket[1m]))), rate(http_server_requests_seconds_count{status="503"}[1m])
|
F1-c, F4, F5 |
์ปจํ
์ด๋ยทํธ์คํธ ์งํ๋ cAdvisorยทNode Exporter๋ฅผ ์ด๋ค. ์ปจํ
์ด๋ ์ด๋ฆ์
compose project๊ฐ moyeota-loadtest-target์ด๋ฏ๋ก
moyeota-loadtest-target-backend-1 ํํ๋ค.
rate(container_cpu_usage_seconds_total{name="moyeota-loadtest-target-backend-1"}[1m])
rate(container_cpu_cfs_throttled_seconds_total{name="moyeota-loadtest-target-backend-1"}[1m])
container_memory_working_set_bytes{name=~"moyeota-loadtest-target-.*"}
๋จ๊ณ๋ณ๋ก ์๋ ๊ฐ์ ๊ณ์ฐํด ํ๋ก ๋จ๊ธด๋ค. ์์ ์งํ๊ฐ ์๋๋ผ ์ด ๊ฐ๋ค์ด V2 ๊ฒฐ์ ์ ๊ทผ๊ฑฐ๋ค.
์ฐ๊ฒฐ๋น heap bytes = ฮ(full GC ์งํ heap used) รท ฮ(์ฐ๊ฒฐ ์)
์ฐ๊ฒฐ๋น direct bytes = ฮ(direct buffer used) รท ฮ(์ฐ๊ฒฐ ์)
์์ฉ ๊ฐ๋ฅ ์ฐ๊ฒฐ ์ํ = (Xmx 512MB ร ์์ ์จ 0.7 โ ๊ธฐ์ heap) รท ์ฐ๊ฒฐ๋น heap bytes
๋ฉ์์ง๋น CPU ms = ฮ(backend CPU core-seconds/s) ร 1000 รท ฮ(msg/s)
KB๋น CPU ms = ฮ(backend CPU core-seconds/s) ร 1000 รท ฮ(msg/s ร payload KB)
์์ฒญ๋น CPU ms = (backend CPU core-seconds/s) ร 1000 รท ์ค์ RPS
quota ์ด๋ก ์ํ RPS = 750 รท ์์ฒญ๋น CPU ms (0.75 CPU = 750 CPU-ms/s)
์ค๋ ๋ ๊ธฐ์ค ์ํ RPS = Tomcat max threads(200) รท ํ๊ท ์๋ต์๊ฐ(s)
ํ ๊ธฐ์ค ์ํ TPS = HIKARI_MAX_POOL_SIZE(10) รท ์ปค๋ฅ์
์ ์ ์๊ฐ(s)
- ํฝ์ค์ฒ ๋ฐฐํฌ์ ์ํ ํ์ธ:
loadtest-target/deploy.sh upํ/api/probe,/api/lab/db-probe,up{...}exporter ์ํ, Grafana ๋์๋ณด๋. - ๋จ๊ณ๋ณ ํฝ์ค์ฒ run ์์ฑ.
chat_hold_msยทlock_hold_ms๋ run ๋จ์ ์ค์ ์ด๋ผ ์ถ๋ง๋ค ๋ณ๋ run์ด ํ์ํ๋ค.
# F2ยทF3์ฉ (์ฑํ
์ ์ฅ ํธ๋์ญ์
์ ์ ์๊ฐ 0/50/200ms)
for h in 0 50 200; do
curl -sk -X POST https://PUBLIC_DOMAIN/api/lab/runs \
-H 'Content-Type: application/json' \
-d "{\"id\":\"f3-h$h\",\"parties\":10,\"seats\":1000,\"chatHoldMs\":$h,\"lockHoldMs\":0}"
done
# F4์ฉ (lock ์ ์ 0/100/500ms, ์ข์ ์ถฉ๋ถ โ 409 full๋ก lock ๋น์ฉ์ด ๊ฐ๋ ค์ง์ง ์๊ฒ)
for h in 0 100 500; do
curl -sk -X POST https://PUBLIC_DOMAIN/api/lab/runs \
-H 'Content-Type: application/json' \
-d "{\"id\":\"f4-L$h\",\"parties\":10,\"seats\":1000,\"chatHoldMs\":0,\"lockHoldMs\":$h}"
done
# F4 ์ ํฉ์ฑ ์ ์ฉ (์ ์ 4์, ์ด๊ณผ ์น์ธยท์์ ์ข์ ๊ฒ์ฆ)
curl -sk -X POST https://PUBLIC_DOMAIN/api/lab/runs \
-H 'Content-Type: application/json' \
-d '{"id":"f4-cap4","parties":2,"seats":4,"chatHoldMs":0,"lockHoldMs":100}'- DATA_FILE ์ธํธ๋ฅผ ๋ง๋ ๋ค. WS payload ํฌ๊ธฐ์
runId์ฟผ๋ฆฌ๋ ๋ฐ์ดํฐ ํ์ผ์ ์์ผ๋ฏ๋ก ์ ๋ง๋ค ํ์ผ์ ๋ถ๋ฆฌํ๋ค.ws๋ฐฐ์ด์๋ ํญ๋ชฉ์ ํ๋๋ง ๋์ด ํฌ๊ธฐ๊ฐ ์์ด์ง ์๊ฒ ํ๋ค(select(data.ws)๊ฐ ๋ฌด์์๋ก ๊ณ ๋ฅธ๋ค).
cd loadtest-scenarios/data
python3 - <<'PY'
import json, copy
base = json.load(open('test-data.json'))
for size in (256, 8000):
for run in ('f3-h0', 'f3-h50', 'f3-h200'):
d = copy.deepcopy(base)
body = 'x' * size
d['ws'] = [{
"name": f"chat-{size}b",
"path": f"/ws?runId={run}",
"headers": {}, "onOpenMessages": [],
"heartbeatMessage": None, "heartbeatIntervalMs": None,
"messages": [{"id": "m-{{runId}}-{{vu}}-{{iteration}}-{{timestamp}}", "body": body}],
}]
json.dump(d, open(f'ws-{size}b-{run}.json', 'w'))
# ์ ์ฅ ์๋ echo ๊ฒฝ๋ก: runId ์ฟผ๋ฆฌ๋ฅผ ์ ๊ฑฐํ๋ฉด ํฝ์ค์ฒ๊ฐ DB๋ฅผ ์ฐ์ง ์๊ณ ์์ฝ๋ง ํ๋ค
d = copy.deepcopy(base)
d['ws'] = [{
"name": f"echo-{size}b", "path": "/ws",
"headers": {}, "onOpenMessages": [],
"heartbeatMessage": None, "heartbeatIntervalMs": None,
"messages": [{"id": "m-{{vu}}-{{iteration}}", "body": 'x' * size}],
}]
json.dump(d, open(f'ws-{size}b-echo.json', 'w'))
PYF4์ฉ ๋ฐ์ดํฐ ํ์ผ๋ run id๋ฅผ ๋ฐ๊ฟ ํจ๊ป ๋ง๋ ๋ค.
python3 - <<'PY2'
import json, copy
base = json.load(open('test-data.json'))
def retarget(d, run):
for group in ('hotRowSame', 'hotRowDistributed', 'hotRowVerify'):
for spec in d['requests'][group]:
spec['path'] = spec['path'].replace('/runs/hot-01/', f'/runs/{run}/')
return d
for run in ('f4-L0', 'f4-L100', 'f4-L500', 'f4-cap4'):
json.dump(retarget(copy.deepcopy(base), run), open(f'test-data-{run}.json', 'w'))
PY2f4-L* run์ ์ข์ 1,000์์ด๋ฏ๋ก hotRowVerify์ approved <= capacity
๋น๊ต๊ฐ์ 4์์ 1000์ผ๋ก ๊ณ ์ณ์ผ ํ๋ค. ์ ํฉ์ฑ ๊ฒ์ฆ์ฉ f4-cap4๋ง 4๋ก ๋๋ค.
- ํฝ์ค์ฒ ์ ์ฝ:
body๋ 8,192์ ์ดํ์ฌ์ผ ์ ์ฅ ๊ฒฝ๋ก๊ฐ ์ฑ๊ณตํ๋ค. ๋ฐ๋ผ์ payload ํฐ ์ชฝ์ 8,000 B๋ฅผ ์ํ์ผ๋ก ์ด๋ค. - ์ ์ฅ ๊ฒฝ๋ก(
?runId=์์)๋ ์ปค๋ฐ ํ{"id","ok"}ACK๋ง ํ์ ํ๊ณ , echo ๊ฒฝ๋ก(?runId=์์)๋ ๋ฐ์ payload๋ฅผ ๊ทธ๋๋ก ๋ฐ์กํ๋ค. ๋ ์กฐ๊ฑด์ ๋น๊ตํ ๋ outbound ๋ฐ์ดํธ ์ฐจ์ด๋ฅผ ๊ฐ์ํ๋ค.
- ๋ฐ์๊ธฐ headroom ๊ฒ์ฆ(T0). F2์ ์ต๋ ์
(์ฐ๊ฒฐ 1,800 ยท 8,000 B ยท 120 msg/s โ
960 KB/s โ 7.7 Mbps upload)๊ณผ F1-a์ ์ต๋ ์ฐ๊ฒฐ(5,000 VU)์ ๋ก์ปฌ์์ 1๋ถ
์ํํ๊ณ
ulimit -n, ๋ก์ปฌ CPU, ์ ๋ก๋ ๋์ญํญ, dropped iterations๋ฅผ ํ์ธํ๋ค.k6/ws๋ VU 1๊ฐ๊ฐ ์ฐ๊ฒฐ 1๊ฐ์ด๋ฏ๋ก ์ฐ๊ฒฐ ์๊ฐ ๊ณง VU ์๋ค.
์ฐ๊ฒฐ๋ง ์ ์งํด ์ฐ๊ฒฐ ์์ฒด์ ์์ ๋จ๊ฐ๋ฅผ ๊ตฌํ๋ค.
- ์ฐ๊ฒฐ ์: control 0 โ 500 โ 1,000 โ 1,575 โ 1,800 โ 2,100 โ 3,000 โ 5,000
-
CONNECT_RATE=6๊ณ ์ ,HOLD_DURATION=30m, ramp-down 1๋ถ -
WS_PER_CONNECTION_BYTES:0(์ฐ๊ฒฐ ์์ ๋น์ฉ)์ผ๋ก ์ ๋จ๊ณ โ32768(์ธ์ ์ด ์ฌ์ฉ์ยท๋ฐฉยท์ต๊ทผ ๋ฉ์์ง ์ํ๋ฅผ ๋ค๊ณ ์๋ ์ค์ ์ฑ ๊ทผ์ฌ)์ผ๋ก 1,800 / 3,000 / 5,000 ์ฌ์ธก์
RUN_ID=f1a-c1800-b0 TARGET_CONNECTIONS=1800 CONNECT_RATE=6 HOLD_DURATION=30m \
DATA_FILE=./data/ws-256b-echo.json \
loadtest-target/k6.sh ws-connect.js \
--summary-export=results/f1a-c1800-b0.json์ธก์ : hold ๊ตฌ๊ฐ์์ jcmd <pid> GC.run ํ heap used, jcmd <pid> VM.native_memory summary(Thread/Internal/Other ์ฆ๊ฐ๋ถ), direct buffer,
lab_ws_connections, backendยทnginx FD์ ESTABLISHED/TIME_WAIT, GC pause,
backendยทnginx CPU์ throttling, container_memory_working_set_bytes.
ํ์ :
- ์ฐ๊ฒฐ๋น heapยทdirect bytes๋ฅผ ๊ณ์ฐํด
์์ฉ ๊ฐ๋ฅ ์ฐ๊ฒฐ ์ํ์ ์ฐ์ถํ๋ค. ์ด ๊ฐ์ด ์์ธก ํผํฌ 2,100์ ๋ฐ๋๋ฉด ์ฐ๊ฒฐ ์ ์์ฒด๊ฐ V1 ํ๊ณ๋ค. - working set์ด 768 MB์ ์ ๊ทผํ๋ฉฐ OOM-kill์ด heap OOM๋ณด๋ค ๋จผ์ ์ค๋ฉด ์์ธ์
heap์ด ์๋๋ผ direct/native ์์ญ์ด๋ค.
-Xmx์ถ์ ๋๋ ์ปจํ ์ด๋ ๋ฉ๋ชจ๋ฆฌ ์ฆ์คยทWS ๋ถ๋ฆฌ๋ก ๋ฐฉํฅ์ด ๊ฐ๋ฆฐ๋ค. - Tomcat
max-connections 8192, backend nofile 16384, nginx nofile 32768(์ฐ๊ฒฐ๋น client+upstream 2 FD)์ด ๊ตฌ์กฐ์ ์ํ์ด๋ค. ๊ทธ ์ ์ CPUยท๋ฉ๋ชจ๋ฆฌ๊ฐ ํฌํ๋๋์ง ํ์ธํ๋ค.
์ฐ๊ฒฐ ์๋ฅผ ๊ณ ์ ํ๊ณ ์ด๋น ์ ๊ท ์ฐ๊ฒฐ๋ง ๋๋ ค ์ฐ๊ฒฐ ์๋ฆฝ ๋น์ฉ์ ๋ถ๋ฆฌํ๋ค.
-
TARGET_CONNECTIONS=1000๊ณ ์ ,CONNECT_RATE= 6 โ 10 โ 20 โ 50 โ 100 โ 200 -
์ธก์ ์ฐฝ์ ramp ๊ตฌ๊ฐ์ด๋ค.
ws-connect.js๋ ์ฐ๊ฒฐ ์๋ช ์ramp + hold + rampDown + 60s๋ก ์ก์ ํ ๋ฒ ๋งบ์ ์ฐ๊ฒฐ์ ํ ์คํธ ๋๊น์ง ์ ์งํ๋ฏ๋ก, hold ๊ตฌ๊ฐ์์๋ ์ ๊ท handshake๊ฐ ๋ฐ์ํ์ง ์๋๋ค. ๋ฐ๋ผ์HOLD_DURATION=2m๋ก ์งง๊ฒ ๋๊ณ ๊ฐ์ ๋จ๊ณ๋ฅผ 5ํ ๋ฐ๋ณตํด ramp ๊ตฌ๊ฐ์ handshake ์งํ๋ฅผ ๋ชจ์๋ค(ramp ๊ธธ์ด =์ฐ๊ฒฐ์ รท ์ฐ๊ฒฐ๋ฅ์ด). - ์ง์์ ์ธ handshake ๋ถํ๊ฐ ํ์ํ๋ฉด
ws-connect.js์ ์ฐ๊ฒฐ ์๋ช (CONNECTION_TTL) ์ถ์ ์ถ๊ฐํด ์ฐ๊ฒฐ์ด ์ฃผ๊ธฐ์ ์ผ๋ก ๋๊ธฐ๊ณ ๋ค์ ๋งบ๋๋ก ๋ฐ๊ฟ์ผ ํ๋ค. ํ์ฌRECONNECT_DELAY๋ ํ ์คํธ ์ข ๋ฃ ํ iteration ๊ฐ๊ฒฉ์ด๋ผ ์ด ๋ชฉ์ ์ ์ฐ์ด์ง ์๋๋ค.
for i in 1 2 3 4 5; do
RUN_ID=f1b-rate50-r$i TARGET_CONNECTIONS=1000 CONNECT_RATE=50 HOLD_DURATION=2m \
DATA_FILE=./data/ws-256b-echo.json \
loadtest-target/k6.sh ws-connect.js --summary-export=results/f1b-rate50-r$i.json
done์ธก์ : handshake p95/p99, 101 ์ฑ๊ณต๋ฅ , ws_errors, nginx active/reading/writing/
waiting๊ณผ accept ์คํจ, listen queue overflow(node_netstat_TcpExt_ListenOverflows),
nginxยทbackend CPU์ throttling, TLS handshake ๋น์ฉ.
ํ์ : TLS์ accept๋ **nginx 0.25 CPU ยท worker_processes 1**์์ ์ฒ๋ฆฌ๋๋ค.
backend๊ฐ ์ฌ์ ๋ก์ด๋ฐ nginx CPU๊ฐ quota๋ฅผ ์ฑ์ฐ๊ณ handshake p95๋ง ์
ํ๋๋ฉด
ํ๊ณ๋ Spring์ด ์๋๋ผ ์ง์
๊ณ์ธต์ด๋ฏ๋ก, Spring ๋ถ๋ฆฌ๋ณด๋ค nginx CPUยทworker
์กฐ์ ๋๋ TLS ์ข
๋ฃ ์์น ๋ณ๊ฒฝ์ด ๋จผ์ ๋ค.
WS ์ฐ๊ฒฐ์ ๋จ๊ณ๋ณ๋ก ๊ณ ์ ํ ์ํ์์ ๋์ผํ REST ๋ถํ๋ฅผ ๋ฐ๋ณตํด control๊ณผ ๋น๊ตํ๋ค.
- control: WS 0์์
http-operation.jsREQUEST_GROUP=light,TARGET_RPS=50 - ํฐ๋ฏธ๋ 1์์
ws-connect.js๋ฅผ hold์ ์ง์ ์ํค๊ณ , ํฐ๋ฏธ๋ 2์์ ๊ฐ์ REST ๋ถํ๋ฅผ ์คํ - WS ์ฐ๊ฒฐ = 1,000 ยท 1,800 ยท 2,100 ยท 3,000 ยท 5,000
- ํ์ ์ F2์ 36 msg/s๋ฅผ ์ถ๊ฐํด "์ฐ๊ฒฐ๋ง์ ๊ฐ์ญ"๊ณผ "๋ฉ์์ง๊น์ง์ ๊ฐ์ญ"์ ๋ถ๋ฆฌ
# ํฐ๋ฏธ๋ 1
RUN_ID=f1c-ws2100 TARGET_CONNECTIONS=2100 CONNECT_RATE=6 HOLD_DURATION=30m \
DATA_FILE=./data/ws-256b-echo.json loadtest-target/k6.sh ws-connect.js
# ํฐ๋ฏธ๋ 2 (control๊ณผ ๋์ผ ์กฐ๊ฑด)
RUN_ID=f1c-rest-ws2100 REQUEST_GROUP=light TARGET_RPS=50 WARMUP=5m DURATION=10m \
loadtest-target/k6.sh http-operation.js \
--summary-export=results/f1c-rest-ws2100.json๊ธฐ๋ก ํ๋ ๋ค์ ํํ๋ก ๋ง๋ ๋ค.
| WS ์ฐ๊ฒฐ | REST p95 | control ๋๋น | ์ค๋ฅ์จ | backend CPU | throttling | heap | GC pause | frontend CPU | mysql CPU | CPU credit |
|---|
ํ์ :
- REST p95๊ฐ control ๋๋น 20% ์ด์ ์ ํ๋๊ณ backend CPUยทGCยทTomcat busy์ ์๊ด๋๋ฉด ๊ฐ์ ์ปจํ ์ด๋ ์์ ๊ณต์ ๊ฐ ์์ธ์ด๋ค โ WS ๋ถ๋ฆฌ(๋ณ๋ ํ๋ก์ธ์ค ๋๋ ๊ฒ์ดํธ์จ์ด)๋ฅผ V2 ํ๋ณด๋ก ์ฌ๋ฆฐ๋ค.
- frontendยทmysql๊น์ง ๋์์ ์ ํ๋๋ฉด ์ปจํ ์ด๋ quota๊ฐ ์๋๋ผ ํธ์คํธ CPUยท ๋คํธ์ํฌยทcredit์ด ์์ธ์ด๋ค. credit balance๋ฅผ ๋จผ์ ํ์ธํ๊ณ ์ฌ์ธก์ ํ๋ค.
- REST๋
light(DB ๋ฏธ์ฌ์ฉ)์detail(DB ์ฌ์ฉ) ๋ ๊ณ์ด๋ก ๊ฐ๊ฐ ๋ณธ๋ค.light๋ง ์ ํ๋๋ฉด CPUยท์ค๋ ๋,detail๋ ์ ํ๋๋ฉด ํยทDB ๊ฒฝ๋ก๊น์ง ๋ฒ์ง ๊ฒ์ด๋ค.
"๋ฉ์์ง ์ปจํ ์คํธ๊ฐ ํฌ๊ณ ์ฐ๊ฒฐ์ด ์ ์ ๊ฒฝ์ฐ"์ "๋ฉ์์ง๊ฐ ์งง๊ณ ์ฐ๊ฒฐ์ด ๋ง์ ๊ฒฝ์ฐ"๋ฅผ ๊ทธ๋ฅ ๋ ๋ฒ ์ฌ๋ฉด ์์ธ์ ๋ถ๋ฆฌํ ์ ์๋ค. ์ฐ๊ฒฐ ์ยทpayloadยท๋ฉ์์ง์จ์ 2ร2ร2 ์์ธ ์ค๊ณ๋ก ๋๋ ค ๊ฑด์ ๋น์ฉ๊ณผ ๋ฐ์ดํธ ๋น์ฉ์ ๋ถ๋ฆฌํ๋ค.
| ์ | ์ฐ๊ฒฐ | payload(body) | aggregate msg/s | inbound bytes/s | ์ฑ๊ฒฉ |
|---|---|---|---|---|---|
| C1 | 200 | 256 B | 36 | 9 KB/s | ๊ธฐ์ค |
| C2 | 200 | 8,000 B | 36 | 288 KB/s | ํฐ ์ปจํ ์คํธยท์ ์ ์ฐ๊ฒฐ |
| C3 | 1,800 | 256 B | 36 | 9 KB/s | ์งง์ ๋ฉ์์งยท๋ง์ ์ฐ๊ฒฐ |
| C4 | 1,800 | 8,000 B | 36 | 288 KB/s | ๊ต์ฐจ ํ์ธ |
| C5 | 200 | 256 B | 120 | 31 KB/s | ๋ฉ์์ง์จ ๊ธฐ์ธ๊ธฐ |
| C6 | 200 | 8,000 B | 120 | 960 KB/s | ํฐ ์ปจํ ์คํธ ์ํฅ |
| C7 | 1,800 | 256 B | 120 | 31 KB/s | ์งง์ ๋ฉ์์ง ์ํฅ |
| C8 | 1,800 | 8,000 B | 120 | 960 KB/s | ์ต๋ |
- 8๊ฐ ์ ๋ชจ๋ REST ๋ฐฐ๊ฒฝ ์์ด echo ๊ฒฝ๋ก(์ ์ฅ ์์)๋ก ๋จผ์ ๋๋ ค Springยท ๋คํธ์ํฌ ๋น์ฉ๋ง ๋ณธ๋ค. DB ์ถ์ F3์์ ๋ค๋ฃฌ๋ค. ์ ์ฅ ๊ฒฝ๋ก์ ๋ณํ REST๋ F3์์ ๋ณ๋์ control/treatment๋ก ์ธก์ ํ๋ค.
-
ws-message.js๋messageIntervalMs = (TARGET_CONNECTIONS รท MESSAGE_RATE) ร 1000์ผ๋ก ์ฐ๊ฒฐ๋น ๊ฐ๊ฒฉ์ ๊ณ์ฐํ๋ฏ๋ก, aggregate msg/s๊ฐ ๊ณ ์ ๋๊ณ ์ฐ๊ฒฐ ์๋ ๋ ๋ฆฝ ์ถ์ด ๋๋ค.
# C4: ์ฐ๊ฒฐ 1,800 ยท 8,000 B ยท 36 msg/s ยท echo
RUN_ID=f2-C4-echo TARGET_CONNECTIONS=1800 MESSAGE_RATE=36 \
CONNECTION_RAMP=5m DURATION=10m \
DATA_FILE=./data/ws-8000b-echo.json \
loadtest-target/k6.sh ws-message.js --summary-export=results/f2-C4-echo.json์ธก์ : backend CPU(core-seconds/s)์ throttling, heap usedยทallocation rateยทGC
pause, direct buffer, rate(lab_ws_messages_total[1m]), ์ปจํ
์ด๋ network
rx/tx, k6 ws_messages_sent/receivedยทws_errors, ์๋ต(ACK/echo) ์ง์ฐ.
ํ์ ์ฐ์:
backend CPU(core) โ a + bยทR + cยท(R ร S_KB) + dยทC
R = aggregate msg/s, S_KB = payload KB, C = ์ฐ๊ฒฐ ์(d๋ F1-a์์ ๊ตฌํ ๊ฐ)
b = ๋ฉ์์ง ๊ฑด๋น ๋น์ฉ (ํ๋ ์ ์ฒ๋ฆฌยท์ญ์ง๋ ฌํยท์ค๋ ๋ ์ ํยทํธ๋์ญ์
์ค๋ฒํค๋)
c = ๋ฐ์ดํธ๋น ๋น์ฉ (๋ณต์ฌยท๋ฒํผยท์ง๋ ฌํยท๋คํธ์ํฌ)
-
b๊ฐ ์ง๋ฐฐ(C3ยทC7์ด C2ยทC6๋ณด๋ค ๋์จ) โ ๋ณ๋ชฉ์ ๊ฑด์๋ค. ๋ฉ์์ง ๋ฐฐ์นญ, ACK ๊ฒฝ๋ํ, ์ ์ฅ ๋น๋๊ธฐํ, ์ฐ๊ฒฐยท์ธ์ ์ฒ๋ฆฌ ๊ฒฝ๋ก ์ต์ ํ๊ฐ ์ฐ์ ์ด๋ค. -
c๊ฐ ์ง๋ฐฐ(C2ยทC6์ด ๋ ๋์จ) โ ๋ณ๋ชฉ์ ๋ฐ์ดํธ๋ค. payload ์ํ, ์์ถ, ๋ณธ๋ฌธ ๋ถ๋ฆฌ ์ ์ฅ(๋ฉํ๋ง ์ค์๊ฐ ์ ๋ฌ)์ด ์ฐ์ ์ด๋ค. - ๋ฉ๋ชจ๋ฆฌ๋ heap ์ฆ๊ฐ๋๊ณผ GC ๋น๋๋ก ๋ณธ๋ค. ํฐ payload๋ allocation rate์
GC ํ์๋ฅผ, ๋ง์ ์ฐ๊ฒฐ์ ์์ฃผ heap(์ฐ๊ฒฐ๋น ์์)์ ์ฌ๋ฆฐ๋ค. ๋ ์ถ ์ค ์ด๋ ๊ฒ์ด
-Xmx512m๋ฅผ ๋จผ์ ์ํํ๋์ง ๋ช ์ํ๋ค. - ์ด๋ค ์ ์ด๋ dropped iterationยท๋ฐ์๊ธฐ ํฌํ๊ฐ ์์ผ๋ฉด ๊ทธ ์ ์ ํ๊ท์์ ์ ์ธํ๋ค.
ํฝ์ค์ฒ์ ์ ์ฅ ๊ฒฝ๋ก๋ ์ปค๋ฐ ํ ACK๋ฅผ ๋ณด๋ด๋ฏ๋ก WS ์๋ต ๊ฒฝ๋ก๊ฐ DB ํธ๋์ญ์ ์ ์ง์ ๋ฌถ์ธ๋ค. ์ด ๊ฒฐํฉ์ด ์ด๋์ ๊นจ์ง๋์ง, ํ 10๊ฐ๋ก ๊ฐ๋น ๊ฐ๋ฅํ msg/s๊ฐ ์ผ๋ง์ธ์ง ๊ตฌํ๋ค.
-
chat_hold_ms= 0 / 50 / 200 (f3-h0,f3-h50,f3-h200run) - aggregate msg/s = 36 โ 120 โ 300
- ์ฐ๊ฒฐ 1,800 ๊ณ ์ , payload 256 B ๊ณ ์ (๋ฐ์ดํธ ์ถ ์ ๊ฑฐ)
๊ฐ ์กฐ๊ฑด์ ๋ ๋ฒ ์ธก์ ํ๋ค.
- WS ์ ์ฅ๋ง ์คํํด DB commitยทHikari์ ์์ ์ ์ ๋น์ฉ์ ์ธก์ ํ๋ค.
- ๊ฐ์ WS ๋ถํ์
REQUEST_GROUP=detail,TARGET_RPS=50์ ๋ณํํด REST ๊ฐ์ญ์ ์ธก์ ํ๋ค.
๋ ๋ฒ์งธ ์คํ์ ์ฒซ ๋ฒ์งธ ์คํ์ ๋์ฒด๊ฐ ์๋๋ผ ๋ณ๋์ treatment๋ค. ์ฒซ ๋ฒ์งธ ์คํ์ด ์์ผ๋ฉด Hikari pending ์ฆ๊ฐ๊ฐ ์ ์ฅ ์์ฒด ๋๋ฌธ์ธ์ง ๋ณํ REST์์ ๊ฒฝํฉ ๋๋ฌธ์ธ์ง ๊ตฌ๋ถํ ์ ์๋ค.
# ์ฒซ ๋ฒ์งธ ์คํ: WS ์ ์ฅ๋ง ์ธก์
RUN_ID=f3-h50-r120 TARGET_CONNECTIONS=1800 MESSAGE_RATE=120 \
CONNECTION_RAMP=5m DURATION=10m \
DATA_FILE=./data/ws-256b-f3-h50.json \
loadtest-target/k6.sh ws-message.js --summary-export=results/f3-h50-r120.json
# ๋ณ๋ ๋ฐ๋ณต: ๊ฐ์ WS ์กฐ๊ฑด์ REST ์กฐํ๋ฅผ ์ถ๊ฐํ treatment
# ํฐ๋ฏธ๋ 1
RUN_ID=f3-ws-h50-r120-rest TARGET_CONNECTIONS=1800 MESSAGE_RATE=120 \
CONNECTION_RAMP=5m DURATION=10m \
DATA_FILE=./data/ws-256b-f3-h50.json \
loadtest-target/k6.sh ws-message.js --summary-export=results/f3-ws-h50-r120-rest.json
# ํฐ๋ฏธ๋ 2: ์ WS ์คํ๊ณผ ๋์์
RUN_ID=f3-rest-h50-r120 REQUEST_GROUP=detail TARGET_RPS=50 WARMUP=5m DURATION=10m \
loadtest-target/k6.sh http-operation.js \
--summary-export=results/f3-rest-h50-r120.json์์ธก๊ฐ์ ๋จผ์ ์ ๊ณ ์ค์ธก๊ณผ ๋น๊ตํ๋ค(ํ ๊ธฐ์ค ์ํ TPS = 10 รท ์ ์ ์๊ฐ).
| chat_hold_ms | ์ปค๋ฅ์ ์ ์ ์๊ฐ(๊ฐ์ ) | ํ ๊ธฐ์ค ์ํ msg/s | ์ค์ธก C_knee |
|---|---|---|---|
| 0 | ~3 ms | ~3,300 (CPU๊ฐ ๋จผ์ ) | |
| 50 | ~53 ms | ~190 | |
| 200 | ~203 ms | ~49 |
์ธก์ : lab_chat_commit p95/p99, lab_chat_errors_total(= ACK ok:false),
hikaricp_connections_pendingยทactive, ํ๋ ์๊ฐ p95(1,000 ms ์ด๊ณผ ์ ์คํจ),
MySQL redoยทfsyncยทdirty pageยทrow lock, EBS await, ๊ทธ๋ฆฌ๊ณ ๋ณํ REST์ p95์
503 ๋น์จ.
ํ์ :
| ์ฆ๊ฑฐ | ๊ฒฐ๋ก |
|---|---|
| ํ pendingยทํ๋ ์๊ฐ์ด ๋จผ์ ์์นํ๊ณ MySQL CPUยทI/O๋ ์ฌ์ | ์ปค๋ฅ์ ์ ์ ์๊ฐ ๋ฌธ์ โ ์ ์ฅ ๋น๋๊ธฐํ(ํ + ๋ฐฐ์น insert)๋ก WS ์๋ต ๊ฒฝ๋ก์์ ๋ถ๋ฆฌ |
| MySQL CPUยทredoยทfsync๊ฐ ํจ๊ป ํฌํ | DB ์ฐ๊ธฐ ์์ฒด ํ๊ณ โ ๋ฐฐ์น ์ปค๋ฐยท์ธ๋ฑ์ค ์กฐ์ ํ DB ๋ถ๋ฆฌ/RDS |
| ๋ณํ REST ์กฐํ p95ยท503์ด WS ์ ์ฅ๊ณผ ํจ๊ป ์ ํ | ํ์ด ๊ณต์ ์์์ผ๋ก ์ฅ์ ๋ฅผ ์ ํ โ ํ ๋ถ๋ฆฌ(์ฝ๊ธฐ/์ฐ๊ธฐ) ๋๋ ์กฐํ ์บ์ |
| WS ์ ์ฅ ์์(echo) ๋๋น ์ ์ฅ ์กฐ๊ฑด์์๋ง ์ ํ | ์ค์๊ฐ ๊ฒฝ๋ก์ ์์ ๊ฒฝ๋ก ๋ถ๋ฆฌ๊ฐ V2 ํ์ ํญ๋ชฉ |
| ์กฐํ p95๊ฐ ๋ฐ์ดํฐ๋ ์ฆ๊ฐ์ ๋น๋ก |
/api/lab/posts๋ ์ ์ฒด ์ ๋ ฌ์ด๋ฏ๋ก ์บ์ยท์ธ๋ฑ์คยทํ์ด์ง ์ฐ์ |
ํฝ์ค์ฒ ์ฃผ์: saveMessage๋ ๋ฉ์์ง๋ง๋ค SELECT chat_hold_ms๋ฅผ ํ ๋ฒ ๋
์ํํ๋ฏ๋ก ์ค์ ์ฑ๋ณด๋ค ์ปค๋ฅ์
์ ์ ๊ฐ ๊ธธ๋ค. ์ ๋ msg/s๊ฐ ์๋๋ผ ์กฐ๊ฑด ๊ฐ
๋น๊ต๋ก ํด์ํ๋ค.
์น์ธ API๋ ํ ํ์ SELECT ... FOR UPDATE๋ก ์ก์ผ๋ฏ๋ก ๋์ผ ํ ์์ฒญ์
์ง๋ ฌํ๋๋ค. RPS๊ฐ ์๋๋ผ ๊ฐ์ ํ์ ๋์์ ๋๋ฌํ๋ ์์ฒญ ์๋ฅผ ์ ์ดํ๋ค.
- ๋์ผ ํ:
REQUEST_GROUP=hotRowSame, ๋์กฐ๊ตฐ:hotRowDistributed - ๋์์ฑ: 2 ยท 5 ยท 10 ยท 20 ยท 50 ยท 100
-
lock_hold_ms: 0 ยท 100 ยท 500 (f4-L0,f4-L100,f4-L500run) - ๋ณํ REST:
REQUEST_GROUP=light์detail๊ฐ๊ฐ 50 RPS
RUN_ID=f4-same-c20-L100 REQUEST_GROUP=hotRowSame VERIFY_GROUP=hotRowVerify \
CONCURRENCY=20 ROUNDS=3 ROUND_PAUSE=10s \
DATA_FILE=./data/test-data-f4-L100.json \
loadtest-target/k6.sh hot-row.js --summary-export=results/f4-same-c20-L100.json๋ ์คํจ ๋ชจ๋๋ฅผ ๋ฐ๋์ ๊ตฌ๋ถํ๋ค. ์ค์ ์ ์๊ณ๊ฐ ๋ค๋ฅด๋ค.
ํ timeout : ๋์์ฑ > HIKARI_MAX_POOL_SIZE(10) โ ๋๊ธฐ 1,000ms ์ด๊ณผ โ 503 database_error
์ฆ๊ฑฐ: hikaricp_connections_pendingโ, ํ๋ ์๊ฐ p95 โ 1s, lab_seat_errors_totalโ
lock wait : ๋์์ฑ ร lock_hold_ms > innodb_lock_wait_timeout(3,000ms) โ 503
์ฆ๊ฑฐ: innodb_row_lock_current_waitsโ, lab_seat_lock p95 โ 3s
์์ธก ์๊ณ(์ค์ธก์ผ๋ก ํ์ธ): lock_hold_ms=500์ ๋์์ฑ 6๋ถํฐ, 100์ ๋์์ฑ
30๋ถํฐ lock wait timeout ์์ญ์ ๋ค์ด๊ฐ๋ค. ๋์์ฑ 10์ ๋๋ ์๊ฐ๋ถํฐ๋ ํ
timeout์ด ๋จผ์ ๋ํ๋ ์ ์์ผ๋ฏ๋ก, HIKARI_MAX_POOL_SIZE๋ฅผ 10์ผ๋ก ๊ณ ์ ํ
๊ฒฐ๊ณผ์ 20์ผ๋ก ์ฌ๋ฆฐ ๋์กฐ ์คํ์ ํ ์ ๋จ๊ฒจ ๋ ์์ธ์ ๋ถ๋ฆฌํ๋ค.
์ ํฉ์ฑ ๊ฒ์ฆ(ํ ๊ฑด์ด๋ผ๋ ์๋ฐ์ด๋ฉด ์คํจ):
-
hotRowVerify(/api/lab/runs/{run}/stats)์parties.N.remaining >= 0,parties.N.approved <= capacity - k6 assertion์ผ๋ก๋ ํญ๋ฑ์์ ํํํ ์ ์์ผ๋ฏ๋ก, round ์ข
๋ฃ ํ stats ์๋ต์
์ ์ฅํด
approved + remaining == capacity๋ฅผ ๋ณ๋๋ก ํ์ธํ๋ค -
f4-cap4run(์ ์ 4์)์ผ๋ก ์ด๊ณผ ์น์ธยท์ค๋ณต ์น์ธ์ ์ฌํ ์๋ํ๋ค. ์คํค๋ง์CHECK (remaining >= 0)๊ฐ ์์ด ์๋ฐ์ด ์์ ๊ฐ์ด ์๋๋ผ 503์ผ๋ก ๋ํ๋ ์ ์์ผ๋, 503 ์์ธ์ ํยทlockยทCHECK ์ค ๋ฌด์์ธ์ง ๋ก๊ทธ๋ก ๊ตฌ๋ถํ๋ค
ํ์ : ๋์ผ ํ์์๋ง ์ง์ฐ์ด ๊ธ์ฆํ๊ณ ๋์กฐ๊ตฐ์ ํํํ๋ฉด hot-row๊ฐ ์์ธ์ด๋ค.
์ด๋ ๋ณํ REST(light)๊น์ง ์
ํ๋๋ฉด ๊ฒฝํฉ์ด ์ปจํ
์ด๋ ์ค๋ ๋ยทCPU๊น์ง
๋ฒ์ง ๊ฒ์ด๊ณ , detail๋ง ์
ํ๋๋ฉด ํ ๊ฒฝํฉ์ ๊ตญํ๋๋ค. ์ ์๋ ์น์ธ ๊ฒฝ๋ก ๊ตฌ์กฐ
๋ณ๊ฒฝ(Redis ์์ ์นด์ดํฐยท๋ฉฑ๋ฑํคยท๋๊ธฐ์ด), ํ์๋ ํ ๋ถ๋ฆฌยทํ์์์ ์กฐ์ ์ด ์ฐ์ ์ด๋ค.
๋ ๊ณ์ด์ ๊ฐ์ ๋จ๊ณ๋ก ์ฌ๋ ค Spring ์์ฒด ๋น์ฉ๊ณผ DB ๊ฒฝ๋ก ๋น์ฉ์ ๋ถ๋ฆฌํ๋ค.
-
light=/api/probe(DBยท์ธ๋ถ ํธ์ถ ์์) -
detail=/api/lab/posts/{id}(DB 1ํ ์กฐํ, ํ ์ฌ์ฉ) - ์ฐธ๊ณ ๋ก
list=/api/lab/posts(์ ์ฒด ์ ๋ ฌ + LIMIT 20, ๋ฐ์ดํฐ๋ ๋ฏผ๊ฐ) - RPS: 25 โ 40 โ 46 โ 53 โ 75 โ 100 โ 150 โ 200 โ 300 โ 400 โ 512
- WS ์ฐ๊ฒฐ 0, ๋ณ๋ REST ๋ฐฐ๊ฒฝ ๋ถํ ์์(F1-c์์ control๋ก ์ฌ์ฌ์ฉํ ์ ์๋ค)
RUN_ID=f5-light-100 REQUEST_GROUP=light TARGET_RPS=100 WARMUP=5m DURATION=10m \
loadtest-target/k6.sh http-operation.js \
--summary-export=results/f5-light-100.json --out json=results/f5-light-100-raw.json๊ธฐ๋ก ํ:
| ๋ชฉํ RPS | ์ค์ RPS | p50 | p95 | p99 | ์ค๋ฅ์จ | dropped | backend CPU(core) | throttled s/s | ์์ฒญ๋น CPU-ms | Tomcat busy | heap | GC pause | nginx CPU | ํธ์คํธ CPU | credit |
|---|
ํ์ :
-
์์ฒญ๋น CPU-ms๊ฐ RPS ์ ๊ตฌ๊ฐ์์ ์ผ์ ํ๋ฉด ์ฑ๋ฅ ์ ํ๋ CPU ๋จ๊ฐ๊ฐ ์๋๋ผ ํ์์ด๋ค.quota ์ด๋ก ์ํ RPS = 750 รท ์์ฒญ๋น CPU-ms์ ์ค์ธกC_knee๋ฅผ ๋น๊ตํด quota ํฌํ ์ฌ๋ถ๋ฅผ ํ์ ํ๋ค. -
container_cpu_cfs_throttled_seconds_total์ด ์ค๋ฅด๊ธฐ ์์ํ๋ RPS๊ฐ 0.75 CPU quota์ ์ค์ง ํ๊ณ๋ค. ์ด ์ง์ ์ด ๋ชฉํ ํผํฌ(50 RPS)์ ๋ช ๋ฐฐ์ธ์ง๊ฐ V1 ์ฌ์ ์จ์ด๋ค. -
light๋ ํํํ๋ฐdetail๋ง ๊บพ์ด๋ฉด ํ๊ณ๋ Spring์ด ์๋๋ผ DB ๊ฒฝ๋ก(ํยท์ฟผ๋ฆฌ)๋ค. - ํธ์คํธ CPU๊ฐ baseline 20%๋ฅผ ๋๋ ๊ตฌ๊ฐ์์ credit์ด ์ค์ด๋๋์ง ํ์ธํ๊ณ ,
credit ๊ณ ๊ฐ๋ก ์ธํ ์ ํ๋
C_knee์์ ์ ์ธํ๋ค. ํ์ํ๋ฉดC_safe์์ 60๋ถ soak์ ๋๋ ค credit ์ํฅ๊น์ง ํฌํจํ ์ง์ ๊ฐ๋ฅ RPS๋ฅผ ๋ฐ๋ก ๋จ๊ธด๋ค.
| ๋จ๊ณ | ์คํ ์ | 1ํ ๊ธธ์ด | ์๊ณ |
|---|---|---|---|
| F0 ์ค๋นยท๋ฐ์๊ธฐ ๊ฒ์ฆ | - | - | 1.5 h |
| F1-a ์ฐ๊ฒฐ ์ (b0 8๋จ๊ณ + b32768 3๋จ๊ณ) | 11 | ramp + 30m hold | 7.5 h |
| F1-b ์ฐ๊ฒฐ๋ฅ | 6 | 15 m | 1.5 h |
| F1-c REST ๊ฐ์ญ (control + 5๋จ๊ณ ร 2๊ณ์ด) | 11 | 15 m | 3.0 h |
| F2 ๋ฉ์์ง ์ ํ (echo 8์ + ์ ์ฅ 4์ ) | 12 | 15 m | 3.0 h |
| F3 DB ์ ์ (3 hold ร 3 msg/s) | 9 | 15 m | 2.5 h |
| F4 hot-row (6 ๋์์ฑ ร 3 hold + ๋์กฐ๊ตฐยท์ ํฉ์ฑ) | 24 | 5 m | 2.5 h |
| F5 ์กฐํ RPS (11๋จ๊ณ ร 2๊ณ์ด) | 22 | 15 m | 5.5 h |
| ์๊ณ ๊ทผ์ฒ 3ํ ๋ฐ๋ณตยท์ฌ์ธก์ ์ฌ์ | - | - | 6.0 h |
์ด ์ฝ 33์๊ฐ, ํ๋ฃจ 8์๊ฐ ๊ธฐ์ค 4~5์ผ์ด๋ค. ์์๋ F0 โ F5(๊ธฐ์ค์ ) โ F1-a โ F1-b โ F1-c โ F2 โ F3 โ F4๋ค. F5๋ฅผ ๋จผ์ ํ๋ ์ด์ ๋ WS ์๋ REST ๊ธฐ์ค์ ์ด F1-cยทF3ยทF4์ control๋ก ์ฐ์ด๊ธฐ ๋๋ฌธ์ด๋ค.
์ธก์ ์ฐฝ์ด 2์๊ฐ๋ฟ์ธ ๊ฒฝ์ฐ๋ ยง13์ ์์ถ ์คํ์์ ์ด๋ค. ์ด ์ ์ 33์๊ฐ ๊ณํ์ ์ฐฝ์ด ๋ฉฐ์น ํ๋ณด๋ ๋์ ๊ธฐ์ค์ด๋ค.
402 ยง4.2๋ฅผ ๊ทธ๋๋ก ์ ์ฉํ๊ณ ๋ค์์ ์ถ๊ฐํ๋ค.
- backend ์ปจํ
์ด๋ OOM-kill ๋๋ ์ฌ์์ (
mem_limit 768m์ด๊ณผ) -
CPUCreditBalance๊ฐ 0์ ๋๋ฌ (ํด๋น ๋จ๊ณ๋ ๋ฌดํจ ์ฒ๋ฆฌํ๊ณ ํ๋ณต ํ ์ฌ์ธก์ ) -
approved + remaining != capacity๋๋ ์ค๋ณต ์น์ธ 1๊ฑด - nginx 502/504๊ฐ 1๋ถ ์ด์ ์ง์ (upstream ๋จ์ โ ์ํ ๋ณด์กด ํ ์ค๋จ)
- ๋ก์ปฌ ๋ฐ์๊ธฐ CPU 60% ์ด๊ณผ, swap ๋ฐ์, dropped iterations ๋ฐ์
RUN_ID = <๋จ๊ณ>-<์ถ๊ฐ>-<๋ฐ๋ณต> (์: f1a-c1800-b0-r2, f2-C6-echo-r1,
f4-same-c50-L500-r3). ๊ฐ ์คํ์ k6 summary JSON๊ณผ raw JSON์
loadtest-scenarios/results/์, Grafana ๊ตฌ๊ฐ ์คํฌ๋ฆฐ์ท๊ณผ jcmd ์ถ๋ ฅ์ ๊ฐ์
RUN_ID ์ด๋ฆ์ผ๋ก ๋จ๊ธด๋ค. ์คํ๋ง๋ค target.env ๊ฐ, ์ด๋ฏธ์ง digest, ํฝ์ค์ฒ run
์ค์ , credit ์ํ, ๋ฐ์๊ธฐ headroom์ ํจ๊ป ๊ธฐ๋กํ๋ค.
์ต์ข
๋ณด๊ณ ์์๋ ยง2.2์ ํ์๊ฐ ํ์ ๋จ๊ณ๋ณ C_knee/C_safe, ๊ทธ๋ฆฌ๊ณ ์๋
๊ฒฐ์ ํ๋ฅผ ์ฑ์ด๋ค.
| ๊ด์ธก ์ฆ๊ฑฐ | V2 ๊ฒฐ์ ํ๋ณด |
|---|---|
์ฐ๊ฒฐ๋น heapยทdirect ๋น์ฉ์ด ์ปค์ ์์ธก ํผํฌ ์ ์ -Xmx512mยท768 MB๋ฅผ ์ํ |
WS ํ๋ก์ธ์ค ๋ถ๋ฆฌ ๋๋ backend ๋ฉ๋ชจ๋ฆฌ ์ฆ์ค |
| handshake๋ง ์ ํ๋๊ณ nginx CPU๊ฐ ๋จผ์ ํฌํ | nginx workerยทCPU ์ฌ๋ฐฐ๋ถ, TLS ์ข ๋ฃ ์์น ๋ณ๊ฒฝ |
| WS ์ฐ๊ฒฐ๋ง์ผ๋ก REST p95๊ฐ 20% ์ด์ ์ ํ | RESTยทWS ๋ถ๋ฆฌ (V2 ์ค๊ณ ํ์ ๊ทผ๊ฑฐ) |
| ๋ฉ์์ง ๊ฑด์ ๋น์ฉ(b)์ด ์ง๋ฐฐ | ๋ฐฐ์นญยท์ ์ฅ ๋น๋๊ธฐํยทACK ๊ฒฝ๋ํ |
| ๋ฉ์์ง ๋ฐ์ดํธ ๋น์ฉ(c)์ด ์ง๋ฐฐ | payload ์ํยท์์ถยท๋ณธ๋ฌธ ๋ถ๋ฆฌ |
| ์ ์ฅ ์กฐ๊ฑด์์๋ง ํ pendingยทREST 503 | ์ฑํ ์ ์ฅ ๋น๋๊ธฐํ, ํ ๋ถ๋ฆฌ, ์กฐํ ์บ์ |
| ๋์ผ ํ์์๋ง ์ง์ฐ ๊ธ์ฆยท503 | Redis ์์ ์นด์ดํฐยท๋ฉฑ๋ฑํคยท๋๊ธฐ์ด๋ก hot-row ๊ตฌ์กฐ ๋ณ๊ฒฝ |
| ์กฐํ RPS์์ throttling์ด ๋ชฉํ ํผํฌ ๊ทผ์ฒ์์ ์์ | ์ธ์คํด์ค ์ํฅ ๋๋ ์ปจํ ์ด๋ quota ์ฌ๋ฐฐ๋ถ |
| credit ๊ณ ๊ฐ์ด ์ง์ ์ฑ๋ฅ์ ์ข์ฐ | unlimited ๊ณ ์ ๋๋ ๋น๋ฒ์คํฐ๋ธ ์ธ์คํด์ค |
ํฝ์ค์ฒ(perf/ws-lab/demo)์ ๊ตฌ์กฐ์ ํ๊ณ์ด๋ฏ๋ก ๊ฒฐ๋ก ์ ๋ช
์ํ๋ค.
- fan-out์ด ์๋ค. ํธ๋ค๋ฌ๋ ๋ฐ์ ์์๊ฒ๋ง ACK ๋๋ echo๋ฅผ ๋ณด๋ด๊ณ ์ธ์ ๋ ์ง์คํธ๋ฆฌยท๋ฐฉ ๊ฐ๋ ์ด ์๋ค. ๋ฐ๋ผ์ "์์ ์ 1ยท3ยท9๋ช "๊ณผ "ํ ๋ฐฉ ์ง์ค โ ์ฌ๋ฌ ๋ฐฉ ๋ถ์ฐ" ์ถ์ ์ธก์ ๋ถ๊ฐ๋ค. ํ์ํ๋ฉด ํธ๋ค๋ฌ์ ๋ฐฉยท์ธ์ ๋ ์ง์คํธ๋ฆฌ๋ฅผ ์ถ๊ฐํ๋ ๋ณ๋ ์์ ์ด ์ ํ๋์ด์ผ ํ๋ค(402 T10์ ํด๋น ํญ๋ชฉ๋ ๊ฐ์ ์ ์ฝ์ ๋ฐ๋๋ค).
- ์ธ์ฆยท๊ถํ ๊ฒฝ๋ก๊ฐ ์๋ค(
tokens๋น์ด ์์). ์ค์ ์ฑ์ ํ ํฐ ๊ฒ์ฆ CPU๋ ํฌํจ๋์ง ์๋๋ค. - ํผ์ก๋ ์ธ๋ถ API(FastAPIยทLLM) ํธ์ถ์ด ์๋ค. 402 T5๋ ์ด ๊ณํ ๋ฒ์ ๋ฐ์ด๋ค.
- ์ฟผ๋ฆฌ ๋ณต์ก๋ยท๋ฐ์ดํฐ๋์ด ์ค์ ์คํค๋ง์ ๋ค๋ฅด๋ค.
/api/lab/posts๋ ์ ์ฒด ์ ๋ ฌ ์ด๋ฏ๋ก ๋ฐ์ดํฐ๋์ ๋ฏผ๊ฐํ๊ณ ,/api/lab/posts/{id}๋ ์ค์ ์์ธ ์กฐํ๋ณด๋ค ๋จ์ํ๋ค. -
saveMessage์ ์ถ๊ฐSELECT,chat_hold_msยทlock_hold_ms์Thread.sleep์ ํฉ์ฑ ์ง์ฐ์ด๋ค. ์ ๋๊ฐ์ด ์๋๋ผ ์กฐ๊ฑด ๊ฐ ์๋ ๋น๊ต๋ก๋ง ์ฌ์ฉํ๋ค.
2์๊ฐ์ ๊ทธ๋๋ก ์ธก์ ์ ์ธ ์ ์๋ค. ์ค์ผ ์ ์๋ ์ค๋ฒํค๋๊ฐ ๋จผ์ 40๋ถ์ ๊ฐ์ ธ๊ฐ๋ค.
| ํญ๋ชฉ | ์๊ฐ | ์ค์ผ ์ ์๋ ์ด์ |
|---|---|---|
| ์ค๋น (status, credit ๊ธฐ๋ก, ๋ฐ์ดํฐ ํ์ผ, run seed, smoke) | 10๋ถ | ํฝ์ค์ฒ run๊ณผ payload๋ณ DATA_FILE์ด ์์ผ๋ฉด ์์ ์์ฒด๊ฐ ๋ถ๊ฐ |
| JVM ์๋ฐ์ | 3๋ถ | JITยทํด๋์ค๋ก๋ฉ์ด ๋๋๊ธฐ ์ 60~90์ด๋ ๋ํ์ฑ์ด ์๋ค. ์ด๊ฑธ ๊ฑด๋๋ฐ๋ฉด ์ฒซ ๋ธ๋ก ์ ์ฒด๊ฐ ๋ฒ๋ ค์ง๋ค |
| ๋ธ๋ก ๊ฐ ๊ณต๋ฐฑ (12ํ ร 45~90์ด) | 12๋ถ | ๊ณต๋ฐฑ์ด ๊ฐ ๋ธ๋ก์ control ๊ตฌ๊ฐ์ด๋ค. ์์ ๋ฉด "๊ฐ์ญ"์ ์ฆ๋ช ํ ๋์กฐ๊ตฐ์ด ์ฌ๋ผ์ง๋ค |
| ๋ง๋ฌด๋ฆฌ (ํ์๊ฐ ์ถ์ถ, ์ ํฉ์ฑ ํ์ธ, ํ์ ํ) | 20๋ถ | ์ธก์ ์งํ์ ์ฑ์ฐ์ง ์์ผ๋ฉด ํด์ ๋ถ๊ฐํ ์ซ์ ๋๋ฏธ๋ง ๋จ๋๋ค |
| ์ค๋ฒํค๋ ํฉ | 45๋ถ | |
| ๋ถํ ์คํ ๊ฐ๋ฅ ์๊ฐ | ์ฝ 75๋ถ | ์ด ์ค ์ ํจ ์ธก์ ์ฐฝ(warm-upยทramp ์ ์ธ)์ ์ฝ 55๋ถ |
์ ์ : ํฝ์ค์ฒ๊ฐ ์ด๋ฏธ ๋ฐฐํฌ๋์ด ์๊ณ exporterยทPrometheusยทGrafana๊ฐ ์ด์
์๋ค. deploy.sh up๋ถํฐ ์์ํด์ผ ํ๋ฉด ๋น๋ยท์ ์กยท๊ธฐ๋์ 20๋ถ ์ด์์ด ๋
๋ค๊ณ ์ด ์ฐ์ ์ ์ฑ๋ฆฝํ์ง ์๋๋ค. ๋ฐฐํฌ๋ 2์๊ฐ ์ฐฝ ๋ฐ์์ ๋๋ด ๋๋ค.
- ๋ฐฐ๊ฒฝ ๋ถํ๋ฅผ ํ์ํ ๋ธ๋ก์๋ง ์ผ ๋ค. F1-aยทF1-bยทF2 echoยทF5๋ REST ์์ด ์คํํ๋ค. F1-cยทF3ยทF4์์๋ง REST control/treatment๋ฅผ ์คํํ๋ค. ๋ฐฐ๊ฒฝ์ ๊ณ์ ์ ์งํ๋ฉด ์์ ์ฐ๊ฒฐยท๋ฉ์์ง ๋จ๊ฐ์ REST ๊ฒฝํฉ ๋น์ฉ์ด ์์ด๋ฏ๋ก, ์์ถ ์คํ์ ํธ์๋ณด๋ค ๋น๊ต ๊ฐ๋ฅ์ฑ์ ์ฐ์ ํ๋ค.
-
๋จํ ์์ฒด๋ฅผ ๋
๋ฆฝ๋ณ์๋ก ์ด๋ค. ์ฐ๊ฒฐ ์๋ฅผ 8๋จ๊ณ๋ก ๋๋ ๊ฐ๊ฐ 30๋ถ ์ ์งํ๋
๋์ , 0โ3,000์ 12.5๋ถ์ ๊ฑธ์ณ ์ ํ์ผ๋ก ์ฌ๋ฆฌ๊ณ
lab_ws_connections์ ๋ํด heapยทdirectยทCPU๋ฅผ ํ๊ทํ๋ค. 5์ด scrape์ด๋ฏ๋ก ํ๋ณธ ์ฝ 150์ ์ด ๋์ค๊ณ , ์ฐ๊ฒฐ๋น ๋จ๊ฐ(๊ธฐ์ธ๊ธฐ)๋ ๋จ๊ณ๋ณ ํ๊ท ๋ณด๋ค ์คํ๋ ค ์์ ์ ์ด๋ค. ์ด ๋จํ๋ REST ์์ด F1-a๋ฅผ ์ธก์ ํ๊ณ , ๊ฐ์ ์ฐ๊ฒฐ ์์ค์ ๋ณ๋ REST treatment์์ ์ฌํํด F1-c๋ฅผ ์ธก์ ํ๋ค. - ์งง์ ์ฐฝ์์๋ ์ด๋ฒคํธ์จ์ ์ฌ๋ฆฐ๋ค. 90~120์ด ์ธก์ ์์ 36 msg/s๋ ํ๋ณธ์ด ๋๋ฌด ์ ๋ค. ๋ฉ์์ง ์ถ์ 120 msg/s๋ก ๊ณ ์ ํ๊ณ ์ฐ๊ฒฐ ์ยทpayload๋ง ๋ฐ๊พผ๋ค. RPS ๊ณ๋จ๋ 90์ด(warm-up 15์ด + ์ธก์ 75์ด)๋ก ์๋ฅธ๋ค.
์๋๋ REST ๋ฐฐ๊ฒฝ ๋ถํ๋ฅผ ยง1.5์ ๋ง๊ฒ ๋ชฉ์ ๋ณ๋ก ๋ถ๋ฆฌํ ์ค์ผ์ค์ด๋ค.
loadtest-target/run-2h.sh๊ฐ ์ด ์์๋ฅผ ๊ทธ๋๋ก ์คํํ๋ค(--plan ์ถ๋ ฅ๊ณผ
๋์ผ). ๋ธ๋ก ๋จ์ ์๋ ์คํ์ --block <์ด๋ฆ>์ ์ด๋ค.
loadtest-target/run-2h.sh --plan # ์ค์ผ์ค ํ์ธ (๋ถํ ์์)
loadtest-target/run-2h.sh --prepare # T+00~10: ๋ฐ์ดํฐ ํ์ผ, run seed, smoke
loadtest-target/run-2h.sh --run # T+10~94: ์๋ ํ ์ ์ฒด๋ฅผ ๋ฌด์ธ ์คํ
loadtest-target/run-2h.sh --collect # T+94~: ๊ตฌ๊ฐ๋ณ ํ์๊ฐ CSV
loadtest-target/run-2h.sh --block a # ๊ฐ๋ณ ๋ธ๋ก๋ง (warm a b c d e f1c f g)| ๊ตฌ๊ฐ | ๋ด์ฉ | ๊ธธ์ด | ๋์ |
|---|---|---|---|
| ์ค๋น |
--prepare: status, credit ๊ธฐ๋ก, ๋ฐ์ดํฐ ํ์ผ 3์ข
, run seed, smoke |
10๋ถ | T+10 |
warm |
light 30 RPS. ์ดํ ์ปจํ
์ด๋ ์ฌ๊ธฐ๋ ๊ธ์ง |
3๋ถ | T+13 |
a |
REST ์์ด ws-connect 0โ3,000 ๋จํ 12.5๋ถ + hold 3๋ถ โ F1-a
|
16๋ถ | T+30 |
b |
REST ์์ด handshake rate 20 / 100 / 200 conn/s โ F1-b | 5๋ถ | T+36 |
c |
REST ์์ด ๋ฉ์์ง ์ ํ 2ร2 4์ (echo, 120 msg/s) โ F2 | 16๋ถ | T+53 |
d |
detail control โ WS ์ ์ฅ๋ง โ ์ ์ฅ+detail treatment โ F3. ์ ์ฅ ์์ ๋์กฐ๊ตฐ์ c3 ์ฌ์ฌ์ฉ |
8๋ถ | T+62 |
e |
light control โ hot-row ๋จ๋
4๋จ๊ณ โ hot-row+detail treatment โ ๋ถ์ฐ ๋์กฐ๊ตฐ โ F4
|
9๋ถ | T+71 |
f1c |
light 50 RPS control โ WS 2,100 ์ ์ง + ๋์ผ REST treatment โ F1-c
|
4๋ถ | T+75 |
f |
REST ์์ด RPS ๊ณ๋จ light 50/150/300/500/700, detail 50/150/300 โ F5
|
14๋ถ | T+90 |
g |
c3 ๋ฐ๋ณต (๋ณ๋ํญ ํ์ธ) |
4๋ถ | T+94 |
| ๋ง๋ฌด๋ฆฌ |
--collect, ์ ํฉ์ฑ ํ์ธ, ํ์๊ฐยทํ์ ํ |
20๋ถ | T+114 |
C ๋ธ๋ก์ 4์
์ 200conn/256B ยท 200conn/8000B ยท 1800conn/256B ยท
1800conn/8000B๋ค. 2ร2๊ฐ ์์ฑ๋์ด์ผ ยง5์ ํ๊ท๋ก ๊ฑด์ ๋น์ฉ b์ ๋ฐ์ดํธ
๋น์ฉ c๋ฅผ ๋ถ๋ฆฌํ ์ ์๋ค. 3์
์ด๋ฉด ๊ต์ฐจํญ์ ๊ฒ์ฆํ ์ ์์ด "ํฐ ์ปจํ
์คํธ๊ฐ
๋ ๋ฌด๊ฒ๋ค" ์์ค์ ์ธ์๋ง ๋จ๋๋ค. 90๋ถ ์ฐฝ์ด๋ผ๋ฉด ์ฌ๊ธฐ์ ํ ์
์ ์๋๋ค.
F1-c์ REST ๊ฐ์ญ ๊ฒฐ๊ณผ๋ AยทBยทC์ ์์ ๋น์ฉ ๊ฒฐ๊ณผ์ ์์ง ์๋๋ค. ๋ณ๋์
REST๋ง control๊ณผ REST + WS treatment ๊ตฌ๊ฐ์ ๋ง๋ค๊ณ , control ๋๋น REST
p95ยท์ค๋ฅ์จยทTomcatยทHikari ๋ณํ๋ฅผ ๋ณด๊ณ ํ๋ค.
์๊ฐ์ด ๋ฐ๋ฆด ๋ ๋ฒ๋ฆฌ๋ ์์: f์ 700 RPS โ g โ b์ 200 conn/s โ
d์ treatment โ f1c. ๋ธ๋ก a์ e๋ ๋ง์ง๋ง๊น์ง ์งํจ๋ค. a๋ V2์
RESTยทWS ๋ถ๋ฆฌ ๊ฒฐ์ ์ ์ง์ ์ฐ์ด๊ณ , e๋ 1๋ถ์ง๋ฆฌ ์คํ์ผ๋ก ๊ฐ์ฅ ๊ฐํ ์ ํธ๋ฅผ
์ค๋ค.
๊ฒฐ๋ก ์ ๋ฐ๋์ ํจ๊ป ์ ๋๋ค.
-
๋ฐ๋ณต 3ํ๊ฐ ์๋ค. A'์ G๊ฐ ๊ฐ๊ฐ 1ํ control/treatment ๋๋ ์ฌ์ธก์ ์ผ ๋ฟ์ด๋ค. 90
120์ด ๋จ์ผ ์ธก์ ์์ p95๋ ยฑ2030% ํ๋ค๋ฆฌ๋ฏ๋ก, ์ง์ฐ ์ฐจ์ด๋ 30% ์ด์์ผ ๋๋ง ์ค์ฌ๋ก ์ธ์ ํ๊ณ , 1์ฐจ ๊ทผ๊ฑฐ๋ ๋ณ๋์ด ์์ ์์ ์งํ(์ฐ๊ฒฐ๋น heap, ๋ฉ์์ง๋น CPU-ms, CPU quota ์ฌ์ฉ๋ฅ )๋ก ์ผ๋๋ค. -
30๋ถ idle hold๊ฐ ์๋ค. ์ฐ๊ฒฐ ๋์ยทheartbeat ๋์ ยท์๋งํ heap ์ฆ๊ฐ๋
๊ฒ์ถ๋์ง ์๋๋ค.
C_safesoak(60~120๋ถ)๋ ์ด ์ฐฝ ๋ฐ์ ๊ณผ์ ๋ค. -
์๋ฒ ์ค์ ์ถ์ ๊ฑด๋๋ฆด ์ ์๋ค.
HIKARI_MAX_POOL_SIZE,WS_PER_CONNECTION_BYTES,JVM_XMX๋ณ๊ฒฝ์ ์ฌ๋ฐฐํฌ์ JVM ๋์๋์ ๋ถ๋ฅด๊ณ ๋ธ๋ก ๊ฐ ๋น๊ต ๊ฐ๋ฅ์ฑ์ ๊นจ๋จ๋ฆฐ๋ค. ์ด ์ฐฝ์ ๋ชจ๋ ์ถ์ k6ยท๋ฐ์ดํฐ ํ์ผ ์ชฝ์๋ง ๋๋ค. ํ ํฌ๊ธฐ ๋์กฐ(10 โ 20)๋ ๋ณ๋ ์ฐฝ์์ ํ๋ค. -
CPU credit์ ํต์ ํ ์ ์๋ค. 120๋ถ ์ฐ์ ๋ถํ๋ baseline 20%๋ฅผ ๊ณ์
๋์ผ๋ฏ๋ก credit์ ์๋ชจํ๋ค. ์์ ์
CPUCreditBalance๋ฅผ ๊ธฐ๋กํ๊ณ , standard ๋ชจ๋์์ ์๋์ด ์ ์ผ๋ฉด unlimited๋ก ๋ฐ๊พธ๊ฑฐ๋ ๋ธ๋ก A๋ฅผ ๋จผ์ ๋๋ธ๋ค ๋ ์ ์ ๋ก ์งํํ๋ค. balance๊ฐ 0์ ๋ฟ์ ๋ค์ ๊ตฌ๊ฐ์ ์ฉ๋ ํ๊ณ๊ฐ ์๋๋ค. -
lock_hold_msยทchat_hold_ms๋ ๊ฐ๊ฐ ํ ๊ฐ(100ms / 0ยท50ms)๋ง ๋ณธ๋ค. ยง6ยทยง7์ ๋ค๋จ๊ณ ๋น๊ต๋ ์ด ์ฐฝ์์ ์ฑ๋ฆฝํ์ง ์๋๋ค. - ยง12์ ํฝ์ค์ฒ ํ๊ณ(fan-outยท๋ฐฉ ๊ฐ๋ ์์)๋ ์๊ฐ๊ณผ ๋ฌด๊ดํ๊ฒ ๊ทธ๋๋ก๋ค.
loadtest-target/collect-window.py๊ฐ results/runs.tsv์ ์คํ ๊ตฌ๊ฐ๋ง๋ค
Prometheus๋ฅผ ์กฐํํด ยง2.2 ํ์๊ฐ์ CSV๋ก ๋ง๋ ๋ค. ๋จํ ๋ฐ(a-, a2-)์
lab_ws_connections์ ๋ํ ์ต์์ ๊ณฑ ํ๊ท๋ก ์ฐ๊ฒฐ๋น heapยทdirect bytes์
1,000 ์ฐ๊ฒฐ๋น CPU ์ฝ์ด๊น์ง ํจ๊ป ์ถ๋ ฅํ๋ค.
loadtest-target/run-2h.sh --collect # PROM_URL ์ terraform output ์์ ์๋
PROM_URL=http://<monitoring-ip>:9090 loadtest-target/run-2h.sh --collectCSV๋ฅผ ๋ฐ์ผ๋ฉด ยง11์ ๊ฒฐ์ ํ๋ฅผ ๊ทธ ์๋ฆฌ์์ ์ฑ์ด๋ค. ์ ํฉ์ฑ์ hot run stats๋ก ํ์ธํ๋ค.
curl -sk https://$(cat loadtest-target/.local/public_host)/api/lab/runs/h-L100/stats \
| python3 -m json.tool
# parties[i].approved + parties[i].remaining == capacity ์ธ์ง ํ์ธ--prepare๊ฐ .local/fixture-runs.json์ base/hot์ ์ run์ผ๋ก ๋ฎ์ด์ฐ๋ฏ๋ก,
์ฐฝ์ด ๋๋๋ฉด ๋๋๋ฆฐ๋ค.
python3 loadtest-target/make-test-data.py --base-run base-01 --hot-run hot-01