402 V1 load test design v2 - 100-hours-a-week/KTB4-3rd-CLOUD GitHub Wiki

402 V1 ํ•œ๊ณ„ ์ง€์  ์ธก์ •์„ ์œ„ํ•œ ๋ถ€ํ•˜ํ…Œ์ŠคํŠธ ์„ค๊ณ„ V2

1. ๋ชฉ์ ๊ณผ ํŒ์ • ์›์น™

์ด ํ…Œ์ŠคํŠธ์˜ ๋ชฉ์ ์€ V1์ด ๋‹จ์ˆœํžˆ ๋ช‡ RPS๋ฅผ ์ฒ˜๋ฆฌํ•˜๋Š”์ง€ ํ™•์ธํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋‹ค. ์‚ฌ์šฉ์ž ์ฆ๊ฐ€ ์‹œ ์ตœ์ดˆ๋กœ ํฌํ™”๋˜๋Š” ์ž์›๊ณผ ์žฅ์•  ์ „ํŒŒ ๊ฒฝ๋กœ๋ฅผ ์ˆ˜์น˜๋กœ ํ™•์ธํ•˜๊ณ  ๋‹ค์Œ ํ™•์žฅ ๋ฐฉํ–ฅ์„ ๊ฒฐ์ •ํ•˜๋Š” ๊ฒƒ์ด๋‹ค.

  • ๋‹จ์ผ EC2์˜ ์ˆ˜์ง ํ™•์žฅ ๋˜๋Š” ์ปจํ…Œ์ด๋„ˆ ์ž์› ์žฌ๋ฐฐ๋ถ„์œผ๋กœ ์ถฉ๋ถ„ํ•œ๊ฐ€
  • MySQL์„ ๋ณ„๋„ ํ˜ธ์ŠคํŠธ๋‚˜ RDS๋กœ ๋ถ„๋ฆฌํ•ด์•ผ ํ•˜๋Š”๊ฐ€
  • REST์™€ WebSocket์„ ๋ถ„๋ฆฌํ•ด์•ผ ํ•˜๋Š”๊ฐ€
  • ํ˜ผ์žก๋„ ๊ณ„์‚ฐยท์™ธ๋ถ€ API ํ˜ธ์ถœ์„ ๋น„๋™๊ธฐํ™”ํ•˜๊ฑฐ๋‚˜ ๋ณ„๋„ ์„œ๋น„์Šค๋กœ ๊ฒฉ๋ฆฌํ•ด์•ผ ํ•˜๋Š”๊ฐ€
  • ๋ฌด์ค‘๋‹จ ๋ชฉํ‘œ ๋•Œ๋ฌธ์— ๋‹ค์ค‘ EC2์™€ ๋กœ๋“œ๋ฐธ๋Ÿฐ์„œ๊ฐ€ ํ•„์š”ํ•œ๊ฐ€

์„ฑ๋Šฅ ํ•œ๊ณ„๋Š” ๊ฐ€์žฅ ๋†’์€ ์ˆœ๊ฐ„ RPS๊ฐ€ ์•„๋‹ˆ๋ผ SLO๋ฅผ ์—ฐ์†์œผ๋กœ ๋งŒ์กฑํ•˜๋Š” ์ตœ๋Œ€ ์ง€์† ์ฒ˜๋ฆฌ๋Ÿ‰์œผ๋กœ ์ •์˜ํ•œ๋‹ค.

C_knee = SLO ๋˜๋Š” ์ •ํ•ฉ์„ฑ์ด ์ฒ˜์Œ ๊นจ์ง€๋Š” ์ง€์† ๋ถ€ํ•˜
C_safe = C_knee ร— 0.7
ํ•„์š” ์šฉ๋Ÿ‰ = ๊ณ„ํš ํ”ผํฌ ร— ๋ณ„๋„ ์šด์˜ ์—ฌ์œ ์œจ

์‘๋‹ต์‹œ๊ฐ„ยท์˜ค๋ฅ˜์œจยท์ •ํ•ฉ์„ฑ์„ 1์ฐจ ํŒ์ •๊ฐ’์œผ๋กœ ์‚ฌ์šฉํ•˜๊ณ  CPU, GC, HikariCP, MySQL lock, ๋””์Šคํฌ ์ง€ํ‘œ๋Š” ์›์ธ์„ ์„ค๋ช…ํ•˜๋Š” ์ฆ๊ฑฐ๋กœ ์‚ฌ์šฉํ•œ๋‹ค.

2. MAUยทDAU ์žฌ์„ ์ •๊ณผ RPS ์‚ฐ์ •

2.1 ์™ธ๋ถ€ ๋ฒค์น˜๋งˆํฌ์™€ ๋‚ด๋ถ€ ๊ฐ€์ • ๋ถ„๋ฆฌ

BlaBlaCar๋Š” ์ „์ฒด ์„œ๋น„์Šค์˜ DAU๋ฅผ ๊ณต๊ฐœํ•˜์ง€ ์•Š๋Š”๋‹ค. ๋”ฐ๋ผ์„œ ๊ตญ๊ฐ€ยท์—ฐ๋„ ๋ฒ”์œ„๊ฐ€ ์ผ์น˜ํ•˜๋Š” ์ŠคํŽ˜์ธ 2025 ๊ณต์‹ ์ž๋ฃŒ๋กœ DAU/MAU ํ™œ๋™ ํ”„๋ก์‹œ๋ฅผ ๋งŒ๋“ ๋‹ค. ๋ชจ์—ฌํƒ€ MAU๋Š” 1,150,000๋ช…์œผ๋กœ ๊ณ ์ •ํ•˜๋ฉฐ ์ด ๊ฐ’์— ์นจํˆฌ์œจ์„ ๋‹ค์‹œ ์ ์šฉํ•˜์ง€ ์•Š๋Š”๋‹ค.

