402 V1 load test execution - 100-hours-a-week/KTB4-3rd-CLOUD GitHub Wiki
V1 ๋ถํํ ์คํธ ์คํ ๋ฌธ์
1. ๋ชฉ์ ๊ณผ ๋ฒ์
์ด ๋ฌธ์๋ MAU 1,150,000๋ช ์ ๊ธฐ์ค์ผ๋ก V1์ ์ง์ ์ฒ๋ฆฌ๋๊ณผ ๋ณ๋ชฉ ์ง์ ์ ์์นํํ๊ณ , ๊ทธ ๊ฒฐ๊ณผ๋ก ์์ง ํ์ฅยทDB ๋ถ๋ฆฌยท์ธ๋ถ ํธ์ถ ๊ฒฉ๋ฆฌยทWebSocket ๋ถ๋ฆฌ ์ฌ๋ถ๋ฅผ ๊ฒฐ์ ํ๊ธฐ ์ํ ์คํ ๊ธฐ์ค์ด๋ค.
์ธก์ ๋์์ ๋ก์ปฌ์์ ์คํํ k6๊ฐ V1์ ๊ณต๊ฐ ์ง์ ์ ์ผ๋ก ๋ณด๋ธ ํธ๋ํฝ์ด๋ค. ์ฆ, ๋ถํ ๊ฒฝ๋ก์ public DNS/EIP, Internet routing, TLS, Nginx๋ฅผ ํฌํจํ๋ค. V1 private IP๋ ๋ถํ ๋์์ด ์๋๋ผ Prometheus๊ฐ exporter๋ฅผ ์์งํ๋ ์ฃผ์๋ก๋ง ์ฌ์ฉํ๋ค.
๊ธฐ์กด perf/ ๋ถํํ
์คํธ ์ฝ๋๋ ์ฌ์ฉํ์ง ์๋๋ค. ์ ์ฝ๋๋
loadtest-scenarios/์ ๋
๋ฆฝ์ ์ผ๋ก ์์ฑ๋์ด ์๋ค.
ํ์ ์ ์
C_knee = SLO ๋๋ ๋ฐ์ดํฐ ์ ํฉ์ฑ์ด ์ฒ์ ๊นจ์ง๋ ์ต๋ ์ง์ ๋ถํ
C_safe = C_knee ร 0.7
์๋ต์๊ฐยท์ค๋ฅ์จยท์ ํฉ์ฑ์ 1์ฐจ ํ์ ๊ฐ์ผ๋ก ์ฌ์ฉํ๊ณ CPU, GC, HikariCP, MySQL lock, ๋์คํฌ์ ๋คํธ์ํฌ ์งํ๋ ์์ธ ๋ถ์์ฉ ์ฆ๊ฑฐ๋ก ์ฌ์ฉํ๋ค.
2. MAUยทDAUยทRPS ์ฌ์ฐ์
2.1 ๊ณ ์ ๊ฐ๊ณผ ๋ฒค์น๋งํฌ์ ์ญํ
๋ชจ์ฌํ MAU๋ 1,150,000๋ช ์ผ๋ก ๊ณ ์ ํ๋ค. BlaBlaCar ์์น๋ ๋ชจ์ฌํ์ MAU๋ฅผ ๋ค์ ๊ณ์ฐํ๋ ์นจํฌ์จ์ด ์๋๋ผ, ์ด์ ๋ก๊ทธ๊ฐ ์์ ๋ DAU/MAU ํ๋๋ฅ ๊ณผ ์ธ์ ๋น๋๋ฅผ ์ ํ๋ ์ฐธ๊ณ ๊ฐ์ผ๋ก๋ง ์ฌ์ฉํ๋ค.
BlaBlaCar ์คํ์ธ 2025 ๊ณต์ ์๋ฃ์๋ ๋ค์ ๊ฐ์ด ๊ณต๊ฐ๋์ด ์๋ค.
- ์ํ๊ท ๊ณ ์ ํ์ฑ ์ฌ์ฉ์: 300,000~400,000๋ช
- ์ฐ๊ฐ ์นดํ ์น๊ฐ: 4,000,000๋ช
์ถ์ฒ: BlaBlaCar Spain 2025 activity report
์ฐ๊ฐ ์น๊ฐ ์๋ฅผ ์ผ๊ฐ ํ๋ ํ๋ก์๋ก ๋ณํํ๋ค.
์ผ ํ๊ท ์น๊ฐ ํ๋ = 4,000,000 รท 365 = 10,959๋ช
/day
DAU/MAU ํ๋จ = 10,959 รท 400,000 = 2.740%
DAU/MAU ์ค์ = 10,959 รท 350,000 = 3.131%
DAU/MAU ์๋จ = 10,959 รท 300,000 = 3.653%
๋ฐ๋ผ์ ๊ณ ์ MAU์ ์ ์ฉํ DAU ๋ฒ์๋ ๋ค์๊ณผ ๊ฐ๋ค.
| ๊ตฌ๋ถ | ํ๋๋ฅ ํ๋ก์ | ๊ณ์ฐ | ์ถ์ DAU |
|---|---|---|---|
| ํ๋จ | 2.740% | 1,150,000 ร 2.740% | 31,507 |
| ์ค์ | 3.131% | 1,150,000 ร 3.131% | 36,008 |
| ์๋จ | 3.653% | 1,150,000 ร 3.653% | 42,009 |
์ด ๊ฐ์ ๊ณ ์ ๋ก๊ทธ์ธ DAU๊ฐ ์๋๋ค. ํ๋ฃจ ๋ณต์ ์น๊ฐ ํ๋์ด ํฉ์ณ์ง๊ฑฐ๋ ์ด์ ์ยท๊ฒ์๋ง ํ ์ฌ์ฉ์๊ฐ ๋น ์ง ์ ์์ผ๋ฏ๋ก, ์ค์ ๋ก๊ทธ๊ฐ ํ๋ณด๋๋ฉด ๊ณ ์ DAUยท์ธ์ ์ยท์ธ์ ๋น ์์ฒญ ์๋ก ๊ต์ฒดํ๋ค.
2.2 ๊ธฐ์ค ํผํฉ RPS
ํ์ฌ ์ํ์ค์ ํ ์ธ์ ์ HTTP 13๊ฑด์ผ๋ก ์ ์ํ๋ค.
๋ชฉ๋กยท๊ฒ์ 4๊ฑด + ์์ธ 4๊ฑด + ํผ์ก๋ 3๊ฑด + ์ฐ๊ธฐ 1๊ฑด + ์ธ์ฆยท๊ธฐํ 1๊ฑด
= ์ธ์
๋น HTTP 13๊ฑด
ํผํฌ 4์๊ฐ์ ์ผ๊ฐ ์ธ์ ์ 70%๊ฐ ์ง์ค๋๊ณ , ๊ทธ ์์์ ์๊ฐ ํผํฌ ๊ณ์ 2.0์ด ์ ์ฉ๋๋ค๊ณ ๊ฐ์ ํ๋ค.
ํผํฌ ์ธ์
์์๋ฅ
= DAU ร (์ผ ์ธ์
/DAU) ร 70% รท (4 ร 3,600์ด) ร 2.0
ํผํฌ HTTP RPS
= ํผํฌ ์ธ์
์์๋ฅ ร 13๊ฑด
์ผ ์ธ์ /DAU๋ฅผ 1ํ๋ก ๋ ๊ฒฐ๊ณผ๋ ๋ค์๊ณผ ๊ฐ๋ค.
| ๊ตฌ๋ถ | DAU | ํผํฌ ์ธ์ ์์๋ฅ | ๊ณ์ฐ HTTP RPS |
|---|---|---|---|
| ํ๋จ | 31,507 | 3.063/s | 39.82 |
| ์ค์ | 36,008 | 3.501/s | 45.51 |
| ์๋จ | 42,009 | 4.084/s | 53.09 |
๋ฐ๋ผ์ ์ด์ ๋ฐ์ดํฐ๊ฐ ์๋ ์ฒซ ๊ธฐ์ค ๋ถํ๋ 50 RPS๋ก ๊ณ ์ ํ๋ค. ์ค์๊ฐ 45.51 RPS์์์ ์์ ๋ณ ๋ถ๋ฐฐ๋ ๋ค์๊ณผ ๊ฐ๋ค.
| ์์ | ์ธ์ ๋น์จ | ์ค์ RPS |
|---|---|---|
| ๋ชฉ๋กยท๊ฒ์ | 4/13 | 14.00 |
| ์์ธ | 4/13 | 14.00 |
| ํผ์ก๋ | 3/13 | 10.50 |
| ์ฐ๊ธฐ | 1/13 | 3.50 |
| ์ธ์ฆยท๊ธฐํ | 1/13 | 3.50 |
์ธ์ ์ด ํ๋ฃจ 2ํยท3ํ๋ผ๋ฉด RPS๋ ์ ํ์ผ๋ก ์ฝ 91ยท137 RPS๊ฐ ๋๋ค. ์ด๋ ํ๊ณ๊ฐ์ด ์๋๋ผ ๋ฏผ๊ฐ๋ ํ์ธ๊ฐ์ด๋ค.
2.3 ์ฉ๋ ํ์ ๋จ๊ณ
๊ธฐ์ค๊ฐ ์ฌํ ํ์๋ ๋ค์ ์์๋ก ํ ๋จ๊ณ์ฉ ์ฌ๋ฆฐ๋ค.
25 โ 50 โ 75 โ 100 โ 150 โ 200 โ 300 โ 400 โ 512 RPS
๊ฐ ๋จ๊ณ๋ ์๋ฐ์
5๋ถ, ์ธก์ 10๋ถ, ๋์ผ ์กฐ๊ฑด 3ํ ๋ฐ๋ณต์ ๊ธฐ๋ณธ์ผ๋ก ํ๋ค.
์ต์ด SLO ์๋ฐ ๋จ๊ณ์ ์๋ค๋ฅผ 10~20% ๊ฐ๊ฒฉ์ผ๋ก ์ฌ์ธก์ ํด C_knee๋ฅผ ์ขํ๋ค.
2.4 ํ์ฌ burst
ํ์ฌ ์ฌ์ฉ์ ์๋ DAU์ 10%, ์ด๋ฒคํธ ์ธ์ ์ ์ฌ์ฉ์๋น HTTP 15๊ฑด, ๊ทธ์ค 50%๊ฐ WebSocket์ ์ ์ํ๊ณ ์ ์์๋น 10๋ถ ๋์ ๋ฉ์์ง 6๊ฑด์ ๋ณด๋ธ๋ค๋ ๊ฐ์ ์ด๋ค.
0 โ 5๋ถ ๋์ peak๊น์ง ์์น โ 5๋ถ ๋์ 0๊น์ง ํ๊ฐ
HTTP peak RPS = 2 ร ์ด๋ฒคํธ ์ฌ์ฉ์ ร 15 รท 600์ด
| ๊ตฌ๋ถ | ์ด๋ฒคํธ ์ฌ์ฉ์ | HTTP peak | ์ต์ข WS ์ฐ๊ฒฐ | ์ฐ๊ฒฐ๋ฅ | inbound ๋ฉ์์ง |
|---|---|---|---|---|---|
| ํ๋จ | 3,151 | 157.5 RPS | 1,575 | 5.25/s | 31.5/s |
| ์ค์ | 3,601 | 180.0 RPS | 1,800 | 6.00/s | 36.0/s |
| ์๋จ | 4,201 | 210.0 RPS | 2,100 | 7.00/s | 42.0/s |
์์ burst๋ 160 โ 180 โ 210 RPS, ํ์ burst๋ 250 โ 300 โ 400 โ 512 RPS๋ก
์คํํ๋ค. WebSocket์ ์ฐ๊ฒฐ ์์ ๋ฉ์์ง ์๋ฅผ HTTP์ ๋ณ๋๋ก ์ฆ๊ฐ์ํจ๋ค.
3. ๋ถํํ ์คํธ ํ๊ฒฝ ์ค์
3.1 ์คํ ํ ํด๋ก์ง
๋ก์ปฌ k6 HTTP ํ๋ก์ธ์ค โโ
โโ Public DNS/EIP โ TLS โ Nginx โ Spring โโฌโ MySQL
๋ก์ปฌ k6 WS ํ๋ก์ธ์ค โโโโ โโ FastAPI/์ธ๋ถ API
V1 EC2 โโ Node Exporter / cAdvisor / Spring metrics / MySQL exporter / Nginx exporter
โ
โโ private scrape โโ ์์ Prometheus + Grafana EC2
- ๋ถํ ๋ฐ์๊ธฐ๋ EC2์ ๋ง๋ค์ง ์๊ณ ๋ก์ปฌ์์ ์คํํ๋ค.
- HTTP์ WebSocket์ ๋ก์ปฌ์์ ๋ณ๋ ํ๋ก์ธ์ค๋ก ์คํํ๋ค.
BASE_URL์https://,WS_URL์wss://public ์ฃผ์๋ง ์ฌ์ฉํ๋ค.target_private_ip๋ Prometheus scrape ์ ์ฉ์ด๋ฉฐ k6 ๋์์ ๋ฃ์ง ์๋๋ค.- ๋ก์ปฌ CPU 60% ๋ฏธ๋ง, swap 0, ์ ๋ก๋ ๋์ญํญ 70% ๋ฏธ๋ง, dropped iterations 0, ๋ชฉํ ์ ๋ฌ๋ฅ 95% ์ด์์ ์ ์งํ๋ค.
3.2 Terraform ์คํ์ ์ฑ ์
loadtest-infra/๋ ๊ธฐ์กด infra/์ ๋ณ๋ state๋ฅผ ์ฌ์ฉํ๋ค. ๋ค์๋ง ๊ด๋ฆฌํ๋ค.
- ์์ Prometheus/Grafana EC2 ๋ฐ EIP
- Prometheus ๊ฒฐ๊ณผ ๋ณด๊ด์ฉ private S3 bucket
- monitoring security group
- ๊ธฐ์กด V1 SG์ exporter port๋ฅผ ์์๋ก ํ์ฉํ๋ ingress rule
- ๊ธฐ์กด V1 EC2์ exporter๋ฅผ ์ค์นยท์ ๊ฑฐํ๋ SSM Command document
์ด ์คํ์ ์ ํ๋ฆฌ์ผ์ด์
์ปจํ
์ด๋๋ฅผ ์์ฑํ์ง ์๋๋ค. ๋์ ์ ํ๋ฆฌ์ผ์ด์
์
๊ธฐ์กด V1 ๋ฐฐํฌ๋ฅผ ์ฌ์ฉํด์ผ ํ๋ค. ํ์ฌ V1 ์ด๋ฏธ์ง ์์ฒ์ infra/ecr.tf์ ECR
repository์ด๋ฉฐ, ์ ํ๋ฆฌ์ผ์ด์
๋ฐฐํฌ๊ฐ ์๋ฃ๋์ด์ผ ํ
์คํธ๋ฅผ ์์ํ ์ ์๋ค.
| ์๋น์ค | ์ด๋ฏธ์ง ์์ฒ |
|---|---|
| Nginx | moyeota/nginx (Amazon ECR) |
| Frontend | moyeota/fe (Amazon ECR) |
| Backend | moyeota/be (Amazon ECR) |
| AI/FastAPI | moyeota/ai (Amazon ECR) |
docker ps์ loadtest-node-exporter์ loadtest-cadvisor๋ง ๋ณด์ด๋ฉด ๊ด์ธก
์ปจํ
์ด๋๋ง ์ค๋น๋ ๊ฒ์ด๋ฉฐ, ๋ถํ ๋์ ์ ํ๋ฆฌ์ผ์ด์
์ ์์ง ์ค๋น๋์ง ์์
์ํ๋ค. ์ ํ๋ฆฌ์ผ์ด์
์ ECR digest, compose.yaml, runtime.env,
release.env๋ฅผ ๊ธฐ์กด ๋ฐฐํฌ ์ ์ฐจ(SSM/CI)๋ก ๋ฐฐํฌํ๋ค. loadtest-infra์
Prometheus/Grafana compose๊ฐ ์ ํ๋ฆฌ์ผ์ด์
์ ๋์ ์คํํ์ง ์๋๋ค.
3.3 ๋ชจ๋ํฐ๋ง ์ปจํ ์ด๋ ์์ฒ
๋ชจ๋ํฐ๋ง EC2์ user data๊ฐ Docker์ Compose๋ฅผ ์ค์นํ๊ณ ๋ค์ ์ด๋ฏธ์ง๋ฅผ pullํ๋ค.
| ์ปจํ ์ด๋ | ์ด๋ฏธ์ง | ์ญํ |
|---|---|---|
| Prometheus | prom/prometheus:v3.13.3 |
5์ด scrape, ์๊ณ์ด ์ ์ฅ |
| Grafana | grafana/grafana:13.2.1 |
๋์๋ณด๋ |
| Node Exporter | quay.io/prometheus/node-exporter:v1.12.1 |
V1 ํธ์คํธ ์งํ |
| cAdvisor | ghcr.io/google/cadvisor:v0.60.5 |
์ปจํ ์ด๋ ์งํ |
Node Exporter์ cAdvisor๋ ๊ธฐ์กด V1 EC2์ SSM ๋ช
๋ น์ผ๋ก ์ค์นํ๋ค. Node
Exporter๊ฐ host network๋ก ์คํ๋์ด docker ps์ ํฌํธ๊ฐ ํ์๋์ง ์๋ ๊ฒ์
์ ์์ด๋ค. cAdvisor๋ 8081:8080์ผ๋ก ๋
ธ์ถ๋๋ค.
3.4 k6 ์ฝ๋์ ์ ๋ ฅ ํ์ผ
| ํ์ผ | ์ฉ๋ |
|---|---|
smoke.js |
๋ค์ฏ ์์ ์ ๊ธฐ๋ฅยท์ธ์ฆยท๊ฒฝ๋ก ํ์ธ |
http-mixed.js |
4:4:3:1:1 ํผํฉ HTTP RPS |
http-operation.js |
ํ๋์ ์์ ๊ทธ๋ฃน๋ง ๊ณ ์ ํด T2ยทT4ยทT5ยทT6ยทT7 ์ธก์ |
event-burst.js |
์ผ๊ฐํ HTTP burst |
hot-row.js |
๋์ผ ํ๊ณผ ๋ถ์ฐ ํ์ ๋ณ๋ ฌ ์ฐ๊ธฐ ๊ฒฝํฉ |
ws-connect.js |
๋ฉ์์ง ์๋ ๋์ WebSocket ์ฐ๊ฒฐ |
ws-message.js |
๊ณ ์ ์ฐ๊ฒฐ ์์์ aggregate ๋ฉ์์ง์จ |
lib/ |
์ ๋ ฅ ๊ฒ์ฆ, ์ธ์ฆ, ํ๊น , ๊ณตํต metric |
์
๋ ฅ์ test-data.example.json์
๋ณต์ฌํด data/test-data.json์ผ๋ก ๋ง๋ ๋ค. ์ค์ ๊ฒฝ๋กยทIDยทpayloadยทtest token์
์
๋ ฅํ๊ณ , data/test-data.json์ Git์ ์ปค๋ฐํ์ง ์๋๋ค. ์ ํํ scenario์
ํ์ group์ REPLACE_๊ฐ ๋จ์ ์์ผ๋ฉด ์คํ ์ ์ ์ค๋จ๋๋ค.
cp loadtest-scenarios/data/test-data.example.json \
loadtest-scenarios/data/test-data.json
mkdir -p loadtest-scenarios/results
์ฐ๊ธฐ ์์ฒญ์ ์ ์ฉ test account์ disposable/idempotent ๋ฐ์ดํฐ๋ฅผ ์ฌ์ฉํ๋ค. 409๋ฅผ ์ฑ๊ณต์ผ๋ก ๋ ๊ฒฝ์ฐ์๋ ์์๋๋ ์ค๋ณตยท์ ์ ์ด๊ณผ ๊ฒฐ๊ณผ์ธ์ง ๋ณ๋ ์ ํฉ์ฑ ๊ฒ์ฆ์ ์ํํด์ผ ํ๋ค.
3.5 ์์ ๋ช ๋ น
๋จผ์ public ๊ฒฝ๋ก๋ก smoke๋ฅผ ์คํํ๋ค.
k6 run \
-e BASE_URL=https://PUBLIC_DOMAIN \
-e DATA_FILE=./data/test-data.json \
-e RUN_ID=smoke-01 \
--summary-export=loadtest-scenarios/results/smoke-01.json \
loadtest-scenarios/smoke.js
๊ธฐ์ค ํผํฉ ๋ถํ๋ ๋ค์๊ณผ ๊ฐ์ด ์คํํ๋ค.
k6 run \
-e BASE_URL=https://PUBLIC_DOMAIN \
-e DATA_FILE=./data/test-data.json \
-e TARGET_RPS=50 \
-e WARMUP=5m \
-e DURATION=10m \
-e RUN_ID=http-50-01 \
--summary-export=loadtest-scenarios/results/http-50-01-summary.json \
--out json=loadtest-scenarios/results/http-50-01-raw.json \
loadtest-scenarios/http-mixed.js
์คํ ์ ํ์ RUN_ID, git/image digest, ๋์ public URL, ๋ก์ปฌ ์ฅ๋น, ์๊ฐ๋,
๋์ WS ์, ํ
์คํธ data ๋ฒ์ ์ ๊ธฐ๋กํ๋ค.
4. ๊ด์ธก ๊ตฌ์กฐ์ ๊ฒ์ฆ๊ฐ
4.1 ์์ง ๊ฒฝ๋ก
| ๊ณ์ธต | ์์ง ๋ฐฉ๋ฒ | ํต์ฌ ๊ฐ |
|---|---|---|
| k6 ๋ก์ปฌ | summary + JSON output | ์ค์ RPS, dropped iterations, p50/p95/p99, status, checks, timeout |
| ํธ์คํธ | Node Exporter | CPU, load, memory available, filesystem, disk I/O, network, FD |
| ์ปจํ ์ด๋ | cAdvisor | container CPU, working set, throttling, network, filesystem |
| Spring | Micrometer /actuator/prometheus |
HTTP p95, Tomcat busy/max, JVM heap/direct, GC, Hikari active/pending |
| MySQL | mysqld-exporter | Threads, row lock wait/deadlock, buffer pool, redo, fsync, disk latency |
| Nginx | exporter ๋๋ access log | active/reading/writing/waiting, upstream time, 4xx/5xx, accept ์คํจ |
| WebSocket | k6 custom + ์๋ฒ ์งํ | open/close/error, handshake, ESTABLISHED/TIME_WAIT, message delivery |
Prometheus ๊ธฐ๋ณธ scrape interval์ 5์ด๋ค. Prometheus Targets ํ์ด์ง ๋๋ ๋ค์ PromQL๋ก exporter ์ํ๋ฅผ ๋จผ์ ํ์ธํ๋ค.
up{job=~"v1-node|v1-cadvisor|v1-spring|v1-mysql|v1-nginx"}
๊ด์ธก endpoint๊ฐ ์๋ ๊ณ์ธต์ ์์ธ ๋ถ์์ด ์๋๋ผ ๊ฒฐ๊ณผ ํ์ธ๋ง ๊ฐ๋ฅํ๋ค. ํนํ SpringยทMySQLยทNginx exporter๋ ์๊ฒฉ ์ฆ๋ช ๊ณผ ์๋น์ค ์ค์ ์ด ํ์ํ๋ฏ๋ก Terraform state์ ๋น๋ฐ๋ฒํธ๋ฅผ ๋ฃ์ง ์๊ณ ๋ณ๋ ๊ตฌ์ฑํ๋ค.
4.2 ๊ณตํต ์ค๋จ ์กฐ๊ฑด
๋ค์ ์ค ํ๋๋ฉด ํด๋น ๋จ๊ณ๋ฅผ ์ฆ์ ์ค๋จํ๊ณ ์ํ๋ฅผ ๋ณด์กดํ๋ค.
- 5xx ๋๋ timeout์ด 2๋ถ ์ด์ 5% ์ด๊ณผ
- OOM, container restart, disk full
- ์ข์ ์ด๊ณผยท์์ฌ ์ข์ ์์ยท์ค๋ณต ์น์ธยท๋ฉ์์ง ์ ์ค/์ค๋ณต/์์ ์ค๋ฅ
- k6 ๋ชฉํ ์ ๋ฌ๋ฅ 95% ๋ฏธ๋ง ๋๋ dropped iterations ๋ฐ์
- DB๊ฐ ๋ณต๊ตฌ ์์ ์ ์๊ตฌํ๋ ๋น์ ์ ์ํ
5. ์๋น์ค ๋ณ๋ชฉ ๊ตฌ๊ฐ๋ณ ์๋๋ฆฌ์ค
๋ชจ๋ ์๋๋ฆฌ์ค๋ ํ ๋ฒ์ ํ ์ถ๋ง ๋ฐ๊พผ๋ค. ๊ฐ ๋จ๊ณ๋ ๊ธฐ๋ณธ์ ์ผ๋ก 5๋ถ warm-up โ 10๋ถ measure โ 3ํ ๋ฐ๋ณต์ด๋ฉฐ, ์ธก์ ์ค์๋ ๊ธฐ์กด V1 ์ ํ๋ฆฌ์ผ์ด์ ์ ์ด๋ฏธ์งยทDB snapshotยทCPU creditยทexporter ์ํ๋ฅผ ๊ณ ์ ํ๋ค.
T2. Spring ์์ฒญ ์ฒ๋ฆฌ์ JVM
๋ณ๋ชฉ ์ ์
Nginx์ DB๊ฐ ์ฌ์ ๋ก์ด๋ฐ Spring์ Tomcat thread, JVM CPU/GC, heap/direct memory, JSON serialization ๋๋ container throttling์ด ๋จผ์ ํฌํ๋๋ ํ๋ฆ์ด๋ค.
k6 HTTPS โ Nginx โ Spring Controller โ service/serialization โ response
๋ถํ ์ค๊ณ
- DBยท์ธ๋ถ API๋ฅผ ์ฌ์ฉํ์ง ์๋ ๊ฐ๋ฒผ์ด
lightgroup์ผ๋ก Spring ์ฒ๋ฆฌ ๊ธฐ์ค์ ์ ์ธก์ ํ๋ค. - ๊ฐ์ ์กฐ๊ฑด์์ ์ค์
list,detail,congestion,write,auth๋ฅผ ๊ฐ๊ฐhttp-operation.js๋ก ์ธก์ ํ๋ค. - 40 โ 46 โ 53 RPS๋ก ๋ฒค์น๋งํฌ ์ฌํ ํ 25 โ 50 โ 75 โ 100 โ 150 โ 200 โ 300 โ 400 โ 512 RPS๋ก ์ฉ๋์ ํ์ํ๋ค.
http_req_durationp95/p99์ Tomcat busy/max, JVM CPUยทheapยทdirect, allocation rate, GC pause, process CPU, context switch, cgroup throttling์ ๊ฐ์ ์๊ฐ์ถ์์ ๊ธฐ๋กํ๋ค.
์์:
k6 run \
-e BASE_URL=https://PUBLIC_DOMAIN \
-e DATA_FILE=./data/test-data.json \
-e REQUEST_GROUP=light \
-e TARGET_RPS=50 \
-e WARMUP=5m -e DURATION=10m \
-e RUN_ID=t2-light-50-01 \
loadtest-scenarios/http-operation.js
ํ์
DBยท์ธ๋ถ ํธ์ถ ์งํ๊ฐ ์์ ์ ์ธ๋ฐ Tomcat busy/max์ CPU๊ฐ ํจ๊ป ํฌํ๋๋ฉด Spring thread/CPU/์ง๋ ฌํ ๊ฒฝ๋ก๊ฐ 1์ฐจ ๋ณ๋ชฉ์ด๋ค. GC pause์ heap๋ง ์ฆ๊ฐํ๋ฉด ๊ฐ์ฒด ์์ฑยท์๋ต ํฌ๊ธฐยทheap sizing์, throttling์ด ์ฆ๊ฐํ๋ฉด ์ปจํ ์ด๋ quota์ EC2 ํฌ๊ธฐ๋ฅผ ๋จผ์ ๊ฒํ ํ๋ค.
T4. ์์ธ ์กฐํ, N+1๊ณผ ์ง๋ ฌํ
๋ณ๋ชฉ ์ ์
์์ธ ์กฐํ ํ ๊ฑด์ด ์ฐธ์ฌ์ยท์ ์ฐยท์ฑํ ์ด๋ ฅ์ ์ฌ๋ฌ query๋ก ์ฝ๊ฑฐ๋ ํฐ JSON์ผ๋ก ์ง๋ ฌํํ๋ฉด์ DB query ์, response bytes, Spring CPU/GC๊ฐ ์ฆ๊ฐํ๋ ํ๋ฆ์ด๋ค.
๋ถํ ์ค๊ณ
requests.detail์ ๋ค์ fixture๋ฅผ ์ฌ๋ฌ entry๋ก ์ค๋นํ๊ณ REQUEST_GROUP=detail
๋ก ๊ณ ์ ํ๋ค.
- ์กด์ฌํ๋ ํ: ์ฐธ์ฌ์ 0๋ช ยท์์ยทํฐ ๋ชฉ๋ก
- ์กด์ฌํ์ง ์๋ ํ: 404๊ฐ ์ ์์ธ์ง ๋ช ์
- ์์/์ค๊ฐ/ํฐ ์ฑํ ยท์ ์ฐ ์ด๋ ฅ
- ๋์ผ ID ๋ฐ๋ณต๊ณผ ์ฌ๋ฌ ID ๋ถ์ฐ
๊ฐ fixture๋ฅผ ๊ฐ์ RPS์์ ๋ฐ๋ณตํ๊ณ captureResponseBody๋ฅผ ํ์ํ ๊ทธ๋ฃน์๋ง
์ผ์ response_bytes์ JSON assertion์ ์์งํ๋ค.
k6 run \
-e BASE_URL=https://PUBLIC_DOMAIN \
-e DATA_FILE=./data/test-data.json \
-e REQUEST_GROUP=detail \
-e TARGET_RPS=50 -e WARMUP=5m -e DURATION=10m \
-e RUN_ID=t4-detail-large-50-01 \
loadtest-scenarios/http-operation.js
์ธก์ ๊ฐ๊ณผ ํ์
- HTTP p50/p95/p99, status๋ณ ์ค๋ฅ์จ, response bytes
- request๋น DB query count ๋ฐ SQL ํฉ๊ณ์๊ฐ
- Spring serialization ์๊ฐ, CPU, allocation, GC
- Hikari active/usage/acquire/pending
DB ์๊ฐ๊ณผ query ์๊ฐ ํจ๊ป ์ฆ๊ฐํ๋ฉด N+1ยท์ธ๋ฑ์คยทfetch ์ ๋ต์ ์ฐ์ ํ์ธํ๋ค.
DB ์๊ฐ์ ์์ ์ ์ธ๋ฐ ์ ์ฒด ์๋ต๊ณผ response_bytes๋ง ์ฆ๊ฐํ๋ฉด ๊ฐ์ฒด ๊ทธ๋ํ์
JSON ์ง๋ ฌํยท์๋ต ํฌ๊ธฐ๊ฐ ๋ณ๋ชฉ์ด๋ค. ์๋ ID๋ง ๋๋ฆฌ๋ฉด ์์ธ ์ฒ๋ฆฌ๋ ๊ฒ์ฆ query๋ฅผ
๋ณ๋๋ก ํ์ธํ๋ค.
T5. ํผ์ก๋ ์ธ๋ถ ํธ์ถ
๋ณ๋ชฉ ์ ์
ํผ์ก๋ ๊ณ์ฐ ์์ฒญ์ด Spring์์ FastAPI/์ธ๋ถ LLM์ ๋๊ธฐ ํธ์ถํ๊ณ , ์ธ๋ถ ์ง์ฐ์ด Tomcat threadยทoutbound poolยทHikari ๋๋ transaction ์ ์ ๋ก ์ ํ๋๋ ํ๋ฆ์ด๋ค.
HTTP โ Spring โ outbound connection pool โ FastAPI/์ธ๋ถ API โ Spring response
๋ถํ ์ค๊ณ
requests.congestion์ ๋์ผ spot๊ณผ 10ยท100๊ฐ spot ๋ถ์ฐ fixture๋ฅผ ์ค๋นํ๋ค.- ์ธ๋ถ ์์กด์ฑ์ ํ ์คํธ ํ๋กํ์ผ์ ์ ํ๋ฆฌ์ผ์ด์ ์ค์ ๋๋ ๋ณ๋ stub์ผ๋ก ๊ณ ์ ํ๋ค. ์ง์ฐ์ 50ยท200ยท1,000ยท3,000ms, ์ค๋ฅ์จ์ 0ยท1ยท5ยท20%๋ก ๋ถ๋ฆฌํ๋ค.
- ๊ฐ profile์์
http-operation.js์REQUEST_GROUP=congestion์ ๋์ผ RPS๋ก ์คํํ๋ค. ์ง์ฐยท์ค๋ฅ๋ฅผ k6๊ฐ ์์๋ก ์ฃผ์ ํ๋ ๊ฒ์ด ์๋๋ฏ๋ก, ํด๋น profile์ ํต์ ํ ์ ์์ผ๋ฉด ์์ธ ๋ถ๋ฆฌ ํ ์คํธ๋ก ๊ฐ์ฃผํ์ง ์๋๋ค. - retry๊ฐ ํ์ฑํ๋์ด ์์ผ๋ฉด retry ํ์์ backoff๋ฅผ ๊ณ ์ ํ๊ณ ๋ณ๋ ๊ฒฐ๊ณผ๋ก ๊ธฐ๋กํ๋ค.
์ธก์ ๊ฐ๊ณผ ํ์
- Spring HTTP p95/p99, Tomcat busy/max, request queue
- outbound active/pending, timeout, retry, FastAPI worker queue
- Hikari active/pending ๋ฐ transaction duration
- ์ธ๋ถ ์ค๋ฅ์จ๊ณผ ์ฌ์ฉ์ ์๋ต ์ค๋ฅ์จ์ ์ ํ ๋น์จ
์ธ๋ถ ์ง์ฐ์ Tomcatยทoutbound pending์ด ๋น๋กํ๊ณ DB๋ ํจ๊ป ์ ์ ๋๋ฉด ๋๊ธฐ ํธ์ถ ๋๋ transaction ๋ฒ์๊ฐ ๋์ ๊ฒ์ด๋ค. ์ธ๋ถ ์ค๋ฅ๋ณด๋ค ์ฌ์ฉ์ ์ค๋ฅ๊ฐ ํฌ๋ฉด retry stormยทfallbackยทtimeout ์ฒ๋ฆฌ๋ฅผ ๋ณ๋๋ก ํ๋จํ๋ค.
T6. ํผ์ก๋ ์ต์ ๊ฐ upsert์ ์ด๋ ฅ ์ ์ฅ
๋ณ๋ชฉ ์ ์
์ธ๋ถ ๊ณ์ฐ ๊ฒฐ๊ณผ๋ฅผ ์ต์ ๊ฐ row์ upsertํ๊ฑฐ๋ ์ด๋ ฅ row๋ก insertํ ๋ ๋์ผ spot์ row lock, redo/fsync, ์ธ๋ฑ์ค์ Hikari ๋๊ธฐ๊ฐ ์ฆ๊ฐํ๋ ํ๋ฆ์ด๋ค.
๋ถํ ์ค๊ณ
์ธ๋ถ ๊ฒฐ๊ณผ๋ฅผ ๊ณ ์ ํ ํ ์คํธ profile์์ ๋ค์ ๋ endpoint group์ ๋ณ๋๋ก ๋ง๋ ๋ค.
congestionWriteLatest: ์ต์ ๊ฐ upsert๋ง ์ํcongestionWriteHistory: ์ต์ ๊ฐ upsert + ์ด๋ ฅ insert ์ํ
๊ฐ group์ ๋์ผ spot, 10๊ฐ spot, 100๊ฐ spot fixture๋ฅผ ์ค๋นํ๊ณ
http-operation.js๋ฅผ 1 โ 5 โ 10 โ 20 โ 40 โ 80 writes/s๋ก ์คํํ๋ค.
์ต์ ๊ฐ๊ณผ ์ด๋ ฅ ์ ์ฅ์ ๋์์ ์ผ์ง ์๊ณ ๊ฐ๊ฐ ์ธก์ ํด์ผ ์ธ๋ถ ํธ์ถ ์ํฅ์
์ ๊ฑฐํ ์ ์๋ค.
์ธก์ ๊ฐ๊ณผ ํ์
Innodb_row_lock_time, current waits, deadlock- Threads_running, MySQL CPU, buffer pool hit
- redo bytes, fsync, dirty page, EBS queue/await
- Hikari pending, transaction duration, write p95/p99
๋์ผ spot์์๋ง ๊ธ๊ฒฉํ ๋๋น ์ง๋ฉด hot-row lock, ๋ชจ๋ spot์์ ๋๋น ์ง๋ฉด redoยทI/Oยท์ธ๋ฑ์ค ๋น์ฉ์ผ๋ก ๋ถ๋ฅํ๋ค. deadlockยท์ค๋ณต ์ด๋ ฅยท์ต์ ๊ฐ ์ ์ค์ latency์ ๋ฌด๊ดํ๊ฒ ์คํจ๋ค.
T7. ์ฐธ์ฌ ์์ฒญ ์ ์ฅ ๊ธฐ์ค์
๋ณ๋ชฉ ์ ์
์ข์ ์ ์ ๊ฒฝํฉ์ ์ ์ธํ๊ณ ์๋ก ๋ค๋ฅธ ํ์ ์ฐธ์ฌ ์์ฒญ์ ๋ถ์ฐํ์ ๋์ ์์ insert ์ฒ๋ฆฌ๋์ ๊ตฌํ๋ ๋จ๊ณ๋ค.
๋ถํ ์ค๊ณ
requests.write์ ์๋ก ๋ค๋ฅธ ํ ID์ ์ฌ์ฉ์ยท๋ฉฑ๋ฑ request ID๋ฅผ ์ถฉ๋ถํ ์ค๋นํ๋ค.
http-operation.js์์ ์ฐ๊ธฐ group๋ง ๊ณ ์ ํ๊ณ 1 โ 5 โ 10 โ 20 โ 40 โ 80
writes/s๋ฅผ ์คํํ๋ค.
k6 run \
-e BASE_URL=https://PUBLIC_DOMAIN \
-e DATA_FILE=./data/test-data.json \
-e REQUEST_GROUP=write \
-e TARGET_RPS=20 -e WARMUP=5m -e DURATION=10m \
-e RUN_ID=t7-write-20-01 \
loadtest-scenarios/http-operation.js
์ธก์ ๊ฐ๊ณผ ํ์
์ฑ๊ณตยท์ค๋ณตยท์ ์ฝ์กฐ๊ฑด ์ค๋ฅ๋ฅผ status์ business result๋ก ๋ถ๋ฆฌํ๊ณ insert p95/p99, Hikari pending, MySQL CPU/lock/I/O, commitยทredo๋ฅผ ๊ธฐ๋กํ๋ค. ๋ถ์ฐ insert๊ฐ ์์ ์ ์ธ๋ฐ ๋์ผ ํ ์น์ธ๋ง ์ ํ๋๋ฉด ์ผ๋ฐ ์ฐ๊ธฐ ์ฒ๋ฆฌ๋๊ณผ ์ข์ hot-row ๊ฒฝํฉ์ ํผ๋ํ์ง ์๋๋ค.
T8. ์ธ๊ธฐ ํ ์น์ธ hot-row
๋ณ๋ชฉ ์ ์
๋์ผ ํ์ ์ ์/์น์ธ row๋ฅผ ์ฌ๋ฌ ์์ฒญ์ด ๋์์ ๊ฐฑ์ ํ๋ฉด์ DB row lock, deadlock, Hikari ๋๊ธฐ์ ์ ํฉ์ฑ ์๋ฐ์ด ๋ฐ์ํ๋ ํ๋ฆ์ด๋ค.
๋ถํ ์ค๊ณ
hot-row.js๊ฐ ํ round๋ง๋ค http.batch๋ก ๋์ผ ์์ ์ ์์ฒญ์ ๋ฐํํ๊ณ ,
round ๋ค hotRowVerify๋ฅผ ํธ์ถํ๋ค.
- ๋์ผ ํ:
REQUEST_GROUP=hotRowSame - ๋์กฐ๊ตฐ:
REQUEST_GROUP=hotRowDistributed - ๋์์ฑ:
CONCURRENCY=2,5,10,20,50,100 - ๊ธฐ๋ณธ round: 3ํ, round ๊ฐ๊ฒฉ 10์ด
- ์์ status๋ ์ค์ ๋น์ฆ๋์ค ๊ฒฐ๊ณผ๋ง ํ์ฉํ๊ณ , 409๋ฅผ ํ์ฉํ๋ฉด ์ค๋ณต/์ ์ ์ด๊ณผ ๊ฒฐ๊ณผ์์ ๋ณ๋ ๊ธฐ๋ก
k6 run \
-e BASE_URL=https://PUBLIC_DOMAIN \
-e DATA_FILE=./data/test-data.json \
-e REQUEST_GROUP=hotRowSame \
-e VERIFY_GROUP=hotRowVerify \
-e CONCURRENCY=20 -e ROUNDS=3 -e ROUND_PAUSE=10s \
-e RUN_ID=t8-same-20-01 \
loadtest-scenarios/hot-row.js
hotRowVerify.assertions์ JSON path์ ์ ์ ๊ฐ์ ์ค์ API ์๋ต์ ๋ง๊ฒ
์์ ํ๋ค. ์์ฌ ์ข์ ์์, ์น์ธ ์ ์ด๊ณผ, ์ค๋ณต ์น์ธ, deadlock์ ๋จ ํ ๊ฑด์ด์ด๋
์คํจ๋ค. ๋์ผ ํ๊ณผ ๋ถ์ฐ ํ์ latency ์ฐจ์ด๊ฐ row lock์ ์ฆ๊ฑฐ๊ฐ ๋๋ค.
T9. WebSocket ์ฐ๊ฒฐ ์์ฒด
๋ณ๋ชฉ ์ ์
๋ฉ์์ง๋ฅผ ๋ณด๋ด์ง ์๊ณ WebSocket handshake, Nginx proxy, Spring session, file descriptor, heap/direct memory๊ฐ ๋์ ์ฐ๊ฒฐ ์์ ๋ฐ๋ผ ํฌํ๋๋ ํ๋ฆ์ด๋ค.
๋ถํ ์ค๊ณ
ws-connect.js๋ฅผ local process์์ ์คํํ๋ค.
- ์์ ์ฌํ: 1,575 โ 1,800 โ 2,100 connections
- ์ฉ๋ ํ์: 500 โ 1,000 โ 1,500 โ 3,000 โ 5,000 connections
- ์ฐ๊ฒฐ๋ฅ : 5.25 โ 6 โ 7 โ 10 โ 20 โ 50 connections/s
- ๊ฐ ๋จ๊ณ idle hold 30๋ถ, ramp-down 1๋ถ
k6 run \
-e WS_URL=wss://PUBLIC_DOMAIN \
-e DATA_FILE=./data/test-data.json \
-e TARGET_CONNECTIONS=1800 \
-e CONNECT_RATE=6 \
-e HOLD_DURATION=30m \
-e RUN_ID=t9-ws-1800-01 \
loadtest-scenarios/ws-connect.js
์ธก์ ๊ฐ๊ณผ ํ์
handshake p95/p99ยท์ฑ๊ณต๋ฅ , k6์ open/close/error, Nginx active/reading/writing/ waiting, Spring FDยทESTABLISHED/TIME_WAIT, heap/direct memoryยทGCยทheartbeat, host/container CPU๋ฅผ ๊ธฐ๋กํ๋ค. ๋ก์ปฌ file descriptorยทCPUยท๋คํธ์ํฌ๊ฐ ๋จผ์ ํฌํ๋๋ฉด ์๋ฒ ํ๊ณ๋ก ํ์ ํ์ง ๋ง๊ณ generator headroom ์คํจ๋ก ํ์ํ๋ค.
T10. WebSocket ๋ฉ์์งยทfan-outยท์ ์ฅ
๋ณ๋ชฉ ์ ์
๊ณ ์ ๋ WebSocket ์ฐ๊ฒฐ์์ inbound message๊ฐ Spring fan-out, outbound delivery, DB commit๊ณผ ๊ฒฐํฉ๋์ด REST์ ๊ณต์ ์์์ ์๋ฐํ๋ ํ๋ฆ์ด๋ค.
๋ถํ ์ค๊ณ
ws-message.js์์ ์ฐ๊ฒฐ ์๋ฅผ ๊ณ ์ ํ๊ณ aggregate MESSAGE_RATE๋ฅผ ๋ณ๊ฒฝํ๋ค.
- ์์ inbound: 31.5 โ 36 โ 42 msg/s
- ์ฉ๋ ํ์: 10 โ 20 โ 50 โ 100 โ 300 msg/s
- ์ฐ๊ฒฐ ์: 1,575ยท1,800ยท2,100 ๋ฐ ํ์ ์ 3,000
- ๋ฐฉ ๋ถํฌ: ํ ๋ฐฉ ์ง์ค, ์ฌ๋ฌ ๋ฐฉ ๋ถ์ฐ
- message profile: ์ ์ฅ ์๋ heartbeat, DB ์ ์ฅ chat message
- fan-out: ํ๊ท ์์ ์ 1ยท3ยท9๋ช
k6 run \
-e WS_URL=wss://PUBLIC_DOMAIN \
-e DATA_FILE=./data/test-data.json \
-e TARGET_CONNECTIONS=1800 \
-e MESSAGE_RATE=36 \
-e CONNECTION_RAMP=5m -e DURATION=10m \
-e RUN_ID=t10-message-36-01 \
loadtest-scenarios/ws-message.js
๋ฉ์์ง payload์๋ runId, VU, iteration, timestamp๋ฅผ ํฌํจํด ์์ ์ ์คยท์ค๋ณตยท
์์ ์ค๋ฅ๋ฅผ ์๋ณํ๋ค. end-to-end delivery p95/p99, sent/received/lost/duplicate,
outbound deliveries/s, Spring CPU, network, DB commit, Hikari pending์ ํจ๊ป
๊ธฐ๋กํ๋ค. ๋ฉ์์ง ์ ์ฅ ์์๋ง REST p95๊ฐ ์
ํ๋๋ฉด ์ ์ฅ ๊ฒฝ๋ก ๋น๋๊ธฐํ ๋๋
DB write path ๋ถ๋ฆฌ๋ฅผ ์ฐ์ ๊ฒํ ํ๋ค.
T11. RESTยทWebSocket ๊ณต์ ์์ ๊ฐ์ญ
๋ณ๋ชฉ ์ ์
WebSocket connection/session/fan-out์ด REST์ ๊ฐ์ Spring process, heap, thread, Hikari, host network๋ฅผ ์ฌ์ฉํด HTTP p95 ๋๋ ์ค๋ฅ์จ์ ์ ํ์ํค๋ ํ๋ฆ์ด๋ค.
๋ถํ ์ค๊ณ
- WebSocket ์์ด
http-mixed.js๋ฅผTARGET_RPS=50์ผ๋ก ์คํํด control์ ๋ง๋ ๋ค. - ๋ณ๋ ๋ก์ปฌ process์์
ws-connect.js๋ฅผ ์์ํ๊ณ hold ๋จ๊ณ์ ์ง์ ์ํจ๋ค. - WS ์ฐ๊ฒฐ์ 1,575ยท1,800ยท2,100ยท3,000ยท5,000์ผ๋ก ๊ณ ์ ํ ์ํ์์ ๋์ผํ HTTP ํผํฉ ๋ถํ๋ฅผ ๋ฐ๋ณตํ๋ค.
- ํ์ํ๋ฉด T10์ 36 msg/s๋ฅผ ์ถ๊ฐํด ์ฐ๊ฒฐ๋ง์ ๊ฐ์ญ๊ณผ ๋ฉ์์ง fan-out ๊ฐ์ญ์ ๋ถ๋ฆฌํ๋ค.
# ํฐ๋ฏธ๋ 1: WS hold
k6 run -e WS_URL=wss://PUBLIC_DOMAIN \
-e DATA_FILE=./data/test-data.json \
-e TARGET_CONNECTIONS=1800 -e CONNECT_RATE=6 -e HOLD_DURATION=30m \
-e RUN_ID=t11-ws-1800-01 loadtest-scenarios/ws-connect.js
# ํฐ๋ฏธ๋ 2: ๊ฐ์ ์๊ฐ๋ REST
k6 run -e BASE_URL=https://PUBLIC_DOMAIN \
-e DATA_FILE=./data/test-data.json \
-e TARGET_RPS=50 -e WARMUP=5m -e DURATION=10m \
-e RUN_ID=t11-http-with-ws-1800-01 loadtest-scenarios/http-mixed.js
ํ์
WS๊ฐ ์๋ control ๋๋น REST p95๊ฐ 20% ์ด์ ์ ํ๋๊ณ Spring CPU/heap/GC, Tomcat busy, Hikari ๋๋ network ์๊ด๊ด๊ณ๊ฐ ํ์ธ๋๋ฉด ๊ณต์ process/resource ๋ถ๋ฆฌ๊ฐ ์ฐ์ ์ด๋ค. ๋ก์ปฌ generator ์งํ๊ฐ ๋จผ์ ํฌํ๋ ๊ฒฝ์ฐ์๋ ๊ฒฐ๊ณผ๋ฅผ ์๋ฒ ํ๊ณ๋ก ์ฌ์ฉํ์ง ์๋๋ค.
6. ๊ฒฐ๊ณผ๋ฌผ๊ณผ ํ์ฅ ๋ฐฉํฅ ๊ฒฐ์
๊ฐ ์คํ์ ๋ค์์ ๋จ๊ธด๋ค.
- scenario,
RUN_ID, ๋ชฉํ/์ค์ RPS ๋๋ WS ์ฐ๊ฒฐยท๋ฉ์์ง์จ - p50/p95/p99, status๋ณ ์ค๋ฅ์จ, checks, timeout, dropped iterations
- ์ต์ด SLO ์๋ฐ ์๊ฐ๊ณผ
C_knee,C_safe - ํธ์คํธยท์ปจํ ์ด๋ยทSpringยทMySQLยทNginx ์งํ์ ๋์ผ ์๊ฐ ๋ฒ์
- ์ข์ยท๋ฉ์์ง ์ ํฉ์ฑ ๊ฒฐ๊ณผ
- ๋ก์ปฌ generator CPU/memory/FD/network headroom
- k6 summary/raw JSON, Grafana screenshot, image digest์ DB snapshot ์ ๋ณด
ํ์ ์์๋ ๋ค์๊ณผ ๊ฐ๋ค.
| ๊ด์ธก ์ฆ๊ฑฐ | ์ฐ์ ๊ฒํ ํ ํ์ฅ ๋ฐฉํฅ |
|---|---|
| Host CPUยทcontainer throttling์ด ๋จผ์ ํฌํ, DB ์ฌ์ | EC2 ํฌ๊ธฐ์ container quota ์ฌ๋ฐฐ๋ถ |
| MySQL CPUยทlockยทI/O์ Hikari pending์ด ํจ๊ป ์ฆ๊ฐ | query/transaction ๊ฐ์ ํ DB ๋ถ๋ฆฌ ๋๋ RDS |
| ์ธ๋ถ API ์ง์ฐ์ Tomcatยทoutbound pending์ด ๋น๋ก | timeout, cache, single-flight, bulkhead, ๋น๋๊ธฐํ |
| WebSocket ์ฐ๊ฒฐ๋ง์ผ๋ก heapยทFD๊ฐ ํฌํ | WebSocket gateway ๋๋ process ๋ถ๋ฆฌ |
| ๋ฉ์์ง ์ ์ฅ ์์๋ง REST๊ฐ ์ ํ | ์ฑํ ์ ์ฅ ๋น๋๊ธฐํ ๋๋ DB write path ๋ถ๋ฆฌ |
| ๋์ผ row์์๋ง ์ง์ฐ ๊ธ์ฆยทdeadlock | Redis ์์ ์นด์ดํฐ/๋ฉฑ๋ฑํค ๋ฑ hot-row ๊ตฌ์กฐ ๋ณ๊ฒฝ |
C_safe < ๊ณํ ํผํฌ ร ์ด์ ์ฌ์ ์จ |
์ต์ ํ ๋๋ ์์ง/์ํ ํ์ฅ ํ ๋์ผ ์กฐ๊ฑด ์ฌ์ํ |
์ต์ข ๋ณด๊ณ ์๋ ์๋๋ฆฌ์ค๋ณ 3ํ ๋ฐ๋ณต์ ์ค์๊ฐ๊ณผ ๋ณ๋ํญ์ ํจ๊ป ์ ์ํ๊ณ , ๋ถํ ๋ฐ์๊ธฐ ํ๊ณ๋ก ์ธํด ๋ชฉํ๋ฅผ ๋ฌ์ฑํ์ง ๋ชปํ ์คํ์ ์๋ฒ ์ฉ๋ ๊ณ์ฐ์์ ์ ์ธํ๋ค.