Big Bang - 100-hours-a-week/9-team-Devths-WIKI GitHub Wiki
๋ชฉ์ฐจ (ํผ์น๊ธฐ/์ ๊ธฐ)
๐ก Big Bang ๋ฐฐํฌ๋? ๋ชจ๋ ์ปดํฌ๋ํธ๋ฅผ ํ ๋ฒ์ ์๋์ผ๋ก ์ค์น ๋ฐ ๋ฐฐํฌํ๋ ์ ๋ต์ผ๋ก, ์ด๊ธฐ ์๋น์ค ๊ฐ๋ฐ ๋ฐ ํ ์๋ จ๋ ํฅ์์ ์ ํฉํ ๋ฐฉ์์ด๋ค.
1. ๋น ๋ฅธ MVP ์ถ์
- ์ด๊ธฐ ๋จ๊ณ์์๋ ๊ธฐ๋ฅ ์์ฑ๋๋ณด๋ค ์ฌ์ฉ์ ํผ๋๋ฐฑ ํ๋ณด์ ๋ฌธ์ ๊ฒ์ฆ์ด ์ฐ์
- ๋ณต์กํ ์๋ํ ์ฒด๊ณ ๊ตฌ์ถ๋ณด๋ค ์๋น์ค ๊ตฌ์กฐ์ ์์ฒญ ํ๋ฆ์ ๋น ๋ฅด๊ฒ ๊ฒ์ฆํ ์ ์๋ ์์์ ๋ฐฐํฌ ๋ฐฉ์์ ์ฑํ
2. ์ ์ ์ด์ฉ์ ์์ ๋ฐ๋ฅธ ์ธ์คํด์ค ์ ์ฝ
- Devths ์๋น์ค๋ ์ ํ๊ท ํ์ฑ ์ฌ์ฉ์ ์(MAU) ์ฝ 200๋ช ์์ค
- Devths ์๋น์ค๋ ํ์ฌ DAU ์ฝ 40๋ช , ํ๊ท ์ต๋ ๋์์ ์์ 3๋ช ์์ค์ผ๋ก ํธ๋ํฝ ์์ฒด๊ฐ ๋ฎ์
- ๋จ์ผ ์ธ์คํด์ค ์ฅ์ ๋ฐ์ ์์๋ ์ํฅ์ ๋ฐ๋ ์ฌ์ฉ์ ์๊ฐ ๊ทนํ ์ ํ์ ์ด๋ฉฐ, ์ ๋ฌด ์ค๋จ์ ๋ํ ์ฌํ์ ยท๊ธ์ ์ ๋น์ฉ์ด ๋ฎ์
- ์ด๋ก ์ธํด ๊ณ ๊ฐ์ฉ์ฑ(HA)์ ์ ์ ๋ก ํ ์ด์คํยท์คํ ์ค์ผ์ผ๋ง ๊ตฌ์กฐ๋ ํ์ฌ ๋จ๊ณ์์๋ ๊ณผ์ ์ค๊ณ(over-engineering)๋ก ํ๋จ
- ํ์ง๋ง, ๋ฐฐํฌ ๋น์ผ์๋ง ๋ด๋ถ ์๊ฐ์์ ์ด์ฉ์ผ๋ก ํธ๋ํฝ์ด ๊ฐ์์ค๋ฝ๊ฒ ๋์ด๋ ๊ฐ๋ฅ์ฑ ๊ณ ๋ คํด์ผํจ
2-1. ์ฌ์ฉ์ ์งํ ๊ณ์ฐ
| ํญ๋ชฉ | ๊ฐ | ๊ทผ๊ฑฐ / ์ค๋ช |
|---|---|---|
| MAU | 200๋ช | KTB ๋ด๋ถ 150 + ๋์ค์ฝฐ์ด์ 50 |
| DAU | 40๋ช | DAU/MAU 20% (Mixpanel, a16z) |
| ํ๊ท ์ฒด๋ฅ์๊ฐ | 10๋ถ | SimilarWeb ์ํฐ๋ ๋ฐ์ดํฐ |
| PCU | 3๋ช | (1์ผ ์ด ๋ฐฉ๋ฌธ์ ์ * ํ๊ท ๋ฐฉ๋ฌธ ์ง์์๊ฐ) / (์ง์ค ์ฌ์ฉ์๊ฐ) |
- ๋์ค์ฝฐ์ด์ ์ต๊ทผ ํ๋ก์ ํธ ํด๋ฆญ ์ ๊ธฐ๋ฐ ๋์ถ. (๋งํฌ ๊ธฐ์ค 7์ผ๊ฐ ๋ ธ์ถ 30~50, ์ธ๊ธฐ๊ธ ๊ธฐ์ค ์ฝ 250๊ฑด ํด๋ฆญ)
- ํ ์คํธ: 1KB ๋ฏธ๋ง
- ์ด๋ฏธ์ง: 2MB
- 1์ธ๋น ์ผ์ผ ํ์ด์ง ์กฐํ ์: ์ฝ 5ํ (ํ๊ท ์ฒด๋ฅ์๊ฐ 10๋ถ ๊ธฐ์ค)
- 1์ธ๋น ์ผ์ผ ๊ฒ์๊ธ ์กฐํ ์: ์ฝ 10ํ (ํ๊ท ์ฒด๋ฅ์๊ฐ 10๋ถ ๊ธฐ์ค)
- ์ฑ ์คํ ๋ฐ ์๋ฆผ ํ์ธ: 1๋ถ(2PV)
- ์ฑ์ฉ ๊ณต๊ณ ๋ฐ ํผ๋ ์ค์บ๋, ์ผ๋ถ ์ ์: 3๋ถ(3PV)
- AI ์์ฝ ๋ถ์ ํ์ธ: 3๋ถ (1PV)
- ์ปค๋ฎค๋ํฐ, ์บ๋ฆฐ๋: 2๋ถ (4PV)
- 1์ธ๋น AI ์ฑ๋ด ํธ์ถ ์: 6ํ (๊ทผ๊ฑฐ)
- ํ์: 1์๊ฐ (์ฑ์ฉ ํ๋ซํผ ๋ฑ์์ ์ง์ํ ๋งํ ๊ณต๊ณ ๋ฅผ ํ์)
- AI ํธ์ถ ์ฝ 3ํ(๊ณต๊ณ ๋ถ์, ๊ธฐ์ ์คํ ๋งค์นญ ๋ฑ)
- ์๋ฅ ์์ฑ: 1.5์๊ฐ(ํ๊ฒ ๊ธฐ์ ์ ์๋ง๊ฒ ์ด๋ ฅ์ ๋ฐ ์์์๋ฅผ ์์ )
- AI ํธ์ถ ์ฝ 3ํ (์ด์ ์์ฑ, ๋ฌธ๋ฒ ๊ต์ ๋ฐ ๋ง ๋ค๋ฌ๊ธฐ, ๋ฉด์ ์์ ์ง๋ฌธ ๋ถ์)
- ์ง์ ๋ฐ ๊ด๋ฆฌ: ์ฝ 30๋ถ
- AI ํธ์ถ 0ํ
- ํธ๋ํฝ์ผ๋ก ์ธํ ์๋ฒ ๋ค์ด์ ํผํฌํ์์ ๋ฐ์ํจ. ๋ฐ๋ผ์ ํผํฌ ํ์ ๊ธฐ์ค ๋์์ ์์ ์ฐ์
- ์ทจ์ค์, ํ๋ ํจํด ๊ธฐ์ค ํ๋ฃจ ํ๊ท 4์๊ฐ(240๋ถ) ์ ๋ ์๊ฐ์ ํ๋์ด ๋ชฐ๋ฆฌ๋ ๊ฒ์ผ๋ก ๊ฐ์
- PCU = (1์ผ ์ด ๋ฐฉ๋ฌธ์ ์ * ํ๊ท ๋ฐฉ๋ฌธ ์ง์์๊ฐ) / (์ง์ค ์ฌ์ฉ์๊ฐ)
- 1์ผ ์ด ๋ฐฉ๋ฌธ์ : 200
- ํ๊ท ๋ฐฉ๋ฌธ ์ง์์๊ฐ: 10๋ถ
- ํผํฌํ์ ๋ถํ
- ํธ๋ํฝ์ 1/3์ด ํด๋น ์๊ฐ์ ๋ชฐ๋ฆฐ๋ค๊ณ ๊ฐ์
- ํผํฌ ํธ๋ํฝ ๊ณ์ 2.0์ผ๋ก ์ ์ฉ(ํ๊ท ๋๋น ์ต๋ ๋ถํ, ๊ทผ๊ฑฐ)
- ๋ถ๋น ํ๊ท ์ ์์: 2000๋ถ / 1440๋ถ(ํ๋ฃจ) = 1.39
- ์ต๋ ๋์ ์ ์์: 1.39 * 2.0 = 2.78โฆ๋ช
- ์ฝ 3๋ช
2-2. RPS ์งํ ๊ณ์ฐ
| ์๋๋ฆฌ์ค | RPS(HTTP ์ด ์์ฒญ) |
|---|---|
| ์ผ ํ๊ท (DAU=40 ๊ธฐ์ค) | 0.01 ~ 0.03 |
| ์ ์ ํผํฌํ์ (PCUโ3) | 0.15 ~ 0.30 |
| ์ด๋ฒคํธ ์ต๋ ๋ถํ (๋ฐฐํฌ์ผ PCUโ100) | 5 ~ 10 |
RPS ์ฐ์ (์์ฒญ ์) ๊ฐ์
- ์ฌ์ฉ์ 1๋ช
๊ธฐ์ค์ผ๋ก 1ํ ๋ฐฉ๋ฌธ(ํ๊ท 10๋ถ) ๋์ ์ฝ 10PV๊ฐ ๋ฐ์ํ๋ค๊ณ ๊ฐ์ ํ์ต๋๋ค.
- ์ฑ ์คํ ๋ฐ ์๋ฆผ ํ์ธ: 1๋ถ (2PV)
- ์ฑ์ฉ ๊ณต๊ณ ๋ฐ ํผ๋ ์ค์บ๋, ์ผ๋ถ ์ ์: 3๋ถ (3PV)
- AI ์์ฝ ๋ถ์ ํ์ธ: 3๋ถ (1PV)
- ์ปค๋ฎค๋ํฐ, ์บ๋ฆฐ๋: 2๋ถ (4PV)
- ์ด๋ฅผ ํ์ด์ง ๋จ์ ์์ฒญ์ผ๋ก ํ์ฐํ๋ฉด 1๋ถ๋น ์ฝ 1PV(= 60์ด๋น 1PV) ์์ค์ ํ๋ ๋น๋๋ผ๊ณ ํ๋จํ์์ต๋๋ค.
ํผํฌ ํ์ RPS ๊ฐ์
ํ๊ท ์ ์ผ๋ก ํ๋์ ํ์ด์ง ๋น ์ฝ 3~6ํ์ HTTP ์์ฒญ์ด ๋ฐ์ํ๋ค๊ณ ๊ฐ์ ํ์์ต๋๋ค.
- ์ ์ ํผํฌ ํ์ ๋์ ์ ์์ ์(PCU)๋ฅผ 3๋ช ์ผ๋ก ์ฐ์ ํ ๊ฒฝ์ฐ,
-
(3~6) ร 3 / 60 โ 0.15~0.30 RPS๋ก ๊ณ์ฐ๋์์ต๋๋ค. ์ด์ ๋ฐ๋ผ ์ ์ ํผํฌ ํ์ ๊ธฐ์ค HTTP RPS๋ 0.15~0.30 ์์ค์ผ๋ก ํ๋จํ์์ต๋๋ค.
์ต๋ ๋ถํ RPS ๊ฐ์
๋ฐฐํฌ ์ผ์๋ ๋ถํธ์บ ํ ๋ด๋ถ ์ด๋ฒคํธ๋ก ๋์ ์ ์์ ์๊ฐ 100๋ช ๊น์ง ์ฆ๊ฐํ ์ ์๋ค๊ณ ๊ฐ์ ํ์์ต๋๋ค.
-
(3~6) ร 100 / 60 โ 5~10 RPS๋ก ๊ณ์ฐ๋์์ต๋๋ค. - ์ด์ ๋ฐ๋ผ ์ด๋ฒคํธ ์ต๋ ๋ถํ ๊ธฐ์ค HTTP RPS๋ 5~10 ์์ค์ผ๋ก ํ๋จํ์์ต๋๋ค.
- AWS์ ๋จ์ผ EC2
- ํ๋์ ์๋ฒ ๋ด์์ ํ๋ก ํธ์๋, ๋ฐฑ์๋, AI ์๋ฒ, DB ๋์ ์ด์
- Nginx๋ฅผ ํตํ ์๋ธ๋๋ฉ์ธ ๊ธฐ๋ฐ ๋ผ์ฐํ
๋ฆฌ๋ฒ์ค ํ๋ก์ + TLS ์ข ๋ฃ + ์ฅ๊ธฐ ์ฐ๊ฒฐ(์คํธ๋ฆฌ๋ฐ) ์ฒ๋ฆฌ๊ฐ ํต์ฌ- ๋จ์ผ ์ธ์คํด์ค๋ฅผ ์ฌ์ฉํ๊ธฐ์ ํธ๋ํฝ์ ์ ์ ํ๊ฒ ๋ถ์ฐํด์ฃผ๋ ๋ฆฌ๋ฒ์ค ํ๋ก์ ๊ธฐ๋ฅ ํ์
- TLS termination ์ค์
- ์ฑ๋ด SSE(๋จ๋ฐฉํฅ ์คํธ๋ฆฌ๋ฐ ๋ฐ์ดํฐ ์ฒ๋ฆฌ)๋ฅผ ์ํด์ keep-alive ์ฐ๊ฒฐ ํ์
- ์ฐ๋ฆฌ ์๋น์ค๋ ์ธ๋ถ API ์ด์ฉ์ด 3๊ฐ ์กด์ฌ
- keep-alive/์คํธ๋ฆฌ๋ฐ ์ฐ๊ฒฐ์์๋ ๋คํธ์ํฌ ์ง์ฐ์ด ์ฐ๊ฒฐ ์ฒ๋ฆฌ ๋ชจ๋ธ์ด ๋ฉ๋ชจ๋ฆฌยท์ค๋ ๋ ํจ์จ์ ์ง๊ฒฐ
- ์ ์ ํ์ผ์๋น
- ํ๋ฐํธ ๋น๋ ์ฐ์ถ๋ฌผ์ ๋ํ ์ ์ ํ์ผ ์๋น ํ์ง๋ง, PDF/์ด๋ฏธ์ง๋ ์ธ๋ถ ์ ์ฅ์ ์ด์ฉํ์ฌ ์ ์ ํ์ผ ์๋น ์ญํ ์ถ์
์ ์ ์จ ์์ 3๊ฐ Cloudflare๋ ๋ฆฌ๋ฒ์ค ํ๋ก์/CDN ์๋น์ค์ด๊ณ LiteSpeed๋ ์ ๋ฃ ๊ธฐ๋ฐ์ ์์ฉ ์๋ฒ๋ผ, ์์ ์คํ์์ค ๊ธฐ๋ฐ์ ์๊ฐ ์ค์นํ ์น ์๋ฒ(Self-hosted)๋ค ์์ฃผ๋ก ๋น๊ต
| ๊ตฌ๋ถ | Apache | Microsoft IIS | โ Nginx |
|---|---|---|---|
| ์ฐ๊ฒฐ ์ฒ๋ฆฌ ๋ฐฉ์ | ๋ค์ค ์ฒ๋ฆฌ ๋ชจ๋์ ์ฌ์ฉํ์ฌ ์ฐ๊ฒฐ๋ง๋ค ํ๋ก์ธ์ค/์ค๋ ๋(MPM: prefork/worker/event).๋ชจ๋ ์กฐํฉ ์ ์ฐ |
Windows ์ปค๋/HTTP.sys ๊ธฐ๋ฐ + ์์ปค ํ๋ก์ธ์ค,์ ํ๋ฆฌ์ผ์ด์ ํ(App Pool) |
์ด๋ฒคํธ ๊ธฐ๋ฐ(๋น๋๊ธฐ), ์์ปค ํ๋ก์ธ์ค ์ค์ฌ.keep-alive/๋ฆฌ๋ฒ์ค ํ๋ก์์ ๊ฐํจ |
| CPU ์ฌ์ฉ | ์ค์ /MPM์ ๋ฐ๋ผ ํธ์ฐจ. ๋์์ฑ์ด ๋์ ๊ณณ์์ ์๋์ ์ผ๋ก ๋ถ๋ฆฌํ ์ ์์ |
Windows ํ๊ฒฝ ์ต์ ํ. .NET/Windows ํตํฉ ์ ํจ์จ์ ์ด๋ ๋ฆฌ๋ ์ค ๋๋น ์ค๋ฒํค๋ ๊ฐ๋ฅ |
๋์์ฑ์ด ๋์ ๊ณณ์์ ํจ์จ์ (์ปจํ ์คํธ ์ค์์นญ ์ ์) |
| ๋ฉ๋ชจ๋ฆฌ | ๋ชจ๋/MPM์ ๋ฐ๋ผ ์ฆ๊ฐ (ํนํ prefork๋ ๋ฉ๋ชจ๋ฆฌ ๋ถ๋ด ์ปค์ง ์ ์์) |
App Pool/๋ชจ๋ ๊ตฌ์ฑ์ ๋ฐ๋ผ ์ฆ๊ฐ. Windows ๋ฐํ์/์๋น์ค ์ค๋ฒํค๋ ์กด์ฌ |
๋น๊ต์ ์ ๊ฒ ์ฌ์ฉ(๋๋ ์ฐ๊ฒฐ์ ์ ๋ฆฌ) |
| ํ๋ก์ ์๋ฒ | mod_proxy(ProxyPass ๋ฑ) ๋ก ๋ฆฌ๋ฒ์ค ํ๋ก์ ๊ฐ๋ฅ | URL Rewrite + ARR๋ก ๋ฆฌ๋ฒ์ค ํ๋ก์ ๊ตฌํ | ๋ฆฌ๋ฒ์ค ํ๋ก์/๋ก๋๋ฐธ๋ฐ์/TCPยทUDP ํ๋ก์๊น์ง ์ง์ |
| ๋์ ์ฐ๊ฒฐ์ฑ |
event MPM์ด๋ฉด keep-alive ์ฐ๊ฒฐ ํจ์จโ (๋จ, ์ค์ ์ํฅ ํผ) |
HTTP.sys ํ + ์์ปค ํ๋ก์ธ์ค ๋ชจ๋ธ๋ก ์ค์ผ์ผ ๊ฐ๋ฅ(๊ตฌ์ฑ ์์กด) |
์ด๋ฒคํธ ๊ธฐ๋ฐ์ผ๋ก ๋์ ์ฐ๊ฒฐ์ ๊ฐํ ํธ |
| ์ฅ์ | - ํ๋ก์ธ์ค ๊ธฐ๋ฐ์ด๊ธฐ ๋๋ฌธ์ ํ ์์ฒญ์ด ์๋ฒ์ ๋ค๋ฅธ ๋ถ๋ถ์ ์ํฅ์ ๋ฏธ์น์ง ์์, ํ์ผ์ ๋ณ๊ฒฝํ์ง ์๋ ์ ์ ์ฝํ
์ธ ์ ๊ณต์ ์์ ์ - ๋์ ์ปจํ ์ธ ๋จ๋ ์ฒ๋ฆฌ ๊ฐ๋ฅ |
- Windows/AD/.NET/์ธ์ฆ(Integrated Auth) ๋ฑ ์ํฐํ๋ผ์ด์ฆ ํตํฉ ๊ฐ์ , GUI ์ด์ ํธ์ | - Nginx๋ ๋ชจ๋ ์์ฒญ์ ๋น๋๊ธฐ์ ์ผ๋ก ์ฒ๋ฆฌ - I/O ์์ (๋คํธ์ํฌ ์์ฒญ, ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ ๊ทผ ๋ฑ)์ ๋์ฑ ๋น ๋ฅด๊ฒ ์ฒ๋ฆฌ |
| ๋จ์ | - ์ค์ ๋ณต์กํด์ง๊ธฐ ์ฌ์ - ๊ณ ๋์์ฑ/๋ฆฌ๋ฒ์คํ๋ก์ ์ฉ๋์์ Nginx ๋๋น ๋ฌด๊ฑฐ์ธ ์ ์์ |
- Windows ์ข ์(๋น์ฉ/์ด์), ๋ฆฌ๋ ์ค ๊ธฐ๋ฐ ์คํ๊ณผ์ ์ผ๊ด์ฑ ๋จ์ด์ง | - ๋์ ์ปจํ ์ธ ๋จ๋ ์ฒ๋ฆฌ ๋ถ๊ฐ๋ฅํ๋ฉฐ, ํ๋ก์ ์์ฃผ ๊ธฐ๋ฅ ์ํ |
1. ๋์ ์ฐ๊ฒฐ ์ฒ๋ฆฌ ๋ฐฉ์ (Scalability)
์ฐ๋ฆฌ ์๋น์ค์ ํต์ฌ ๊ธฐ๋ฅ์ธ ์ฑ๋ด์ ์ฐ๊ฒฐ์ ๋์ง ์๊ณ ๊ณ์ ์ ์งํด์ผ ํฉ๋๋ค.
| ์๋๋ฆฌ์ค | RPS | ์๋ต ์๊ฐ ๊ฐ์ | ๋ถ์กํ ์ค๋ ๋ ๊ฐ์ | CPU ๋ถํ ์ฒด๊ฐ | |
|---|---|---|---|---|---|
| ์ ์ ํผํฌํ์ | ํ๊ท ์ง์ฐ | 0.3 | 0.5์ด | 0.15 (1๊ฐ ๋ฏธ๋ง) | ์ฌ์ ๋ก์ |
| ์ธ๋ถ API ์ง์ฐ (Worst) | 0.3 | 5.0์ด | 1.5 | ์์ ์ | |
| ์ด๋ฒคํธ ์ต๋ ๋ถํ | ํ๊ท ์ง์ฐ | 10 | 0.5์ด | 5.0 | ์ ์ ์จ ์์น ์์ |
| ์ธ๋ถ API ์ง์ฐ (Worst) | 10 | 5.0์ด | 50.0 | ์ค๋ ๋ ํญ์ฆ, ๋ณ๋ชฉ ๋ฐ์ |
โ ์ด๋๋ถํฐ ์ค๋ ๋/์ปค๋ฅ์ ์ด ์์ด๋ฉฐ ์ฑ๋ฅ์ ๋นํด์ ๋ ๋นจ๋ฆฌ ์ธ์คํด์ค๊ฐ ์ฃฝ์ ์ ์๋ค๊ณ ํ๋จํ์ต๋๋ค.
- Apache(Event MPM)์กฐ์ฐจ๋ ๊ฒฐ๊ตญ ๋๊ธฐ ์ฐ๊ฒฐ์ ๊ด๋ฆฌํ๋ ๋ฆฌ์ค๋์ ์ค์ ์ฒ๋ฆฌ๋ฅผ ์ํ ์์ปค ์ค๋ ๋๊ฐ ํ์ํ์ฌ, ์ ์์๊ฐ ๋์ด๋ ์๋ก ์์คํ ๋ฆฌ์์ค๋ฅผ ์ ํ์ ์ผ๋ก ์ ์ํฉ๋๋ค.
- Nginx๋ ๋จ ๋ช ๊ฐ์ ์์ปค ํ๋ก์ธ์ค๋ง์ผ๋ก ์์ฒ ๊ฐ์ SSE ์ฐ๊ฒฐ์ ์ด๋ฒคํธ ๋ฐฉ์์ผ๋ก ๊ฐ๋ณ๊ฒ ์ฒ๋ฆฌํ ์ ์์ด, ์ฑ๋ด ์๋น์ค ํ์ฅ์ ๊ฐ์ฅ ์ ๋ฆฌํฉ๋๋ค.
2. ์์์ ํจ์จ (Efficiency)
์ฐ๋ฆฌ ์๋น์ค์ ์ํฉ์ ์น ์๋ฒ๊น์ง ๋ฉ๋ชจ๋ฆฌ๊ฐ ๋ง์์ผํ๋ ์ฌ์ ๊ฐ ์์ต๋๋ค. ๋ํ. ์ธ๋ถ API ์๋ต ์ง์ฐ์ ๋ํ ์ฐ๋ฆฌ ์๋น์ค์ ์ํ ์์๊ฐ ๋ ๊ฐ๋ฅ์ฑ์ด ์์ต๋๋ค.
- Apache๋ ์ธ๋ถ API ์๋ต์ ๊ธฐ๋ค๋ฆฌ๋ ๋์ ์ค๋ ๋๊ฐ '์ฐจ๋จ(Blocking)' ์ํ๋ก ๋จธ๋ฌผ๋ฉฐ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ๋ถ์ก๊ณ ์์ต๋๋ค. Worst ์๋๋ฆฌ์ค(RPS 10, ์ง์ฐ 5์ด) ๋ฐ์ ์ ์ค๋ ๋๊ฐ ํญ๋ฐํ๋ฉฐ ์๋ฒ๊ฐ ์ฆ์ ์ค๋จ๋ ์ ์์ต๋๋ค.
- Nginx๋ ๋น๋๊ธฐ ํธ์ถ ํ ์๋ต์ด ์ฌ ๋๊น์ง ๋ค๋ฅธ ์์ฒญ์ ์ฒ๋ฆฌํ๋ฏ๋ก, ํน์ API์ ์ง์ฐ์ด ์ ์ฒด ์๋ฒ์ ๋ง๋น๋ก ์ด์ด์ง๋ ๊ฒ์ ์์ฒ ์ฐจ๋จํฉ๋๋ค.
- ์ด์ ๋ฆฌ์คํฌ ๊ด๋ฆฌ (Sustainability)
- IIS๋ ๋ฆฌ๋ ์ค ํ๊ฒฝ๊ณผ์ ํธํ์ฑ ๋ฐ ๋ผ์ด์ ์ค ๋น์ฉ ๋ฌธ์ ๋ก ๋ฐฐ์ ํ์์ต๋๋ค.
- Nginx๋ ์ด๋ฏธ "์ ๊ณ ํ์ค"์ผ๋ก ์๋ฆฌ ์ก์, SSE ์ค์ ์ด๋ ํ๋ก์ ํ์์์ ํ๋ ๋ฑ ์ด์ ์ด์์ ๋ํด ๊ฒ์ฆ๋ ํด๊ฒฐ์ฑ (Best Practice)์ ์ฐพ์ ์ ์์ต๋๋ค.
โ ํด๋น ๊ธฐ์ค์ ๋ฐํ์ผ๋ก Nginx๋ฅผ ์ ํํ์์ต๋๋ค. โ
EC2 ์ค์ธก ๋ฐ ๋ฆฌ์์ค ์ค๊ณ ์์ธ ๋ฐ์ดํฐ (Idle & Peak)
์ค์ ๋ก EC2์์ ๊ฐ ํ๋ก์ธ์ค๋ฅผ ์คํํ์ฌ ์ธก์ ํ ๊ฒฐ๊ณผ์
๋๋ค.