๊ณต๊ฐœ ์ง€ํ‘œ ๊ฐ’ ์‚ฌ์šฉ ๋ฐฉ๋ฒ•
2025 ์ŠคํŽ˜์ธ ํ‰๊ท  ์›”๊ฐ„ ๊ณ ์œ  ํ™œ์„ฑ ์‚ฌ์šฉ์ž 300,000~400,000 ์ค‘์•™๊ฐ’ 350,000์„ MAU ๊ธฐ์ค€์œผ๋กœ ์‚ฌ์šฉ
2025 ์ŠคํŽ˜์ธ ์—ฐ๊ฐ„ ์Šน๊ฐ 4,000,000 ์ผ๊ฐ„ ์Šน๊ฐ ํ™œ๋™ ํ”„๋ก์‹œ

๊ณต๊ฐœ๊ฐ’์—์„œ ๋‹ค์Œ ๋น„์œจ์„ ๊ณ„์‚ฐํ•œ๋‹ค.

์ผ ํ‰๊ท  ์Šน๊ฐ ํ™œ๋™ = 4,000,000 รท 365 = 10,959/day
์Šน๊ฐ ํ™œ๋™ DAU/MAU = 10,959 รท 300,000~400,000 = 2.740~3.653%
์ฑ„ํƒ DAU/MAU = 10,959 รท 350,000 = 3.131%

๋ชจ์—ฌํƒ€ DAU ๋ฒ”์œ„ = 1,150,000 ร— 2.740~3.653% = 31,507~42,009
์ฑ„ํƒ DAU = 1,150,000 ร— 3.131% = 36,008
๊ณ ์ • MAU BlaBlaCar DAU/MAU ๋ฒ”์œ„ ์ถ”์ • DAU ๋ฒ”์œ„ ์ฑ„ํƒ DAU
1,150,000 2.740~3.653% 31,507~42,009 36,008

์œ„ DAU๋Š” ๋กœ๊ทธ์ธ ๊ธฐ์ค€ ๊ณ ์œ  DAU ์‹ค์ธก๊ฐ’์ด ์•„๋‹ˆ๋ผ ์Šน๊ฐ ๊ฑด์ˆ˜/365๋ฅผ ์‚ฌ์šฉํ•œ ์ผ๊ฐ„ ํ™œ๋™ ํ”„๋ก์‹œ๋‹ค. ์šด์ „์žยท๊ฒ€์ƒ‰๋งŒ ํ•œ ์‚ฌ์šฉ์ž๋ฅผ ๋น ๋œจ๋ฆฌ๊ณ  ํ•˜๋ฃจ ๋ณต์ˆ˜ ์ด์šฉ์ž๋ฅผ ์ค‘๋ณต ์ง‘๊ณ„ํ•  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ์ œํ’ˆ KPI๋กœ ์“ฐ์ง€ ์•Š๋Š”๋‹ค. ์šด์˜ ๋กœ๊ทธ๊ฐ€ ์—†์„ ๋•Œ ๋ถ€ํ•˜ํ…Œ์ŠคํŠธ ์ดˆ๊ธฐ๊ฐ’์„ ์ •ํ•˜๋Š” ๋ฒค์น˜๋งˆํฌ์—๋งŒ ์‚ฌ์šฉํ•˜๊ณ , ์ดํ›„ ๊ณ ์œ  DAUยท์ธ๋‹น ์„ธ์…˜ยท์„ธ์…˜๋‹น ํ˜ธ์ถœ ํšŸ์ˆ˜๋กœ ๊ต์ฒดํ•œ๋‹ค.

2.2 RPS ๊ณต์‹

์ผ ์„ธ์…˜ = DAU ร— 1ํšŒ

ํ”ผํฌ ์„ธ์…˜ ์‹œ์ž‘๋ฅ 
= DAU ร— ์ผ ์„ธ์…˜/DAU ร— ํ”ผํฌ ์ง‘์ค‘๋ฅ  70%
  รท ํ”ผํฌ 4์‹œ๊ฐ„ ร— ์ˆœ๊ฐ„ ํ”ผํฌ ๊ณ„์ˆ˜ 2.0

ํ”ผํฌ RPS = ํ”ผํฌ ์„ธ์…˜ ์‹œ์ž‘๋ฅ  ร— ์„ธ์…˜๋‹น HTTP 13๊ฑด
๊ตฌ๋ถ„ DAU/MAU DAU ํ”ผํฌ ์„ธ์…˜/s ๊ณ„์‚ฐ RPS
ํ•˜๋‹จ 2.740% 31,507 3.063 39.82
์ค‘์•™ 3.131% 36,008 3.501 45.51
์ƒ๋‹จ 3.653% 42,009 4.084 53.09

๋”ฐ๋ผ์„œ ์šด์˜ ๋ฐ์ดํ„ฐ๊ฐ€ ์—†์„ ๋•Œ์˜ ์ฒซ ํ˜ผํ•ฉ ๋ถ€ํ•˜ ๊ธฐ์ค€์€ ์•ฝ 50 RPS๋กœ ๋‘๋ฉด ๋œ๋‹ค. ์ธ๋‹น ์ผ ์„ธ์…˜์ด 2ํšŒ๋ฉด 91 RPS, 3ํšŒ๋ฉด 137 RPS๋กœ ์„ ํ˜• ์ฆ๊ฐ€ํ•œ๋‹ค. ์ด ๊ฐ’์€ V1 ์šฉ๋Ÿ‰ ์ƒํ•œ์ด ์•„๋‹ˆ๋ฏ€๋กœ ํ•œ๊ณ„ ํƒ์ƒ‰์€ ๋ณ„๋„๋กœ 25โ†’50โ†’75โ†’100โ†’150โ†’200โ†’300โ†’400โ†’512 RPS๋ฅผ ์ ์šฉํ•ด C_knee๊นŒ์ง€ ๊ณ„์†ํ•œ๋‹ค.

