Big Bang - 100-hours-a-week/9-team-Devths-WIKI GitHub Wiki

๋ชฉ์ฐจ (ํŽผ์น˜๊ธฐ/์ ‘๊ธฐ)

Big Bang ๋ฐฉ์‹ ์ˆ˜์ž‘์—… ๋ฐฐํฌ ์„ค๊ณ„

๐Ÿ’ก Big Bang ๋ฐฐํฌ๋ž€? ๋ชจ๋“  ์ปดํฌ๋„ŒํŠธ๋ฅผ ํ•œ ๋ฒˆ์— ์ˆ˜๋™์œผ๋กœ ์„ค์น˜ ๋ฐ ๋ฐฐํฌํ•˜๋Š” ์ „๋žต์œผ๋กœ, ์ดˆ๊ธฐ ์„œ๋น„์Šค ๊ฐœ๋ฐœ ๋ฐ ํŒ€ ์ˆ™๋ จ๋„ ํ–ฅ์ƒ์— ์ ํ•ฉํ•œ ๋ฐฉ์‹์ด๋‹ค.


โœจ 1. ๋„์ž… ๋ฐฐ๊ฒฝ

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 ์ˆ˜์ค€์œผ๋กœ ํŒ๋‹จํ•˜์˜€์Šต๋‹ˆ๋‹ค.

๐Ÿ“‚ 2. ๋ฐฐํฌ ์•„ํ‚คํ…์ฒ˜ ๋‹ค์ด์–ด๊ทธ๋žจ (V1 ๊ธฐ์ค€)

image
  • AWS์˜ ๋‹จ์ผ EC2
  • ํ•˜๋‚˜์˜ ์„œ๋ฒ„ ๋‚ด์—์„œ ํ”„๋ก ํŠธ์—”๋“œ, ๋ฐฑ์—”๋“œ, AI ์„œ๋ฒ„, DB ๋™์‹œ ์šด์˜
  • Nginx๋ฅผ ํ†ตํ•œ ์„œ๋ธŒ๋„๋ฉ”์ธ ๊ธฐ๋ฐ˜ ๋ผ์šฐํŒ…


๐ŸŒ 3. ๊ฐœ๋ฐœ ๊ด€๋ จ ์„ค๊ณ„

3-1. Devths ์„œ๋น„์Šค ๋‚ด ์›น ์„œ๋ฒ„ ์—ญํ• 

  • ๋ฆฌ๋ฒ„์Šค ํ”„๋ก์‹œ + TLS ์ข…๋ฃŒ + ์žฅ๊ธฐ ์—ฐ๊ฒฐ(์ŠคํŠธ๋ฆฌ๋ฐ) ์ฒ˜๋ฆฌ๊ฐ€ ํ•ต์‹ฌ
  • ๋‹จ์ผ ์ธ์Šคํ„ด์Šค๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ์— ํŠธ๋ž˜ํ”ฝ์„ ์ ์ ˆํ•˜๊ฒŒ ๋ถ„์‚ฐํ•ด์ฃผ๋Š” ๋ฆฌ๋ฒ„์Šค ํ”„๋ก์‹œ ๊ธฐ๋Šฅ ํ•„์š”
  • TLS termination ์„ค์ •
  • ์ฑ—๋ด‡ SSE(๋‹จ๋ฐฉํ–ฅ ์ŠคํŠธ๋ฆฌ๋ฐ ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ)๋ฅผ ์œ„ํ•ด์„œ keep-alive ์—ฐ๊ฒฐ ํ•„์š”
    • ์šฐ๋ฆฌ ์„œ๋น„์Šค๋Š” ์™ธ๋ถ€ API ์ด์šฉ์ด 3๊ฐœ ์กด์žฌ
    • keep-alive/์ŠคํŠธ๋ฆฌ๋ฐ ์—ฐ๊ฒฐ์—์„œ๋Š” ๋„คํŠธ์›Œํฌ ์ง€์—ฐ์ด ์—ฐ๊ฒฐ ์ฒ˜๋ฆฌ ๋ชจ๋ธ์ด ๋ฉ”๋ชจ๋ฆฌยท์Šค๋ ˆ๋“œ ํšจ์œจ์— ์ง๊ฒฐ
  • ์ •์  ํŒŒ์ผ์„œ๋น™
    • ํ”„๋ŸฐํŠธ ๋นŒ๋“œ ์‚ฐ์ถœ๋ฌผ์— ๋Œ€ํ•œ ์ •์  ํŒŒ์ผ ์„œ๋น™ ํ•˜์ง€๋งŒ, PDF/์ด๋ฏธ์ง€๋Š” ์™ธ๋ถ€ ์ €์žฅ์†Œ ์ด์šฉํ•˜์—ฌ ์ •์  ํŒŒ์ผ ์„œ๋น™ ์—ญํ•  ์ถ•์†Œ

