405 V1 limit analysis measured - 100-hours-a-week/KTB4-3rd-CLOUD GitHub Wiki

405 V1 ํ•œ๊ณ„ ์ง€์  โ€” ๋ถ€ํ•˜ํ…Œ์ŠคํŠธ ์‹ค์ธก ๋ถ„์„

์œ„ํ‚ค [402 V2 ํŠธ๋ž˜ํ”ฝ ์‹œ๋‚˜๋ฆฌ์˜ค ๊ธฐ๋ฐ˜ V1 ํ•œ๊ณ„ ์ง€์  ๋ถ„์„]์˜ ์„ธ ์‹œ๋‚˜๋ฆฌ์˜ค์— ๋Œ€ํ•ด 2026-09-20 ์‹ค์ธก๊ฐ’์œผ๋กœ ๋‹ต์„ ์ฑ„์šด ๋ฌธ์„œ๋‹ค. ๋ฌธ์„œ ๊ณจ๊ฒฉ์€ 404, ์ธก์ • ์„ค๊ณ„๋Š” 403์— ์žˆ๋‹ค.

๊ฐ ์ ˆ์€ ์˜ˆ์™ธ ์—†์ด ๊ฐ™์€ ์‚ฌ์Šฌ์„ ๋”ฐ๋ฅธ๋‹ค. ์„œ๋น„์Šค ๋™์ž‘ โ†’ ์˜ˆ์ƒ ํŠธ๋ž˜ํ”ฝ โ†’ ๋ถ€ํ•˜ ํŠน์„ฑ โ†’ ์ ์œ  ์ธํ”„๋ผ ์ž์› โ†’ ์ธก์ • ์„ค๊ณ„ โ†’ ์ธก์ • ๊ฒฐ๊ณผ โ†’ ์ธํ”„๋ผ ๊ตฌ์„ฑ ๋ณ€๊ฒฝ.


0. ์š”์•ฝ

0.1 ๊ฒฐ๋ก  ์„ธ ์ค„

  1. V1์˜ ํ•œ๊ณ„๋Š” RPS๊ฐ€ ์•„๋‹ˆ๋‹ค. ๋‹จ์ˆœ ์กฐํšŒ๋Š” ๋ชฉํ‘œ ํ”ผํฌ(60.4 RPS)์˜ 10๋ฐฐ์ธ 641 RPS์—์„œ๋„ p95 19.4 ms, ์˜ค๋ฅ˜ 0%, CPU throttling 0์ด์—ˆ๋‹ค.
  2. ํ•œ๊ณ„๋Š” ์„ธ ๊ฐœ์˜ ๊ณต์œ  ์ž์›์— ์žˆ๋‹ค. WebSocket ๋™์‹œ ์—ฐ๊ฒฐ ์•ฝ 1,700๊ฐœ(ํ–‰์‚ฌ ๋ชฉํ‘œ 3,000์˜ 57%), HikariCP ๊ณต์šฉ ํ’€ 10๊ฐœ, ๋™์ผ ํŒŸ ํ–‰์˜ lock์ด๋‹ค.
  3. ์„ธ ์ž์›์€ ๋ชจ๋‘ ๋‹ค๋ฅธ ๊ธฐ๋Šฅ์œผ๋กœ ์žฅ์• ๋ฅผ ์ „ํŒŒํ•œ๋‹ค. WS ์—ฐ๊ฒฐ 2,100๊ฐœ์—์„œ ์ผ๋ฐ˜ ์กฐํšŒ p99๊ฐ€ 27๋ฐฐ, ์ฑ„ํŒ… ์ €์žฅ 47 msg/s์—์„œ ์กฐํšŒ p95๊ฐ€ 13.6๋ฐฐ, ์ธ๊ธฐ ํŒŸ ๋™์‹œ ์Šน์ธ 50๊ฑด์—์„œ ์กฐํšŒ p99๊ฐ€ 48๋ฐฐ ์•…ํ™”๋๋‹ค.

0.2 ์œ„ํ‚ค ์„ธ ์‹œ๋‚˜๋ฆฌ์˜ค์— ๋Œ€ํ•œ ํŒ์ •

์œ„ํ‚ค ์‹œ๋‚˜๋ฆฌ์˜ค ์š”๊ตฌ ์ˆ˜์ค€ ์‹ค์ธก ๊ฒฐ๊ณผ ํŒ์ •
(1) ์ถœํ‡ด๊ทผ ํŒŸ ํƒ์ƒ‰ ์กฐํšŒ ์ฆ๊ฐ€ ์กฐํšŒ 60.4 RPS 641 RPS๊นŒ์ง€ p95 19.4 ms, ์˜ค๋ฅ˜ 0% ์—ฌ์œ  ์žˆ์Œ
(1) ํ˜ผ์žก๋„ DB ์“ฐ๊ธฐ 37.6 row ์“ฐ๊ธฐ/s ์œ ์‚ฌ ๊ทœ๋ชจ(47 write/s)์—์„œ ํ’€ 10๊ฐœ ํฌํ™”, ๋Œ€๊ธฐ 53๊ฑด ์œ„ํ—˜ (์ง์ ‘ ์ธก์ • ์•„๋‹˜)
(2) ์ธ๊ธฐ ํŒŸ ์ขŒ์„ ๊ฒฝ์Ÿ ์ธ๊ธฐ ํŒŸ ์ž ๊ธˆ 1.05 RPS ๋™์‹œ 20๊ฑด์—์„œ ํ’€ ๊ณ ๊ฐˆ, 50๊ฑด์—์„œ ์‹คํŒจ์œจ 59.5% ๊ฐ€์ • ๋‹จ์œ„๋ฅผ ๋ฐ”๊ฟ”์•ผ ํ•จ
(3) ํ–‰์‚ฌ WS ๋™์‹œ ์—ฐ๊ฒฐ ๋™์‹œ 3,000๊ฐœ ์ตœ๋Œ€ 1,734๊ฐœ, ์ดํ›„ handshake 30์ดˆ ํƒ€์ž„์•„์›ƒ ๋ชฉํ‘œ ๋ฏธ๋‹ฌ
(3) ํ–‰์‚ฌ ์‹ ๊ทœ ์—ฐ๊ฒฐ๋ฅ  10 conn/s 20 conn/s์—์„œ handshake p95 33.5 ms ์—ฌ์œ  ์žˆ์Œ
(3) ํ–‰์‚ฌ API ํ”ผํฌ 140 RPS 641 RPS๊นŒ์ง€ ์—ฌ์œ  ์—ฌ์œ  ์žˆ์Œ
(3) ์ฑ„ํŒ… ๋ฉ”์‹œ์ง€ ์ฆ๊ฐ€ โ€” 47 msg/s ์ €์žฅ์—์„œ ์ผ๋ฐ˜ ์กฐํšŒ p95 13.6๋ฐฐ ์•…ํ™” ์œ„ํ—˜

0.3 ์ตœ์ดˆ ํฌํ™” ์ž์› ์ˆœ์œ„

์ˆœ์œ„ ํฌํ™” ์ž์› ์ž„๊ณ„๊ฐ’ ๊ทผ๊ฑฐ RUN_ID ๋ชฉํ‘œ ๋Œ€๋น„
1 WebSocket ๋™์‹œ ์—ฐ๊ฒฐ ์•ฝ 1,700๊ฐœ a-ramp3000, c3, d1, g 3,000 ๋ชฉํ‘œ์˜ 57%
2 HikariCP ๊ณต์šฉ ํ’€ (10) ๋™์‹œ ์“ฐ๊ธฐ 20๊ฑด / ์ €์žฅ 47 msg/s e-same-c20, d1-save-h50 1.05 RPS ๊ฐ€์ •์€ ํ†ต๊ณผ, ๋™์‹œ์„ฑ์€ ์‹คํŒจ
3 ๋™์ผ ํŒŸ row lock ๋™์‹œ 50๊ฑด์—์„œ ์‹คํŒจ์œจ 59.5% e-same-c50 โ€”
4 Nginx ์—ฐ๊ฒฐ ์ˆ˜๋ฆฝ ์ฒ˜๋ฆฌ 200 conn/s์—์„œ p95 3.57์ดˆ b-rate200 10 conn/s ๋ชฉํ‘œ์˜ 20๋ฐฐ
5 Spring CPU quota (0.75) 641 RPS์—์„œ๋„ throttling 0 f-light-700 60.4 RPS์˜ 10๋ฐฐ ์ด์ƒ

1. ์ธก์ • ๊ฐœ์š”

1.1 ๋Œ€์ƒ๊ณผ ํ™˜๊ฒฝ

t3.medium(2 vCPU ยท 4 GiB) 1๋Œ€์— ์ปจํ…Œ์ด๋„ˆ 4๊ฐœ. ํ•ฉ๊ณ„๊ฐ€ ํ˜ธ์ŠคํŠธ CPU๋ฅผ 100% ์†Œ์ง„ํ•˜๋„๋ก ๋ฐฐ๋ถ„๋˜์–ด ์žˆ๋‹ค.

์ปจํ…Œ์ด๋„ˆ CPU ๋ฉ”๋ชจ๋ฆฌ ์ด ๋ฌธ์„œ์—์„œ ์ค‘์š”ํ•œ ์„ค์ •
Nginx 0.25 128 MB worker_processes 1, nofile 32768
Next.js(placeholder) 0.50 512 MB ์ƒ์‹œ 384 MB ์ ์œ 
Spring Boot 0.75 768 MB -Xmx512m, Tomcat threads 200 / max-connections 8192
MySQL 0.50 768 MB buffer pool 384 MB
  • HikariCP ์ตœ๋Œ€ 10, ์ปค๋„ฅ์…˜ ํš๋“ ํƒ€์ž„์•„์›ƒ 1,000 ms, innodb_lock_wait_timeout 3์ดˆ
  • REST์™€ WebSocket์ด ๊ฐ™์€ Spring ์ปจํ…Œ์ด๋„ˆ์˜ CPUยทheapยทTomcatยทํ’€์„ ๊ณต์œ ํ•œ๋‹ค
  • ๋ถ€ํ•˜๋Š” ๋กœ์ปฌ k6 โ†’ ๊ณต๊ฐœ HTTPS/WSS โ†’ Nginx ๊ฒฝ์œ . ๊ด€์ธก์€ Prometheus 5์ดˆ scrape

1.2 ์‹คํ–‰ ๋ชฉ๋ก

31๊ฐœ ์‹คํ–‰, 2026-09-20 18:47~21:00. ๊ตฌ๊ฐ„์€ results/runs.tsv, ๊ตฌ๊ฐ„๋ณ„ ์ž์› ์ง‘๊ณ„๋Š” results/derived-20260920T210124.csv.

๋ธ”๋ก ๋ชฉ์  RUN_ID
a ์—ฐ๊ฒฐ๋‹น ์ž์› ๋‹จ๊ฐ€ a-ramp3000 (0โ†’3,000 ๋žจํ”„ 12.5๋ถ„)
b ์—ฐ๊ฒฐ ์‹œ๋„์œจ b-rate20, b-rate100, b-rate200
c ๋ฉ”์‹œ์ง€ ์œ ํ˜• 2ร—2 c1-200c-256b, c2-200c-8000b, c3-1800c-256b, c4-1800c-8000b
d ์ฑ„ํŒ… ์ €์žฅ๊ณผ ํ’€ ๊ฒฝํ•ฉ d0-rest-control, d1-save-h50, d2-save-h50-ws, d2-rest-treatment
e ์ธ๊ธฐ ํŒŸ hot-row e0-rest-control, e-same-c5/20/50/100, e-mix-c50, e-mix-rest, e-dist-c50
f1c WS๊ฐ€ REST์— ์ฃผ๋Š” ๊ฐ„์„ญ f1c-rest-control, f1c-ws2100, f1c-rest-treatment
f ์กฐํšŒ RPS ๊ณ„๋‹จ f-light-50~700, f-detail-50~300
g ๋ฐ˜๋ณต ์ธก์ • g-c3-repeat