์„ธ์…˜๋‹น HTTP 13๊ฑด์€ ํ˜„์žฌ ์‹œํ€€์Šค๋ฅผ ๋ชฉ๋กยท๊ฒ€์ƒ‰ 4, ์ƒ์„ธ 4, ํ˜ผ์žก๋„ 3, ์“ฐ๊ธฐ 1, ์ธ์ฆยท๊ธฐํƒ€ 1๋กœ ๋ถ„ํ•ดํ•œ ๋‚ด๋ถ€ ์„ค๊ณ„๊ฐ’์ด๋‹ค. ์ค‘์•™ RPS 45.51์˜ endpoint ๋ถ„๋ฐฐ๋Š” ๋ชฉ๋กยท๊ฒ€์ƒ‰ 14.00, ์ƒ์„ธ 14.00, ํ˜ผ์žก๋„ 10.50, ์“ฐ๊ธฐ 3.50, ์ธ์ฆยท๊ธฐํƒ€ 3.50 RPS๋‹ค. ์šด์˜ ๋กœ๊ทธ๊ฐ€ ์ƒ๊ธฐ๋ฉด ๋ฐ˜๋“œ์‹œ ์„ธ์…˜/DAU์™€ endpoint ํ˜ธ์ถœ ํšŸ์ˆ˜๋กœ ๊ต์ฒดํ•œ๋‹ค.

2.3 ํ–‰์‚ฌ ์ข…๋ฃŒ burst ์žฌ๊ณ„์‚ฐ

ํŠน์ • ํ–‰์‚ฌ ์‚ฌ์šฉ์ž๋Š” ํ•ด๋‹น ๊ตฌ๊ฐ„ DAU์˜ 10%๊ฐ€ 10๋ถ„ ์•ˆ์— ์ง„์ž…ํ•œ๋‹ค๊ณ  ๊ฐ€์ •ํ•œ๋‹ค. ๊ฐ ์‚ฌ์šฉ์ž๋Š” ํ–‰์‚ฌ ์„ธ์…˜์—์„œ HTTP ์š”์ฒญ 15๊ฑด์„ ๋งŒ๋“ค๊ณ , 50%๊ฐ€ ์ฑ„ํŒ…์— ์ ‘์†ํ•˜๋ฉฐ, ์ ‘์† ์‚ฌ์šฉ์ž๋Š” 10๋ถ„ ๋™์•ˆ ๋ฉ”์‹œ์ง€ 6๊ฑด์„ ๋ณด๋‚ธ๋‹ค.

์š”์ฒญ๋ฅ ์€ ์ด ์š”์ฒญ ์ˆ˜๋ฅผ ๋ณด์กดํ•˜๋Š” ์‚ผ๊ฐํ˜• ๋ถ€ํ•˜๋กœ ๋งŒ๋“ ๋‹ค.

0 โ†’ 5๋ถ„ ๋™์•ˆ peak๊นŒ์ง€ ์ƒ์Šน โ†’ 5๋ถ„ ๋™์•ˆ 0๊นŒ์ง€ ํ•˜๊ฐ•
peak RPS = 2 ร— ์ด๋ฒคํŠธ ์‚ฌ์šฉ์ž ร— ์‚ฌ์šฉ์ž๋‹น ์š”์ฒญ รท 600์ดˆ
๊ตฌ๋ถ„ ์ด๋ฒคํŠธ ์‚ฌ์šฉ์ž HTTP peak ์ตœ์ข… WS ์—ฐ๊ฒฐ peak ์—ฐ๊ฒฐ๋ฅ  inbound ๋ฉ”์‹œ์ง€ peak
ํ•˜๋‹จ 3,151 157.5 RPS 1,575 5.25/s 31.5 msg/s
์ค‘์•™ 3,601 180.0 RPS 1,800 6.00/s 36.0 msg/s
์ƒ๋‹จ 4,201 210.0 RPS 2,100 7.00/s 42.0 msg/s

4์ธ ํŒŸ์—์„œ ๋ฐœ์‹ ์ž๋ฅผ ์ œ์™ธํ•œ 3๋ช…์—๊ฒŒ ์ „๋‹ฌ๋œ๋‹ค๋ฉด ์ค‘์•™ ๊ธฐ์ค€ ๋„คํŠธ์›Œํฌ ์ „๋‹ฌ๋Ÿ‰์€ ์ตœ๋Œ€ ์•ฝ 108 deliveries/s๋‹ค. ์ด๋ฒคํŠธ ์‚ฌ์šฉ์ž 10%, WS ์ ‘์† 50%, 15 HTTP/user, 6 messages/user๋Š” ๋ชจ๋‘ ๋‚ด๋ถ€ ๊ฐ€์ •์ด๋‹ค. ์˜ˆ์ƒ burst๋Š” 160โ†’180โ†’210 RPS, ์šฉ๋Ÿ‰ ํƒ์ƒ‰์€ 250โ†’300โ†’400โ†’512 RPS๋กœ ์ด์–ด๊ฐ„๋‹ค. WS๋Š” ์—ฐ๊ฒฐยท๋ฉ”์‹œ์ง€๋ฅผ ๋ณ„๋„ ์ฆ๊ฐ€์‹œ์ผœ ํ•œ๊ณ„๋ฅผ ์ฐพ๋Š”๋‹ค. ๋ฐฉ ํฌ๊ธฐ๊ฐ€ ๋‹ฌ๋ผ์ง€๋ฉด inbound ร— ํ‰๊ท  ์ˆ˜์‹ ์ž ์ˆ˜๋กœ ๋‹ค์‹œ ์‚ฐ์ •ํ•œ๋‹ค.

3. ๋ถ€ํ•˜ยท๊ด€์ธก ๊ตฌ์กฐ

๋ณ„๋„ Terraform ์Šคํƒ์€ loadtest-infra/์— ๋‘๊ณ  ์ž„์‹œ PrometheusยทGrafana EC2, ๊ด€์ธก์šฉ ์ ‘๊ทผ ๊ทœ์น™, exporter ์„ค์น˜ ๋ฌธ์„œ๋งŒ ๊ด€๋ฆฌํ•œ๋‹ค. ๋ถ€ํ•˜ ๋ฐœ์ƒ๊ธฐ EC2๋Š” ๋งŒ๋“ค์ง€ ์•Š์œผ๋ฉฐ ๊ธฐ์กด V1 Terraform state์™€ ํŒŒ์ผ์„ ์ˆ˜์ •ํ•˜์ง€ ์•Š๋Š”๋‹ค. Public 80/443 ๊ทœ์น™์€ ๊ธฐ์กด infra/ state๋งŒ ์†Œ์œ ํ•˜๊ณ , ๋ณ„๋„ ์Šคํƒ์€ ํ…Œ์ŠคํŠธ ๊ธฐ๊ฐ„์—๋งŒ monitoring SG์—์„œ exporter port๋กœ ๋“ค์–ด๊ฐ€๋Š” ๊ทœ์น™์„ ์ถ”๊ฐ€ํ•œ๋‹ค.

