
๐ก ์ด๋ฉ์ผ ์ธ์ฆ ์๋ ๊ฐ์ , ์ด๋ป๊ฒ ์ธก์ ํด์ผ ํ ๊น?
์ง๋๋ฒ ๊ธ์์๋ ์ด๋ฉ์ผ ์ธ์ฆ์ Map ๋ฐฉ์์ผ๋ก ๊ด๋ฆฌํ์ ๋์ ๋ฌธ์ ์ ๊ณผ Redis๋ก ์ ํํ๋ฉด์ ์ป์ ์ฑ๋ฅ ํฅ์์ ๋ํด ๋ค๋ค๋ค.
(ํน์ ๋ชป ๋ดค๋ค๋ฉด ์ด์ ๊ธ์ ๋จผ์ ๋ณด๊ณ ์ค๋ ๊ฑธ ์ถ์ฒํ๋ค! ๐ง)
ํ์ง๋ง Redis๋ก ๋ฐ๊ฟจ๋ค๊ณ ํด์ ๋์ด ์๋๋ค. ์ ๋ง ์ฑ๋ฅ์ด ํฅ์๋์๋์ง, ๋ณ๋ชฉ์ ์๋์ง ๊ฐ๊ด์ ์ธ ๋ฐ์ดํฐ๊ฐ ํ์ํ๋ค.
๊ทธ๋์ ์ด๋ฒ์๋ "Grafana k6"๋ผ๋ ๊ฐ๋ ฅํ ์ฑ๋ฅ ํ
์คํธ ๋๊ตฌ๋ฅผ ์ฌ์ฉํ์ฌ ์ด๋ฉ์ผ ์ธ์ฆ ๋ก์ง์ ์ ๋ฐํ๊ฒ ๋ถ์ํด๋ดค๋ค!
์ด๋ฉ์ผ ์ธ์ฆ ๋ก์ง์ ๊ฐ์ ํ ๋, ๋จ์ํ "์ฒด๊ฐ ์๋๊ฐ ๋นจ๋ผ์ก๋ค!"๋ผ๊ณ ๋งํ ์๋ ์๋ค.
์ผ๋ง๋ ๋นจ๋ผ์ก๋์ง?
๋ถํ๊ฐ ๊ฑธ๋ฆฌ๋ฉด ์๋๊ฐ ์ผ๋ง๋ ์ ํ๋๋์ง?
์์ํ์ง ๋ชปํ ์๋ฌ๊ฐ ๋ฐ์ํ๋์ง?
์ด๋ฐ ๊ฒ๋ค์ ์์น๋ก ํ์ธํด์ผ ์ ๋๋ก ๋ ๊ฐ์ ์ด๋ผ๊ณ ํ ์ ์๋ค. ๐
์ฑ๋ฅ ํ ์คํธ ํด์ JMeter, Locust, Gatling ๋ฑ ๋ค์ํ๋ฐ, ๋๋ k6๋ฅผ ์ ํํ๋ค.
๊ฐ๊ฒฐํ ์คํฌ๋ฆฝํธ - JMeter์ฒ๋ผ ๋ณต์กํ GUI ์์ด JavaScript ๊ธฐ๋ฐ์ ์ฝ๋๋ก ์ฝ๊ฒ ์์ฑ ๊ฐ๋ฅ โ๏ธ
๊ณ ์ฑ๋ฅ - ๊ฐ๋ฒผ์ด Go ์ธ์ด๋ก ๊ตฌํ๋์ด ์์ฒ ๊ฐ์ ์์ฒญ์ ๊ฐ๋ณ๊ฒ ์ฒ๋ฆฌ ๐
์ค์๊ฐ ๊ฒฐ๊ณผ ๋ถ์ - ์คํ ์ค์๋ Grafana ๋์๋ณด๋์ ์ฐ๋ํ์ฌ ๋ฐ์ดํฐ ์๊ฐํ ๊ฐ๋ฅ ๐
CI/CD ์ฐ๋ ์ฉ์ด - GitHub Actions ๋ฑ๊ณผ ์ฝ๊ฒ ์ฐ๊ฒฐํ ์ ์์ด ์๋ํ๋ ์ฑ๋ฅ ํ ์คํธ ๊ฐ๋ฅ โก
๊ฒฐ๋ก : ๊ฐํธํ๋ฉด์๋ ๊ฐ๋ ฅํ ์ฑ๋ฅ ํ
์คํธ๋ฅผ ํ ์ ์๋ "k6"๊ฐ ์ด๋ฉ์ผ ์ธ์ฆ ๋ก์ง ๊ฐ์ ์ ์ต์ ์ด์๋ค!
๐ Mac (Homebrew ์ฌ์ฉ)
brew install k6
๐ Linux (Debian/Ubuntu)
sudo gpg -k | grep cloudflare
curl -fsSL https://dl.k6.io/key.gpg | sudo gpg --dearmor -o /etc/apt/trusted.gpg.d/k6.gpg
sudo apt update && sudo apt install k6
๐ Windows (Chocolatey ์ฌ์ฉ)
choco install k6
์ค์น๊ฐ ์๋ฃ๋์์ผ๋ฉด, k6 version ๋ช ๋ น์ด๋ก ์ ์์ ์ผ๋ก ์ค์น๋์๋์ง ํ์ธํ์!
k6 version
# k6 v0.56.0 (commit/50afb99947, go1.23.4, windows/amd64)
k6 ์คํฌ๋ฆฝํธ๋ JavaScript ๊ธฐ๋ฐ์ผ๋ก ์์ฑ๋๋ค. ๋๋ ์ด๋ฉ์ผ ์ธ์ฆ API๋ฅผ ๋ถํ ํ ์คํธํ ์ ์๋๋ก ์๋์ฒ๋ผ ์์ฑํ๋ค. ๐
import http from 'k6/http';
import { check, sleep, Trend } from 'k6';
let sendMailTrend = new Trend('send_mail_duration');
let verifyCodeTrend = new Trend('verify_code_duration');
export let options = {
vus: 2, // ๋์์ ์คํ๋ ์ฌ์ฉ์ ์ (SMTP ์๋ฒ ๋ถํ ๋ฐฉ์ง)
duration: '1m', // 1๋ถ ๋์ ํ
์คํธ ์คํ
};
export default function () {
let uniqueEmail = `test+${__VU}@kumoh.ac.kr`;
let sendStart = new Date();
let sendRes = http.post('http://localhost:8080/register/mail', JSON.stringify({
username: uniqueEmail
}), { headers: { 'Content-Type': 'application/json' } });
let sendDuration = new Date() - sendStart;
sendMailTrend.add(sendDuration);
console.log(`๐ฉ Send API Response: ${sendRes.status} - ${sendRes.body}`);
check(sendRes, { 'โ
send status is 200': (r) => r.status === 200 });
sleep(Math.random() * 5 + 3); // 3~8์ด ๋๋ค ๋๊ธฐ
let verifyStart = new Date();
let verifyRes = http.post('http://localhost:8080/register/mail/verification', JSON.stringify({
username: uniqueEmail,
mailCode: 123456
}), { headers: { 'Content-Type': 'application/json' } });
let verifyDuration = new Date() - verifyStart;
verifyCodeTrend.add(verifyDuration);
console.log(`๐ Verify API Response: ${verifyRes.status} - ${verifyRes.body}`);
check(verifyRes, { '๐ verify status is 200': (r) => r.status === 200 });
sleep(1);
}
k6 run test.js
๐ ์คํ ๊ฒฐ๊ณผ (Redis vs Java ๋ด์ฅ HashMap ๋น๊ต)
Metric Redis ์ฌ์ฉ HashMap ์ฌ์ฉ
์์ฒญ ์ฑ๊ณต๋ฅ โ
100% โ
100%
ํ๊ท ์๋ต ์๊ฐ 13.56ms 31.83ms
์ต๋ ์๋ต ์๊ฐ 26.49ms 692.69ms
์์ฒญ ๋๊ธฐ ์๊ฐ 12.19ms 30.04ms
๋ฉ์ผ ์ ์ก ์๊ฐ 15.35ms 53.45ms
๐ ๊ฒฐ๋ก : Redis ์ฌ์ฉ ์ ์๋ต ์๋๊ฐ 2~3๋ฐฐ ๋น ๋ฅด๊ณ , ๊ทน๋จ์ ์ธ ์ง์ฐ(692ms)์ด ๋ฐ์ํ์ง ์์๋ค. ๐
์ด๋ฒ์๋ ๋จ์ํ POST ์์ฒญ์ ๋ณด๋ด์ ํ ์คํธ๋ฅผ ์งํํ์๋ค!
๊ทธ๋ฌ๋ ์ฑ๋ฅ ํ ์คํธ๋ฅผ ๋จ์ํ ๋จ์ผ POST ๋ฐ๋ณต ์์ฒญ์ผ๋ก ์งํํ๋ฉด ์บ์ ์ ์ค๋ฅ ์ด ๋์์ ธ์ ์ค์ ์๋น์ค ๋ถํ๋ฅผ ์ ๋๋ก ์ธก์ ํ๊ธฐ ์ด๋ ค์, ๋ฐ๋ผ์ ๋ค์ํ ์๋๋ฆฌ์ค๋ฅผ ์ ์ฉํ ํ ์คํธ ์ ๋ต์ ์ธ์ฐ๋๊ฒ ์ค์ํ๋ค!
๊ทธ๋์ ๋ค์ ํฌ์คํ ์๋ ์ฌ๋ฌ ํ ์คํธ ์๋๋ฆฌ์ค ์ ๋ต์ ์ ์ฉํด์ Grafna๋ฅผ ์ด์ฉํด์ k6 ์๊ฐํ๋ฅผ ํด๋ณด๊ฒ ์ต๋๋ค!
(๋ค์ ํฌ์คํ ์์ ๊ณ์)