1.3 ํŒ์ • ๊ทœ์น™๊ณผ ์‹ ๋ขฐ ๋ฒ”์œ„

  • ์ธก์ •์ฐฝ์€ ๋ธ”๋ก๋‹น 75~150์ดˆ, ๋ฐ˜๋ณต 1ํšŒ๋‹ค. g-c3-repeat์™€ c3์˜ ์ฐจ์ด๊ฐ€ 8%(CPU 0.0357 vs 0.0388 cores)์˜€์œผ๋ฏ€๋กœ, 30% ๋ฏธ๋งŒ์˜ ์ง€์—ฐ ์ฐจ์ด๋Š” ์‹ค์žฌ๋กœ ์ธ์ •ํ•˜์ง€ ์•Š๋Š”๋‹ค.
  • ์ง€์—ฐยท์˜ค๋ฅ˜์œจ์€ k6 ํด๋ผ์ด์–ธํŠธ ์ธก์ •๊ฐ’์„ ์“ด๋‹ค. ์„œ๋ฒ„ ์ธก http_server_requests ํžˆ์Šคํ† ๊ทธ๋žจ ๋ถ„์œ„๋Š” ๊ฑฐ์˜ ๋ชจ๋“  ๊ตฌ๊ฐ„์—์„œ 0.95 ms๋กœ ๊ณ ์ •๋˜์–ด ์‚ฐ์ • ์˜ค๋ฅ˜๊ฐ€ ํ™•์ธ๋๋‹ค(ยง8.2).
  • ์ž์› ์ง€ํ‘œ(์—ฐ๊ฒฐ๋‹น heap, ์š”์ฒญ๋‹น CPU)๋Š” ๋ณ€๋™์ด ์ž‘์•„ 1์ฐจ ๊ทผ๊ฑฐ๋กœ, ์ง€์—ฐ์€ ๋ณด์กฐ ๊ทผ๊ฑฐ๋กœ ์“ด๋‹ค.

2. ๊ณตํ†ต ๊ธฐ์ค€์„ 

์ดํ›„ ๋ชจ๋“  ์ ˆ์ด ์ด ๋‘ ๊ฐ’์„ ๋น„๊ต ๊ธฐ์ค€์œผ๋กœ ์“ด๋‹ค.

2.1 WebSocket ์—ฐ๊ฒฐ 1๊ฐœ์˜ ์ž์› ๋‹จ๊ฐ€

a-ramp3000์˜ ๋žจํ”„ ๊ตฌ๊ฐ„(0โ†’1,734๊ฐœ, 12.5๋ถ„)์„ lab_ws_connections์— ๋Œ€ํ•ด ์ตœ์†Œ์ œ๊ณฑ ํšŒ๊ท€ํ•œ ๊ฐ’์ด๋‹ค.

ํ•ญ๋ชฉ ์‹ค์ธก 3,000 ์—ฐ๊ฒฐ ํ™˜์‚ฐ Spring ๋ฐฐ์ •๋Ÿ‰ ๋Œ€๋น„
์—ฐ๊ฒฐ๋‹น heap 28.2 KB 84.6 MB -Xmx512m์˜ 16.5%
์—ฐ๊ฒฐ๋‹น direct buffer 0.2 KB 0.6 MB ๋ฌด์‹œ ๊ฐ€๋Šฅ
1,000 ์—ฐ๊ฒฐ๋‹น CPU 0.0092 cores 0.028 cores 0.75 CPU์˜ 3.7%

heap ๊ธฐ์ค€ ์ˆ˜์šฉ ๊ฐ€๋Šฅ ์—ฐ๊ฒฐ = (512 MB ร— 0.7 โˆ’ ๊ธฐ์ € heap 31.9 MB) รท 28.2 KB โ‰ˆ 11,800๊ฐœ. ์ฆ‰ ๋ฉ”๋ชจ๋ฆฌ๋„ CPU๋„ 3,000 ์—ฐ๊ฒฐ์„ ๊ฐ๋‹นํ•œ๋‹ค. ๊ทธ๋Ÿฐ๋ฐ ์‹ค์ œ ์ƒํ•œ์€ 1,700๊ฐœ์˜€๋‹ค(ยง5.1). ์ด ๋ถˆ์ผ์น˜๊ฐ€ ์ด ๋ฌธ์„œ์˜ ๊ฐ€์žฅ ์ค‘์š”ํ•œ ๋ฏธํ•ด๊ฒฐ ํ•ญ๋ชฉ์ด๋‹ค.

2.2 ์กฐํšŒ API 1๊ฑด์˜ ์ž์› ๋‹จ๊ฐ€

๊ณ„์—ด ์ตœ๋Œ€ ์‹ค์ธก RPS ๊ทธ๋•Œ backend CPU ์š”์ฒญ๋‹น CPU quota ์ด๋ก  ์ƒํ•œ
light (DB ๋ฏธ์‚ฌ์šฉ) 641.6 0.148 cores 0.231 CPU-ms ์•ฝ 3,250 RPS
detail (DB ์กฐํšŒ) 274.5 0.125 cores 0.455 CPU-ms ์•ฝ 1,650 RPS

ํ”ฝ์Šค์ฒ˜ endpoint๊ฐ€ ์‹ค์ œ API๋ณด๋‹ค ๋‹จ์ˆœํ•˜๋ฏ€๋กœ ์ ˆ๋Œ€ RPS๋Š” ์ƒํ•œ ๋ณด์ฆ๊ฐ’์ด ์•„๋‹ˆ๋‹ค. ์ด ํ‘œ๋Š” "์กฐํšŒ ๊ฒฝ๋กœ๊ฐ€ V1์˜ 1์ฐจ ๋ณ‘๋ชฉ์ด ์•„๋‹ˆ๋‹ค"๋ฅผ ๋ณด์ด๋Š” ๋ฐ๋งŒ ์“ด๋‹ค.


3. ์‹œ๋‚˜๋ฆฌ์˜ค (1) โ€” ์ถœํ‡ด๊ทผ ํŒŸ ํƒ์ƒ‰: ์กฐํšŒ ์ฆ๊ฐ€์™€ ํ˜ผ์žก๋„ ์ €์žฅ

3.1 ์„œ๋น„์Šค ๋™์ž‘

๊ตํ†ต ์žฅ์•  ๋ฐœ์ƒ โ†’ ์ฃผ๋ณ€ ํ˜ผ์žก๋„ ํ™•์ธ โ†’ ๋ชฉ์ ์ง€ ๋ฐฉํ–ฅ ํŒŸ ๊ฒ€์ƒ‰ โ†’ ์—ฌ๋Ÿฌ ํŒŸ ๋น„๊ต โ†’ ์กฐ๊ฑด ๋ณ€๊ฒฝ ํ›„ ์žฌ๊ฒ€์ƒ‰. V2์—์„œ๋Š” ์„ ํƒ์ง€๊ฐ€ ๋Š˜์–ด ๋ชฉ๋กยท์ƒ์„ธ ์žฌ์กฐํšŒ๊ฐ€ ๋ฐ˜๋ณต๋œ๋‹ค.

3.2 ์˜ˆ์ƒ ํŠธ๋ž˜ํ”ฝ (์œ„ํ‚ค 402)

์กฐํšŒ ์ข…๋ฅ˜ ์‚ฌ์šฉ์ž๋‹น ์ผ์ผ ํ”ผํฌ ํ‰๊ท  RPS
์ปค๋ฎค๋‹ˆํ‹ฐ ๋ชฉ๋ก 10๊ฑด 20.8
๊ฒŒ์‹œ๊ธ€ยทํŒŸ ์ƒ์„ธ 10๊ฑด 20.8
ํ˜ผ์žก๋„ 9๊ฑด 18.8
ํ•ฉ๊ณ„ 29๊ฑด 60.4
ํ˜ผ์žก๋„ DB ์“ฐ๊ธฐ (K=1) โ€” 37.6 row/s

3.3 ๋ถ€ํ•˜ ํŠน์„ฑ

์ •์ƒ ์ƒํƒœ์˜ ์ฒ˜๋ฆฌ๋Ÿ‰ ๋ถ€ํ•˜๋‹ค. ์š”์ฒญ๋‹น ๋น„์šฉ์ด ๊ณง ์šฉ๋Ÿ‰์„ ์ •ํ•œ๋‹ค. ๋‹จ ํ˜ผ์žก๋„๋Š” ์กฐํšŒ๊ฐ€ ๊ณง ์“ฐ๊ธฐ(์ตœ์‹ ๊ฐ’ upsert + ์ด๋ ฅ insert)๋ฅผ ๋งŒ๋“œ๋Š” ์ฝ๊ธฐ์ฒ˜๋Ÿผ ๋ณด์ด๋Š” ์“ฐ๊ธฐ ๋ถ€ํ•˜๋‹ค.

3.4 ์ ์œ  ์ธํ”„๋ผ ์ž์›

์ฝ๊ธฐ ๊ฒฝ๋กœ : Nginx(0.25) โ†’ Spring Tomcat ์Šค๋ ˆ๋“œยทCPU(0.75) โ†’ [detail] Hikari(10) โ†’ MySQL(0.5)
์“ฐ๊ธฐ ๊ฒฝ๋กœ : ์œ„ + ๋™์ผ spot_id row lock + redo/fsync + EBS

ํ˜ผ์žก๋„ ์“ฐ๊ธฐ๋Š” ์ฑ„ํŒ… ์ €์žฅยท์ขŒ์„ ์Šน์ธ๊ณผ ๊ฐ™์€ ํ’€ 10๊ฐœ๋ฅผ ๊ณต์œ ํ•œ๋‹ค.

3.5 ์ธก์ • ์„ค๊ณ„

  • ์กฐํšŒ: light(DB ๋ฏธ์‚ฌ์šฉ) 50โ†’150โ†’300โ†’500โ†’700 RPS, detail(DB ์กฐํšŒ) 50โ†’150โ†’300 RPS, ๊ฐ warm-up 15์ดˆ + ์ธก์ • 75์ดˆ, WS ์—†์Œ
  • ํ˜ผ์žก๋„ ์“ฐ๊ธฐ: ํ”ฝ์Šค์ฒ˜์— ํ˜ผ์žก๋„ API๊ฐ€ ์—†์–ด ์ง์ ‘ ์ธก์ •ํ•˜์ง€ ์•Š์•˜๋‹ค. ๋™์ผ ํ’€ยท๋™์ผ ๊ทœ๋ชจ์˜ ์“ฐ๊ธฐ ๋ถ€ํ•˜์ธ ์ฑ„ํŒ… ์ €์žฅ(ยง5.4, 47 write/s)์œผ๋กœ ๊ฐ„์ ‘ ํŒ๋‹จํ•œ๋‹ค

3.6 ์ธก์ • ๊ฒฐ๊ณผ