๋กœ์ปฌ ๋ถ€ํ•˜ ๋ฐœ์ƒ๊ธฐ
 โ”œโ”€ HTTP ํ”„๋กœ์„ธ์Šค โ”€โ”
 โ”œโ”€ WS ํ”„๋กœ์„ธ์Šค โ”€โ”€โ”€โ”œโ”€ Public DNS/EIP โ†’ HTTPS/WSS โ†’ Nginx โ†’ Spring โ”€โ”ฌโ†’ MySQL
 โ”‚                    โ”‚                                โ””โ†’ FastAPI โ†’ ์™ธ๋ถ€ LLM
 โ””โ”€ ๋กœ์ปฌ JSON/CSV ๊ฒฐ๊ณผ

V1 EC2
 โ”œโ”€ Node Exporter: ํ˜ธ์ŠคํŠธ CPUยท๋ฉ”๋ชจ๋ฆฌยท๋””์Šคํฌยท๋„คํŠธ์›ŒํฌยทFD
 โ”œโ”€ cAdvisor: ์ปจํ…Œ์ด๋„ˆ CPUยท๋ฉ”๋ชจ๋ฆฌยทthrottlingยทI/O
 โ”œโ”€ Micrometer: HTTPยทTomcatยทJVMยทHikariCP
 โ”œโ”€ mysqld-exporter: MySQL connectionยทlockยทbufferยทredo
 โ””โ”€ nginx exporter/access log: ์—ฐ๊ฒฐยทupstream ์‹œ๊ฐ„
              โ†“ 5์ดˆ scrape
์ž„์‹œ Prometheus + Grafana EC2

๋ถ€ํ•˜ ๊ฒฝ๋กœ๋Š” ๋ฐ˜๋“œ์‹œ ๊ณต๊ฐœ ๋„๋ฉ”์ธ ๋˜๋Š” EIP์˜ https://ยทwss://๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค. ์ด๋กœ์จ ๊ณต๊ฐœ DNS, ์ธํ„ฐ๋„ท ๊ฒฝ๋กœ, TLS, Nginx๋ฅผ ํฌํ•จํ•œ ์‹ค์ œ ์ง„์ž… ๊ฒฝ๋กœ๋ฅผ ์ธก์ •ํ•œ๋‹ค. V1 private IP๋Š” ๋ถ€ํ•˜ ๋Œ€์ƒ์ด ์•„๋‹ˆ๋ฉฐ Prometheus EC2๊ฐ€ exporter๋ฅผ ์ˆ˜์ง‘ํ•˜๋Š” ๊ด€์ธก ๊ฒฝ๋กœ์—๋งŒ ์‚ฌ์šฉํ•œ๋‹ค.

Node Exporter์™€ cAdvisor๋Š” Terraform์ด ์ƒ์„ฑํ•œ SSM ๋ฌธ์„œ๋กœ ์„ค์น˜ยท์ œ๊ฑฐํ•  ์ˆ˜ ์žˆ๋‹ค. Spring, MySQL, Nginx exporter๋Š” ์ธ์ฆ ์ •๋ณด์™€ ์„œ๋น„์Šค ์„ค์ •์ด ํ•„์š”ํ•˜๋ฏ€๋กœ ์ž๊ฒฉ ์ฆ๋ช…์„ Terraform state์— ๋„ฃ์ง€ ์•Š๊ณ  ๋ณ„๋„๋กœ ๊ตฌ์„ฑํ•œ ๋’ค scrape target๋งŒ Terraform ๋ณ€์ˆ˜๋กœ ์—ฐ๊ฒฐํ•œ๋‹ค.

4. ๋ณ‘๋ชฉ๋ณ„ ์„ธ๋ถ„ํ™” ํ…Œ์ŠคํŠธ

T0. ๋กœ์ปฌ ๋ถ€ํ•˜ ๋ฐœ์ƒ๊ธฐ ๊ฒ€์ฆ

  • V1 ํ…Œ์ŠคํŠธ ์ „์— ์‘๋‹ต์ด ๊ณ ์ •๋œ endpoint๋กœ ๋กœ์ปฌ ํ˜ธ์ŠคํŠธ์˜ ํ•œ๊ณ„๋ฅผ ์ธก์ •ํ•œ๋‹ค.
  • ๋กœ์ปฌ CPU 60% ๋ฏธ๋งŒ, swap 0, ์‹ค์ธก ์—…๋กœ๋“œ ๋Œ€์—ญํญ 70% ๋ฏธ๋งŒ, dropped iteration 0, ๋ชฉํ‘œ ์š”์ฒญ ๋„๋‹ฌ๋ฅ  95% ์ด์ƒ์„ ์œ ์ง€ํ•œ๋‹ค.
  • ์œ ์„ /Wi-Fi, VPNยทproxy ์‚ฌ์šฉ ์—ฌ๋ถ€, ๊ณต์ธ IP, target RTTยทjitterยทpacket loss์™€ ๋กœ์ปฌ ํ•˜๋“œ์›จ์–ด ์‚ฌ์–‘์„ ๋ชจ๋“  ๊ฒฐ๊ณผ์— ๊ธฐ๋กํ•œ๋‹ค.
  • HTTP์™€ WebSocket์€ ๋ณ„๋„ ๋กœ์ปฌ ํ”„๋กœ์„ธ์Šค๋กœ ์‹คํ–‰ํ•œ๋‹ค. ๋™์ผ ํ˜ธ์ŠคํŠธ์—์„œ ์—ฌ์œ ์œจ์„ ๋งŒ์กฑํ•˜์ง€ ๋ชปํ•˜๋ฉด ๊ฐ™์€ ํ†ต์ œ ๋„คํŠธ์›Œํฌ์˜ ๋กœ์ปฌ ๋จธ์‹  ๋‘ ๋Œ€๋กœ ๋‚˜๋ˆˆ๋‹ค.