3-1-2. ์›น ์„œ๋ฒ„ ์ข…๋ฅ˜ ๋น„๊ต

์ ์œ ์œจ ์ƒ์œ„ 3๊ฐœ Cloudflare๋Š” ๋ฆฌ๋ฒ„์Šค ํ”„๋ก์‹œ/CDN ์„œ๋น„์Šค์ด๊ณ  LiteSpeed๋Š” ์œ ๋ฃŒ ๊ธฐ๋ฐ˜์˜ ์ƒ์šฉ ์„œ๋ฒ„๋ผ, ์ˆœ์ˆ˜ ์˜คํ”ˆ์†Œ์Šค ๊ธฐ๋ฐ˜์˜ ์ž๊ฐ€ ์„ค์น˜ํ˜• ์›น ์„œ๋ฒ„(Self-hosted)๋“ค ์œ„์ฃผ๋กœ ๋น„๊ต

image
๊ตฌ๋ถ„ 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 ์ข…์†(๋น„์šฉ/์šด์˜), ๋ฆฌ๋ˆ…์Šค ๊ธฐ๋ฐ˜ ์Šคํƒ๊ณผ์˜ ์ผ๊ด€์„ฑ ๋–จ์–ด์ง - ๋™์  ์ปจํ…์ธ  ๋‹จ๋… ์ฒ˜๋ฆฌ ๋ถˆ๊ฐ€๋Šฅํ•˜๋ฉฐ, ํ”„๋ก์‹œ ์œ„์ฃผ ๊ธฐ๋Šฅ ์ˆ˜ํ–‰

3-1-3. ์šฐ๋ฆฌ ์„œ๋น„์Šค์— ๋งž๋Š” ์›น ์„œ๋ฒ„ ์„ ํƒ ๊ธฐ์ค€


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์˜ ์ง€์—ฐ์ด ์ „์ฒด ์„œ๋ฒ„์˜ ๋งˆ๋น„๋กœ ์ด์–ด์ง€๋Š” ๊ฒƒ์„ ์›์ฒœ ์ฐจ๋‹จํ•ฉ๋‹ˆ๋‹ค.

  1. ์šด์˜ ๋ฆฌ์Šคํฌ ๊ด€๋ฆฌ (Sustainability)
  • IIS๋Š” ๋ฆฌ๋ˆ…์Šค ํ™˜๊ฒฝ๊ณผ์˜ ํ˜ธํ™˜์„ฑ ๋ฐ ๋ผ์ด์„ ์Šค ๋น„์šฉ ๋ฌธ์ œ๋กœ ๋ฐฐ์ œํ•˜์˜€์Šต๋‹ˆ๋‹ค.
  • Nginx๋Š” ์ด๋ฏธ "์—…๊ณ„ ํ‘œ์ค€"์œผ๋กœ ์ž๋ฆฌ ์žก์•„, SSE ์„ค์ •์ด๋‚˜ ํ”„๋ก์‹œ ํƒ€์ž„์•„์›ƒ ํŠœ๋‹ ๋“ฑ ์šด์˜ ์ด์Šˆ์— ๋Œ€ํ•ด ๊ฒ€์ฆ๋œ ํ•ด๊ฒฐ์ฑ…(Best Practice)์„ ์ฐพ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

โ‡’ ํ•ด๋‹น ๊ธฐ์ค€์„ ๋ฐ”ํƒ•์œผ๋กœ Nginx๋ฅผ ์„ ํƒํ•˜์˜€์Šต๋‹ˆ๋‹ค. โœ…


3-2. ์‚ฌ์šฉ๋˜๋Š” CPU/๋ฉ”๋ชจ๋ฆฌ ๊ณ„์‚ฐ(์„ฑ๋Šฅ ์ถ”์‚ฐ)