๋ชฉํ‘œ RPS ์‹ค์ œ RPS p95 p99 ์˜ค๋ฅ˜์œจ dropped backend CPU throttling ํ˜ธ์ŠคํŠธ CPU
light 50 45.9 11.5 ms 16.9 ms 0% 0 0.029 0 8.4%
light 150 137.6 11.3 ms 18.2 ms 0% 0 0.066 0 13.5%
light 300 275.0 11.5 ms 21.9 ms 0% 0 0.085 0 17.4%
light 500 458.3 15.0 ms 53.6 ms 0% 0 0.120 0 22.6%
light 700 641.6 19.4 ms 64.1 ms 0% 0 0.148 0 27.8%
detail 50 45.9 13.2 ms 26.4 ms 0% 0 0.047 0 10.5%
detail 150 137.5 12.3 ms 24.8 ms 0% 0 0.086 0 18.0%
detail 300 274.5 16.7 ms 44.1 ms 0% 0 0.125 0 26.0%
  • C_knee์— ๋„๋‹ฌํ•˜์ง€ ๋ชปํ–ˆ๋‹ค. 641 RPS์—์„œ๋„ ์˜ค๋ฅ˜ 0%, throttling 0, Tomcat busy ์ตœ๋Œ€ 1์ด๋‹ค. ๋ชฉํ‘œ 60.4 RPS๋Š” ์ธก์ • ์ตœ๋Œ€๊ฐ’์˜ 9.4%๋‹ค.
  • MySQL CPU๋Š” detail 300 RPS์—์„œ 0.105 cores(๋ฐฐ์ • 0.5์˜ 21%)๋กœ ์—ฌ์œ ๊ฐ€ ์žˆ๋‹ค.
  • 700 RPS ๋ชฉํ‘œ์—์„œ ์‹ค์ œ 641 RPS(91.7%)์— ๊ทธ์นœ ๊ฒƒ์€ dropped iteration 0์ด๋ฏ€๋กœ ์„œ๋ฒ„ ํฌํ™”๊ฐ€ ์•„๋‹ˆ๋ผ ๋ฐœ์ƒ๊ธฐยท๋„คํŠธ์›Œํฌ ์ชฝ ์ƒํ•œ์œผ๋กœ ๋ณธ๋‹ค.

3.7 ํŒ์ •๊ณผ ์ธํ”„๋ผ ๊ตฌ์„ฑ ๋ณ€๊ฒฝ

  • ์กฐํšŒ ๊ฒฝ๋กœ๋Š” V1์—์„œ ๋ณ€๊ฒฝ ์šฐ์„ ์ˆœ์œ„๊ฐ€ ๊ฐ€์žฅ ๋‚ฎ๋‹ค. ์ธ์Šคํ„ด์Šค ์ƒํ–ฅยทscale-out์„ ์กฐํšŒ ๋•Œ๋ฌธ์— ๊ฒฐ์ •ํ•  ๊ทผ๊ฑฐ๋Š” ์—†๋‹ค.
  • ๋‹ค๋งŒ ํ˜ผ์žก๋„ ์“ฐ๊ธฐ(37.6 row/s)๋Š” ๋ณ„๊ฐœ๋‹ค. ยง5.4์—์„œ 47 write/s๊ฐ€ ํ’€ 10๊ฐœ๋ฅผ ํฌํ™”์‹œํ‚ค๊ณ  ๊ฐ™์€ ํ’€์„ ์“ฐ๋Š” ์กฐํšŒ p95๋ฅผ 13.6๋ฐฐ ์•…ํ™”์‹œ์ผฐ๋‹ค. ํ˜ผ์žก๋„ ์ €์žฅ์ด ์ถ”๊ฐ€๋˜๋ฉด ์กฐํšŒ ์ง€์—ฐ์€ ์กฐํšŒ๋Ÿ‰ ๋•Œ๋ฌธ์ด ์•„๋‹ˆ๋ผ ์“ฐ๊ธฐ ๋•Œ๋ฌธ์— ๋ฌด๋„ˆ์ง„๋‹ค.
  • ๋ณ€๊ฒฝ์•ˆ: ํ˜ผ์žก๋„ ์ตœ์‹ ๊ฐ’์€ ์บ์‹œ(TTL) + ๋‹จ์ผ ๋น„ํ–‰(single-flight)์œผ๋กœ ์“ฐ๊ธฐ ํšŸ์ˆ˜๋ฅผ ์ค„์ด๊ณ , ์ด๋ ฅ ์ €์žฅ์€ ๋น„๋™๊ธฐ ๋ฐฐ์น˜๋กœ ๋ถ„๋ฆฌํ•œ๋‹ค. ์ฝ๊ธฐยท์“ฐ๊ธฐ ํ’€์„ ๋ถ„๋ฆฌํ•œ๋‹ค.
  • ์žฌ๊ฒ€์ฆ: ํ˜ผ์žก๋„ endpoint๋ฅผ ํ”ฝ์Šค์ฒ˜์— ์ถ”๊ฐ€ํ•ด K=1๊ณผ K=5๋กœ ยง5.4์™€ ๋™์ผํ•œ control/treatment ๋น„๊ต๋ฅผ ์ˆ˜ํ–‰ํ•œ๋‹ค.

4. ์‹œ๋‚˜๋ฆฌ์˜ค (2) โ€” ์ธ๊ธฐ ํŒŸ ์ขŒ์„ ๊ฒฝ์Ÿ

4.1 ์„œ๋น„์Šค ๋™์ž‘

ํŒŸ ๋ชฉ๋ก ๋น„๊ต โ†’ ๋‚จ์€ ์ขŒ์„ ํ™•์ธ โ†’ ์ฐธ์—ฌ ์š”์ฒญ โ†’ ์Šน์ธ. ์ขŒ์„์ด ๋งˆ๊ฐ๋˜๋ฉด ์ƒˆ๋กœ๊ณ ์นจ๊ณผ ์žฌ๊ฒ€์ƒ‰์ด ์ด์–ด์ง„๋‹ค. ์Šน์ธ์€ ์ขŒ์„ ํ–‰์„ SELECT ... FOR UPDATE๋กœ ์ž ๊ทผ๋‹ค.

4.2 ์˜ˆ์ƒ ํŠธ๋ž˜ํ”ฝ (์œ„ํ‚ค 402)

์š”์ฒญ ์ข…๋ฅ˜ ๊ณ„์‚ฐ RPS
ํŒŸ ์ฐธ์—ฌ ์š”์ฒญ 30,000 รท 14,400 2.1
์ฐธ์—ฌ ์Šน์ธยท๊ฑฐ์ ˆ 30,000 รท 14,400 2.1
์ธ๊ธฐ ํŒŸ ์ง‘์ค‘(h=50%) 2.1 ร— 0.5 1.05

4.3 ๋ถ€ํ•˜ ํŠน์„ฑ

์ง๋ ฌํ™”๋˜๋Š” ๊ฒฝํ•ฉ ๋ถ€ํ•˜. ๋ณ€์ˆ˜๋Š” RPS๊ฐ€ ์•„๋‹ˆ๋ผ ๊ฐ™์€ ํ–‰์— ๋™์‹œ์— ๋„์ฐฉํ•˜๋Š” ์š”์ฒญ ์ˆ˜๋‹ค. ๋Œ€๊ธฐ ์ค‘์—๋„ ์ปค๋„ฅ์…˜์„ ์ ์œ ํ•˜๋ฏ€๋กœ ๋ถ€ํ•˜๊ฐ€ ์ž์›์„ ์ด์ค‘์œผ๋กœ ๋จน๋Š”๋‹ค.

4.4 ์ ์œ  ์ธํ”„๋ผ ์ž์›

์Šน์ธ ์š”์ฒญ โ†’ Spring ์Šค๋ ˆ๋“œ โ†’ Hikari ์ปค๋„ฅ์…˜ 1๊ฐœ ์ ์œ 
          โ†’ MySQL ๋™์ผ row X-lock (๋ณด์œ  ์‹œ๊ฐ„ = ํŠธ๋žœ์žญ์…˜ ์‹œ๊ฐ„)
          โ†’ ๋Œ€๊ธฐ ์š”์ฒญ์€ lock ๋Œ€๊ธฐ + ์ปค๋„ฅ์…˜ ์ ์œ ๋ฅผ ๋™์‹œ์— ์œ ์ง€

์ž„๊ณ„ ์กฐ๊ฑด์ด ๋‘˜์ด๊ณ  ์„œ๋กœ ๋‹ค๋ฅด๋‹ค.

ํ’€ ๊ณ ๊ฐˆ  : ๋™์‹œ ์š”์ฒญ > 10 โ†’ ํš๋“ ๋Œ€๊ธฐ 1,000 ms ์ดˆ๊ณผ โ†’ 503
lock ์ดˆ๊ณผ: ๋™์‹œ ์š”์ฒญ ร— ํŠธ๋žœ์žญ์…˜ ์‹œ๊ฐ„ > 3,000 ms โ†’ 503

4.5 ์ธก์ • ์„ค๊ณ„

hot-row.js๋กœ ๋™์ผ ํŒŸ์— ๋™์‹œ 5ยท20ยท50ยท100๊ฑด์„ 3๋ผ์šด๋“œ ๋ฐœํ–‰(lock_hold_ms=100). ๋Œ€์กฐ๊ตฐ์€ ๋ถ„์‚ฐ ํŒŸ(e-dist-c50), ์ „ํŒŒ ์ธก์ •์€ detail 50 RPS ๋ณ‘ํ–‰(e-mix-*), control์€ e0-rest-control.

4.6 ์ธก์ • ๊ฒฐ๊ณผ

๋™์ผ ํŒŸ ๋™์‹œ์„ฑ๋ณ„(ํด๋ผ์ด์–ธํŠธ ์ธก์ •):

๋™์‹œ์„ฑ p95 p99 ์‹คํŒจ์œจ Hikari ๋Œ€๊ธฐ ํš๋“ p95 ์ขŒ์„ lock p95 ์„œ๋ฒ„ 5xx/s
5 542 ms 546 ms 0% 0 2.3 ms 425 ms 0
20 1,961 ms 2,033 ms 4.76% 10 934 ms 971 ms 0.05
50 1,872 ms 2,106 ms 59.5% 32 1,061 ms 976 ms 1.14
100 1,627 ms 2,042 ms 79.9% 84 1,067 ms 1,046 ms 5.73
  • ๋™์‹œ 20๊ฑด์ด ๋ถ„๊ธฐ์ ์ด๋‹ค. ํ’€(10๊ฐœ)์„ ๋„˜๋Š” ์ˆœ๊ฐ„ ๋Œ€๊ธฐ๊ฐ€ ์ƒ๊ธฐ๊ณ  ํš๋“ p95๊ฐ€ 934 ms๋กœ ํƒ€์ž„์•„์›ƒ(1,000 ms) ์ง์ „๊นŒ์ง€ ์˜ฌ๋ผ๊ฐ„๋‹ค. ์˜ˆ์ธก๋Œ€๋กœ ๋™์‹œ์„ฑ > ํ’€ ํฌ๊ธฐ๊ฐ€ ์ฒซ ์ž„๊ณ„์˜€๋‹ค.
  • ๋™์‹œ 50๊ฑด ์ด์ƒ์—์„œ๋Š” ํš๋“ p95๊ฐ€ 1,060 ms๋กœ ํƒ€์ž„์•„์›ƒ์— ๋ถ™์–ด ์‹คํŒจ์œจ์ด 59.5%โ†’79.9%๋กœ ๋›ด๋‹ค. ์ฆ‰ ์‹คํŒจ์˜ ์ฃผ๋œ ์›์ธ์€ lock ์ž์ฒด๊ฐ€ ์•„๋‹ˆ๋ผ lock ๋Œ€๊ธฐ๊ฐ€ ์ปค๋„ฅ์…˜์„ ์žก๊ณ  ์žˆ์–ด ๋ฐœ์ƒํ•œ ํ’€ ๊ณ ๊ฐˆ์ด๋‹ค.
  • ๋ถ„์‚ฐ ํŒŸ ๋Œ€์กฐ๊ตฐ(e-dist-c50)์€ ์‹คํŒจ์œจ 43.1%๋กœ ๋™์ผ ํŒŸ(59.5%)๋ณด๋‹ค ๋‚ฎ์ง€๋งŒ 0%๊ฐ€ ์•„๋‹ˆ๋‹ค. ํ”ฝ์Šค์ฒ˜์˜ hot run์— ํŒŸ์ด 2๊ฐœ๋ฟ์ด์–ด์„œ ๋™์‹œ 50๊ฑด์ด 25๊ฑด์”ฉ ๋‘ ํ–‰์— ๋‚˜๋‰˜์—ˆ์„ ๋ฟ์ด๋‹ค. ๋Œ€์กฐ๊ตฐ์œผ๋กœ์„œ ์•ฝํ•˜๋‹ค(ยง8.3).