T1. ๋„คํŠธ์›ŒํฌยทTLSยทNginx ์—ฐ๊ฒฐ ์ฒ˜๋ฆฌ

๋™์ผํ•œ ๊ฐ€๋ฒผ์šด endpoint์— ๋Œ€ํ•ด ๋‹ค์Œ์„ ๋น„๊ตํ•œ๋‹ค.

  • keep-alive ํ™œ์„ฑ๊ณผ ๋งค ์š”์ฒญ ์‹ ๊ทœ ์—ฐ๊ฒฐ
  • HTTP์™€ HTTPS
  • 1โ†’10โ†’50โ†’100โ†’200โ†’400 connections/s

์ธก์ •๊ฐ’์€ TCP connect, TLS handshake, Nginx active/reading/writing/waiting, accept ์‹คํŒจ, host socket ์ˆ˜, FD, listen queue, Nginx container CPU์™€ throttling์ด๋‹ค. upstream์ด ์—ฌ์œ ๋กœ์šด ์ƒํƒœ์—์„œ connect ์‹œ๊ฐ„์ด ๋จผ์ € ์ƒ์Šนํ•˜๋ฉด NginxยทOS ๊ณ„์ธต ๋ณ‘๋ชฉ์œผ๋กœ ํŒ์ •ํ•œ๋‹ค.

T2. Spring ์š”์ฒญ ์ฒ˜๋ฆฌ์™€ JVM

DBยท์™ธ๋ถ€ API๋ฅผ ํ˜ธ์ถœํ•˜์ง€ ์•Š๋Š” ๊ฐ€์žฅ ๊ฐ€๋ฒผ์šด endpoint์™€ ์‹ค์ œ endpoint๋ฅผ ๋น„๊ตํ•œ๋‹ค.

  • BlaBlaCar ํ™œ๋™๋ฅ  ๊ธฐ์ค€ 40โ†’46โ†’53 RPS๋ฅผ ๋จผ์ € ์žฌํ˜„
  • ํ•œ๊ณ„ ํƒ์ƒ‰์€ 25โ†’50โ†’75โ†’100โ†’150โ†’200โ†’300โ†’400โ†’512 RPS
  • ์ž„๊ณ„์  ๋ถ€๊ทผ๋ถ€ํ„ฐ 10~20% ๋‹จ์œ„ ์ฆ๊ฐ€
  • ๊ฐ ๋‹จ๊ณ„ ์›Œ๋ฐ์—… 5๋ถ„, ์ธก์ • 10๋ถ„, 3ํšŒ ๋ฐ˜๋ณต

Tomcat busy/max, ์š”์ฒญ queue, JVM heapยทdirect memory, allocation rate, GC pause, process CPU, context switch, container throttling์„ ์ธก์ •ํ•œ๋‹ค. DB ์ง€์—ฐ ์—†์ด Tomcat๊ณผ CPU๊ฐ€ ๋จผ์ € ํฌํ™”๋˜๋ฉด Spring ๊ณ„์‚ฐยท์ง๋ ฌํ™”ยทthread ์„ค์ • ๋ฌธ์ œ๋‹ค.

T3. ๋ชฉ๋ก ์ฟผ๋ฆฌ

๋‹ค์Œ ์ถ•์„ ๋…๋ฆฝ์ ์œผ๋กœ ๋ฐ”๊พผ๋‹ค.

  • ํ˜„์žฌ V1, MAU 115๋งŒ ์˜ˆ์ƒ ๋ˆ„์ ์น˜, ๊ทธ 2๋ฐฐ์˜ ๋ฐ์ดํ„ฐ ๊ฑด์ˆ˜
  • ์ฒซ ํŽ˜์ด์ง€์™€ ๊นŠ์€ ํŽ˜์ด์ง€
  • ๋™์ผ ๊ฒ€์ƒ‰์กฐ๊ฑด ๋ฐ˜๋ณต๊ณผ ๋‹ค์–‘ํ•œ ์œ„์น˜ยทํ•„ํ„ฐ
  • cold cache์™€ warm cache
  • ๋ชฉ๋ก ํฌ๊ธฐ 10ยท20ยท50

์ฟผ๋ฆฌ p95/p99, rows examined/sent, buffer-pool hit, temporary table, sort, MySQL CPU, disk read latency, Hikari usage/acquire/pending์„ ์ธก์ •ํ•œ๋‹ค. ์ฒซ ํŽ˜์ด์ง€ ๋ฐ˜๋ณต ๊ฒฐ๊ณผ๋งŒ์œผ๋กœ ์กฐํšŒ ์šฉ๋Ÿ‰์„ ํŒ์ •ํ•˜์ง€ ์•Š๋Š”๋‹ค.

T4. ์ƒ์„ธ ์กฐํšŒ์™€ N+1ยท์ง๋ ฌํ™”

  • ์กด์žฌํ•˜๋Š” ํŒŸ๊ณผ ์—†๋Š” ํŒŸ
  • ์ฐธ์—ฌ์žยท์ •์‚ฐยท์ฑ„ํŒ… ์ด๋ ฅ ํฌ๊ธฐ๋ณ„ ์ƒ์„ธ
  • ๋™์ผ ์ƒ์„ธ ๋ฐ˜๋ณต๊ณผ ID ๋ถ„์‚ฐ

DB query count/request, SQL ํ•ฉ๊ณ„์‹œ๊ฐ„, ์‘๋‹ต ์ง๋ ฌํ™” ์‹œ๊ฐ„, response bytes, Spring CPU์™€ GC๋ฅผ ์ธก์ •ํ•œ๋‹ค. DB ์‹œ๊ฐ„์ด ์งง์ง€๋งŒ ์ „์ฒด ์‘๋‹ต์ด ๊ธธ๋ฉด ๊ฐ์ฒด ๋ณ€ํ™˜ยทJSON ์ง๋ ฌํ™” ๋˜๋Š” ๊ณผ๋„ํ•œ ์‘๋‹ต ํฌ๊ธฐ๋กœ ํŒ์ •ํ•œ๋‹ค.

T5. ํ˜ผ์žก๋„ ์™ธ๋ถ€ ํ˜ธ์ถœ