| ์ข ๋ฅ | ์ ์ ์จ (%) | ์ค์ฌ์ฉ ๋ฉ๋ชจ๋ฆฌ |
|---|---|---|
| JAVA (Spring) | 8.0 | 640 MB (0.64GB) |
| MySQL | 5.2 | 416 MB |
| FastAPI | 1.8 | 144 MB |
| NextJS | 0.7 | 56 MB |
| Nginx | 0.1 | 8 MB |
| ์ด ํฉ | - | ์ฝ 1.2 GB |
- ๋ฉ๋ชจ๋ฆฌ: ํผํฌ ์ ์ต๋ 10.75GB๊ฐ ํ์ํ์ฌ ๋ฌผ๋ฆฌ RAM(8GB)์ ์ด๊ณผํ ์ ์์ต๋๋ค. ์ด๋ฅผ ๋ฐฉ์งํ๊ธฐ ์ํด 4GB ์ด์์ Swap ๋ฉ๋ชจ๋ฆฌ ์ค์ ๊ณผ Java/MySQL์ ๋ฉ๋ชจ๋ฆฌ ์ํ์ (Limit) ํ๋์ด ํ์์ ์ ๋๋ค.
- ๋ฐฐํฌ ์ ๋ต: ๋น ๋ฑ ๋ฐฐํฌ ์ ์๊ฐ์ ์ธ ๋ฆฌ์์ค ํญ๋ฐ์ด ์์๋๋ฏ๋ก, ์๋น์ค ๊ฐ ์์ฐจ์ ๊ธฐ๋ ์คํฌ๋ฆฝํธ ์ ์ฉ์ ๊ถ์ฅํฉ๋๋ค.
๋ถ์ ๊ธฐ์ค ๋ฐ ๊ณต์
-
๋ฉ๋ชจ๋ฆฌ ๋ถ์ ๊ณต์(JVM ๊ธฐ์ค) TotalProcessMemory = Heap + Metaspace + (ThreadStackSizeรThreadCount) + DirectMemory + CodeCache + OHS(Overhead)
-
CPU ์ ์ ์ฐ์ : ํธ๋ํฝ ๊ธฐ๋ฐ ์ถ์ฐ(์์ฒญ๋ ๊ธฐ์ค)
- ์ด๋น ์์ฒญ ์ * ์์ฒญ๋น CPU ์๋ชจ๋
- ์ด CPU ์๋ชจ = (๊ฐ API์ RPS * ํ๊ท ์ฒ๋ฆฌ ์๊ฐ)์ ์ด ํฉ
- ๋ชฉํ ํธ๋ํฝ: MAU 200๋ช , PCU 3๋ช ( +์ด๋ฒคํธ์ฑ ํผํฌ 100๋ช )
- ๊ตฌ์ฑ: ์น์๋ฒ + ๋ฐฑ์๋(Spring Boot) + AI ์๋ฒ(fastAPI) + DB(MySQL)
์ปดํฌ๋ํธ ๋ณ ๋ฆฌ์์ค ๋ถ์
Spring Boot ์๋ฒ
-
ํน์ฑ: I/O ์ด ๋ง๊ณ ๊ฐ์ฒด ์์ฑ/์ญ์ (GC ๋ฐ์) ๋น๋ฒ, AI ์๋ต์ผ๋ก ์ธํ ๊ธด ํ ์คํธ ๋ค์ ์์ฑ๋จ.
-
๋ฉ๋ชจ๋ฆฌ(์ฐธ๊ณ )
-
Heap ๋ฉ๋ชจ๋ฆฌ (์์ฑ๋ ๊ฐ์ฒด + ๋ฌธ์์ด ํ)
- ํธ๋ํฝ ์์ฒด๋ ๋์์ ์์ 3~5์ ๋๋ก ๋ฎ์.
- ๋๋ฌด ์์ผ๋ฉด GC์์ฃผ ๋ฐ์ โ ์ฑ๋ฅ ์ ํ
- ์๋ต ํ ์คํธ ์ ๋ฌ ์ํด ์ฌ์ ๊ณต๊ฐ ํ์
- JVM ๊ธฐ๋ณธ ์ต์ 256MB
- ๋จ์ API ์๋ฒ ๊ธฐ์ค ์ฝ 512MB
- ์ผ๋ฐ์ ์ธ Spring Boot ํ๋ก์ ํธ ๊ธฐ์ค 750MB ์ด์
โ Spring Boot ๊ณ ๋ คํ์ฌ ์ฌ์ 1GB ์ฐ์
-
Metaspace (๊ทผ๊ฑฐ)
- ๋ก๋ ๋ ํด๋์ค ๋ฉํ๋ฐ์ดํฐ, static ๋ณ์
- JVM ๊ธฐ๋ณธ ์ด๊ธฐ ๊ฐ12~20MB
- Spring Boot ์์์ ์ฝ 5000๊ฐ ์ด์์ ํด๋์ค ๋ก๋ฉ
โ 100MB ์ฐ์
-
Thread(Tomcat)(๊ทผ๊ฑฐ)
- ๊ธฐ๋ณธ 200๊ฐ, ๊ฐ๋น ์ฝ 1MB(64bit JVM ๊ธฐ๋ณธ ๊ฐ)
- ํผํฌ ์ฌ์ฉ์ ์ต๋ 100๋ช ์ด๋ผ๊ณ ๊ฐ์ , FastAPI์์ ํต์ ๋ ๊ณ ๋ คํด 200๊ฐ ์ค๋ ๋ ์ ์ง **โ ์ด 200MB ์ฐ์ **
-
Code Cache(๊ทผ๊ฑฐ)
- JIT ์ปดํ์ผ๋ฌ ๋ฐํ Native ์ฝ๋, ์์ฃผ ์คํ๋๋ ๋ฉ์๋ ์บ์ฑ โ ๊ธฐ๋ณธ ~240MB
-
Direct Memory(๊ทผ๊ฑฐ)
- ํ์ผ ์ ์ถ๋ ฅ, ์์ผ ํต์ ์ ํ์ ๊ฑฐ์น์ง ์๊ณ ์์คํ ์ฝ ํ์ฌ OS ๋ฉ๋ชจ๋ฆฌ ์ง์ ์ฌ์ฉ(NIO)
- ๊ธฐ๋ณธ๊ฐ = ํ ํฌ๊ธฐ์ ๋์ผ
- ํ์ผ ์ ๋ก๋ ๋น๋ฒํ์ง ์์ ๊ฒ์ผ๋ก ์์ ๋ฐ ๋ก์ปฌ์ ํ์ผ ์ ์ฅํ์ง ์์
- ๋ฐ๋ผ์ ์๊ฒ ์ฌ์ฉํด๋ ๋ฌธ์ ์์ ๊ฒ์ผ๋ก ์์
โ ์ด 128MB ์ฐ์
-
JVM Native Memory
- GC
- GIT
- JVM ๋ด๋ถ ๊ตฌ์กฐ์ฒด
- Symbol table
- Compiler
โ 50~100MB ์ฐ์
์ด ํฉ 1792
โ ๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ ์ด ํฉ ์ฝ 1.8GB ์ฐ์
-
FastAPI(AI Worker)(์ฃผ์ ๋ณ๋ชฉ ์ง์ )
-
ํน์ฑ: ์ธ๋ถ API๋ฅผ ํธ์ถํ๊ณ , ์๋ต์ ๊ธฐ๋ค๋ฆฌ๋ I/O Bound ์์ ๋ค์. ๊ธด ํ ์คํธ ํ์ฑ ์ํด CPU ์ฌ์ฉ
-
๋ฉ๋ชจ๋ฆฌ
-
Python Heap
- ์์ฒญ, ์๋ต JSON ๊ฐ์ฒด, ์๋ต ํ ์คํธ, ํ์ฑ ์ค ์์ฑ๋๋ ์์ ๊ฐ์ฒด, ๋ฌธ์์ด, ๋ฆฌ์คํธ ๋ฑ
- JSON ๊ธฐ๋ณธ ๊ตฌ์กฐ ์ฝ 20KB
- ์์ฒญ๋น ํ๊ท ํ ์คํธ 100๊ธ์ + ํ๋กฌํํธ ์๋ฐฑ ๊ธ์๋ก ๊ฐ์ (๊ทผ๊ฑฐ)
- ํ๊ธ ๊ธฐ์ค ์์ฒญ ํ ์คํธ 1KB๋ก ๊ฐ์
- ์๋ต ํ ์คํธ 5000์๋ก ๊ฐ์ (2ํ์ด์ง ๋ณด๊ณ ์ ๋ถ๋)
- ํ๊ธ ๊ธฐ์ค ์๋ต ํ ์คํธ 10KB๋ก ๊ฐ์
- ํ์ฑ ์ ๋ฐ์ํ๋ ์ค๋ณต ๋ฌธ์์ด: ๊ธฐ๋ณธ ๋ฌธ์์ด์ 2~3๋ฐฐ
- Python์ ํ์ fragmentation์ผ๋ก ์ธํด ์ฌ์ ๊ณต๊ฐ ์ถ๊ฐ ํ์
- ์์ฒญ์ ์ฌ์ฉ๋ 50KB, ์๋ต์ ์ฌ์ฉ๋ 60KB, ํ์ฑ ์์๊ฐ์ฒด 40KB โ ์์ฒญ 1๊ฑด ๋น 150KB ์ฐ์
- ๋์ ์ฒ๋ฆฌ 3๊ฐ
- ๊ธฐ๋ณธ ํ์ ๊ณต๊ฐ 1MB ์ถ์
- ๋จํธํ, GC ์ ์ง, ํธ๋ํฝ ํผํฌ, ์์ธ, Python ๊ฐ์ฒด ์ค๋ฒํค๋ ๋ฑ ๊ณ ๋ คํ์ฌ 10~50๋ฐฐ๊น์ง ๊ณต๊ฐ ํ๋ณด ํ์(๊ทผ๊ฑฐ)
- ๊ฐ์ฒด๋ง๋ค ๋ฉํ๋ฐ์ดํฐ ์ค๋ฒํค๋ ํผ
- pymalloc arena๋ก ์ธํ OS ๋ฉ๋ชจ๋ฆฌ ๋ฐํ ์ง์ฐ
- ๋ง์ JSON / ํ์ฑ๊ฐ์ฒด ๋์ ์ผ๋ก ๋จํธํ ์ฆ๊ฐ
- ๋ณด์์ ์ผ๋ก 50๋ฐฐ ๊ณต๊ฐ ํ๋ณด
โ ํ ๋ฉ๋ชจ๋ฆฌ 50MB ์ฐ์
-
Python Module, Interpreter ๋ฉ๋ชจ๋ฆฌ(๊ทผ๊ฑฐ)
- FastAPI, Uvicorn, Pydantic, httpx / aiohttp, OpenAI SDK, JSON, asyncio ๋ฑ ํฌํจ
- ์ค์ธก ๊ธฐ์ค
- ์์ ํ์ด์ฌ: ์ฝ 20~30MB
- FastAPI : ์ฝ 60MB
- Pydantic: ์ฝ 20MB
- httpx: ์ฝ 10MB
โ ๋ชจ๋, ์ธํฐํ๋ฆฌํฐ ์์ญ: ์ฝ 120MB
-
Worker / Proces
- Uvicorn: Worker = ํ๋ก์ธ์ค
- ํ๋ก์ธ์ค ์ ๋งํผ ๋ฉ๋ชจ๋ฆฌ ๋ณต์
- I/O ๋ฐ์ด๋๊ฐ ๋ง์ ํน์ฑ ์ Worker ๋ง์ด ํ์ ์์
- 2 Worker ์ํฉ ๊ฐ์ (๋์์ ์ 3 ์์ค์์๋ ์ถฉ๋ถ)
-
Thread Stack(๊ทผ๊ฑฐ)
- FastAPI๋ async ๊ธฐ๋ฐ์ด๋, ๋ด๋ถ์ ์ผ๋ก๋ threadpool ์ฌ์ฉ
- DNS, TLS, HTTP client
- ์ค๋ ๋ ๋น ์ฝ 8MB ์ฐ์
- ๊ธฐ๋ณธ Thread pool limit 40๊ฐ, ๋ณธ ์๋น์ค๋ ๋์์ ์ฐ์ด๋ ์ฐ๋ ๋๊ฐ ์ ์
- Thread ์ 10๊ฐ๋ก ๊ฐ์
- Stack 8MB (๋ฆฌ๋ ์ค ๊ธฐ๋ณธ ์ค๋ ๋ ํฌ๊ธฐ)
โ 80MB ์ฐ์
-
Network / Socket Buffer
- OpehnAPI ํธ์ถ, TLS, HTTP Keep-alive
- TLS handshake buffer, TCP send/receive buffers, Python socket objects ๊น์ง ๊ณ ๋ คํ์ฌ ๋ณด์์ ์ถ์ ํ์
โ 30MB ์ฐ์
-
Python Native / C Extensions
- SSL, JSON parser, regex, uvloop
โ 50MB ์ฐ์
โ 1 Worker ๊ธฐ์ค ๋ฉ๋ชจ๋ฆฌ ์ด ํฉ 330MB ํ์ โ 2 Worker ๊ธฐ์ค ๋ฉ๋ชจ๋ฆฌ ์ด ํฉ 660MB ํ์
-
MySQL
-
๋ฉ๋ชจ๋ฆฌ
-
Global Memory (์๋ฒ ์ ์ฒด ๊ณต์ฉ)(๊ทผ๊ฑฐ)
- ๋ชจ๋ ์ปค๋ฅ์ ์ด ๊ณต์ ํ๋ ๊ณต๊ฐ
- InnoDB BufferPool(๊ฐ์ฅ ํฐ ๊ณต๊ฐ ์ฐจ์ง)
- InnoDB Log Buffer(๊ธฐ๋ณธ ๊ฐ 16MB)
- Key Buffer: MyISAM ๋ฏธ์ฌ์ฉ ์ ๊ฑฐ์ 0MB
- Table Cache / Open Table Cache: ํ ์ด๋ธ ๋ฉํ๋ฐ์ดํฐ
-
Per-Connection Memory (์ปค๋ฅ์ ๋น)
- ์ฐ๊ฒฐ๋ง๋ค ํ ๋น๋๋ ๊ณต๊ฐ
- ์ปค๋ฅ์ ์์ ๋น๋กํ์ฌ ์ฆ๊ฐ
-
OS / Filesystem Cache
- InnoDB๊ฐ ์ง์ ์ฌ์ฉํ๋ ๊ณณ์ด ์๋ ๊ณต๊ฐ
-
-
ERD ์ค๊ณ ์ค์ผ๋ก ๊ตฌ์ฒด์ ๊ฐ ๊ณ์ฐ ๋ถ๊ฐ
-
MySQL ๊ณต์ ๋ ํผ๋ฐ์ค๋ ์์คํ ๋ฉ๋ชจ๋ฆฌ ์ ์ฒด์ 50~75% ๊ถ์ฅ(๋จ๋ ์๋ฒ ๊ธฐ์ค)(๊ทผ๊ฑฐ)
-
ํ ์๋น์ค์ ํจ๊ป ์ฌ์ฉํ๋ ๊ฒฝ์ฐ ๋ฎ๊ฒ ์ค์ ๊ถ๊ณ (30~50)
-
๋ค์ํ ์๋น์ค๊ฐ ๋จ์ผ ์ธ์คํด์ค์ ์ฌ๋ผ๊ฐ๋ฏ๋ก ๋ณด์์ ์ผ๋ก 30%๋ก ์ฐ์
์น ์๋ฒ(Nginx) (๊ทผ๊ฑฐ)
-
Master Process
- ์ค์ ํ์ผ ํ์ฑ, ์์ปค ํ๋ก์ธ์ค ์์ฑ/๊ด๋ฆฌ, ์์ผ ์คํ, ์๊ทธ๋ ์ฒ๋ฆฌ
- ๊ณ ์ ํฌ๊ธฐ **์ฝ 15MB **์ฌ์ฉ
-
Worker Processes
- ๊ธฐ๋ณธ ๋ฐ์ด๋๋ฆฌ ๋ฉ๋ชจ๋ฆฌ: 80MB
- Per-Connection Memory: ๊ฑฐ์ ์ ์ ํ์ง ์์
- Worker Memory Summary: 80MB
โ ๊ธฐ๋ณธ ๋์์ 200MB ์ดํ, ์ฐ๊ฒฐ ๋ง์์ ธ๋ 1GB ์ดํ ์ด์ ๊ฐ๋ฅ
OS + ๊ธฐํ
- Linux ๊ธฐ๋ณธ ์ปค๋ : ์ฝ 50MB
- SSH: 10MB
- systemd: 5~20MB
- page cache: OS์ ์ํด ๋์ ๊ด๋ฆฌ
โ ์ฝ 100 MB ์ฐ์
๋ํฉ
| Spring Boot + FastAPI + Web(Nginx) + OS(Ubuntu) | 2.76 GB |
|---|---|
| MySQL(30%) ํฌํจ ์ด RAM | ์ฝ 4 GB |
| ์๋น์ค ์ด์ ์ฌ์ ํฌํจ ์ | 6~8 GB ์ด์ |
์ธ์คํด์ค ์ฌ์ ๋น๊ต ํ
์ปดํฌ๋ํธ ๋ณ ๋ฆฌ์์ค ๋ถ์ ๋ฐํ์ผ๋ก ์ต์ ๋ฉ๋ชจ๋ฆฌ๊ฐ ๋๋ ๊ฒ ์ค์์ ๋น๊ต
| 2์ฝ์ด 8๊ธฐ๊ฐ | 4์ฝ์ด 16๊ธฐ๊ฐ | |
|---|---|---|
| ํ๊ท (0.01~0.30 RPS) | ๋์๊ฐ (ํ๋ ํ์) | ๋งค์ฐ ์์ |
| Peak(5~10 RPS, timeout 5s) | ๋ถ์์ (์ค์ ๋ฉ๋ชจ๋ฆฌ ํ์) | ๋์ฒด๋ก ์์ |
| ์ฅ์ | ๋น์ฉ ์ต์ | ์ด์ ์ฅ์ ๋ด์ฑ |
| ๋จ์ | GC/์ค์/DB์บ์ ์ถ์๋ก โ๋๋ฆฌ๊ฒ ์ฃฝ์โ | ๋น์ฉโ |
์ต์ข ์ธ์คํด์ค ์ฌ์ ์ ํ ์ด์
- ๋น์ฉ ํจ์จ์ฑ ๊ทน๋ํ: 4์ฝ์ด 16๊ธฐ๊ฐ ๋๋น ๋น์ฉ์ ์ฝ 50% ์ ๊ฐํ์ฌ ์ด๊ธฐ ์ธํ๋ผ ์ด์ ๋ถ๋ด์ ์ต์ํํจ.
- ํ๊ท ๋ถํ ์ต์ ํ: ํ์ฌ ํ๊ท RPS(0.01~0.30) ๊ธฐ์ค, 2์ฝ์ด๋ ์ ํด ์์ ์์ด ๊ฐ์ฅ ๋์ ๊ฐ๋๋ฅ ์ ๋ณด์ด๋ ์ฌ์์.
์ ์ ์จ ์์ 3๊ฐ + ๊ตญ๋ด 1๊ฐ
๋น๊ต ๊ธฐ์ค ์ธ์คํด์ค ์ฌ์: 2 vCPU / 8GB RAM์ธ์คํด์ค ์ฌ์ ๋น๊ต ํ
| ๊ตฌ๋ถ | AWS | Azure | GCP | NAVER Cloud |
|---|---|---|---|---|
| ์ธ์คํด์ค ํ์ | t3.large |
B2ms |
e2-standard-2 |
Standard s2-g3
|
| ์ ์์ ๋น์ฉ | ์ฝ $75.92 | ์ฝ $60.74 | ์ฝ $63.15 | 100,120์ |
| ์ ๊ท ํฌ๋ ๋ง | $100 / 90์ผ (+ ์ง์๊ธ) | $200 / 30์ผ | $300 / 90์ผ | 10๋ง / 90์ผ (+ ์ง์๊ธ) |
| ํต์ฌ ๊ฐ์ | ์๋์ ์ธ ์์ฅ ์ ์ ์จ ๋ฐ ์ปค๋ฎค๋ํฐ | MS ์ํํธ์จ์ด์์ ํตํฉ์ฑ | ๋ฐ์ดํฐ ๋ถ์ ๋ฐ Kubernetes ๊ฐ์ | ๊ตญ๋ด ๋ฐ์ฐฉํ ๊ธฐ์ ์ง์ ๋ฐ ๊ฒฐ์ ํธ์์ฑ |
์ต์ข AWS ์ ํ ์ด์
- GCP๋ ์ ๊ท ์ฌ์ฉ์์๊ฒ $300(43๋ง์) ํฌ๋ ๋ง์ ์ ๊ณตํ๋ฉฐ, ์ธ์คํด์ค ๋น์ฉ๋ ์ ๋ ดํ์ฌ ์์ฐ์ด ์ ํ๋ ์ด๊ธฐ ํ์ ์ ํฉํ์ต๋๋ค.
- ํ์ง๋ง, ๋น ๋ฅธ ๋ฐฐํฌ๊ฐ ํ์ํ ๋งํผ, ํ์ด ์ต์ํ๊ณ ํธํ AWS๋ก ์ ํํ์ต๋๋ค.
- ๋ถ๊ฐ์ ์ผ๋ก, AWS์ ๋ฒ์คํธ ํด๋์ค๋ฅผ ์ฐ๊ฒ ๋๋ค๋ฉด ์์์น๋ชปํ ๊ฐ์์ค๋ฌ์ด ํธ๋ํฝ์ด ๋ชฐ๋ ธ์ ๋์๋ ๋์์ด ๊ฐ๋ฅํ๋ค๊ณ ํ๋จํ์ต๋๋ค.
์ต๋ ์ ์ ์์
- ๋ฉ๋ชจ๋ฆฌ: ์ค๋ ๋๋น 1MB ์ค์ ์ ์์ ์ฑ
- 5~6GB๋ฅผ ์ ์ ํ๊ณ ์๋๋ผ๋, ๋จ์ 2GB ์ด์์ ๊ฐ์ฉ ๋ฉ๋ชจ๋ฆฌ๋ 100๋ช ์ ์ ์ ๊ฐ ๋ง๋๋ ์์ ๊ฐ์ฒด(Heap)์ ์ค๋ ๋ ์คํ์ ์์ฉํ๊ธฐ์ ์ถฉ๋ถํ ๋๋
- CPU : T3 ๋ฒ์คํธ ๊ธฐ๋ฅ: ํ์ 0.3 RPS ์์ค์์๋ CPU ํฌ๋ ๋ง์ ์์๋์๋ค๊ฐ, 100๋ช ์ด ๋ชฐ๋ฆฌ๋ ํผํฌ ํ์์ ๊ธฐ๋ณธ ์ฑ๋ฅ ์ด์์ CPU ์์
- ์ต๋ 100๋ช
- ๋จ์ผ ์ธ์คํด์ค์ ์ฑ๊ฒฉ ์, ๋น ๋ฅด๊ฒ ๋ฐฐํฌ๊ฐ ๊ฐ๋ฅํ ํผ๋ธ๋ฆญ ์๋ธ๋ท์ผ๋ก ๊ตฌ์ถ
- ์ค์จ๊ฑฐ ๋ฑ ์ธ๋ถ์์ ์ ๊ทผํด์ผ๋๋ ๊ฒฝ์ฐ๊ฐ ์กด์ฌํ๊ธฐ์ SSL ์ค์ ์งํ
| ๋์ ์๋น์ค | ์๋ธ๋๋ฉ์ธ | ํฌํธ | ์ค๋ช |
|---|---|---|---|
| ํ๋ก ํธ์๋ | www.devths.com | 80, 443 โ 3000 | SSL ์ ๊ณต, ์ ์ ํ์ผ ๋น๋ |
| ๋ฐฑ์๋ API | api.devths.com | 80, 443 โ 8080 | SSL ์ ๊ณต, REST API ์์ฒญ ์ฒ๋ฆฌ |
| AI ์๋ฒ | ai.devths.com | 80, 443 โ 8000 | SSL ์ ๊ณต, AI ๋ชจ๋ธ ์๋ต ์ฒ๋ฆฌ์ฉ API |
| DB (MySQL) | - | 3306 | ์ธ๋ถ ๋น๊ณต๊ฐ, ์๋ฒ ๋ด ์๋น์ค ๊ฐ ์ ๊ทผ๋ง ํ์ฉ |
- ๋ฐฐํฌ ๋ฐฉ์: ์ผ๊ด ์์์ ๋ฐฐํฌ (Big Bang)
- ๋ฐฐํฌ ํ๊ฒฝ: GCP Compute Engine (1๋)
- ๋ฐฐํฌ ๋์: FE, BE, AI, DB
- ์ ์ ๋ฐฉ์: SSH ์ง์ ์ ์
| ์ญํ | ๋ด๋น์ | ์ค๋ช |
|---|---|---|
| ๋ฐฐํฌ ์ด๊ด | ํ ๋ฆฌ๋ | ๋ฐฐํฌ ์์ ๊ฒฐ์ ๋ฐ ์ ์ฒด ์งํ ๊ด๋ฆฌ |
| ํ๋ก ํธ ๋น๋ ๋ฐ ๋ฐฐํฌ | ํด๋ผ์ฐ๋ ๋ด๋น์ | ํ๋ก ํธ ๋น๋ ๋ฐ ์ ์ ํ์ผ ๋ฐฐํฌ |
| ๋ฐฑ์๋ ๋น๋ ๋ฐ ๋ฐฐํฌ | ํด๋ผ์ฐ๋ ๋ด๋น์ | API ์๋ฒ ๋น๋ ๋ฐ ์คํ |
| AI ์๋ฒ ๋น๋ ๋ฐ ๋ฐฐํฌ | ํด๋ผ์ฐ๋ ๋ด๋น์, AI ๋ด๋น์ | AI ์๋ฒ ํ๊ฒฝ ์ค์ ๋ฐ ์คํ |
| ๋๋ฉ์ธ ๋ฐ ์ธํ๋ผ ์ ๊ฒ | ํด๋ผ์ฐ๋ ๋ด๋น์ | Nginx, ๋๋ฉ์ธ, ํฌํธ ์ํ ํ์ธ |
| ๊ธฐ๋ฅ ํ ์คํธ ๋ฐ ์๋ฃ ๋ณด๊ณ | ๊ฐ ํํธ๋ณ ๋ด๋น์ | ๋ฐฐํฌ ํ ๊ธฐ๋ฅ ๊ฒ์ฆ ๋ฐ ๋ณด๊ณ |
| ๋จ๊ณ | ์ ์ฐจ๋ช | ์์ธ ์์ ๋ด์ฉ (Action) | ์์ ์๊ฐ | ์ฐ์ถ ๊ทผ๊ฑฐ ๋ฐ ์ฒดํฌํฌ์ธํธ |
|---|---|---|---|---|
| 1 | ์ฌ์ ์ ๊ฒ(Pre-flight) | 1. ๋์คํฌ/๋ฉ๋ชจ๋ฆฌ/์ค์ ์ฌ์ ํ์ธ2. Git ์ํ ํ์ธ ๋ฐ Pull | 2~3๋ถ | โข Swap ์ฒดํฌ ํ์: ๋น๋ ๋ฐ ์ด์ค ์คํ ์ ๋ฉ๋ชจ๋ฆฌ ํญ์ฆ ๋๋น |
| 2 | ๋น๋ ์งํ(Build) | 1. ๋ฐฑ์๋: ./gradlew clean build -x test2. ํ๋ก ํธ: npm run build3. AI: pip install (ํ์์) | 6~10๋ถ | โข ์์ ์ง์ค ๊ตฌ๊ฐ: ์๋น์ค ์ค๋จ์ ์์ผ๋ ์๋ฒ๊ฐ ๋๋ ค์ง ์ ์์โข ๋ฐฑ์๋/ํ๋ก ํธ ๋น๋๋ฅผ ์์ฐจ์ ์ผ๋ก ์งํํ์ฌ ๋ถํ ๋ถ์ฐ |
| 3 | ์ ๋ฐฑ์๋ ์คํ(Boot-up) | 1. ํ์ฌ ํฌํธ(Old) ํ์ธ2. ๋ฐ๋ ํฌํธ(New)๋ก JAR ์คํ(์์ง ํธ๋ํฝ์ Old๋ก ํ๋ฆ) | 1๋ถ | โข ๊ณ ๋ฆฝ๋ ์คํ: ์ฌ์ฉ์๋ ์์ง ์ ์๋ฒ์ ์ ๊ทผ ๋ถ๊ฐ๋ฅโข ๋ถํ ์ค ์๋ฌ๊ฐ ๋๋ ์ค์ ์๋น์ค์ ์ํฅ ์์ |
| 4 | ํฌ์ค ์ฒดํฌ(Verification) | 1. curl localhost:NewPort/health2. 200 OK ์๋ต์ด ์ฌ ๋๊น์ง ๋ฐ๋ณต ํ์ธ(์คํจ ์ ๋ฐฐํฌ ์ค๋จ ๋ฐ ๋กค๋ฐฑ) | 1~2๋ถ | โข ์์ ์ฅ์น(Safety Catch): Spring์ด ์๋ฒฝํ ๋ฐ ๋๊น์ง ๋๊ธฐโข DB ์ฐ๊ฒฐ, ์ด๊ธฐํ ์คํจ ์ ์ฌ๊ธฐ์ ๊ฑธ๋ฌ์ง |
| 5 | Nginx ํธ๋ํฝ ์ ํ(Switching) | 1. inc ํ์ผ ๋ด ํฌํธ ๋ณ๊ฒฝ(8080 โ 8081)2. sudo nginx -s reload | 10์ด | โข ํธ๋ํฝ ์ค์์นญ ์์ : Nginx๊ฐ ์ฆ์ ์ ํฌํธ๋ก ๋ผ์ฐํ ์์โข reload๋ ์ฐ๊ฒฐ์ ๋์ง ์๊ณ ์ค์ ๋ง ๋ฐ์ํ๋ฏ๋ก ๋ค์ดํ์ 0์ด |
| 6 | ํ๋ก ํธ/AI ๋ฐ์(Reload) | 1. Next.js: pm2 reload frontend2. FastAPI: systemctl reload ai-worker | 1๋ถ | โข ๋ฐฑ์๋๊ฐ ์์ ํ๋ ํ ํ๋ก ํธ/AI ์ฌ์์โข ์ต์ ์ฝ๋๊ฐ ์ด๋ฏธ ๋น๋๋์ด ์์ผ๋ฏ๋ก ์ฆ์ ๋ฐ์๋จ |
| 7 | ๋ฆฌ์์ค ์ ๋ฆฌ(Cleanup) | 1. ๊ตฌ๋ฒ์ (Old) ๋ฐฑ์๋ ์ข ๋ฃ2. ์์ ํ์ผ ์ ๋ฆฌ | 1๋ถ | โข ๋ฉ๋ชจ๋ฆฌ ํ๋ณด๋ฅผ ์ํด ๊ตฌ๋ฒ์ ํ๋ก์ธ์ค killโข ๋ฐฐํฌ ์๋ฃ |
- ์ด ๋ฐฐํฌ ์๊ฐ: ์ฝ 12~18๋ถ
- ์๋น์ค ์ค๋จ ๊ฐ๋ฅ์ฑ: 0์ด
- ์๋น์ค ์๋ต ์ง์ฐ๊ฐ๋ฅ์ฑ: ๋น๋ ์ค CPU ์ฌ์ฉ๋ ์ฆ๊ฐ๋ก ๋ฐ์ ๊ฐ๋ฅ์ฑ ์์
- ๋ฐฐํฌ ์๊ฐ๋ ๊ถ์ฅ: โฐ ์๋ฒฝ 2์~5์ (ํธ๋ํฝ ์ต์ ์๊ฐ๋) โ ์ฐ๋ฆฌ ์๋น์ค์ ์ฃผ์ ํ๊ฒ์ด ํ์/๊ตฌ์ง์์ด๋ฏ๋ก ์ถํด๊ทผยท์ ์ฌ์๊ฐ ์ธ ์๊ฐ๋์ ์งํ
| ๊ตฌ๋ถ | ํญ๋ชฉ | ํ์ธ |
|---|---|---|
| ๋ฐฐํฌ ์ | ์ธ์คํด์ค ์ํ(CPU/๋ฉ๋ชจ๋ฆฌ/๋์คํฌ) | โ |
| ๋ฐฐํฌ ์ | Git ์ต์ ์ฝ๋ ๋ฐ์ ์ฌ๋ถ | โ |
| ๋ฐฐํฌ ์ค | Nginx ์ ๊ฒ ํ์ด์ง ํ์ธ | โ |
| ๋ฐฐํฌ ํ | API ํฌ์ค ์ฒดํฌ | โ |
| ๋ฐฐํฌ ํ | ํ๋ก ํธ ์ฃผ์ ํ๋ฉด ๋์ | โ |
| ๋ฐฐํฌ ํ | ์๋ฌ ๋ก๊ทธ ํ์ธ | โ |
- ๋ฐฐํฌ ๋ช ๋ น์ด๋ฅผ ์ ๋ฆฌํ ์คํฌ๋ฆฝํธ ๋ฌถ์์ผ๋ก ์ฌ์ฉ
- ๋ฐฐํฌ ์ฌ๋ถ ํ๋จ, ๊ฒ์ฆ, ๋กค๋ฐฑ ๊ฒฐ์ ์ ์ฌ๋์ด ์ง์ ์ํ
- ๋ฐฐํฌ ๋ช ๋ น์ด ์คํ ์์น๋ EC2 ์ธ์คํด์ค ๋ด๋ถ๋ก ํ์
| ๊ตฌ๋ถ | โ ๋ก์ปฌ ์ปดํจํฐ ๋น๋ ํ scp ์ ๋ฌ (๊ฒํ ํ ์ ์ธ) | โก EC2 ์ธ์คํด์ค ๋ด๋ถ ๋น๋ ๋ฐ ๋ฐฐํฌ (์ต์ข ์ ํ) |
|---|---|---|
| ๋น๋ ์์น | ๊ฐ๋ฐ์ ๊ฐ์ธ ๋ก์ปฌ PC | EC2 ์ด์ ์ธ์คํด์ค ๋ด๋ถ |
| ํ๋ฐํธ์๋ ์ฒ๋ฆฌ | ๋ก์ปฌ build ํ scp ์ ์ก | ์๋ฒ์์ ์ง์ build ๋๋ ์ ์ ํ์ผ ์์ฑ |
| ๋ฐฑ์๋ ์ฒ๋ฆฌ | ๋ก์ปฌ Gradle build โ JAR scp | ์๋ฒ์์ Gradle build โ JAR ์คํ |
| AI ์๋ฒ ์ฒ๋ฆฌ | ์คํ ์ฐ์ถ๋ฌผ ๊ฐ๋ ์์ โ ๋ณ๋ ์ฒ๋ฆฌ ํ์ | venv ํฌํจ ์คํ ํ๊ฒฝ ๊ทธ๋๋ก ๊ตฌ์ฑ |
| ํ๊ฒฝ ์ผ๊ด์ฑ | โ OS, ๋ผ์ด๋ธ๋ฌ๋ฆฌ, ๋ฒ์ ์ ๋ฐ๋ผ ๊ฒฐ๊ณผ ๋ฌ๋ผ์ง | โ ์ค์ ์ด์ ํ๊ฒฝ๊ณผ 100% ๋์ผ |
| ์ฌํ์ฑ | โ ๋์ผ ์ปค๋ฐ์ด์ด๋ ๋น๋ ๊ฒฐ๊ณผ ์์ด ๊ฐ๋ฅ | โ ์ฅ์ ์ ๋์ผ ํ๊ฒฝ์์ ์ฌํ ๊ฐ๋ฅ |
| ๋ณด์ ๊ด์ | โ ๋ก์ปฌ PC๋ ์ ๋ขฐ ๊ฒฝ๊ณ ๋ฐ, ํคยท๊ถํ ๋ ธ์ถ ์ํ | โ ์ด์ ์๋ฒ ๋ด๋ถ์์๋ง ๋ฐฐํฌ ์ํ |
| ๊ฐ์ฌยท์ถ์ | โ ๋๊ฐยท์ด๋์ ๋น๋ํ๋์ง ์ถ์ ์ด๋ ค์ | โ ์๋ฒ ๋ก๊ทธ ๊ธฐ์ค ๋ฐฐํฌ ์ด๋ ฅ ๊ด๋ฆฌ ๊ฐ๋ฅ |
| ์ด์ ์ ํฉ์ฑ | โ ๊ฐ์ธ ํ๋ก์ ํธ ์์ค์๋ง ์ ํฉ | โ ์ด์ ํ๊ฒฝ ๋ฐฐํฌ ๋ฐฉ์์ผ๋ก ์ ํฉ |
| ์ต์ข ํ๋จ | ์ด์ ๋ฐฐํฌ ๋ฐฉ์์ผ๋ก ๋ถ์ ์ ํ์ฌ ์ ์ธ | ์ต์ข ์ฑํ |
#!/bin/bash
# ==============================================================================
# [Devths] ๋ฌด์ค๋จ ๋ฐฐํฌ ์คํฌ๋ฆฝํธ (Rollback ๊ธฐ๋ฅ ํฌํจ)
# ์ํคํ
์ฒ: Spring Boot (Blue/Green) + Next.js + FastAPI
# ์์ ์ผ: 2026-01-07
# ==============================================================================
# ------------------------------------------------------------------------------
# 0. ํ๊ฒฝ ๋ณ์ ์ค์
# ------------------------------------------------------------------------------
PROJECT_ROOT="/home/ubuntu/devths"
BACKEND_DIR="$PROJECT_ROOT/backend"
FRONTEND_DIR="$PROJECT_ROOT/frontend"
AI_DIR="$PROJECT_ROOT/ai"
NGINX_INC="/home/ubuntu/nginx/backend_url.inc"
# ๋ฐฑ์
์ ์ ์ฅํ ์์ ๋๋ ํ ๋ฆฌ
BACKUP_DIR="/home/ubuntu/deployment_backups/$(date +%Y%m%d_%H%M%S)"
mkdir -p $BACKUP_DIR
# ๋ก๊ทธ ์์ ์ค์
TXT_GREEN='\033[0;32m'
TXT_RED='\033[0;31m'
TXT_YELLOW='\033[1;33m'
TXT_RESET='\033[0m'
function log_info() { echo -e "${TXT_GREEN}[INFO] $1${TXT_RESET}"; }
function log_warn() { echo -e "${TXT_YELLOW}[WARN] $1${TXT_RESET}"; }
function log_err() { echo -e "${TXT_RED}[ERROR] $1${TXT_RESET}"; }
# ------------------------------------------------------------------------------
# [ํต์ฌ] ๋กค๋ฐฑ(Rollback) ํจ์ ์ ์
# ์๋ฌ ๋ฐ์ ์(trap) ์ด ํจ์๊ฐ ํธ์ถ๋จ
# ------------------------------------------------------------------------------
function rollback() {
log_err "๋ฐฐํฌ ์ค ์ค๋ฅ๊ฐ ๋ฐ์ํ์ต๋๋ค! ๋กค๋ฐฑ์ ์์ํฉ๋๋ค..."
# 1. ๋กค๋ฐฑ ์ค ์๋ฌ๊ฐ ๋๋ ๋ฉ์ถ์ง ์๋๋ก ์ค์ ๋ณ๊ฒฝ
set +e
# 2. ์์ค์ฝ๋ ๋กค๋ฐฑ (Git)
if [ -n "$PREV_COMMIT_SHA" ]; then
log_warn "git reset --hard $PREV_COMMIT_SHA ์คํ ์ค..."
cd $PROJECT_ROOT
git reset --hard $PREV_COMMIT_SHA
fi
# 3. ๋ฐฑ์๋ ์ํฐํฉํธ(JAR) ๋ณต๊ตฌ
if [ -f "$BACKUP_DIR/app.jar" ]; then
log_warn "์ด์ app.jar ๋ณต๊ตฌ ์ค..."
cp "$BACKUP_DIR/app.jar" "$BACKEND_DIR/build/libs/app.jar"
fi
# 4. ํ๋ก ํธ์๋ ๋น๋(.next) ๋ณต๊ตฌ
if [ -d "$BACKUP_DIR/.next" ]; then
log_warn "์ด์ .next ํด๋ ๋ณต๊ตฌ ์ค..."
rm -rf "$FRONTEND_DIR/.next"
cp -r "$BACKUP_DIR/.next" "$FRONTEND_DIR/.next"
fi
# 5. Nginx ์ค์ ์๋ณต (ํฌํธ๊ฐ ๋ณ๊ฒฝ๋์๋ค๋ฉด)
# CURRENT_PORT๋ ๋ฐฐํฌ ์์ ์ ์ ํฌํธ์
if [ -n "$CURRENT_PORT" ]; then
log_warn "Nginx ์ค์ ์ ์ด์ ํฌํธ($CURRENT_PORT)๋ก ๋๋๋ฆฝ๋๋ค..."
echo "set \$service_url http://127.0.0.1:$CURRENT_PORT;" > $NGINX_INC
sudo nginx -s reload
fi
# 6. ์๋ก ๋ด๋ ํ๋ก์ธ์ค(NEW_PID)๊ฐ ์๋ค๋ฉด ์ฌ์ด
if [ -n "$NEW_PID" ]; then
log_warn "์คํจํ ์ ๊ท ํ๋ก์ธ์ค(PID: $NEW_PID) ์ข
๋ฃ ์ค..."
kill -9 $NEW_PID 2>/dev/null
fi
# 7. ์๋น์ค ์ฌ์์ (๋ณต๊ตฌ๋ ํ์ผ ๊ธฐ๋ฐ)
log_warn "์ด์ ๋ฒ์ ์ผ๋ก ์๋น์ค ์ฌ์์..."
cd $FRONTEND_DIR && pm2 reload frontend
sudo systemctl reload ai-worker
# ๊ธฐ์กด ๋ฐฑ์๋๋ ์ข
๋ฃ๋์ง ์์์ผ๋ฏ๋ก(Blue/Green์ ์ฅ์ )
# ํฌํธ๋ง ์ ๋ฐ๋์๋ค๋ฉด ๊ทธ๋๋ก ์ด์์์.
log_err "๋กค๋ฐฑ์ด ์๋ฃ๋์์ต๋๋ค. ๋ก๊ทธ๋ฅผ ํ์ธํด์ฃผ์ธ์."
exit 1
}
# ์คํฌ๋ฆฝํธ ์คํ ์ค ์๋ฌ(ERR) ๋ฐ์ ์ rollback ํจ์ ํธ์ถ
trap 'rollback' ERR
set -e
# ==============================================================================
# [Step 1] ์ฌ์ ์ ๊ฒ ๋ฐ ์ํ ๋ฐฑ์
(Backup)
# ==============================================================================
log_info "[Step 1] ํ์ฌ ์ํ ๋ฐฑ์
๋ฐ ์ฌ์ ์ ๊ฒ..."
# 1. ํ์ฌ Git ์ปค๋ฐ ํด์ ์ ์ฅ (๋กค๋ฐฑ์ฉ)
cd $PROJECT_ROOT
PREV_COMMIT_SHA=$(git rev-parse HEAD)
log_info "ํ์ฌ ์ปค๋ฐ ํด์ ์ ์ฅ: $PREV_COMMIT_SHA"
# 2. ํ์ฌ ์คํ ์ค์ธ ์ํฐํฉํธ ๋ฐฑ์
# (๋น๋ ์คํจ๋ ๋ฐํ์ ์๋ฌ ์ ๋๋๋ฆฌ๊ธฐ ์ํจ)
log_info "ํ์ฌ ๋น๋ ํ์ผ๋ค์ ๋ฐฑ์
ํฉ๋๋ค... ($BACKUP_DIR)"
# Backend Jar ๋ฐฑ์
if [ -f "$BACKEND_DIR/build/libs/app.jar" ]; then
cp "$BACKEND_DIR/build/libs/app.jar" "$BACKUP_DIR/app.jar"
fi
# Frontend Build ๋ฐฑ์
if [ -d "$FRONTEND_DIR/.next" ]; then
cp -r "$FRONTEND_DIR/.next" "$BACKUP_DIR/.next"
fi
# 3. ํ์ฌ ํฌํธ ํ์ธ (Blue/Green ํ๋จ์ฉ)
CURRENT_PORT=$(grep -oP '127.0.0.1:\K\d+' $NGINX_INC) || CURRENT_PORT="8080"
log_info "ํ์ฌ ํ์ฑ ํฌํธ: $CURRENT_PORT"
# ==============================================================================
# [Step 2] ์ฝ๋ ์ต์ ํ (Git Pull)
# ==============================================================================
log_info "[Step 2] ์ต์ ์ฝ๋๋ฅผ ๊ฐ์ ธ์ต๋๋ค (Git Pull)..."
cd $PROJECT_ROOT
git pull origin main
# ==============================================================================
# [Step 3] ๋ฐฑ์๋ ๋น๋ (Spring Boot)
# ==============================================================================
log_info "[Step 3] ๋ฐฑ์๋ ๋น๋ ์์..."
cd $BACKEND_DIR
chmod +x gradlew
./gradlew clean build -x test
# ==============================================================================
# [Step 4] ํ๋ก ํธ์๋ ๋น๋ (Next.js)
# ==============================================================================
log_info "[Step 4] ํ๋ก ํธ์๋ ๋น๋ ์์..."
cd $FRONTEND_DIR
npm install --production=false
npm run build
# ==============================================================================
# [Step 5] AI ์๋ฒ ์ค๋น (FastAPI)
# ==============================================================================
log_info "[Step 5] AI ์๋ฒ ํจํค์ง ์ค์น..."
cd $AI_DIR
if [ ! -d "venv" ]; then python3 -m venv venv; fi
source venv/bin/activate
pip install -r requirements.txt
# ==============================================================================
# [Step 6] ๋ฐฑ์๋ ๋ฌด์ค๋จ ๋ฐฐํฌ (Blue/Green)
# ==============================================================================
log_info "[Step 6] ๋ฐฑ์๋ ํฌํธ ์ค์์นญ ์์..."
# 1. ์๋ก์ด ํฌํธ ๊ฒฐ์
if [ "$CURRENT_PORT" == "8080" ]; then
NEW_PORT=8081
else
NEW_PORT=8080
fi
log_info "์๋ก ๋์ธ ํฌํธ: $NEW_PORT"
# 2. ํฌํธ ์ ๋ฆฌ
TARGET_PID=$(lsof -ti :$NEW_PORT || true)
if [ -n "$TARGET_PID" ]; then kill -9 $TARGET_PID; fi
# 3. ์ ์๋ฒ ์คํ
# nohup ์คํ ์ set -e ๋๋ฌธ์ ์ข
๋ฃ๋์ง ์๋๋ก ์ฃผ์ ํ์ํ๋, ๋ฐฑ๊ทธ๋ผ์ด๋(&)๋ ์ํฅ ์ ์
nohup java -Xms2048m -Xmx2048m \
-Dserver.port=$NEW_PORT \
-Dserver.tomcat.threads.max=150 \
-jar $BACKEND_DIR/build/libs/app.jar > /dev/null 2>&1 &
NEW_PID=$!
log_info "์ ์๋ฒ($NEW_PORT) ๋ถํ
์ค... (PID: $NEW_PID)"
# 4. ํฌ์ค ์ฒดํฌ
log_info "ํฌ์ค ์ฒดํฌ ์งํ ์ค..."
HEALTH_SUCCESS=false
for i in {1..12}; do
sleep 5
RESPONSE=$(curl -s -o /dev/null -w "%{http_code}" http://127.0.0.1:$NEW_PORT/health)
if [ "$RESPONSE" == "200" ]; then
log_info "ํฌ์ค ์ฒดํฌ ํต๊ณผ (HTTP 200)"
HEALTH_SUCCESS=true
break
fi
log_warn "๋๊ธฐ ์ค... ($i/12)"
done
if [ "$HEALTH_SUCCESS" = false ]; then
log_err "์ ์๋ฒ ํฌ์ค ์ฒดํฌ ์คํจ. ๋กค๋ฐฑ์ ํธ๋ฆฌ๊ฑฐํฉ๋๋ค."
# ์ฌ๊ธฐ์ false๋ฅผ ๋ฐํํ์ฌ trap์ด ๊ฑธ๋ฆฌ๊ฒ ํจ
false
fi
# 5. Nginx ํธ๋ํฝ ์ ํ
echo "set \$service_url http://127.0.0.1:$NEW_PORT;" > $NGINX_INC
sudo nginx -s reload
log_info "Nginx ํธ๋ํฝ ์ ํ ์๋ฃ ($CURRENT_PORT -> $NEW_PORT)"
# ==============================================================================
# [Step 7] ํ๋ก ํธ/AI ์ฌ์์
# ==============================================================================
log_info "[Step 7] ํ๋ก ํธ์๋ ๋ฐ AI ์๋ฒ ๋ฐ์..."
cd $FRONTEND_DIR
pm2 reload frontend || pm2 start npm --name "frontend" -- start
sudo systemctl reload ai-worker
# ==============================================================================
# [Step 8] ๋ฆฌ์์ค ์ ๋ฆฌ
# ==============================================================================
log_info "[Step 8] ๊ตฌ๋ฒ์ ์๋ฒ ์ ๋ฆฌ..."
OLD_PID=$(lsof -ti :$CURRENT_PORT || true)
if [ -n "$OLD_PID" ]; then
kill -15 $OLD_PID
log_info "๊ตฌ๋ฒ์ ์๋ฒ($CURRENT_PORT) ์ข
๋ฃ ์๋ฃ."
fi
# ์ฑ๊ณต ์ ๋ฐฑ์
ํ์ผ ์ญ์ (๊ณต๊ฐ ํ๋ณด)
rm -rf $BACKUP_DIR
log_info "[Success] ๋ฐฐํฌ ์ฑ๊ณต! ๋ฐฑ์
ํ์ผ์ ์ ๋ฆฌํ์ต๋๋ค."๋ฐฐํฌ ์, ์ด์ ๋ฒ์ ์ ๋ฐฑ์ ํด๋์๋ค๊ฐ, ๋กค๋ฐฑ์ ์ฌ์ฉํ ์ ์๋๋ก ํจ
#!/bin/bash
# ==========================================
# ์ค์ ๋ณ์
# ==========================================
APP_NAME="my-web-service"
BASE_DIR="/home/user/app"
RELEASES_DIR="$BASE_DIR/releases"
LINK_PATH="$BASE_DIR/current"
# ==========================================
# 1. ํ์ฌ ์ฐ๊ฒฐ๋ ๋ฒ์ ํ์ธ (readlink)
CURRENT_VERSION=$(readlink -f "$LINK_PATH")
echo "ํ์ฌ ๋ฐฐํฌ๋ ๋ฒ์ : $(basename "$CURRENT_VERSION")"
# 2. ์ด์ ๋ฒ์ ์ฐพ๊ธฐ (ํ์ฌ ๋ฒ์ ์ ์ ์ธํ ๊ฐ์ฅ ์ต์ ๋ฒ์ )
# (grep -v: ํ์ฌ ๋ฒ์ ์ ์ธ, head -n 1: ๊ทธ ๋ค์ ์ต์ )
PREVIOUS_VERSION=$(ls -td "$RELEASES_DIR"/*/ | grep -v "$CURRENT_VERSION" | head -n 1)
if [ -z "$PREVIOUS_VERSION" ]; then
echo "[Error] ๋์๊ฐ ์ด์ ๋ฒ์ ์ ์ฐพ์ ์ ์์ต๋๋ค."
exit 1
fi
echo "๋กค๋ฐฑ ํ๊ฒ ๋ฒ์ : $(basename "$PREVIOUS_VERSION")"
# 3. ์ฌ๋ณผ๋ฆญ ๋งํฌ ๊ต์ฒด (ํต์ฌ: -nfs ์ต์
์ผ๋ก ์์์ ๊ต์ฒด)
echo "SWITCHING symlink..."
ln -nfs "$PREVIOUS_VERSION" "$LINK_PATH"
# 4. ์๋น์ค ์ฌ์์
echo "RESTARTING service..."
sudo systemctl restart $APP_NAME
echo "๋กค๋ฐฑ ์๋ฃ! ํ์ฌ ๋ฒ์ ์ $(basename "$PREVIOUS_VERSION") ์
๋๋ค."| ๋ฌธ์ | ์ค๋ช | ํด๊ฒฐ๋ฐฉ์ |
|---|---|---|
| ์๋ ๋ฐฐํฌ ๋ถ๋ด | ๋ฐ๋ณต์ ์ธ scp, ssh ์๋ ๋ฐฐํฌ๋ก ์ธํ ์ค์ ๊ฐ๋ฅ์ฑ | ๋ฐฐํฌ ์คํฌ๋ฆฝํธ๋ฅผ ์ ๋นํ๊ณ , GitHub Actions ๋ฑ CI/CD ์๋ํ๋ก ์ ํ |
| ์ ์ฒด ์๋น์ค ์ค๋จ | ํ๋์ ์ปดํฌ๋ํธ ์ฅ์ ๊ฐ ์ ์ฒด ์๋น์ค ๊ฐ์ฉ์ฑ์ ์ง์ ์ ์ธ ์ํฅ์ ๋ฏธ์นจ | ๊ฐ ์๋น์ค๋ณ๋ก ์ธ์คํด์ค๋ฅผ ๋ถ๋ฆฌํ์ฌ ์ฅ์ ์ํฅ ๋ฒ์๋ฅผ ์ต์ํ |
| ํ์ฅ์ฑ ๋ถ์กฑ | ํธ๋ํฝ์ด ๋ง์ด ๋ชฐ๋ฆฌ๊ฒ ๋ ์, ๊ณ์ํด์ ์ฑ๋ฅ์ ์ฌ๋ฆด ์ ์์ | ๋จ์ผ ์ธ์คํด์ค์์ ๋ค์ค ์ธ์คํด์ค๋ก ํ์ฅํ์ฌ ์ฅ์ ์ ๋์ |
| ํญ๋ชฉ | ๋ชฉํ | ํ์ค์ ํ๊ณ | ํด๊ฒฐ๋ฐฉ์ |
|---|---|---|---|
| RTO (Recovery Time Objective) | 30๋ถ ์ด๋ด | Big Bang ์์์ ๋ฐฐํฌ ํน์ฑ์, ๋ฐฐํฌ ์ค ์ค๋ฅ๊ฐ ๋ฐ์ํ๋ฉด ์๋ ํ์ธ๊ณผ ๋ณต๊ตฌ์ ์๊ฐ์ด ๋ ์์๋ ์ ์์. ์ค์ ์ฅ์ ๋ฐ์ ์ 30๋ถ ๋ด ๋ณต๊ตฌ๊ฐ ํญ์ ๋ณด์ฅ๋์ง๋ ์์ | ๋ชจ๋ํฐ๋ง/์๋ ์ฒด๊ณ ๊ตฌ์ถ์ ํตํด ๋์ ์๋ ํฅ์ |
| RPO (Recovery Point Objective) | ์ต๊ทผ ๋ฐฐํฌ ์์ ๊ธฐ์ค (์๋ ๋ฐฑ์ ๊ธฐ์ค) | ์๋ ๋ฐฑ์ ์์ ์ดํ์ ๋ฐ์ดํฐ๋ ๋ณต๊ตฌ ๋ถ๊ฐ. ํนํ DB ๋ณ๊ฒฝ์ด ๋ง๊ฑฐ๋ ํธ๋์ญ์ ์ด ๋ง์ผ๋ฉด ์ผ๋ถ ๋ฐ์ดํฐ ์์ค ๊ฐ๋ฅ | ๋ชจ๋ํฐ๋ง/์๋ ์ฒด๊ณ ๊ตฌ์ถ์ ํตํด ๋์ ์๋ ํฅ์ |