๋‹ค๋ฅธ API๋กœ์˜ ์ „ํŒŒ(detail 50 RPS):

๊ตฌ๊ฐ„ p95 p99 ์‹คํŒจ์œจ
control e0-rest-control (hot-row ์—†์Œ) 10.7 ms 17.5 ms 0%
treatment e-mix-rest (๋™์‹œ 50๊ฑด ๋ณ‘ํ–‰) 26.4 ms 844.5 ms 0.38%
๋ณ€ํ™” 2.5๋ฐฐ 48๋ฐฐ โ€”

์ผ๋ฐ˜ ์กฐํšŒ์˜ p95๋Š” 2.5๋ฐฐ์ง€๋งŒ p99๊ฐ€ 48๋ฐฐ๋‹ค. ์ขŒ์„ ๊ฒฝํ•ฉ์ด ๊ณต์šฉ ํ’€์„ ํ†ตํ•ด ์กฐํšŒ API์˜ ๊ผฌ๋ฆฌ ์ง€์—ฐ์„ ๋งŒ๋“ ๋‹ค๋Š” ์œ„ํ‚ค์˜ ์žฅ์•  ํ๋ฆ„ ๊ฐ€์„ค์ด ์ˆ˜์น˜๋กœ ํ™•์ธ๋๋‹ค.

4.7 ํŒ์ •๊ณผ ์ธํ”„๋ผ ๊ตฌ์„ฑ ๋ณ€๊ฒฝ

  • ์œ„ํ‚ค์˜ ๊ฐ€์ • ๋‹จ์œ„๋ฅผ ๋ฐ”๊ฟ”์•ผ ํ•œ๋‹ค. "์ธ๊ธฐ ํŒŸ ์ž ๊ธˆ 1.05 RPS"๋Š” ํŠธ๋žœ์žญ์…˜ ์‹œ๊ฐ„ 0.5์ดˆ๋ฅผ ์ ์šฉํ•˜๋ฉด ํ‰๊ท  ๋™์‹œ์„ฑ 0.5๋กœ, V1์ด ํ†ต๊ณผํ•œ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์‹ค์ œ ์œ„ํ—˜์€ ํ‰๊ท ์ด ์•„๋‹ˆ๋ผ ์ขŒ์„ ๊ณต๊ฐœยท๋งˆ๊ฐ ์ˆœ๊ฐ„์˜ ๋™์‹œ ๋„์ฐฉ ์ˆ˜๋‹ค. ์œ„ํ‚ค (2)์˜ ํŠธ๋ž˜ํ”ฝ ๊ฐ€์ •์„ ๋™์‹œ ์Šน์ธ ์š”์ฒญ ์ˆ˜ ๊ธฐ์ค€์œผ๋กœ ์žฌ์‚ฐ์ •ํ•  ๊ฒƒ์„ ์ œ์•ˆํ•œ๋‹ค.
  • ๋ณ€๊ฒฝ์•ˆ ์šฐ์„ ์ˆœ์œ„
    1. ์ขŒ์„ ์ฐจ๊ฐ์„ DB row lock ๋ฐ–์œผ๋กœ ์˜ฎ๊ธด๋‹ค โ€” Redis ์›์ž ์นด์šดํ„ฐ + ๋ฉฑ๋“ฑํ‚ค. lock ๋ณด์œ  ์‹œ๊ฐ„์ด ์‚ฌ๋ผ์ง€๋ฉด ํ’€ ์ ์œ ๋„ ์‚ฌ๋ผ์ง„๋‹ค.
    2. ์“ฐ๊ธฐ ๊ฒฝ๋กœ์˜ ํ’€์„ ์กฐํšŒ์™€ ๋ถ„๋ฆฌํ•œ๋‹ค. ์Šน์ธ API๊ฐ€ ํ’€ ์ „์ฒด๋ฅผ ์ž ์‹ํ•˜์ง€ ๋ชปํ•˜๊ฒŒ ํ•œ๋‹ค.
    3. ํ’€ ํฌ๊ธฐ ์ฆ์„ค์€ ํ›„์ˆœ์œ„๋‹ค. 10โ†’20์€ ์ž„๊ณ„๋ฅผ ๋™์‹œ 20โ†’40์œผ๋กœ ๋ฏธ๋ฃฐ ๋ฟ, MySQL ๋™์‹œ ์‹คํ–‰๋งŒ ๋Š˜๋ฆฐ๋‹ค.
  • ์ •ํ•ฉ์„ฑ์€ ์ด๋ฒˆ ์ธก์ •์—์„œ ์œ„๋ฐ˜์ด ํ™•์ธ๋˜์ง€ ์•Š์•˜๋‹ค(์Œ์ˆ˜ ์ขŒ์„ยท์ •์› ์ดˆ๊ณผ 0๊ฑด). ๋‹จ ์Šคํ‚ค๋งˆ์˜ CHECK (remaining >= 0)๊ฐ€ ์œ„๋ฐ˜์„ 503์œผ๋กœ ๋ฐ”๊ฟ” ๋“œ๋Ÿฌ๋‚ด๋ฏ€๋กœ, 503 ์ค‘ CHECK ์œ„๋ฐ˜๋ถ„์„ ๋ถ„๋ฆฌํ•˜๋Š” ๋กœ๊ทธ ํ™•์ธ์ด ๋‚จ์•„ ์žˆ๋‹ค.

5. ์‹œ๋‚˜๋ฆฌ์˜ค (3) โ€” ํ–‰์‚ฌ ์ข…๋ฃŒ: WebSocket ์ง‘์ค‘๊ณผ ๊ณต์œ  ์ž์› ๊ณ ๊ฐˆ

5.1 ๋™์‹œ ์—ฐ๊ฒฐ ์ˆ˜ โ€” ๋ชฉํ‘œ 3,000๊ฐœ์— ๋„๋‹ฌํ•˜์ง€ ๋ชปํ–ˆ๋‹ค

โ‘  ์„œ๋น„์Šค ๋™์ž‘ ํ–‰์‚ฌ ์ข…๋ฃŒ ํ›„ ์œ ์ž…๋œ ์‚ฌ์šฉ์ž๊ฐ€ ์ฑ„ํŒ…๋ฐฉ์— ์ž…์žฅํ•ด ๋งค์นญ ์„ฑ์‚ฌ๊นŒ์ง€ ์—ฐ๊ฒฐ์„ ์œ ์ง€ํ•œ๋‹ค.

โ‘ก ์˜ˆ์ƒ ํŠธ๋ž˜ํ”ฝ ์œ„ํ‚ค (3)์˜ ๋ชฉํ‘œ๋Š” ๋™์‹œ ์—ฐ๊ฒฐ 3,000๊ฐœ ์ด์ƒ์ด๋‹ค.

โ‘ข ๋ถ€ํ•˜ ํŠน์„ฑ ์žฅ์‹œ๊ฐ„ ์œ ์ง€๋˜๋Š” ์ƒํƒœ ๋ณด์œ ํ˜• ๋ถ€ํ•˜. ๋ฉ”์‹œ์ง€๊ฐ€ ์—†์–ด๋„ ์†Œ์ผ“ยทFDยท ์„ธ์…˜ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ์ ์œ ํ•œ๋‹ค.

โ‘ฃ ์ ์œ  ์ž์› Nginx(์—ฐ๊ฒฐ๋‹น client+upstream 2 FD, 0.25 CPU, 128 MB) โ†’ Spring (heap ์„ธ์…˜ ๊ฐ์ฒด, direct buffer, Tomcat ์ปค๋„ฅ์…˜ ์Šฌ๋กฏ 8192, nofile 16384).

โ‘ค ์ธก์ • ์„ค๊ณ„ ws-connect.js๋กœ 0โ†’3,000์„ 12.5๋ถ„์— ์„ ํ˜• ์ฆ๊ฐ€(4 conn/s). ๋žจํ”„ ์ž์ฒด๋ฅผ ๋…๋ฆฝ๋ณ€์ˆ˜๋กœ ์จ์„œ ์—ฐ๊ฒฐ ์ˆ˜ ๋Œ€๋น„ ์ž์›์„ ํšŒ๊ท€ํ–ˆ๋‹ค. REST ๋ถ€ํ•˜๋Š” ์—†๋‹ค.

โ‘ฅ ์ธก์ • ๊ฒฐ๊ณผ

ํ•ญ๋ชฉ ์‹ค์ธก
๋ชฉํ‘œ ๋™์‹œ ์—ฐ๊ฒฐ 3,000
์‹ค์ œ ์ตœ๋Œ€ ๋™์‹œ ์—ฐ๊ฒฐ (lab_ws_connections) 1,734
handshake p95 30,001 ms (30์ดˆ ํƒ€์ž„์•„์›ƒ)
WS ์˜ค๋ฅ˜์œจ 57.3%
์—ฐ๊ฒฐ๋‹น heap / CPU 28.2 KB / 1,000๊ฐœ๋‹น 0.0092 cores
๊ทธ๋•Œ heap ์ตœ๋Œ€ / working set 301 MB / 604 MB (limit 768 MB)

๊ฐ™์€ ์ƒํ•œ์ด ๋‹ค๋ฅธ ๋ธ”๋ก์—์„œ๋„ ๋ฐ˜๋ณต๋๋‹ค. ๋ชฉํ‘œ 1,800 ์—ฐ๊ฒฐ์„ ์ง€์‹œํ•œ ๋„ค ๋ธ”๋ก์˜ ์‹ค์ธก ์ตœ๋Œ€๋Š” c3 1,708 / c4 1,633 / d1 1,628 / g 1,692๊ฐœ๋‹ค. ๋ฐ˜๋ฉด 1,000 ์—ฐ๊ฒฐ์„ ์ง€์‹œํ•œ b-rate* ์„ธ ๋ธ”๋ก์€ ์˜ค๋ฅ˜ 0%๋กœ 1,000๊ฐœ๋ฅผ ๋ชจ๋‘ ์ˆ˜๋ฆฝํ–ˆ๋‹ค. ๋”ฐ๋ผ์„œ ์ƒํ•œ์€ 1,000๊ณผ 1,800 ์‚ฌ์ด์— ์žˆ๋‹ค.