์™ธ๋ถ€ ์˜์กด์„ฑ์„ ๋‹ค์Œ ๊ณ ์ • ์กฐ๊ฑด์œผ๋กœ ๋ฐ”๊ฟ”๊ฐ€๋ฉฐ ํ…Œ์ŠคํŠธํ•œ๋‹ค.

  • ์ง€์—ฐ 50ยท200ยท1,000ยท3,000ms
  • ์˜ค๋ฅ˜์œจ 0ยท1ยท5ยท20%
  • ๋™์ผ spot๊ณผ 10ยท100๊ฐœ spot ๋ถ„์‚ฐ

Spring outbound connection pool, pending call, Tomcat busy, FastAPI worker queue, timeout, retry ์ˆ˜๋ฅผ ์ธก์ •ํ•œ๋‹ค. ํŠธ๋žœ์žญ์…˜ยทHikari ์‚ฌ์šฉ ์‹œ๊ฐ„์ด ์™ธ๋ถ€ ์ง€์—ฐ๊ณผ ํ•จ๊ป˜ ์ฆ๊ฐ€ํ•˜๋ฉด ํŠธ๋žœ์žญ์…˜ ๋ฒ”์œ„๊ฐ€ ์™ธ๋ถ€ ํ˜ธ์ถœ์„ ํฌํ•จํ•œ ๊ฒƒ์ด๋‹ค.

T6. ํ˜ผ์žก๋„ DB ์ตœ์‹ ๊ฐ’ยท์ด๋ ฅ ์ €์žฅ

์™ธ๋ถ€ ๊ณ„์‚ฐ ๊ฒฐ๊ณผ๋ฅผ ๊ณ ์ •ํ•ด ์™ธ๋ถ€ API ์˜ํ–ฅ์„ ์ œ๊ฑฐํ•œ ๋’ค ๋‹ค์Œ์„ ๋น„๊ตํ•œ๋‹ค.

  • ์ตœ์‹ ๊ฐ’ upsert๋งŒ ์ˆ˜ํ–‰
  • ์ด๋ ฅ insert ํฌํ•จ
  • ๋™์ผ spot๊ณผ ๋‹ค์ˆ˜ spot ๋ถ„์‚ฐ
  • K=1ยท5ยท20

row lock current waits/time, deadlock, transaction duration, redo bytes, fsync, dirty page, EBS queueยทawait, Hikari pending์„ ์ธก์ •ํ•œ๋‹ค. ๋™์ผ spot์—์„œ๋งŒ ๊ธ‰๊ฒฉํžˆ ๋‚˜๋น ์ง€๋ฉด row lock, ๋ชจ๋“  spot์—์„œ ๋‚˜๋น ์ง€๋ฉด redoยทI/O ๋˜๋Š” ์ธ๋ฑ์Šค ๋น„์šฉ์ด๋‹ค.

T7. ์ฐธ์—ฌ ์š”์ฒญ ์ €์žฅ

์„œ๋กœ ๋‹ค๋ฅธ ํŒŸ์— ์“ฐ๊ธฐ๋ฅผ ๋ถ„์‚ฐํ•ด ๋‹จ์ˆœ insert ์ฒ˜๋ฆฌ๋Ÿ‰์„ ๋จผ์ € ์ธก์ •ํ•œ๋‹ค. ์ด ๊ฐ’์€ ์ขŒ์„ ๊ฒฝ์Ÿ๊ณผ ๋ถ„๋ฆฌ๋œ ์“ฐ๊ธฐ ๊ธฐ์ค€์„ ์ด๋‹ค.

  • 1โ†’5โ†’10โ†’20โ†’40โ†’80 writes/s
  • ์„ฑ๊ณตยท์ค‘๋ณตยท์ œ์•ฝ์กฐ๊ฑด ์˜ค๋ฅ˜๋ฅผ ๋ถ„๋ฆฌ ์ง‘๊ณ„

T8. ์ธ๊ธฐ ํŒŸ ์Šน์ธ hot-row

RPS๊ฐ€ ์•„๋‹ˆ๋ผ ๋™์‹œ์— ๊ฐ™์€ ํŒŸ ํ–‰์— ๋„์ฐฉํ•˜๋Š” ์š”์ฒญ ์ˆ˜๋ฅผ ์ œ์–ดํ•œ๋‹ค.

  • ๊ฐ™์€ ํŒŸ์— 2ยท5ยท10ยท20ยท50ยท100 ๋™์‹œ ์Šน์ธ
  • ์„œ๋กœ ๋‹ค๋ฅธ ํŒŸ์— ๊ฐ™์€ ๋™์‹œ์„ฑ์„ ์ฃผ๋Š” ๋Œ€์กฐ๊ตฐ
  • lock์„ 0ยท100ยท500ยท2,000ms ์ ์œ ํ•˜๋Š” ์กฐ๊ฑด

lock wait, deadlock, Hikari pending, ์Šน์ธ latency์™€ ํ•จ๊ป˜ ์ž”์—ฌ ์ขŒ์„ ์Œ์ˆ˜, ์ •์› ์ดˆ๊ณผ, ์ค‘๋ณต ์Šน์ธ์„ ๊ฒ€์ฆํ•œ๋‹ค. ์ •ํ•ฉ์„ฑ ์˜ค๋ฅ˜๋Š” ๋‹จ ํ•œ ๊ฑด์ด์–ด๋„ ์‹คํŒจ๋‹ค.

T9. WebSocket ์—ฐ๊ฒฐ ์ž์ฒด

๋ฉ”์‹œ์ง€๋ฅผ ๋ณด๋‚ด์ง€ ์•Š๊ณ  ์—ฐ๊ฒฐ ๋น„์šฉ๋งŒ ์ธก์ •ํ•œ๋‹ค.

  • ์ˆ˜์š” ์˜ˆ์ธก ๋™์‹œ ์—ฐ๊ฒฐ 1,575โ†’1,800โ†’2,100, ์šฉ๋Ÿ‰ ํƒ์ƒ‰ 500โ†’1,000โ†’1,500โ†’3,000โ†’5,000
  • ์—ฐ๊ฒฐ๋ฅ  5.25โ†’6โ†’7โ†’10โ†’20โ†’50 connections/s
  • 30๋ถ„ idle ์œ ์ง€ ํ›„ ์—ฐ๊ฒฐ ํ•ด์ œ์™€ ์žฌ์—ฐ๊ฒฐ