EC2 ์‹ค์ธก ๋ฐ ๋ฆฌ์†Œ์Šค ์„ค๊ณ„ ์ƒ์„ธ ๋ฐ์ดํ„ฐ (Idle & Peak)

1. EC2 ์‹ค์ธก ๋ฐ์ดํ„ฐ (Idle ์ƒํƒœ)

์‹ค์ œ๋กœ EC2์—์„œ ๊ฐ ํ”„๋กœ์„ธ์Šค๋ฅผ ์‹คํ–‰ํ•˜์—ฌ ์ธก์ •ํ•œ ๊ฒฐ๊ณผ์ž…๋‹ˆ๋‹ค. image

image
์ข…๋ฅ˜ ์ ์œ ์œจ (%) ์‹ค์‚ฌ์šฉ ๋ฉ”๋ชจ๋ฆฌ
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

3. ๋ถ„์„ ๊ฒฐ๋ก 

  • ๋ฉ”๋ชจ๋ฆฌ: ํ”ผํฌ ์‹œ ์ตœ๋Œ€ 10.75GB๊ฐ€ ํ•„์š”ํ•˜์—ฌ ๋ฌผ๋ฆฌ RAM(8GB)์„ ์ดˆ๊ณผํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋ฅผ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•ด 4GB ์ด์ƒ์˜ Swap ๋ฉ”๋ชจ๋ฆฌ ์„ค์ •๊ณผ Java/MySQL์˜ ๋ฉ”๋ชจ๋ฆฌ ์ƒํ•œ์„ (Limit) ํŠœ๋‹์ด ํ•„์ˆ˜์ ์ž…๋‹ˆ๋‹ค.
  • ๋ฐฐํฌ ์ „๋žต: ๋น…๋ฑ… ๋ฐฐํฌ ์‹œ ์ˆœ๊ฐ„์ ์ธ ๋ฆฌ์†Œ์Šค ํญ๋ฐœ์ด ์˜ˆ์ƒ๋˜๋ฏ€๋กœ, ์„œ๋น„์Šค ๊ฐ„ ์ˆœ์ฐจ์  ๊ธฐ๋™ ์Šคํฌ๋ฆฝํŠธ ์ ์šฉ์„ ๊ถŒ์žฅํ•ฉ๋‹ˆ๋‹ค.
๋ถ„์„ ๊ธฐ์ค€ ๋ฐ ๊ณต์‹
  1. ๋ฉ”๋ชจ๋ฆฌ ๋ถ„์„ ๊ณต์‹(JVM ๊ธฐ์ค€) TotalProcessMemory = Heap + Metaspace + (ThreadStackSizeร—ThreadCount) + DirectMemory + CodeCache + OHS(Overhead)

  2. CPU ์ ์œ  ์‚ฐ์ •: ํŠธ๋ž˜ํ”ฝ ๊ธฐ๋ฐ˜ ์ถ”์‚ฐ(์š”์ฒญ๋Ÿ‰ ๊ธฐ์ค€)

    • ์ดˆ๋‹น ์š”์ฒญ ์ˆ˜ * ์š”์ฒญ๋‹น CPU ์†Œ๋ชจ๋Ÿ‰
    • ์ด CPU ์†Œ๋ชจ = (๊ฐ API์˜ RPS * ํ‰๊ท  ์ฒ˜๋ฆฌ ์‹œ๊ฐ„)์˜ ์ด ํ•ฉ

V1: ๋‹จ์ผ ์ธ์Šคํ„ด์Šค

  • ๋ชฉํ‘œ ํŠธ๋ž˜ํ”ฝ: 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 ์šด์˜

3-3. ์ธ์Šคํ„ด์Šค ์ƒ์„ธ์ŠคํŽ™ ์„ค๊ณ„

์ธ์Šคํ„ด์Šค ์‚ฌ์–‘ ๋น„๊ต ํ‘œ

์ปดํฌ๋„ŒํŠธ ๋ณ„ ๋ฆฌ์†Œ์Šค ๋ถ„์„ ๋ฐ”ํƒ•์œผ๋กœ ์ตœ์†Œ ๋ฉ”๋ชจ๋ฆฌ๊ฐ€ ๋„˜๋Š” ๊ฒƒ ์ค‘์—์„œ ๋น„๊ต