์›์ธ์€ ๋‹จ์ •ํ•  ์ˆ˜ ์—†๋‹ค. ยง2.1๋Œ€๋กœ heap(11,800๊ฐœ ์—ฌ์œ )๋„ CPU(3.7% ์‚ฌ์šฉ)๋„ ์„ค๋ช…ํ•˜์ง€ ๋ชปํ•œ๋‹ค. ํ›„๋ณด๋Š” Nginx 128 MB ๋ฉ”๋ชจ๋ฆฌ ํ•œ๋„ ์•ˆ์˜ ์—ฐ๊ฒฐ๋ณ„ ํ”„๋ก์‹œ ๋ฒ„ํผ, Nginx ๋‹จ์ผ worker์˜ ์—ฐ๊ฒฐ ์ฒ˜๋ฆฌ, ๋กœ์ปฌ ๋ฐœ์ƒ๊ธฐยทDocker VM์˜ ์†Œ์ผ“ ํ•œ๋„๋‹ค. ์ด๋ฒˆ ์ธก์ •์˜ ์ปจํ…Œ์ด๋„ˆ๋ณ„ CPU ์ง‘๊ณ„์— ์˜ค๋ฅ˜๊ฐ€ ์žˆ์–ด(ยง8.2) Nginx๋ฅผ ๊ทผ๊ฑฐ๋กœ ์ง€๋ชฉํ•  ์ˆ˜ ์—†๋‹ค.

โ‘ฆ ํŒ์ •๊ณผ ๋ณ€๊ฒฝ

  • ํ–‰์‚ฌ ์‹œ๋‚˜๋ฆฌ์˜ค์˜ ํ•ต์‹ฌ ์š”๊ตฌ(๋™์‹œ 3,000)๋ฅผ V1์€ ์ถฉ์กฑํ•˜์ง€ ๋ชปํ•œ๋‹ค. ๋‹ฌ์„ฑ๋ฅ  57%์ด๋ฉฐ, ์ดˆ๊ณผ๋ถ„์€ ๊ฑฐ๋ถ€๊ฐ€ ์•„๋‹ˆ๋ผ 30์ดˆ ๋Œ€๊ธฐ ํ›„ ์‹คํŒจ๋กœ ๋‚˜ํƒ€๋‚˜ ์‚ฌ์šฉ์ž์—๊ฒŒ๋Š” "์ฑ„ํŒ…๋ฐฉ์ด ์—ด๋ฆฌ์ง€ ์•Š๋Š” ์ƒํƒœ"๋กœ ๋ณด์ธ๋‹ค.
  • ์›์ธ ๊ทœ๋ช… ์ „์—๋Š” ์ธ์Šคํ„ด์Šค ์ƒํ–ฅ๊ณผ WS ๋ถ„๋ฆฌ ์ค‘ ์–ด๋А ๊ฒƒ์ด ํ•ด๋ฒ•์ธ์ง€ ํ™•์ •ํ•  ์ˆ˜ ์—†๋‹ค. ๋‹ค์Œ ์ฐฝ์˜ 1์ˆœ์œ„ ์ž‘์—…์„ ยง8.4์— ์ ์—ˆ๋‹ค.
  • ์—ฐ๊ฒฐ๋‹น ๋‹จ๊ฐ€(28.2 KB, 0.0092 cores/1k)๋Š” ํ™•๋ณดํ–ˆ์œผ๋ฏ€๋กœ, WS ์ „์šฉ ํ”„๋กœ์„ธ์Šค๋ฅผ ๋ถ„๋ฆฌํ•  ๋•Œ์˜ ๋ฉ”๋ชจ๋ฆฌยทCPU ์‚ฐ์ •์€ ์ด ๊ฐ’์œผ๋กœ ๊ฐ€๋Šฅํ•˜๋‹ค.

5.2 ์—ฐ๊ฒฐ ์‹œ๋„์œจ โ€” ๋ชฉํ‘œ 10 conn/s๋Š” ์—ฌ์œ , 200 conn/s์—์„œ ๋ถ•๊ดด

โ‘ก ์œ„ํ‚ค (3)์˜ ์‹ ๊ทœ ์—ฐ๊ฒฐ๋ฅ ์€ ํ‰๊ท  5 conn/s, ํ”ผํฌ 10 conn/s๋‹ค.

โ‘ข ์งง๊ณ  ๋น„์‹ผ ์ˆœ๊ฐ„ ๋ถ€ํ•˜. ์—ฐ๊ฒฐ ์ˆ˜๋ฆฝ๋งˆ๋‹ค TLS handshake๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค.

โ‘ฃ Nginx 0.25 CPU ยท worker_processes 1 ยท accept queue ยท listen backlog.

โ‘ค ์—ฐ๊ฒฐ 1,000๊ฐœ ๊ณ ์ •, CONNECT_RATE 20 / 100 / 200 conn/s. ์ธก์ •์ฐฝ์€ ramp ๊ตฌ๊ฐ„.

โ‘ฅ

์—ฐ๊ฒฐ ์‹œ๋„์œจ handshake p95 WS ์˜ค๋ฅ˜์œจ ๋‹ฌ์„ฑ ์—ฐ๊ฒฐ
20 conn/s 33.5 ms 0% 1,000
100 conn/s 156.6 ms 0% 1,000
200 conn/s 3,568.8 ms 0% 1,000

์‹œ๋„์œจ์ด 10๋ฐฐ(20โ†’200)๊ฐ€ ๋˜๋ฉด handshake ์ง€์—ฐ์€ 107๋ฐฐ๊ฐ€ ๋œ๋‹ค. ์„ ํ˜•์ด ์•„๋‹ˆ๋‹ค. ๋‹ค๋งŒ ์˜ค๋ฅ˜๋Š” 0%์ด๋ฏ€๋กœ ์ด ๊ตฌ๊ฐ„์€ "์‹คํŒจ"๊ฐ€ ์•„๋‹ˆ๋ผ "๋Œ€๊ธฐ"๋‹ค.

โ‘ฆ ๋ชฉํ‘œ 10 conn/s๋Š” ๋ชฉํ‘œ์˜ 2๋ฐฐ์ธ 20 conn/s์—์„œ๋„ 33.5 ms์ด๋ฏ€๋กœ ๋ฌธ์ œ๊ฐ€ ์•„๋‹ˆ๋‹ค. ๋‹จ 3,000๋ช…์ด ๋” ๋น ๋ฅด๊ฒŒ ์œ ์ž…๋˜๋Š” ์‹œ๋‚˜๋ฆฌ์˜ค(์˜ˆ: 100 conn/s ์ด์ƒ)๋ฅผ ๊ฐ€์ •ํ•˜๋ฉด ์ง„์ž… ๊ณ„์ธต์ด ๋จผ์ € ๋А๋ ค์ง„๋‹ค. ๋ณ€๊ฒฝ์ด ํ•„์š”ํ•ด์ง€๋ฉด Spring์ด ์•„๋‹ˆ๋ผ Nginx CPUยทworker ์žฌ๋ฐฐ๋ถ„ ๋˜๋Š” TLS ์ข…๋ฃŒ ์œ„์น˜ ๋ณ€๊ฒฝ์ด ๋จผ์ €๋‹ค.

5.3 ๋ฉ”์‹œ์ง€ ์œ ํ˜• โ€” ๊ฑด์ˆ˜๊ฐ€ ๋ฐ”์ดํŠธ๋ณด๋‹ค 3๋ฐฐ ์ด์ƒ ๋น„์‹ธ๋‹ค

โ‘ โ‘ก ์ฑ„ํŒ… ๋ฉ”์‹œ์ง€. ๊ธด ์•ˆ๋‚ดยท์ •์‚ฐ ๋‚ด์—ญ๊ณผ ์งง์€ ๋Œ€ํ™”๊ฐ€ ์„ž์ธ๋‹ค.

โ‘ข ๋‘ ์ถ•์ด ์„ž์ธ ๋ถ€ํ•˜. ๋ฉ”์‹œ์ง€ ๊ฑด์ˆ˜์™€ payload ๋ฐ”์ดํŠธ๊ฐ€ ๊ฐ๊ฐ ๋‹ค๋ฅธ ๋น„์šฉ์„ ๋งŒ๋“ ๋‹ค.

โ‘ฃ ๊ฑด์ˆ˜ โ†’ Tomcat ์Šค๋ ˆ๋“œยทํ”„๋ ˆ์ž„ ์ฒ˜๋ฆฌยท์—ญ์ง๋ ฌํ™” / ๋ฐ”์ดํŠธ โ†’ ๋ฒ„ํผยท์ง๋ ฌํ™”ยท ๋„คํŠธ์›Œํฌ / ์–‘์ชฝ ๋ชจ๋‘ heap allocation๊ณผ GC.

โ‘ค 2ร—2 ์š”์ธ ์„ค๊ณ„(์—ฐ๊ฒฐ 200ยท1,800 ร— payload 256 Bยท8,000 B), ์ €์žฅ ์—†๋Š” echo ๊ฒฝ๋กœ, ๋ชฉํ‘œ 120 msg/s ๊ณ ์ •.

โ‘ฅ ์—ฐ๊ฒฐ 200๊ฐœ ๋‘ ์…€์€ ๋ฉ”์‹œ์ง€ ๊ฑด์ˆ˜๊ฐ€ 16,684๊ฑด์œผ๋กœ ์ •ํ™•ํžˆ ๊ฐ™์•„ ๋ฐ”์ดํŠธ ๋น„์šฉ๋งŒ ๋ถ„๋ฆฌ๋œ๋‹ค.

์…€ ์—ฐ๊ฒฐ payload ๋ฉ”์‹œ์ง€ ์‹ค์ œ msg/s backend CPU
c1 200 256 B 16,684 97.5 0.0378
c2 200 8,000 B 16,684 94.8 0.0511
c3 1,708 256 B 10,628 44.9 0.0388
c4 1,633 8,000 B 9,928 42.4 0.0494
๋ฉ”์‹œ์ง€ 1๊ฑด ๊ธฐ๋ณธ ๋น„์šฉ = 0.0378 cores รท 97.5 msg/s โ‰ˆ 0.39 CPU-ms/๊ฑด
payload ๋ฐ”์ดํŠธ ๋น„์šฉ  = (0.0511 โˆ’ 0.0378) รท (7.56 KB ร— 94.8/s) โ‰ˆ 0.02 CPU-ms/KB
8,000 B ๋ฉ”์‹œ์ง€ 1๊ฑด   = 0.39 + 0.15 โ‰ˆ 0.54 CPU-ms  โ†’ ๊ฑด์ˆ˜ ๋น„์šฉ์ด 72%

์—ฐ๊ฒฐ 1,800 ์…€(c3)์€ ๋ฉ”์‹œ์ง€๊ฐ€ 44.9 msg/s๋กœ ์ ˆ๋ฐ˜์ธ๋ฐ CPU๋Š” c1๊ณผ ๊ฐ™๋‹ค. ์ฆ‰ ์—ฐ๊ฒฐ 1,508๊ฐœ ์ถ”๊ฐ€๊ฐ€ ๋ฉ”์‹œ์ง€ 52.6๊ฑด/s์™€ ๋งž๋จน๋Š” ๋น„์šฉ์ด๋‹ค.