handshake p95/p99, ์„ฑ๊ณต๋ฅ , Nginx์™€ Spring FD, ESTABLISHED/TIME_WAIT, heapยทdirect memory/connection, GC, heartbeat traffic์„ ์ธก์ •ํ•œ๋‹ค.

T10. WebSocket ๋ฉ”์‹œ์ง€ยทfan-outยท์ €์žฅ

์—ฐ๊ฒฐ ์ˆ˜๋ฅผ ๊ณ ์ •ํ•˜๊ณ  ๋‹ค์Œ ์ถ•์„ ๋ถ„๋ฆฌํ•œ๋‹ค.

  • ์ €์žฅ ์—†๋Š” heartbeat์™€ DB ์ €์žฅ ์ฑ„ํŒ… ๋ฉ”์‹œ์ง€
  • ํ•œ ๋ฐฉ ์ง‘์ค‘๊ณผ ์—ฌ๋Ÿฌ ๋ฐฉ ๋ถ„์‚ฐ
  • ์ˆ˜์‹ ์ž 1ยท3ยท9๋ช…
  • ์ˆ˜์š” ์˜ˆ์ธก inbound 31.5โ†’36โ†’42 msg/s
  • ์šฉ๋Ÿ‰ ํƒ์ƒ‰ inbound 10โ†’20โ†’50โ†’100โ†’300 msg/s

end-to-end ์ „๋‹ฌ p95/p99, ์œ ์‹คยท์ค‘๋ณตยท์ˆœ์„œ ์˜ค๋ฅ˜, outbound deliveries/s, Spring CPU, network, DB commit, Hikari pending์„ ์ธก์ •ํ•œ๋‹ค.

T11. RESTยทWebSocket ๊ณต์œ  ์ž์› ๊ฐ„์„ญ

WebSocket ์—ฐ๊ฒฐ์„ 0, ์˜ˆ์ธก ํ•˜๋‹จยท์ค‘์•™ยท์ƒ๋‹จ 1,575ยท1,800ยท2,100, ์šฉ๋Ÿ‰ ํƒ์ƒ‰๊ฐ’ 3,000ยท5,000์œผ๋กœ ๊ณ ์ •ํ•˜๊ณ  ๊ฐ™์€ REST ๋ถ€ํ•˜๋ฅผ ๋ฐ˜๋ณตํ•œ๋‹ค. ์—ฐ๊ฒฐ์ด ์—†๋Š” ๋Œ€์กฐ๊ตฐ ๋Œ€๋น„ REST p95, ์ฒ˜๋ฆฌ๋Ÿ‰, Spring CPUยท๋ฉ”๋ชจ๋ฆฌ ๋ณ€ํ™”์œจ์„ ๊ธฐ๋กํ•œ๋‹ค. ์ž„์˜์˜ WS ๋‹จ๊ณ„์—์„œ REST p95๊ฐ€ 20% ์ด์ƒ ์•…ํ™”๋˜๊ณ  ์ž์› ์ƒ๊ด€๊ด€๊ณ„๊ฐ€ ํ™•์ธ๋˜๋ฉด WebSocket ์‹คํ–‰๊ธฐ ๋˜๋Š” ์„œ๋น„์Šค ๋ถ„๋ฆฌ๋ฅผ ์šฐ์„  ๊ฒ€ํ† ํ•œ๋‹ค.

T12. ์žฅ์• ยท๋ณต๊ตฌ

C_safe์˜ 70% ๋ถ€ํ•˜์—์„œ Nginx, Spring, FastAPI, MySQL์„ ํ•˜๋‚˜์”ฉ ์ค‘์ง€ยท๋ณต๊ตฌํ•œ๋‹ค. EC2 reboot์™€ ๋ฐฑ์—… ๋ณต์›์€ ๋ณ„๋„ ๊ฒฉ๋ฆฌ ํ™˜๊ฒฝ์—์„œ ์ˆ˜ํ–‰ํ•œ๋‹ค.

  • ์˜ค๋ฅ˜๊ฐ€ ์‹œ์ž‘๋œ ์‹œ๊ฐ๋ถ€ํ„ฐ 5๋ถ„ ์—ฐ์† ์ •์ƒํ™”๋  ๋•Œ๊นŒ์ง€์˜ RTO
  • ๊ธฐ๋Šฅ๋ณ„ ์žฅ์•  ๋ฒ”์œ„
  • WebSocket ์žฌ์—ฐ๊ฒฐ๋ฅ 
  • retry storm๊ณผ queue ํšŒ๋ณต ์‹œ๊ฐ„
  • ๋งˆ์ง€๋ง‰ ์ •์ƒ ๋ฐฑ์—…๋ถ€ํ„ฐ์˜ RPO

๋‹จ์ผ EC2ยท๋‹จ์ผ MySQL์€ ํ˜ธ์ŠคํŠธ ์žฅ์•  ์ค‘ ๋ฌด์ค‘๋‹จ์„ ์ œ๊ณตํ•  ์ˆ˜ ์—†์œผ๋ฏ€๋กœ ์ด ํ…Œ์ŠคํŠธ๋Š” ๊ณ ๊ฐ€์šฉ์„ฑ์„ ์ฆ๋ช…ํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ ํ˜„์žฌ ๋ณต๊ตฌ ๋Šฅ๋ ฅ์„ ์ˆ˜์น˜ํ™”ํ•œ๋‹ค.