2์ฝ”์–ด 8๊ธฐ๊ฐ€ 4์ฝ”์–ด 16๊ธฐ๊ฐ€
ํ‰๊ท (0.01~0.30 RPS) ๋Œ์•„๊ฐ (ํŠœ๋‹ ํ•„์š”) ๋งค์šฐ ์•ˆ์ •
Peak(5~10 RPS, timeout 5s) ๋ถˆ์•ˆ์ • (์Šค์™‘ ๋ฉ”๋ชจ๋ฆฌ ํ•„์š”) ๋Œ€์ฒด๋กœ ์•ˆ์ •
์žฅ์  ๋น„์šฉ ์ตœ์ € ์šด์˜ ์žฅ์•  ๋‚ด์„ฑ
๋‹จ์  GC/์Šค์™‘/DB์บ์‹œ ์ถ•์†Œ๋กœ โ€œ๋А๋ฆฌ๊ฒŒ ์ฃฝ์Œโ€ ๋น„์šฉโ†‘

์ตœ์ข… ์ธ์Šคํ„ด์Šค ์‚ฌ์–‘ ์„ ํƒ ์ด์œ 

  1. ๋น„์šฉ ํšจ์œจ์„ฑ ๊ทน๋Œ€ํ™”: 4์ฝ”์–ด 16๊ธฐ๊ฐ€ ๋Œ€๋น„ ๋น„์šฉ์„ ์•ฝ 50% ์ ˆ๊ฐํ•˜์—ฌ ์ดˆ๊ธฐ ์ธํ”„๋ผ ์šด์˜ ๋ถ€๋‹ด์„ ์ตœ์†Œํ™”ํ•จ.
  2. ํ‰๊ท  ๋ถ€ํ•˜ ์ตœ์ ํ™”: ํ˜„์žฌ ํ‰๊ท  RPS(0.01~0.30) ๊ธฐ์ค€, 2์ฝ”์–ด๋Š” ์œ ํœด ์ž์› ์—†์ด ๊ฐ€์žฅ ๋†’์€ ๊ฐ€๋™๋ฅ ์„ ๋ณด์ด๋Š” ์‚ฌ์–‘์ž„.

3-4. ํด๋ผ์šฐ๋“œ ์ข…๋ฅ˜ ๋น„๊ต

์ ์œ ์œจ ์ƒ์œ„ 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๋ช…

3-5. VPC ๋ฐ ์„œ๋ธŒ๋„ท ์„ค๊ณ„ ์›์น™

  • ๋‹จ์ผ ์ธ์Šคํ„ด์Šค์˜ ์„ฑ๊ฒฉ ์ƒ, ๋น ๋ฅด๊ฒŒ ๋ฐฐํฌ๊ฐ€ ๊ฐ€๋Šฅํ•œ ํผ๋ธ”๋ฆญ ์„œ๋ธŒ๋„ท์œผ๋กœ ๊ตฌ์ถ•
  • ์Šค์›จ๊ฑฐ ๋“ฑ ์™ธ๋ถ€์—์„œ ์ ‘๊ทผํ•ด์•ผ๋˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ์กด์žฌํ•˜๊ธฐ์— SSL ์„ค์ • ์ง„ํ–‰

3-6. ์„œ๋ธŒ๋„๋ฉ”์ธ ๋งคํ•‘ ์ •์ฑ…

๋Œ€์ƒ ์„œ๋น„์Šค ์„œ๋ธŒ๋„๋ฉ”์ธ ํฌํŠธ ์„ค๋ช…
ํ”„๋ก ํŠธ์—”๋“œ 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 ์™ธ๋ถ€ ๋น„๊ณต๊ฐœ, ์„œ๋ฒ„ ๋‚ด ์„œ๋น„์Šค ๊ฐ„ ์ ‘๊ทผ๋งŒ ํ—ˆ์šฉ


๐Ÿ“ƒ 4. ๋ฐฐํฌ ํ”„๋กœ์„ธ์Šค ์„ค๊ณ„

4-1. ๋ฐฐํฌ ๊ฐœ์š”

  • ๋ฐฐํฌ ๋ฐฉ์‹: ์ผ๊ด„ ์ˆ˜์ž‘์—… ๋ฐฐํฌ (Big Bang)
  • ๋ฐฐํฌ ํ™˜๊ฒฝ: GCP Compute Engine (1๋Œ€)
  • ๋ฐฐํฌ ๋Œ€์ƒ: FE, BE, AI, DB
  • ์ ‘์† ๋ฐฉ์‹: SSH ์ง์ ‘ ์ ‘์†