์ฃผ์˜. c3ยทc4๋Š” ๋ชฉํ‘œ 120 msg/s์— ๋Œ€ํ•ด 42~45 msg/s๋งŒ ๋‹ฌ์„ฑํ–ˆ๋‹ค(๋ฐœ์ƒ๊ธฐ ํ•œ๊ณ„, ยง8.3). ๋”ฐ๋ผ์„œ ์—ฐ๊ฒฐ ์ถ•๊ณผ ๋ฉ”์‹œ์ง€ ์ถ•์ด ์™„์ „ํžˆ ๋ถ„๋ฆฌ๋˜์ง€ ์•Š์•˜๊ณ , ์œ„ ํšŒ๊ท€๋Š” ์—ฐ๊ฒฐ 200๊ฐœ ์…€์˜ ๋น„๊ต๊ฐ€ 1์ฐจ ๊ทผ๊ฑฐ๋‹ค.

โ‘ฆ ๊ธด ์ปจํ…์ŠคํŠธ๋ณด๋‹ค ์งง์€ ๋ฉ”์‹œ์ง€๊ฐ€ ๋งŽ์€ ์ชฝ์ด ๋” ์œ„ํ—˜ํ•˜๋‹ค. ๋ณ€๊ฒฝ ์šฐ์„ ์ˆœ์œ„๋Š” payload ์••์ถ•ยท์ƒํ•œ์ด ์•„๋‹ˆ๋ผ ๊ฑด๋‹น ์ฒ˜๋ฆฌ ๋น„์šฉ ์ ˆ๊ฐ(ACK ๊ฒฝ๋Ÿ‰ํ™”, ๋ฉ”์‹œ์ง€ ๋ฐฐ์นญ, ์ €์žฅ ๋น„๋™๊ธฐํ™”)์ด๋‹ค. payload ์ƒํ•œ์€ 8 KB ์ˆ˜์ค€์—์„œ๋Š” ๋ถ€์ฐจ์ ์ด๋‹ค.

5.4 ๋ฉ”์‹œ์ง€ ์ €์žฅ โ€” ๊ณต์šฉ ํ’€์„ ํฌํ™”์‹œ์ผœ ์ผ๋ฐ˜ ์กฐํšŒ๋ฅผ ๋ฌด๋„ˆ๋œจ๋ฆฐ๋‹ค

โ‘  ๋ฉ”์‹œ์ง€๋ฅผ ์ €์žฅํ•œ ๋’ค ์ „๋‹ฌํ•œ๋‹ค(ํ˜„์žฌ ๊ตฌ์กฐ๋Š” ์ปค๋ฐ‹ ํ›„ ACK).

โ‘ก ์œ„ํ‚ค (3)์˜ "์ฑ„ํŒ… ๋ฉ”์‹œ์ง€ ์ฆ๊ฐ€ โ†’ DB ์ปค๋„ฅ์…˜ ๋Œ€๊ธฐ โ†’ ์ฐธ์—ฌ API ์ง€์—ฐ" ๊ฐ€์„ค.

โ‘ข ์‘๋‹ต ๊ฒฝ๋กœ๊ฐ€ DB ํŠธ๋žœ์žญ์…˜์— ๋ฌถ์ธ ๋ถ€ํ•˜. ์ปค๋„ฅ์…˜ ์ ์œ ์‹œ๊ฐ„์ด ์ฒ˜๋ฆฌ๋Ÿ‰ ์ƒํ•œ์„ ๋งŒ๋“ ๋‹ค.

โ‘ฃ HikariCP 10๊ฐœ(ํš๋“ ํƒ€์ž„์•„์›ƒ 1์ดˆ)๋ฅผ ์กฐํšŒยท์Šน์ธยทํ˜ผ์žก๋„ ์ €์žฅ๊ณผ ๊ณต์œ ํ•œ๋‹ค.

โ‘ค ์ €์žฅ ์—†์Œ(c3, ยง5.3) โ†’ ์ €์žฅ๋งŒ(d1-save-h50) โ†’ ์ €์žฅ + detail 50 RPS (d2-*), control์€ d0-rest-control. ํŠธ๋žœ์žญ์…˜ ์ ์œ ์‹œ๊ฐ„์€ chat_hold_ms=50.

โ‘ฅ

ํ•ญ๋ชฉ c3 ์ €์žฅ ์—†์Œ d1 ์ €์žฅ๋งŒ d2 ์ €์žฅ + ์กฐํšŒ
์‹ค์ œ msg/s 44.9 47.4 37.6
์ปค๋ฐ‹ p95 โ€” 494 ms 109~466 ms
Hikari active (์ตœ๋Œ€ 10) 0 10 / 10 7
Hikari ๋Œ€๊ธฐ 0 53 0
ํš๋“ p95 0.97 ms 445 ms 47~214 ms
์ฑ„ํŒ… ์ €์žฅ ์˜ค๋ฅ˜/s 0 1.02 3.03
backend CPU 0.0388 0.0896 0.0734

๊ฐ™์€ ์‹œ๊ฐ„๋Œ€ ์ผ๋ฐ˜ ์กฐํšŒ(detail 50 RPS, ํด๋ผ์ด์–ธํŠธ ์ธก์ •):

๊ตฌ๊ฐ„ p95 p99 ์‹คํŒจ์œจ
control d0-rest-control 12.1 ms 28.5 ms 0%
treatment d2-rest-treatment 164.8 ms 663.6 ms 1.53%
๋ณ€ํ™” 13.6๋ฐฐ 23๋ฐฐ โ€”

โ‘ฆ ํŒ์ •๊ณผ ๋ณ€๊ฒฝ

์ฆ๊ฑฐ ๊ฒฐ๋ก 
์ €์žฅ๋งŒ์œผ๋กœ ํ’€ active 10/10, ๋Œ€๊ธฐ 53, ํš๋“ p95 445 ms ์ปค๋„ฅ์…˜ ์ ์œ ์‹œ๊ฐ„์ด ๋ณ‘๋ชฉ โ†’ ์ €์žฅ ๋น„๋™๊ธฐํ™”(ํ + ๋ฐฐ์น˜ insert)
MySQL CPU 0.072 cores(๋ฐฐ์ • 0.5์˜ 14%)๋กœ ์—ฌ์œ  DB ์ฒ˜๋ฆฌ ๋Šฅ๋ ฅ์ด ์•„๋‹ˆ๋ผ ํ’€์ด ํ•œ๊ณ„ โ†’ ํ’€ ์ฆ์„ค๋ณด๋‹ค ์ ์œ ์‹œ๊ฐ„ ๋‹จ์ถ•
๋ณ‘ํ–‰ ์กฐํšŒ p95 13.6๋ฐฐยท์‹คํŒจ 1.53% ๊ณต์šฉ ํ’€์ด ์žฅ์•  ์ „ํŒŒ ๊ฒฝ๋กœ โ†’ ์ฝ๊ธฐยท์“ฐ๊ธฐ ํ’€ ๋ถ„๋ฆฌ
์ €์žฅ ์—†์Œ(c3)์—์„œ๋Š” ํ’€ ์ง€ํ‘œ ์ „๋ถ€ 0 ์‹ค์‹œ๊ฐ„ ๊ฒฝ๋กœ์™€ ์˜์† ๊ฒฝ๋กœ ๋ถ„๋ฆฌ๊ฐ€ V2 ํ•„์ˆ˜ ํ•ญ๋ชฉ

47 msg/s๊ฐ€ ํ’€์„ ํฌํ™”์‹œ์ผฐ๋‹ค๋Š” ๊ฒƒ์€ ํ˜ผ์žก๋„ ์“ฐ๊ธฐ 37.6 row/s(ยง3)๋„ ๊ฐ™์€ ์ž„๊ณ„ ๊ตฌ๊ฐ„์ž„์„ ๋œปํ•œ๋‹ค. ๋‘ ์“ฐ๊ธฐ๊ฐ€ ๋™์‹œ์— ์กด์žฌํ•˜๋Š” V2์—์„œ๋Š” ์ด ํ•ญ๋ชฉ์ด ์กฐํšŒ ์ง€์—ฐ์˜ ์‹ค์ œ ์›์ธ์ด ๋œ๋‹ค.

5.5 WebSocket ์—ฐ๊ฒฐ์ด REST API์— ์ฃผ๋Š” ๊ฐ„์„ญ

โ‘ค control(f1c-rest-control, WS 0) โ†’ WS 2,100 ์œ ์ง€ ์ƒํƒœ์—์„œ ๋™์ผ REST ๋ฐ˜๋ณต(f1c-rest-treatment). ๋‘ ์‹คํ–‰์„ ์—ฐ์† ๋ฐฐ์น˜ํ•ด ์กฐ๊ฑด์„ ๋งž์ท„๋‹ค.

โ‘ฅ

ํ•ญ๋ชฉ control treatment (WS 1,642๊ฐœ ์œ ์ง€) ๋ณ€ํ™”
REST p95 11.0 ms 167.2 ms 15๋ฐฐ
REST p99 33.4 ms 914.8 ms 27๋ฐฐ
REST ์‹คํŒจ์œจ 0% 4.54% โ€”
dropped iterations 0 24 โ€”
backend CPU 0.032 0.061 1.9๋ฐฐ
heap ์ตœ๋Œ€ 123 MB 277 MB 2.3๋ฐฐ
GC pause p95 3.1 ms 257 ms 82๋ฐฐ
working set 601 MB 632 MB (limit 768) +5%
Hikari ๋Œ€๊ธฐ 0 0 ๋ณ€ํ™” ์—†์Œ
MySQL CPU 0.017 0.018 ๋ณ€ํ™” ์—†์Œ
Next.js CPU ๋ณ€ํ™” ์—†์Œ ๋ณ€ํ™” ์—†์Œ โ€”

โ‘ฆ ํŒ์ •

  • REST p95๊ฐ€ control ๋Œ€๋น„ 15๋ฐฐ, p99 27๋ฐฐ ์•…ํ™”๋˜๊ณ  ์˜ค๋ฅ˜๊ฐ€ 4.54% ๋ฐœ์ƒํ–ˆ๋‹ค. 403์˜ ํŒ์ • ๊ธฐ์ค€(20% ์•…ํ™”)์„ ํฌ๊ฒŒ ๋„˜๋Š”๋‹ค.
  • ์•…ํ™”์˜ ๋™๋ฐ˜ ์ง€ํ‘œ๋Š” **GC pause(3.1 โ†’ 257 ms)์™€ heap(123 โ†’ 277 MB)**์ด๋‹ค. Hikari์™€ MySQL์€ ๋ณ€ํ™”๊ฐ€ ์—†์œผ๋ฏ€๋กœ ์›์ธ์€ DB๊ฐ€ ์•„๋‹ˆ๋ผ ๊ฐ™์€ JVM์˜ ๋ฉ”๋ชจ๋ฆฌยทGC๋‹ค.
  • Next.jsยทMySQL ์ปจํ…Œ์ด๋„ˆ๋Š” ์˜ํ–ฅ์ด ์—†์—ˆ๋‹ค. ์ฆ‰ ํ˜ธ์ŠคํŠธ ์ž์› ๊ฒฝํ•ฉ์ด ์•„๋‹ˆ๋ผ Spring ์ปจํ…Œ์ด๋„ˆ ๋‚ด๋ถ€์˜ ๊ณต์œ  ์ž์› ๊ฒฝํ•ฉ์ด๋‹ค. ์ปจํ…Œ์ด๋„ˆ quota ๊ฒฉ๋ฆฌ๋Š” ์ž‘๋™ํ–ˆ๋‹ค.
  • ๊ฒฐ๋ก : REST์™€ WebSocket์˜ ํ”„๋กœ์„ธ์Šค ๋ถ„๋ฆฌ๊ฐ€ V2 ์„ค๊ณ„์˜ 1์ˆœ์œ„๋‹ค. ๊ฐ™์€ JVM์— ๋‘๋Š” ํ•œ, ์ฑ„ํŒ… ์—ฐ๊ฒฐ์ด ๋Š˜ ๋•Œ๋งˆ๋‹ค ์ผ๋ฐ˜ API์˜ ๊ผฌ๋ฆฌ ์ง€์—ฐ๊ณผ ์˜ค๋ฅ˜์œจ์ด ํ•จ๊ป˜ ์˜ฌ๋ผ๊ฐ„๋‹ค.