5. ๋‹จ๊ณ„์™€ ์ค‘๋‹จ ์กฐ๊ฑด

  1. ๊ณ ์ •๋œ ์ด๋ฏธ์ง€ยทDB snapshotยทCPU credit ์ƒํƒœ๋ฅผ ๊ธฐ๋กํ•œ๋‹ค.
  2. ๋‹จ์ผ ์‚ฌ์šฉ์ž ๊ธฐ๋Šฅ๊ณผ ๊ฒฐ๊ณผ ์ •ํ•ฉ์„ฑ์„ ๊ฒ€์ฆํ•œ๋‹ค.
  3. 5๋ถ„ ์›Œ๋ฐ์—… ํ›„ ๊ฒฉ๋ฆฌ ํ…Œ์ŠคํŠธ๋ฅผ ์ˆ˜ํ–‰ํ•œ๋‹ค.
  4. BlaBlaCar ๊ธฐ์ค€ 40โ†’46โ†’53 RPS์™€ ์„ธ์…˜ ๋ฏผ๊ฐ๋„ 91โ†’137 RPS ์ˆœ์œผ๋กœ ํ˜ผํ•ฉ ๋ถ€ํ•˜๋ฅผ ์ˆ˜ํ–‰ํ•œ๋‹ค.
  5. ์ตœ์ดˆ ์ž„๊ณ„์  ๋ถ€๊ทผ์„ 10~20% ๊ฐ„๊ฒฉ์œผ๋กœ ๋‹ค์‹œ ์ธก์ •ํ•œ๋‹ค.
  6. C_safe์—์„œ 60~120๋ถ„ soak test๋ฅผ ์ˆ˜ํ–‰ํ•œ๋‹ค.
  7. ์˜ˆ์ธก burst 160โ†’180โ†’210 RPS์™€ 250โ†’300โ†’400โ†’512 RPS ํƒ์ƒ‰ burst์˜ ๋ณต๊ตฌ๋ฅผ ์ธก์ •ํ•œ๋‹ค.
  8. ํ•œ ๋ฒˆ์— ๊ฐœ์„  ํ•˜๋‚˜๋งŒ ์ ์šฉํ•˜๊ณ  ๋™์ผ snapshotยท์‹œ๋‚˜๋ฆฌ์˜ค๋กœ ์žฌ์ธก์ •ํ•œ๋‹ค.

๋‹ค์Œ ์ค‘ ํ•˜๋‚˜๋ฉด ํ•ด๋‹น ๋‹จ๊ณ„๋ฅผ ์ค‘์ง€ํ•œ๋‹ค.

  • 5xxยทtimeout 5% ์ดˆ๊ณผ๊ฐ€ 2๋ถ„ ์ง€์†
  • OOM, container restart, disk full
  • ์ขŒ์„ ๋˜๋Š” ๋ฉ”์‹œ์ง€ ์ •ํ•ฉ์„ฑ ์œ„๋ฐ˜
  • ๋ถ€ํ•˜ ๋ฐœ์ƒ๊ธฐ๊ฐ€ ๋ชฉํ‘œ RPS์˜ 95%๋ฅผ ์ „๋‹ฌํ•˜์ง€ ๋ชปํ•จ
  • DB ๋ณต๊ตฌ๊ฐ€ ํ•„์š”ํ•œ ๋น„์ •์ƒ ์ƒํƒœ

6. ํ™•์žฅ ๋ฐฉํ–ฅ์„ ๊ฒฐ์ •ํ•˜๋Š” ๊ฒฐ๊ณผํ‘œ

์ฆ๊ฑฐ ํ™•์žฅ ํŒ๋‹จ
Host CPUยทcontainer throttling์ด ๋จผ์ € ํฌํ™”, DB ์—ฌ์œ  EC2 ํฌ๊ธฐยท์ปจํ…Œ์ด๋„ˆ quota ์žฌ๋ฐฐ๋ถ„ ์šฐ์„ 
MySQL CPUยทlockยทI/O์™€ Hikari pending์ด ํ•จ๊ป˜ ์ฆ๊ฐ€ ์ฟผ๋ฆฌยทํŠธ๋žœ์žญ์…˜ ๊ฐœ์„  ํ›„ DB ๋ถ„๋ฆฌ/RDS ๊ฒ€ํ† 
์™ธ๋ถ€ API ์ง€์—ฐ์— Tomcat busyยทoutbound pending์ด ๋น„๋ก€ timeoutยทcacheยทsingle-flightยทbulkheadยท๋น„๋™๊ธฐํ™”
WebSocket ์—ฐ๊ฒฐ๋งŒ์œผ๋กœ heapยทFD๊ฐ€ ํฌํ™” WS gateway ๋˜๋Š” Spring ํ”„๋กœ์„ธ์Šค ๋ถ„๋ฆฌ
๋ฉ”์‹œ์ง€ ์ €์žฅ ์‹œ์—๋งŒ REST๊ฐ€ ์•…ํ™” ์ฑ„ํŒ… ์ €์žฅ ๋น„๋™๊ธฐํ™” ๋˜๋Š” DB ์“ฐ๊ธฐ ๊ฒฝ๋กœ ๋ถ„๋ฆฌ
๋‹จ์ผ ์ปจํ…Œ์ด๋„ˆ ์žฅ์•  RTO๋Š” ์ถฉ์กฑํ•˜์ง€๋งŒ EC2 RTO ๋ถˆ์ถฉ์กฑ ๋‹ค์ค‘ EC2ยทALBยท์™ธ๋ถ€ DB ํ•„์š”
C_safe < ๊ณ„ํš ํ”ผํฌ ร— ์šด์˜ ์—ฌ์œ ์œจ ์ตœ์ ํ™” ๋˜๋Š” ์ˆ˜ํ‰/์ˆ˜์ง ํ™•์žฅ ํ›„ ์žฌ์‹œํ—˜

์ตœ์ข… ๋ณด๊ณ ์„œ์—๋Š” ์‹œ๋‚˜๋ฆฌ์˜ค๋ณ„ ๋ชฉํ‘œยท์‹ค์ œ RPS, p50/p95/p99, ์˜ค๋ฅ˜์œจ, ๋กœ์ปฌ ๋ฐœ์ƒ๊ธฐ headroom, ์ตœ์ดˆ ํฌํ™” ์ง€ํ‘œ, C_knee, C_safe, ์ •ํ•ฉ์„ฑ, RTO/RPO, ์›์‹œ ๊ฒฐ๊ณผ ์œ„์น˜์™€ ๋™์ผ ์กฐ๊ฑด 3ํšŒ ๊ฒฐ๊ณผ๋ฅผ ํฌํ•จํ•œ๋‹ค.