4-2. ๋‹ด๋‹น์ž ์—ญํ• 

์—ญํ•  ๋‹ด๋‹น์ž ์„ค๋ช…
๋ฐฐํฌ ์ด๊ด„ ํŒ€ ๋ฆฌ๋” ๋ฐฐํฌ ์‹œ์  ๊ฒฐ์ • ๋ฐ ์ „์ฒด ์ง„ํ–‰ ๊ด€๋ฆฌ
ํ”„๋ก ํŠธ ๋นŒ๋“œ ๋ฐ ๋ฐฐํฌ ํด๋ผ์šฐ๋“œ ๋‹ด๋‹น์ž ํ”„๋ก ํŠธ ๋นŒ๋“œ ๋ฐ ์ •์  ํŒŒ์ผ ๋ฐฐํฌ
๋ฐฑ์—”๋“œ ๋นŒ๋“œ ๋ฐ ๋ฐฐํฌ ํด๋ผ์šฐ๋“œ ๋‹ด๋‹น์ž API ์„œ๋ฒ„ ๋นŒ๋“œ ๋ฐ ์‹คํ–‰
AI ์„œ๋ฒ„ ๋นŒ๋“œ ๋ฐ ๋ฐฐํฌ ํด๋ผ์šฐ๋“œ ๋‹ด๋‹น์ž, AI ๋‹ด๋‹น์ž AI ์„œ๋ฒ„ ํ™˜๊ฒฝ ์„ค์ • ๋ฐ ์‹คํ–‰
๋„๋ฉ”์ธ ๋ฐ ์ธํ”„๋ผ ์ ๊ฒ€ ํด๋ผ์šฐ๋“œ ๋‹ด๋‹น์ž Nginx, ๋„๋ฉ”์ธ, ํฌํŠธ ์ƒํƒœ ํ™•์ธ
๊ธฐ๋Šฅ ํ…Œ์ŠคํŠธ ๋ฐ ์™„๋ฃŒ ๋ณด๊ณ  ๊ฐ ํŒŒํŠธ๋ณ„ ๋‹ด๋‹น์ž ๋ฐฐํฌ ํ›„ ๊ธฐ๋Šฅ ๊ฒ€์ฆ ๋ฐ ๋ณด๊ณ 

4-3. ๋ฐฐํฌ ์ ˆ์ฐจ(Step-by-Step)