6. V1 ํ•œ๊ณ„ ์ข…ํ•ฉ

6.1 ์žฅ์•  ์ „ํŒŒ ์ง€๋„ (์‹ค์ธก๊ฐ’ ๋ถ€์ฐฉ)

[ํ–‰์‚ฌ ์œ ์ž…]                          [์ธ๊ธฐ ํŒŸ ๋งˆ๊ฐ]              [์กฐํšŒ ์ฆ๊ฐ€]
 WS ์—ฐ๊ฒฐ 1,700๊ฐœ์—์„œ ํฌํ™”             ๋™์‹œ ์Šน์ธ 20๊ฑด ์ดˆ๊ณผ          641 RPS๊นŒ์ง€ ์—ฌ์œ 
   โ”‚ handshake 30์ดˆ ํƒ€์ž„์•„์›ƒ            โ”‚ ํ’€ 10๊ฐœ ๊ณ ๊ฐˆ              โ”‚ throttling 0
   โ”‚ (๋ชฉํ‘œ 3,000์˜ 57%)                 โ”‚ ํš๋“ p95 1,060ms          โ”‚
   โ†“                                    โ†“                           โ†“
 ๊ฐ™์€ JVM heapยทGC ์••๋ฐ•                ๊ณต์šฉ HikariCP 10             (๋ณ‘๋ชฉ ์•„๋‹˜)
 GC pause 3.1 โ†’ 257ms                  โ”‚
   โ”‚                                    โ”œโ”€ ์ขŒ์„ ์Šน์ธ ์‹คํŒจ 59.5%
   โ†“                                    โ”œโ”€ ์ผ๋ฐ˜ ์กฐํšŒ p99 48๋ฐฐ
 ์ผ๋ฐ˜ REST p99 27๋ฐฐ ยท ์˜ค๋ฅ˜ 4.5%         โ””โ”€ ์ฑ„ํŒ… ์ €์žฅ ์˜ค๋ฅ˜ 1~3/s
                                            โ”‚
 [์ฑ„ํŒ… ๋ฉ”์‹œ์ง€ ์ €์žฅ 47 msg/s] โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
   ํ’€ active 10/10 ยท ๋Œ€๊ธฐ 53 โ†’ ์ผ๋ฐ˜ ์กฐํšŒ p95 13.6๋ฐฐ ยท ์‹คํŒจ 1.53%

์„ธ ์‹œ๋‚˜๋ฆฌ์˜ค๊ฐ€ ์„œ๋กœ ๋‹ค๋ฅธ ์ž…๊ตฌ๋กœ ๋“ค์–ด์™€ ๊ฐ™์€ ๋‘ ์ž์›(Spring JVM, Hikari ํ’€ 10๊ฐœ) ์—์„œ ๋งŒ๋‚œ๋‹ค. ์ด๊ฒƒ์ด V1 ๊ตฌ์กฐ์˜ ํ•ต์‹ฌ ํ•œ๊ณ„๋‹ค.

6.2 V1์ด ๊ฐ๋‹น ๊ฐ€๋Šฅํ•œ ๊ทœ๋ชจ

์ถ• V1 ์‹ค์ธก ํ•œ๊ณ„ V2 ์š”๊ตฌ ์ถฉ์กฑ
์กฐํšŒ RPS 641 RPS ์ด์ƒ (knee ๋ฏธ๋„๋‹ฌ) 60.4 RPS โœ… 10๋ฐฐ ์—ฌ์œ 
ํ–‰์‚ฌ API ํ”ผํฌ 641 RPS ์ด์ƒ 140 RPS โœ…
WS ์‹ ๊ทœ ์—ฐ๊ฒฐ๋ฅ  20 conn/s์—์„œ 33 ms 10 conn/s โœ…
WS ๋™์‹œ ์—ฐ๊ฒฐ ์•ฝ 1,700๊ฐœ 3,000๊ฐœ โŒ 57%
๋™์‹œ ์ขŒ์„ ์Šน์ธ 20๊ฑด ๋ฏธ๋งŒ ์žฌ์‚ฐ์ • ํ•„์š” โŒ
์ฑ„ํŒ… ์ €์žฅ ์ฒ˜๋ฆฌ๋Ÿ‰ 47 msg/s์—์„œ ํ’€ ํฌํ™” ๋ฏธ์‚ฐ์ • โŒ
ํ˜ผ์žก๋„ ์“ฐ๊ธฐ ๋ฏธ์ธก์ • (47 write/s ๊ฐ„์ ‘) 37.6 row/s โš 

7. V2 ์ธํ”„๋ผ ๊ตฌ์„ฑ ๋ณ€๊ฒฝ ๊ฒฐ์ •

์šฐ์„ ์ˆœ์œ„ ๋ณ€๊ฒฝ ๊ทผ๊ฑฐ (์ ˆยท์ง€ํ‘œ) ๊ธฐ๋Œ€ํšจ๊ณผ ์žฌ๊ฒ€์ฆ
1 REST์™€ WebSocket ํ”„๋กœ์„ธ์Šค ๋ถ„๋ฆฌ ยง5.5 REST p99 27๋ฐฐยท์˜ค๋ฅ˜ 4.54%, GC pause 82๋ฐฐ / ยง5.1 ์—ฐ๊ฒฐ ์ƒํ•œ 1,700 ์ฑ„ํŒ… ์—ฐ๊ฒฐ ์ฆ๊ฐ€๊ฐ€ ์ผ๋ฐ˜ API ์ง€์—ฐยท์˜ค๋ฅ˜๋กœ ๋ฒˆ์ง€์ง€ ์•Š์Œ ๋ถ„๋ฆฌ ํ›„ ยง5.5 control/treatment ์žฌ์‹คํ–‰, p95 ์•…ํ™” 20% ๋ฏธ๋งŒ ํ™•์ธ
2 ์ฑ„ํŒ… ์ €์žฅ ๋น„๋™๊ธฐํ™” (ํ + ๋ฐฐ์น˜ insert) ยง5.4 ํ’€ active 10/10ยท๋Œ€๊ธฐ 53ยทํš๋“ p95 445 ms, ๋ณ‘ํ–‰ ์กฐํšŒ p95 13.6๋ฐฐ WS ์‘๋‹ต ๊ฒฝ๋กœ์—์„œ DB ํŠธ๋žœ์žญ์…˜ ์ œ๊ฑฐ, ํ’€ ์ ์œ ์‹œ๊ฐ„ ๋‹จ์ถ• ๋™์ผ 47 msg/s์—์„œ ํ’€ ๋Œ€๊ธฐ 0ยท์กฐํšŒ p95 ๋ณ€ํ™” 20% ๋ฏธ๋งŒ
3 ์ฝ๊ธฐยท์“ฐ๊ธฐ ์ปค๋„ฅ์…˜ ํ’€ ๋ถ„๋ฆฌ ยง4.6 ๋™์‹œ 20๊ฑด์—์„œ ํ’€ ๊ณ ๊ฐˆ / ยง5.4 / ยง3.7 ํ˜ผ์žก๋„ ์“ฐ๊ธฐ ์“ฐ๊ธฐ ๊ฒฝํ•ฉ์ด ์กฐํšŒ API๋ฅผ ์ž ์‹ํ•˜์ง€ ๋ชปํ•˜๊ฒŒ ๊ฒฉ๋ฆฌ e-mixยทd2๋ฅผ ๋™์ผ ์กฐ๊ฑด์œผ๋กœ ์žฌ์‹คํ–‰
4 ์ขŒ์„ ์ฐจ๊ฐ์„ DB row lock ๋ฐ–์œผ๋กœ (Redis ์›์ž ์นด์šดํ„ฐ + ๋ฉฑ๋“ฑํ‚ค) ยง4.6 lock p95 1,046 ms, ์‹คํŒจ์œจ 59.5~79.9% lock ๋ณด์œ  ์‹œ๊ฐ„ ์ œ๊ฑฐ โ†’ ํ’€ ์ ์œ  ๋™๋ฐ˜ ์ œ๊ฑฐ ๋™์‹œ 50ยท100๊ฑด์—์„œ ์‹คํŒจ์œจ 0%ยท์ •ํ•ฉ์„ฑ ์œ ์ง€
5 ํ˜ผ์žก๋„ ์ตœ์‹ ๊ฐ’ ์บ์‹œ + ์ด๋ ฅ ๋น„๋™๊ธฐ ์ €์žฅ ยง3.7 (๊ฐ„์ ‘ ๊ทผ๊ฑฐ) ์กฐํšŒ๋‹น ์“ฐ๊ธฐ 2๊ฑด โ†’ ์บ์‹œ ๋ฏธ์Šค ์‹œ์—๋งŒ ํ˜ผ์žก๋„ endpoint ์ถ”๊ฐ€ ํ›„ K=1ยท5 ์ธก์ •
6 ์—ฐ๊ฒฐ ์ƒํ•œ 1,700 ์›์ธ ๊ทœ๋ช… ํ›„ ๊ฒฐ์ • (์ธ์Šคํ„ด์Šค ์ƒํ–ฅ / Nginx ์กฐ์ • / WS ๊ฒŒ์ดํŠธ์›จ์ด) ยง5.1 heapยทCPU๋กœ ์„ค๋ช… ๋ถˆ๊ฐ€ 3,000 ์—ฐ๊ฒฐ ๋ชฉํ‘œ ๋‹ฌ์„ฑ ยง8.4 ์ ˆ์ฐจ
โ€” ์กฐํšŒ ๋•Œ๋ฌธ์˜ scale-outยท์ธ์Šคํ„ด์Šค ์ƒํ–ฅ ยง3.6 641 RPS์—์„œ throttling 0 โ€” ๊ทผ๊ฑฐ ์—†์Œ, ๋ณด๋ฅ˜

์ ์šฉ ์ˆœ์„œ๋Š” ์œ„ ์ˆœ๋ฒˆ๋Œ€๋กœ ํ•œ ๋ฒˆ์— ํ•˜๋‚˜๋งŒ ์ ์šฉํ•˜๊ณ , ๊ฐ™์€ ์‹œ๋‚˜๋ฆฌ์˜คยท๊ฐ™์€ RUN_ID ๊ทœ์น™์œผ๋กœ ์žฌ์ธก์ •ํ•œ๋‹ค.


8. ์ธก์ •์˜ ์‹ ๋ขฐ ๋ฒ”์œ„

8.1 ํ”ฝ์Šค์ฒ˜์™€ ์‹ค์ œ ์„œ๋น„์Šค์˜ ์ฐจ์ด