๋‹จ๊ณ„ ์ ˆ์ฐจ๋ช… ์ƒ์„ธ ์ž‘์—… ๋‚ด์šฉ (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โ€ข ๋ฐฐํฌ ์™„๋ฃŒ

4-4. ์˜ˆ์ƒ ์†Œ์š” ์‹œ๊ฐ„ ๋ฐ ๋‹ค์šดํƒ€์ž„

  • ์ด ๋ฐฐํฌ ์‹œ๊ฐ„: ์•ฝ 12~18๋ถ„
  • ์„œ๋น„์Šค ์ค‘๋‹จ ๊ฐ€๋Šฅ์„ฑ: 0์ดˆ
  • ์„œ๋น„์Šค ์‘๋‹ต ์ง€์—ฐ๊ฐ€๋Šฅ์„ฑ: ๋นŒ๋“œ ์ค‘ CPU ์‚ฌ์šฉ๋Ÿ‰ ์ฆ๊ฐ€๋กœ ๋ฐœ์ƒ ๊ฐ€๋Šฅ์„ฑ ์žˆ์Œ
  • ๋ฐฐํฌ ์‹œ๊ฐ„๋Œ€ ๊ถŒ์žฅ: โฐ ์ƒˆ๋ฒฝ 2์‹œ~5์‹œ (ํŠธ๋ž˜ํ”ฝ ์ตœ์†Œ ์‹œ๊ฐ„๋Œ€) โ†’ ์šฐ๋ฆฌ ์„œ๋น„์Šค์˜ ์ฃผ์š” ํƒ€๊ฒŸ์ด ํ•™์ƒ/๊ตฌ์ง์ž์ด๋ฏ€๋กœ ์ถœํ‡ด๊ทผยท์ ์‹ฌ์‹œ๊ฐ„ ์™ธ ์‹œ๊ฐ„๋Œ€์— ์ง„ํ–‰

4-5. ๋ฐฐํฌ ์ฒดํฌ๋ฆฌ์ŠคํŠธ

๊ตฌ๋ถ„ ํ•ญ๋ชฉ ํ™•์ธ
๋ฐฐํฌ ์ „ ์ธ์Šคํ„ด์Šค ์ƒํƒœ(CPU/๋ฉ”๋ชจ๋ฆฌ/๋””์Šคํฌ) โ˜
๋ฐฐํฌ ์ „ Git ์ตœ์‹  ์ฝ”๋“œ ๋ฐ˜์˜ ์—ฌ๋ถ€ โ˜
๋ฐฐํฌ ์ค‘ Nginx ์ ๊ฒ€ ํŽ˜์ด์ง€ ํ™•์ธ โ˜
๋ฐฐํฌ ํ›„ API ํ—ฌ์Šค ์ฒดํฌ โ˜
๋ฐฐํฌ ํ›„ ํ”„๋ก ํŠธ ์ฃผ์š” ํ™”๋ฉด ๋™์ž‘ โ˜
๋ฐฐํฌ ํ›„ ์—๋Ÿฌ ๋กœ๊ทธ ํ™•์ธ โ˜

4-6. ๋ฐฐํฌ ๋ช…๋ น์–ด ์Šคํฌ๋ฆฝํŠธ ์ž‘์„ฑ

  • ๋ฐฐํฌ ๋ช…๋ น์–ด๋ฅผ ์ •๋ฆฌํ•œ ์Šคํฌ๋ฆฝํŠธ ๋ฌถ์Œ์œผ๋กœ ์‚ฌ์šฉ
  • ๋ฐฐํฌ ์—ฌ๋ถ€ ํŒ๋‹จ, ๊ฒ€์ฆ, ๋กค๋ฐฑ ๊ฒฐ์ •์€ ์‚ฌ๋žŒ์ด ์ง์ ‘ ์ˆ˜ํ–‰
  • ๋ฐฐํฌ ๋ช…๋ น์–ด ์‹คํ–‰ ์œ„์น˜๋Š” EC2 ์ธ์Šคํ„ด์Šค ๋‚ด๋ถ€๋กœ ํ•œ์ •

4-7. ๋ฐฐํฌ ๋ช…๋ น์–ด ์‹คํ–‰ ์œ„์น˜ ๊ณ ๋ ค

๊ตฌ๋ถ„ โ‘  ๋กœ์ปฌ ์ปดํ“จํ„ฐ ๋นŒ๋“œ ํ›„ scp ์ „๋‹ฌ (๊ฒ€ํ†  ํ›„ ์ œ์™ธ) โ‘ก EC2 ์ธ์Šคํ„ด์Šค ๋‚ด๋ถ€ ๋นŒ๋“œ ๋ฐ ๋ฐฐํฌ (์ตœ์ข… ์„ ํƒ)
๋นŒ๋“œ ์œ„์น˜ ๊ฐœ๋ฐœ์ž ๊ฐœ์ธ ๋กœ์ปฌ PC EC2 ์šด์˜ ์ธ์Šคํ„ด์Šค ๋‚ด๋ถ€
ํ”„๋ŸฐํŠธ์—”๋“œ ์ฒ˜๋ฆฌ ๋กœ์ปฌ build ํ›„ scp ์ „์†ก ์„œ๋ฒ„์—์„œ ์ง์ ‘ build ๋˜๋Š” ์ •์  ํŒŒ์ผ ์ƒ์„ฑ
๋ฐฑ์—”๋“œ ์ฒ˜๋ฆฌ ๋กœ์ปฌ Gradle build โ†’ JAR scp ์„œ๋ฒ„์—์„œ Gradle build โ†’ JAR ์‹คํ–‰
AI ์„œ๋ฒ„ ์ฒ˜๋ฆฌ ์‹คํ–‰ ์‚ฐ์ถœ๋ฌผ ๊ฐœ๋… ์—†์Œ โ†’ ๋ณ„๋„ ์ฒ˜๋ฆฌ ํ•„์š” venv ํฌํ•จ ์‹คํ–‰ ํ™˜๊ฒฝ ๊ทธ๋Œ€๋กœ ๊ตฌ์„ฑ
ํ™˜๊ฒฝ ์ผ๊ด€์„ฑ โŒ OS, ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ, ๋ฒ„์ „์— ๋”ฐ๋ผ ๊ฒฐ๊ณผ ๋‹ฌ๋ผ์ง โœ… ์‹ค์ œ ์šด์˜ ํ™˜๊ฒฝ๊ณผ 100% ๋™์ผ
์žฌํ˜„์„ฑ โŒ ๋™์ผ ์ปค๋ฐ‹์ด์–ด๋„ ๋นŒ๋“œ ๊ฒฐ๊ณผ ์ƒ์ด ๊ฐ€๋Šฅ โœ… ์žฅ์•  ์‹œ ๋™์ผ ํ™˜๊ฒฝ์—์„œ ์žฌํ˜„ ๊ฐ€๋Šฅ
๋ณด์•ˆ ๊ด€์  โŒ ๋กœ์ปฌ PC๋Š” ์‹ ๋ขฐ ๊ฒฝ๊ณ„ ๋ฐ–, ํ‚คยท๊ถŒํ•œ ๋…ธ์ถœ ์œ„ํ—˜ โœ… ์šด์˜ ์„œ๋ฒ„ ๋‚ด๋ถ€์—์„œ๋งŒ ๋ฐฐํฌ ์ˆ˜ํ–‰
๊ฐ์‚ฌยท์ถ”์  โŒ ๋ˆ„๊ฐ€ยท์–ด๋””์„œ ๋นŒ๋“œํ–ˆ๋Š”์ง€ ์ถ”์  ์–ด๋ ค์›€ โœ… ์„œ๋ฒ„ ๋กœ๊ทธ ๊ธฐ์ค€ ๋ฐฐํฌ ์ด๋ ฅ ๊ด€๋ฆฌ ๊ฐ€๋Šฅ
์šด์˜ ์ ํ•ฉ์„ฑ โŒ ๊ฐœ์ธ ํ”„๋กœ์ ํŠธ ์ˆ˜์ค€์—๋งŒ ์ ํ•ฉ โœ… ์šด์˜ ํ™˜๊ฒฝ ๋ฐฐํฌ ๋ฐฉ์‹์œผ๋กœ ์ ํ•ฉ
์ตœ์ข… ํŒ๋‹จ ์šด์˜ ๋ฐฐํฌ ๋ฐฉ์‹์œผ๋กœ ๋ถ€์ ์ ˆํ•˜์—ฌ ์ œ์™ธ ์ตœ์ข… ์ฑ„ํƒ

4-8. ๋ฐฐํฌ ์Šคํฌ๋ฆฝํŠธ ์ž‘์„ฑ

#!/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] ๋ฐฐํฌ ์„ฑ๊ณต! ๋ฐฑ์—… ํŒŒ์ผ์„ ์ •๋ฆฌํ–ˆ์Šต๋‹ˆ๋‹ค."

4-9. ๋กค๋ฐฑ ์Šคํฌ๋ฆฝํŠธ ์ž‘์„ฑ

๋ฐฐํฌ ์‹œ, ์ด์ „ ๋ฒ„์ „์„ ๋ฐฑ์—…ํ•ด๋‘์—ˆ๋‹ค๊ฐ€, ๋กค๋ฐฑ์— ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•จ

#!/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") ์ž…๋‹ˆ๋‹ค."


๐Ÿšจ 5. ํ•œ๊ณ„์  ๋ฐ ์ถ”ํ›„ ํ•ด๊ฒฐ๋ฐฉ์•ˆ

5-1. ๋ฐฐํฌ ํ•œ๊ณ„ ๋ถ„์„ + ํ•ด๊ฒฐ๋ฐฉ์•ˆ

๋ฌธ์ œ ์„ค๋ช… ํ•ด๊ฒฐ๋ฐฉ์•ˆ
์ˆ˜๋™ ๋ฐฐํฌ ๋ถ€๋‹ด ๋ฐ˜๋ณต์ ์ธ scp, ssh ์ˆ˜๋™ ๋ฐฐํฌ๋กœ ์ธํ•œ ์‹ค์ˆ˜ ๊ฐ€๋Šฅ์„ฑ ๋ฐฐํฌ ์Šคํฌ๋ฆฝํŠธ๋ฅผ ์ •๋น„ํ•˜๊ณ , GitHub Actions ๋“ฑ CI/CD ์ž๋™ํ™”๋กœ ์ „ํ™˜
์ „์ฒด ์„œ๋น„์Šค ์ค‘๋‹จ ํ•˜๋‚˜์˜ ์ปดํฌ๋„ŒํŠธ ์žฅ์• ๊ฐ€ ์ „์ฒด ์„œ๋น„์Šค ๊ฐ€์šฉ์„ฑ์— ์ง์ ‘์ ์ธ ์˜ํ–ฅ์„ ๋ฏธ์นจ ๊ฐ ์„œ๋น„์Šค๋ณ„๋กœ ์ธ์Šคํ„ด์Šค๋ฅผ ๋ถ„๋ฆฌํ•˜์—ฌ ์žฅ์•  ์˜ํ–ฅ ๋ฒ”์œ„๋ฅผ ์ตœ์†Œํ™”
ํ™•์žฅ์„ฑ ๋ถ€์กฑ ํŠธ๋ž˜ํ”ฝ์ด ๋งŽ์ด ๋ชฐ๋ฆฌ๊ฒŒ ๋  ์‹œ, ๊ณ„์†ํ•ด์„œ ์„ฑ๋Šฅ์„ ์˜ฌ๋ฆด ์ˆ˜ ์—†์Œ ๋‹จ์ผ ์ธ์Šคํ„ด์Šค์—์„œ ๋‹ค์ค‘ ์ธ์Šคํ„ด์Šค๋กœ ํ™•์žฅํ•˜์—ฌ ์žฅ์• ์— ๋Œ€์‘

5-2. ๋ณต๊ตฌ ๋ฐ ์žฅ์•  ๋Œ€์‘ ํ•œ๊ณ„ ๋ถ„์„ + ํ•ด๊ฒฐ๋ฐฉ์•ˆ

ํ•ญ๋ชฉ ๋ชฉํ‘œ ํ˜„์‹ค์  ํ•œ๊ณ„ ํ•ด๊ฒฐ๋ฐฉ์•ˆ
RTO (Recovery Time Objective) 30๋ถ„ ์ด๋‚ด Big Bang ์ˆ˜์ž‘์—… ๋ฐฐํฌ ํŠน์„ฑ์ƒ, ๋ฐฐํฌ ์ค‘ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด ์ˆ˜๋™ ํ™•์ธ๊ณผ ๋ณต๊ตฌ์— ์‹œ๊ฐ„์ด ๋” ์†Œ์š”๋  ์ˆ˜ ์žˆ์Œ. ์‹ค์ œ ์žฅ์•  ๋ฐœ์ƒ ์‹œ 30๋ถ„ ๋‚ด ๋ณต๊ตฌ๊ฐ€ ํ•ญ์ƒ ๋ณด์žฅ๋˜์ง€๋Š” ์•Š์Œ ๋ชจ๋‹ˆํ„ฐ๋ง/์•Œ๋žŒ ์ฒด๊ณ„ ๊ตฌ์ถ•์„ ํ†ตํ•ด ๋Œ€์‘ ์†๋„ ํ–ฅ์ƒ
RPO (Recovery Point Objective) ์ตœ๊ทผ ๋ฐฐํฌ ์‹œ์  ๊ธฐ์ค€ (์ˆ˜๋™ ๋ฐฑ์—… ๊ธฐ์ค€) ์ˆ˜๋™ ๋ฐฑ์—… ์‹œ์  ์ดํ›„์˜ ๋ฐ์ดํ„ฐ๋Š” ๋ณต๊ตฌ ๋ถˆ๊ฐ€. ํŠนํžˆ DB ๋ณ€๊ฒฝ์ด ๋งŽ๊ฑฐ๋‚˜ ํŠธ๋žœ์žญ์…˜์ด ๋งŽ์œผ๋ฉด ์ผ๋ถ€ ๋ฐ์ดํ„ฐ ์†์‹ค ๊ฐ€๋Šฅ ๋ชจ๋‹ˆํ„ฐ๋ง/์•Œ๋žŒ ์ฒด๊ณ„ ๊ตฌ์ถ•์„ ํ†ตํ•ด ๋Œ€์‘ ์†๋„ ํ–ฅ์ƒ
โš ๏ธ **GitHub.com Fallback** โš ๏ธ