์ธก์ • ๋Œ€์ƒ์€ perf/ws-lab/demo ํ•ฉ์„ฑ ํ”ฝ์Šค์ฒ˜๋‹ค. ์‹ค์ œ moyeota/be๊ฐ€ ์•„๋‹ˆ๋‹ค.

  • fan-out์ด ์—†๋‹ค. ํ•ธ๋“ค๋Ÿฌ๊ฐ€ ๋ฐœ์‹ ์ž์—๊ฒŒ๋งŒ ACK/echo๋ฅผ ๋ณด๋‚ธ๋‹ค. 4์ธ ํŒŸ์—์„œ 1๊ฑด์ด 3๋ช…์—๊ฒŒ ์ „๋‹ฌ๋˜๋Š” ๋น„์šฉ(ยง5.3์˜ 3๋ฐฐ)์€ ๋ฏธ์ธก์ •์ด๋‹ค.
  • ๋ฐฉ(room) ๊ฐœ๋…์ด ์—†์–ด "ํ•œ ๋ฐฉ ์ง‘์ค‘ โ†” ์—ฌ๋Ÿฌ ๋ฐฉ ๋ถ„์‚ฐ" ์ถ•์„ ์ธก์ •ํ•˜์ง€ ๋ชปํ–ˆ๋‹ค.
  • ์ธ์ฆยท๊ถŒํ•œ ๊ฒ€์ฆ์ด ์—†๋‹ค(ํ† ํฐ ๋ฏธ์‚ฌ์šฉ). ์‹ค์ œ ํ† ํฐ ๊ฒ€์ฆ CPU๋Š” ๋น ์ ธ ์žˆ๋‹ค.
  • ํ˜ผ์žก๋„ ์™ธ๋ถ€ API(FastAPIยทLLM) ํ˜ธ์ถœ ๊ฒฝ๋กœ๊ฐ€ ์—†๋‹ค.
  • chat_hold_ms=50, lock_hold_ms=100์€ Thread.sleep ํ•ฉ์„ฑ ์ง€์—ฐ์ด๋‹ค.
  • ์กฐํšŒ endpoint๊ฐ€ ์‹ค์ œ ์ฟผ๋ฆฌ๋ณด๋‹ค ๋‹จ์ˆœํ•˜๋‹ค. ยง2.2์™€ ยง3.6์˜ ์ ˆ๋Œ€ RPS๋Š” ์ƒํ•œ ๋ณด์ฆ๊ฐ’์ด ์•„๋‹ˆ๋‹ค.

8.2 ํ™•์ธ๋œ ๊ณ„์ธก ์˜ค๋ฅ˜ (๊ฒฐ๋ก ์— ์‚ฌ์šฉํ•˜์ง€ ์•Š์€ ๊ฐ’)

๊ฐ’ ๋ฌธ์ œ ๋Œ€์‘
derived-*.csv์˜ rest_p95_ms ๊ฑฐ์˜ ๋ชจ๋“  ๊ตฌ๊ฐ„์—์„œ 0.95 ms ๊ณ ์ • โ†’ ํžˆ์Šคํ† ๊ทธ๋žจ ๋ถ„์œ„ ์‚ฐ์ • ์˜ค๋ฅ˜ ์ง€์—ฐ์€ k6 ํด๋ผ์ด์–ธํŠธ ๊ฐ’๋งŒ ์‚ฌ์šฉ
nginx_cpu_cores ์ „ ๊ตฌ๊ฐ„ 0.0004 cores ๊ณ ์ • โ†’ ์‹œ๋ฆฌ์ฆˆ ๋งค์นญ ์˜ค๋ฅ˜ ์˜์‹ฌ ยง5.1์—์„œ Nginx๋ฅผ ์›์ธ์œผ๋กœ ์ง€๋ชฉํ•˜์ง€ ์•Š์Œ
chat_errorsยทseat_errors 15~20์ดˆ ์ฐฝ์—์„œ increase()๊ฐ€ 0 ๋ฐ˜ํ™˜ ์„œ๋ฒ„ 5xx rate๋กœ ๋Œ€์ฒด
WS ์˜ค๋ฅ˜์œจ 53~57% ์‹คํŒจ ํ›„ ์žฌ์ ‘์†์„ ๋ฐ˜๋ณตํ•ด ๋ถ„๋ชจ๊ฐ€ ์ปค์ง(ws_connections_opened 39,098) ๋™์‹œ ์—ฐ๊ฒฐ ์ตœ๋Œ€๊ฐ’(lab_ws_connections)์„ 1์ฐจ ๊ทผ๊ฑฐ๋กœ ์‚ฌ์šฉ

URI๋ณ„ ๋ถ„๋ฆฌ๊ฐ€ ํ•„์š”ํ•œ ๊ตฌ๊ฐ„์€ ๋‹ค์Œ ์ฟผ๋ฆฌ๋กœ ์žฌ์ง‘๊ณ„ํ•ด์•ผ ํ•œ๋‹ค.

histogram_quantile(0.95, sum by (le) (rate(http_server_requests_seconds_bucket{uri!~"/actuator.*"}[1m])))

8.3 ์ธก์ •์ฐฝ๊ณผ ๋Œ€์กฐ๊ตฐ์˜ ์•ฝ์ 

  • ๋ธ”๋ก๋‹น 75~150์ดˆ, ๋ฐ˜๋ณต 1ํšŒ. g-c3-repeat ๋Œ€๋น„ ๋ณ€๋™ 8%๋ฅผ ๊ด€์ธกํ–ˆ์œผ๋ฏ€๋กœ 30% ๋ฏธ๋งŒ ์ฐจ์ด๋Š” ํŒ์ •์— ์“ฐ์ง€ ์•Š์•˜๋‹ค.
  • 30๋ถ„ idle hold์™€ soak์ด ์—†์–ด ์—ฐ๊ฒฐ ๋ˆ„์ˆ˜ยท์™„๋งŒํ•œ heap ์ฆ๊ฐ€๋Š” ๋ฏธ๊ฒ€์ถœ์ด๋‹ค. working set์ด ์„ธ์…˜ ์ „๋ฐ˜์— 576 โ†’ 651 MB๋กœ ์ƒ์Šนํ–ˆ์œผ๋‚˜(limit 768 MB) ์›์ธ์„ ๋ˆ„์ˆ˜๋กœ ๋‹จ์ •ํ•  ์ˆ˜ ์—†๋‹ค.
  • c3ยทc4ยทd1ยทg๊ฐ€ ๋ชฉํ‘œ 120 msg/s์— ๋Œ€ํ•ด 42~47 msg/s๋งŒ ๋‹ฌ์„ฑํ–ˆ๋‹ค. ๋ฉ”์‹œ์ง€์œจ ์ถ•์ด ๊ณ ์ •๋˜์ง€ ์•Š์•˜๋‹ค.
  • ๋ถ„์‚ฐ ํŒŸ ๋Œ€์กฐ๊ตฐ(e-dist-c50)์€ ํŒŸ์ด 2๊ฐœ๋ฟ์ด์–ด์„œ ๋Œ€์กฐ๊ฐ€ ์•ฝํ•˜๋‹ค.
  • CPU credit ์ž”๋Ÿ‰์„ ๊ธฐ๋กํ•˜์ง€ ๋ชปํ–ˆ๋‹ค. ์„ธ์…˜ ํ›„๋ฐ˜ ๋ธ”๋ก(f, g)์ด credit ์˜ํ–ฅ์„ ๋ฐ›์•˜๋Š”์ง€ ํ™•์ธํ•  ์ˆ˜ ์—†๋‹ค.
  • ์„œ๋ฒ„ ์„ค์ • ์ถ•(ํ’€ 10โ†”20, WS_PER_CONNECTION_BYTES, -Xmx)์€ ์žฌ๋ฐฐํฌ๊ฐ€ ํ•„์š”ํ•ด ์ด ์ฐฝ์—์„œ ๋‹ค๋ฃจ์ง€ ์•Š์•˜๋‹ค.

8.4 ๋‹ค์Œ ์ธก์ • ์ฐฝ์˜ 1์ˆœ์œ„ โ€” ์—ฐ๊ฒฐ ์ƒํ•œ 1,700์˜ ์›์ธ ๊ทœ๋ช…

ยง5.1์˜ ๋ถˆ์ผ์น˜๋ฅผ ํ•ด์†Œํ•˜์ง€ ๋ชปํ•˜๋ฉด ยง7์˜ 6๋ฒˆ ๊ฒฐ์ •์„ ๋‚ด๋ฆด ์ˆ˜ ์—†๋‹ค. ์ˆœ์„œ๋Œ€๋กœ ์ˆ˜ํ–‰ํ•œ๋‹ค.

  1. ์—ฐ๊ฒฐ์„ 1,500 โ†’ 1,600 โ†’ 1,700 โ†’ 1,800์œผ๋กœ 100๊ฐœ ๋‹จ์œ„๋กœ ์˜ฌ๋ฆฌ๋ฉฐ Nginx ์ปจํ…Œ์ด๋„ˆ์˜ working set๊ณผ CPU๋ฅผ ํ•จ๊ป˜ ๋ณธ๋‹ค (128 MB ํ•œ๋„ ๊ฐ€์„ค ๊ฒ€์ฆ).
  2. ๊ฐ™์€ ๊ตฌ๊ฐ„์—์„œ Nginx error log์™€ node_netstat_TcpExt_ListenOverflows, ํ˜ธ์ŠคํŠธ ์†Œ์ผ“ ์ˆ˜ยทFD๋ฅผ ํ™•์ธํ•œ๋‹ค.
  3. Nginx๋ฅผ ์šฐํšŒํ•ด Spring์— ์ง์ ‘(๋‚ด๋ถ€ ๊ฒฝ๋กœ) ์—ฐ๊ฒฐ์„ ์˜ฌ๋ ค ๋™์ผ ์ƒํ•œ์ด ์žฌํ˜„๋˜๋Š”์ง€ ๋ณธ๋‹ค. ์žฌํ˜„๋˜๋ฉด Spring, ์žฌํ˜„๋˜์ง€ ์•Š์œผ๋ฉด Nginx๋‹ค.
  4. ๋กœ์ปฌ ๋ฐœ์ƒ๊ธฐ๋ฅผ 2๋Œ€๋กœ ๋‚˜๋ˆ  ๊ฐ™์€ ์ƒํ•œ์ด ๋‚˜์˜ค๋Š”์ง€ ํ™•์ธํ•œ๋‹ค(๋ฐœ์ƒ๊ธฐ ๋ฐฐ์ œ).
  5. ์›์ธ์ด Nginx ๋ฉ”๋ชจ๋ฆฌ๋ฉด proxy_buffering offยท๋ฒ„ํผ ์ถ•์†Œ ๋˜๋Š” Nginx ์ž์› ์ฆ์„ค๋กœ, Spring์ด๋ฉด WS ๊ฒŒ์ดํŠธ์›จ์ด ๋ถ„๋ฆฌ๋กœ ๊ฐ„๋‹ค.

8.5 ๊ทธ ์™ธ ๋‚จ์€ ํ•ญ๋ชฉ

  • fan-out ๋น„์šฉ(์ˆ˜์‹ ์ž 1ยท3ยท9๋ช…) โ€” ํ•ธ๋“ค๋Ÿฌ์— ๋ฐฉยท์„ธ์…˜ ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ ์ถ”๊ฐ€ ํ›„ ์ธก์ •
  • ํ˜ผ์žก๋„ API ๋ถ€ํ•˜ (K=1ยท5)
  • ํ–‰์‚ฌ burst ์‚ผ๊ฐํ˜• ๋ถ€ํ•˜ 140 RPS
  • ์žฅ์• ยท๋ณต๊ตฌ RTO/RPO
  • ํ’€ ํฌ๊ธฐ ๋Œ€์กฐ(10โ†”20)์™€ -Xmx ์กฐ์ • ์‹คํ—˜