Ver3.0 ๐ ์๋ฒ ๋ถํ ๋ถ์ฐ๊ณผ ํธ๋ํฝ ๊ด๋ฆฌ ๊ธฐ๋ฒ

๐ ์๋ฒ ๋ถํ ๋ถ์ฐ๊ณผ ํธ๋ํฝ ๊ด๋ฆฌ ๊ธฐ๋ฒ
์น๊ตฌ์ฒ๋ผ ์ฝ๊ฒ ๋ฐฐ์ฐ๋ ๋ก๋ ๋ฐธ๋ฐ์ฑ์ ๋ชจ๋ ๊ฒ
์น์ฌ์ดํธ๋ ์ ํ๋ฆฌ์ผ์ด์ ๋ ๋ง์ฐฌ๊ฐ์ง์ผ. ์ฌ์ฉ์๊ฐ ๋ชฐ๋ฆฌ๋ฉด ์๋ฒ ํ๋๋ก๋ ๊ฐ๋น์ด ์ ๋ผ. ์ด๋ ํ์ํ ๊ฒ ๋ฐ๋ก ๋ก๋ ๋ฐธ๋ฐ์ฑ(Load Balancing)์ด์ง. ์ฌ๋ฌ ์๋ฒ์ ํธ๋ํฝ์ ๊ณจ๊ณ ๋ฃจ ๋ถ์ฐ์์ผ์ ์๋น์ค๊ฐ ๋ฉ์ถ์ง ์๊ฒ ํ๋ ๊ฑฐ์ผ.
2023๋ ๋ธ๋ํ๋ผ์ด๋ฐ์ด ๋ ํ ๋ํ ์ผํ๋ชฐ์ ํ์๋ณด๋ค 50๋ฐฐ ๋ง์ ํธ๋ํฝ์ ๊ฒฝํํ์ด. ๋ก๋ ๋ฐธ๋ฐ์ ๋๋ถ์ ์๋น์ค ์ค๋จ ์์ด ๋ชจ๋ ์ฃผ๋ฌธ์ ์ฒ๋ฆฌํ ์ ์์์ง. ๋ง์ฝ ์ค๋น๊ฐ ์ ๋๋ค๋ฉด? ์์ญ์ต ์์ ๋งค์ถ ์์ค์ด์์ ๊ฑฐ์ผ. ๐ฑ
๋ก๋ ๋ฐธ๋ฐ์ฑ์ ์ ๋๋ก ์ดํดํ๋ ค๋ฉด ๋ช ๊ฐ์ง ๊ธฐ๋ณธ ๊ฐ๋ ์ ์์์ผ ํด. ํ๋์ฉ ์น๊ตฌํํ ์ค๋ช ํ๋ฏ์ด ํ์ด๋ณผ๊ฒ!
### ๐ ๋ถํ(Load)๋ ๋ฌด์์ธ๊ฐ?๋ถํ๋ ์๋ฒ๊ฐ ์ฒ๋ฆฌํด์ผ ํ๋ ์์ ๋์ ๋งํด. CPU ์ฌ์ฉ๋ฅ , ๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ๋, ๋คํธ์ํฌ ๋์ญํญ, ๋์ ์ ์์ ์ ๋ฑ ์ฌ๋ฌ ์งํ๋ก ์ธก์ ํ ์ ์์ง. ๐ฅ๏ธ
โข CPU ์ฌ์ฉ๋ฅ : ํ๋ก์ธ์๊ฐ ์ผ๋ง๋ ๋ฐ์์ง
โข ๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ๋: RAM์ด ์ผ๋ง๋ ์ฐจ์๋์ง
โข ๋คํธ์ํฌ ํธ๋ํฝ: ๋ฐ์ดํฐ ์ก์์ ๋
โข ์๋ต ์๊ฐ: ์์ฒญ์ ๋ตํ๋ ๋ฐ ๊ฑธ๋ฆฌ๋ ์๊ฐ
โข ๋์ ์ฐ๊ฒฐ ์: ๋์์ ์ฒ๋ฆฌ ์ค์ธ ์ฌ์ฉ์ ์
๋ก๋ ๋ฐธ๋ฐ์๋ ๊ตํต๊ฒฝ์ฐฐ ๊ฐ์ ์กด์ฌ์ผ. ๋ค์ด์ค๋ ํธ๋ํฝ์ ๋ณด๊ณ ์ด๋ ์๋ฒ๋ก ๋ณด๋ผ์ง ๊ฒฐ์ ํ์ง. ๋จ์ํ ๋ถ์ฐ๋ง ํ๋ ๊ฒ ์๋๋ผ ์๋ฒ ์ํ๋ฅผ ์ฒดํฌํ๊ณ , ๋ฌธ์ ๊ฐ ์๋ ์๋ฒ๋ ์ ์ธ์ํค๊ณ , ์๋ก์ด ์๋ฒ๋ฅผ ์ถ๊ฐํ๋ ๊ฒ๋ ๊ด๋ฆฌํด. ๐ฎ
๋ก๋ ๋ฐธ๋ฐ์ฑ์ ํฌ๊ฒ ๋คํธ์ํฌ ๊ณ์ธต์ ๋ฐ๋ผ ๋ถ๋ฅํ ์ ์์ด. ๊ฐ๊ฐ์ ํน์ง์ ์์๋ณด์!
### ๐ L4 ๋ก๋ ๋ฐธ๋ฐ์ฑ (Transport Layer)L4๋ OSI 7๊ณ์ธต ์ค ์ ์ก ๊ณ์ธต(Transport Layer)์์ ์๋ํด. IP ์ฃผ์์ ํฌํธ ๋ฒํธ๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ํธ๋ํฝ์ ๋ถ์ฐ์ํค์ง. ๋น ๋ฅด๊ณ ํจ์จ์ ์ด์ง๋ง HTTP ํค๋๋ ์ฟ ํค ๊ฐ์ ์ ํ๋ฆฌ์ผ์ด์ ๋ ๋ฒจ ์ ๋ณด๋ ๋ณผ ์ ์์ด.
- โ ๋น ๋ฅธ ์ฒ๋ฆฌ ์๋: ํจํท ํค๋๋ง ํ์ธํ๋ฏ๋ก ์ค๋ฒํค๋๊ฐ ์ ์
- โ ํ๋กํ ์ฝ ๋ ๋ฆฝ์ : TCP, UDP ๋ชจ๋ ์ง์
- โ ๋น์ฉ ํจ์จ์ : ํ๋์จ์ด ๋ฆฌ์์ค๋ฅผ ์ ๊ฒ ์ฌ์ฉ
- โ ์ ํ๋ ๋ถ์ฐ ๋ก์ง: ์ฝํ ์ธ ๊ธฐ๋ฐ ๋ผ์ฐํ ๋ถ๊ฐ
- โ ์ธ์ ์ ์ง ์ด๋ ค์: ์ ํ๋ฆฌ์ผ์ด์ ๋ ๋ฒจ ์ ๋ณด ์ ๊ทผ ๋ถ๊ฐ
์ค์ ์ฌ์ฉ ์์: DNS ์๋ฒ, ๊ฒ์ ์๋ฒ, ์ค์๊ฐ ์คํธ๋ฆฌ๋ฐ ์๋น์ค์ฒ๋ผ ๋น ๋ฅธ ์๋ต์ด ์ค์ํ๊ณ ๋จ์ํ ๋ถ์ฐ์ด ํ์ํ ๊ฒฝ์ฐ์ ์ ํฉํด.
### ๐ฏ L7 ๋ก๋ ๋ฐธ๋ฐ์ฑ (Application Layer)L7์ ์ ํ๋ฆฌ์ผ์ด์ ๊ณ์ธต์์ ์๋ํ๋ฉด์ HTTP ํค๋, ์ฟ ํค, URL ๊ฒฝ๋ก ๋ฑ์ ๋ถ์ํด์ ๋ ๋๋ํ๊ฒ ํธ๋ํฝ์ ๋ถ์ฐ์์ผ. ์๋ฅผ ๋ค์ด ์ด๋ฏธ์ง ์์ฒญ์ ์ด๋ฏธ์ง ์๋ฒ๋ก, API ์์ฒญ์ API ์๋ฒ๋ก ๋ณด๋ผ ์ ์์ง. ๐ง
- โ ์ฝํ ์ธ ๊ธฐ๋ฐ ๋ผ์ฐํ : URL, ํค๋, ์ฟ ํค ๋ฑ์ผ๋ก ์ธ๋ฐํ ์ ์ด
- โ SSL ์ข ๋ฃ: ์ํธํ/๋ณตํธํ๋ฅผ ๋ก๋ ๋ฐธ๋ฐ์์์ ์ฒ๋ฆฌ
- โ ์ธ์ ๊ด๋ฆฌ: ์ฟ ํค ๊ธฐ๋ฐ ์ธ์ ์ ์ง ๊ฐ๋ฅ
- โ ์์ถ ๋ฐ ์บ์ฑ: ์๋ต ์ต์ ํ ๊ธฐ๋ฅ ์ ๊ณต
- โ ๋์ ๋ฆฌ์์ค ์ฌ์ฉ: ํจํท ๋ด์ฉ์ ๋ถ์ํ๋ฏ๋ก CPU ์ฌ์ฉ๋ ์ฆ๊ฐ
- โ ๋ณต์กํ ์ค์ : ๊ตฌ์ฑ๊ณผ ๊ด๋ฆฌ๊ฐ ์๋์ ์ผ๋ก ์ด๋ ค์
์ค์ ์ฌ์ฉ ์์: ์ ์์๊ฑฐ๋ ์ฌ์ดํธ, SaaS ํ๋ซํผ, ๋ง์ดํฌ๋ก์๋น์ค ์ํคํ ์ฒ์ฒ๋ผ ๋ณต์กํ ๋ผ์ฐํ ๊ท์น์ด ํ์ํ ๊ฒฝ์ฐ์ ์ฌ์ฉํด.
### ๐ GSLB (Global Server Load Balancing)GSLB๋ ์ง๋ฆฌ์ ์ผ๋ก ๋ถ์ฐ๋ ์ฌ๋ฌ ๋ฐ์ดํฐ์ผํฐ ๊ฐ์ ํธ๋ํฝ์ ๊ด๋ฆฌํด. ์ฌ์ฉ์์ ๊ฐ์ฅ ๊ฐ๊น์ด ์๋ฒ๋ก ์ฐ๊ฒฐํด์ฃผ๊ฑฐ๋, ์ฅ์ ๊ฐ ๋ฐ์ํ ์ง์ญ์ ํธ๋ํฝ์ ๋ค๋ฅธ ์ง์ญ์ผ๋ก ์ฐํ์ํค์ง. ๐บ๏ธ
๐ ์ง๋ฆฌ์ ๋ถ์ฐ: ์ฌ์ฉ์ ์์น ๊ธฐ๋ฐ ์ต์ ์๋ฒ ์ ํ
๐ ์ฌํด ๋ณต๊ตฌ: ๋ฐ์ดํฐ์ผํฐ ์ฅ์ ์ ์๋ ํ์ผ์ค๋ฒ
โก ์ฑ๋ฅ ์ต์ ํ: ๋คํธ์ํฌ ์ง์ฐ ์๊ฐ ์ต์ํ
๐ ํธ๋ํฝ ๊ด๋ฆฌ: ์ง์ญ๋ณ ๋ถํ ๋ถ์ฐ
๋ก๋ ๋ฐธ๋ฐ์๊ฐ ์ด๋ค ์๋ฒ๋ก ํธ๋ํฝ์ ๋ณด๋ผ์ง ๊ฒฐ์ ํ๋ ๋ฐฉ๋ฒ์ ์๊ณ ๋ฆฌ์ฆ์ด๋ผ๊ณ ํด. ์ํฉ์ ๋ฐ๋ผ ์ ์ ํ ์๊ณ ๋ฆฌ์ฆ์ ์ ํํ๋ ๊ฒ ์ค์ํด! ๐ฒ
### ๐ ๋ผ์ด๋ ๋ก๋น (Round Robin)๊ฐ์ฅ ๋จ์ํ๊ณ ๋ง์ด ์ฌ์ฉ๋๋ ๋ฐฉ์์ด์ผ. ์๋ฒ ๋ชฉ๋ก์ ์์๋๋ก ๋๋ฉด์ ํ๋์ฉ ์์ฒญ์ ๋ฐฐ์ ํด. 1๋ฒ ์๋ฒ โ 2๋ฒ ์๋ฒ โ 3๋ฒ ์๋ฒ โ ๋ค์ 1๋ฒ ์๋ฒ ์ด๋ฐ ์์ผ๋ก!
// ๋ผ์ด๋ ๋ก๋น ์์ฌ ์ฝ๋
servers = [server1, server2, server3]
current_index = 0
function get_next_server():
server = servers[current_index]
current_index = (current_index + 1) % servers.length
return server
์ฅ์ : ๊ตฌํ์ด ๊ฐ๋จํ๊ณ ์๋ฒ๋ค์ ์ฑ๋ฅ์ด ๋น์ทํ ๋ ํจ๊ณผ์ ์ด์ผ.
๋จ์ : ์๋ฒ ์ฑ๋ฅ ์ฐจ์ด๋ ์์ฒญ ์ฒ๋ฆฌ ์๊ฐ ์ฐจ์ด๋ฅผ ๊ณ ๋ คํ์ง ๋ชปํด.
์๋ฒ๋ง๋ค ๊ฐ์ค์น๋ฅผ ๋ถ์ฌํด์ ์ฑ๋ฅ์ด ์ข์ ์๋ฒ์ ๋ ๋ง์ ํธ๋ํฝ์ ๋ณด๋ด๋ ๋ฐฉ์์ด์ผ. ์๋ฅผ ๋ค์ด ์๋ฒ1(๊ฐ์ค์น 3), ์๋ฒ2(๊ฐ์ค์น 2), ์๋ฒ3(๊ฐ์ค์น 1)์ด๋ฉด ์๋ฒ1์ด ์ ์ฒด ํธ๋ํฝ์ 50%๋ฅผ ์ฒ๋ฆฌํ๊ฒ ๋ผ.
โข ์๋ฒ A: CPU 16์ฝ์ด, RAM 64GB โ ๊ฐ์ค์น 5
โข ์๋ฒ B: CPU 8์ฝ์ด, RAM 32GB โ ๊ฐ์ค์น 3
โข ์๋ฒ C: CPU 4์ฝ์ด, RAM 16GB โ ๊ฐ์ค์น 2
์ด 10๊ฐ์ ์์ฒญ์ด ๋ค์ด์ค๋ฉด A๋ 5๊ฐ, B๋ 3๊ฐ, C๋ 2๊ฐ๋ฅผ ์ฒ๋ฆฌํ๊ฒ ๋ผ.
ํ์ฌ ํ์ฑ ์ฐ๊ฒฐ ์๊ฐ ๊ฐ์ฅ ์ ์ ์๋ฒ๋ก ์ ์์ฒญ์ ๋ณด๋ด๋ ๋ฐฉ์์ด์ผ. ์์ฒญ ์ฒ๋ฆฌ ์๊ฐ์ด ๋ค์ญ๋ ์ญํ ๋ ํนํ ์ ์ฉํด. ๐
์๋ ์๋ฆฌ:
1. ์ ์์ฒญ์ด ๋ค์ด์ด
2. ๊ฐ ์๋ฒ์ ํ์ฌ ์ฐ๊ฒฐ ์๋ฅผ ํ์ธ
3. ์ฐ๊ฒฐ ์๊ฐ ๊ฐ์ฅ ์ ์ ์๋ฒ ์ ํ
4. ํด๋น ์๋ฒ๋ก ์์ฒญ ์ ๋ฌ
์ต์ ์ฐ๊ฒฐ ๋ฐฉ์์ ์๋ฒ ์ฑ๋ฅ ๊ฐ์ค์น๋ฅผ ๊ฒฐํฉํ ๊ฑฐ์ผ. ๋จ์ํ ์ฐ๊ฒฐ ์๋ง ๋ณด๋ ๊ฒ ์๋๋ผ ์๋ฒ ์ฑ๋ฅ๋ ํจ๊ป ๊ณ ๋ คํ์ง.
๊ณ์ฐ ๋ฐฉ์: ์ฐ๊ฒฐ ์ / ๊ฐ์ค์น = ๋ถํ ์ ์
๋ถํ ์ ์๊ฐ ๊ฐ์ฅ ๋ฎ์ ์๋ฒ๋ฅผ ์ ํํด.
ํด๋ผ์ด์ธํธ์ IP ์ฃผ์๋ฅผ ํด์ ํจ์์ ๋ฃ์ด์ ํญ์ ๊ฐ์ ์๋ฒ๋ก ์ฐ๊ฒฐ๋๊ฒ ํ๋ ๋ฐฉ์์ด์ผ. ์ธ์ ์ ์ง๊ฐ ์ค์ํ ์ ํ๋ฆฌ์ผ์ด์ ์์ ์ ์ฉํด. ๐
// IP ํด์ ์์ฌ ์ฝ๋
function get_server_by_ip(client_ip):
hash_value = hash(client_ip)
server_index = hash_value % servers.length
return servers[server_index]
// ์์
client_ip = "192.168.1.100"
hash("192.168.1.100") = 12345
12345 % 3 = 0
โ servers[0] ์ ํ
์ฅ์ : ๊ฐ์ ์ฌ์ฉ์๋ ํญ์ ๊ฐ์ ์๋ฒ๋ก ์ฐ๊ฒฐ๋์ด ์ธ์
์ ์ง๊ฐ ์ฌ์.
๋จ์ : ์๋ฒ ์ถ๊ฐ/์ ๊ฑฐ ์ ํด์ ๊ฐ์ด ๋ณ๊ฒฝ๋์ด ์ธ์
์ด ๋๊ธธ ์ ์์ด.
ํ์ฌ ์ฐ๊ฒฐ ์์ ํ๊ท ์๋ต ์๊ฐ์ ๋ชจ๋ ๊ณ ๋ คํด์ ๊ฐ์ฅ ๋น ๋ฅด๊ฒ ์๋ตํ ์ ์๋ ์๋ฒ๋ฅผ ์ ํํ๋ ๋ฐฉ์์ด์ผ. ์ค์๊ฐ ์ฑ๋ฅ ๋ชจ๋ํฐ๋ง์ด ํ์ํ์ง๋ง ์ฌ์ฉ์ ๊ฒฝํ์ ์ต์ ํํ ์ ์์ด. โก
### ๐ฐ ๋๋ค (Random)๋ง ๊ทธ๋๋ก ๋ฌด์์๋ก ์๋ฒ๋ฅผ ์ ํํ๋ ๊ฑฐ์ผ. ๋จ์ํด ๋ณด์ด์ง๋ง ์๋ฒ ์๊ฐ ๋ง๊ณ ํธ๋ํฝ์ด ์ถฉ๋ถํ ๋ง์ผ๋ฉด ํต๊ณ์ ์ผ๋ก ๊ท ๋ฑํ๊ฒ ๋ถ์ฐ๋ผ. ๐ฒ
โข ์๋ฒ ์ฑ๋ฅ์ด ๋์ผํ๊ณ ์์ฒญ ์ฒ๋ฆฌ ์๊ฐ์ด ๋น์ท: ๋ผ์ด๋ ๋ก๋น
โข ์๋ฒ ์ฑ๋ฅ์ด ๋ค๋ฆ: ๊ฐ์ค ๋ผ์ด๋ ๋ก๋น
โข ์์ฒญ ์ฒ๋ฆฌ ์๊ฐ์ด ๋ถ๊ท์น: ์ต์ ์ฐ๊ฒฐ
โข ์ธ์ ์ ์ง ํ์: IP ํด์
โข ์ต๊ณ ์ฑ๋ฅ ์ถ๊ตฌ: ์ต์ ์๋ต ์๊ฐ
โข ๋จ์ํจ ์ ํธ: ๋๋ค
์ด๋ก ์ ์ถฉ๋ถํ ๋ฐฐ์ ์ผ๋ ์ด์ ์ค์ ๋ก ์ด๋ป๊ฒ ๊ตฌํํ๋์ง ์์๋ณด์! ๋ํ์ ์ธ ๋ก๋ ๋ฐธ๋ฐ์๋ค์ ์๊ฐํ ๊ฒ. ๐ ๏ธ
### ๐ Nginx๋ฅผ ์ด์ฉํ ๋ก๋ ๋ฐธ๋ฐ์ฑNginx๋ ๊ฐ์ฅ ์ธ๊ธฐ ์๋ ์คํ์์ค ์น ์๋ฒ์ด์ ๋ก๋ ๋ฐธ๋ฐ์์ผ. ๊ฐ๋ณ๊ณ ๋น ๋ฅด๋ฉฐ ์ค์ ์ด ์ง๊ด์ ์ด๋ผ ๋ง์ ๊ฐ๋ฐ์๋ค์ด ์ ํธํ์ง. ๐
# Nginx ๋ก๋ ๋ฐธ๋ฐ์ฑ ๊ธฐ๋ณธ ์ค์
http {
upstream backend {
# ๋ผ์ด๋ ๋ก๋น (๊ธฐ๋ณธ๊ฐ)
server backend1.example.com;
server backend2.example.com;
server backend3.example.com;
}
server {
listen 80;
location / {
proxy_pass http://backend;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
}
๊ฐ์ค ๋ผ์ด๋ ๋ก๋น ์ค์ :
upstream backend {
server backend1.example.com weight=5;
server backend2.example.com weight=3;
server backend3.example.com weight=2;
}
์ต์ ์ฐ๊ฒฐ ๋ฐฉ์:
upstream backend {
least_conn;
server backend1.example.com;
server backend2.example.com;
server backend3.example.com;
}
IP ํด์ ๋ฐฉ์:
upstream backend {
ip_hash;
server backend1.example.com;
server backend2.example.com;
server backend3.example.com;
}
์๋ฒ๊ฐ ์ ์ ์๋ํ๋์ง ์ฃผ๊ธฐ์ ์ผ๋ก ํ์ธํ๋ ๊ธฐ๋ฅ์ด์ผ. ๋ฌธ์ ๊ฐ ์๋ ์๋ฒ๋ ์๋์ผ๋ก ์ ์ธ์์ผ.
upstream backend {
server backend1.example.com max_fails=3 fail_timeout=30s;
server backend2.example.com max_fails=3 fail_timeout=30s;
server backend3.example.com backup; # ๋ฐฑ์
์๋ฒ
}
# max_fails: ์คํจ ํ์ฉ ํ์
# fail_timeout: ์๋ฒ๋ฅผ ์ฌ์ฉ ๋ถ๊ฐ๋ก ํ์ํ๋ ์๊ฐ
# backup: ๋ค๋ฅธ ์๋ฒ๊ฐ ๋ชจ๋ ์คํจํ ๋๋ง ์ฌ์ฉ
HAProxy๋ ๊ณ ์ฑ๋ฅ TCP/HTTP ๋ก๋ ๋ฐธ๋ฐ์์ผ. ๋๊ท๋ชจ ํธ๋ํฝ ์ฒ๋ฆฌ์ ํนํ๋์ด ์๊ณ ์ธ๋ฐํ ์ค์ ์ด ๊ฐ๋ฅํด. ๋ง์ ๋๊ธฐ์ ๋ค์ด ์ฌ์ฉํ๊ณ ์์ง. ๐ข
# HAProxy ๊ธฐ๋ณธ ์ค์
global
maxconn 4096
log 127.0.0.1 local0
defaults
mode http
timeout connect 5000ms
timeout client 50000ms
timeout server 50000ms
frontend http_front
bind *:80
default_backend http_back
backend http_back
balance roundrobin
option httpchk GET /health
server server1 192.168.1.10:8080 check
server server2 192.168.1.11:8080 check
server server3 192.168.1.12:8080 check
HAProxy์ ๋ค์ํ ๋ฐธ๋ฐ์ฑ ์๊ณ ๋ฆฌ์ฆ:
# ๋ผ์ด๋ ๋ก๋น
balance roundrobin
# ์ต์ ์ฐ๊ฒฐ
balance leastconn
# ์์ค IP ํด์
balance source
# URI ํด์ (๊ฐ์ URL์ ๊ฐ์ ์๋ฒ๋ก)
balance uri
# ํค๋ ๊ธฐ๋ฐ ํด์
balance hdr(User-Agent)
AWS, Azure, GCP ๊ฐ์ ํด๋ผ์ฐ๋ ํ๋ซํผ๋ค์ ๊ด๋ฆฌํ ๋ก๋ ๋ฐธ๋ฐ์ ์๋น์ค๋ฅผ ์ ๊ณตํด. ์ง์ ์๋ฒ๋ฅผ ๊ด๋ฆฌํ ํ์ ์์ด ํด๋ฆญ ๋ช ๋ฒ์ผ๋ก ์ค์ ํ ์ ์์ด์ ํธ๋ฆฌํ์ง. ๐ป
1. Application Load Balancer (ALB):
โข L7 ๋ก๋ ๋ฐธ๋ฐ์
โข HTTP/HTTPS ํธ๋ํฝ ์ฒ๋ฆฌ
โข ๊ฒฝ๋ก ๊ธฐ๋ฐ, ํธ์คํธ ๊ธฐ๋ฐ ๋ผ์ฐํ
โข WebSocket ์ง์
2. Network Load Balancer (NLB):
โข L4 ๋ก๋ ๋ฐธ๋ฐ์
โข ์ด๊ณ ์ฑ๋ฅ (์ด๋น ์๋ฐฑ๋ง ์์ฒญ ์ฒ๋ฆฌ)
โข ๊ณ ์ IP ์ง์
โข TCP/UDP ํธ๋ํฝ ์ฒ๋ฆฌ
3. Gateway Load Balancer (GWLB):
โข ๋ฐฉํ๋ฒฝ, IDS/IPS ๊ฐ์ ๊ฐ์ ์ดํ๋ผ์ด์ธ์ค ๋ฐฐํฌ
โข ๋คํธ์ํฌ ํธ๋ํฝ ํฌ๋ช ํ๊ฒ ์ ๋ฌ
๋ก๋ ๋ฐธ๋ฐ์ฑ์์ ๊ฐ์ฅ ๊น๋ค๋ก์ด ๋ฌธ์ ์ค ํ๋๊ฐ ๋ฐ๋ก ์ธ์ ๊ด๋ฆฌ์ผ. ์ฌ์ฉ์๊ฐ ๋ก๊ทธ์ธํ๋๋ฐ ๋ค์ ์์ฒญ์ด ๋ค๋ฅธ ์๋ฒ๋ก ๊ฐ๋ฉด ๋ก๊ทธ์ธ ์ ๋ณด๊ฐ ์์ด์ง์์? ์ด๊ฑธ ์ด๋ป๊ฒ ํด๊ฒฐํ ๊น? ๐ค
### ๐ ์ธ์ ๊ณ ์ (Session Persistence/Sticky Session)ํน์ ์ฌ์ฉ์์ ๋ชจ๋ ์์ฒญ์ ๊ฐ์ ์๋ฒ๋ก ๋ณด๋ด๋ ๋ฐฉ์์ด์ผ. ์ฟ ํค๋ IP ์ฃผ์๋ฅผ ์ด์ฉํด์ ๊ตฌํํด.
# Nginx ์ธ์
๊ณ ์ ์ค์
upstream backend {
ip_hash; # IP ๊ธฐ๋ฐ ์ธ์
๊ณ ์
server backend1.example.com;
server backend2.example.com;
}
# ๋๋ ์ฟ ํค ๊ธฐ๋ฐ
upstream backend {
server backend1.example.com;
server backend2.example.com;
sticky cookie srv_id expires=1h domain=.example.com path=/;
}
์ฅ์ : ๊ตฌํ์ด ๊ฐ๋จํ๊ณ ๊ธฐ์กด ์ ํ๋ฆฌ์ผ์ด์
์์ ์ด ํ์ ์์ด.
๋จ์ : ์๋ฒ ์ฅ์ ์ ์ธ์
์์ค, ๋ถํ ๋ถ์ฐ์ด ๋ถ๊ท ๋ฑํด์ง ์ ์์ด.
๋ชจ๋ ์๋ฒ๊ฐ ์ธ์ ์ ๋ณด๋ฅผ ๊ณต์ ํ๋ ๋ฐฉ์์ด์ผ. Redis๋ Memcached ๊ฐ์ ์ธ๋ฉ๋ชจ๋ฆฌ ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ฅผ ์ค์ ์ธ์ ์ ์ฅ์๋ก ์ฌ์ฉํ์ง.
// Node.js + Express + Redis ์ธ์
๊ณต์ ์์
const session = require('express-session');
const RedisStore = require('connect-redis')(session);
const redis = require('redis');
const redisClient = redis.createClient({
host: 'redis-server.example.com',
port: 6379
});
app.use(session({
store: new RedisStore({ client: redisClient }),
secret: 'your-secret-key',
resave: false,
saveUninitialized: false,
cookie: {
secure: true,
maxAge: 3600000 // 1์๊ฐ
}
}));
์ฅ์ : ์ง์ ํ ๋ถํ ๋ถ์ฐ, ์๋ฒ ์ฅ์ ์๋ ์ธ์
์ ์ง
๋จ์ : ์ถ๊ฐ ์ธํ๋ผ ํ์, ๋คํธ์ํฌ ์ง์ฐ ๋ฐ์ ๊ฐ๋ฅ
์๋ฒ์ ์ธ์ ์ ์ ์ฅํ์ง ์๊ณ ํด๋ผ์ด์ธํธ๊ฐ ํ ํฐ์ ๊ฐ์ง๊ณ ๋ค๋๋ ๋ฐฉ์์ด์ผ. ์์ฆ ๊ฐ์ฅ ๋ง์ด ์ฌ์ฉ๋๋ ๋ฐฉ๋ฒ์ด์ง. ๐
// JWT ํ ํฐ ์์ฑ ์์ (Node.js)
const jwt = require('jsonwebtoken');
// ๋ก๊ทธ์ธ ์ ํ ํฐ ๋ฐ๊ธ
function login(user) {
const token = jwt.sign(
{
userId: user.id,
username: user.username,
role: user.role
},
'your-secret-key',
{ expiresIn: '1h' }
);
return token;
}
// ์์ฒญ ์ ํ ํฐ ๊ฒ์ฆ
function verifyToken(token) {
try {
const decoded = jwt.verify(token, 'your-secret-key');
return decoded;
} catch(err) {
return null;
}
}
์ฅ์ : ์๋ฒ ๋ถํ ์ต์ํ, ํ์ฅ์ฑ ์ฐ์, ๋ง์ดํฌ๋ก์๋น์ค์ ์ ํฉ
๋จ์ : ํ ํฐ ํฌ๊ธฐ๊ฐ ํผ, ํ ํฐ ๋ฌดํจํ๊ฐ ์ด๋ ค์
โข ์๊ท๋ชจ ์๋น์ค, ๋น ๋ฅธ ๊ตฌํ: ์ธ์ ๊ณ ์
โข ์ค๊ท๋ชจ ์๋น์ค, ์์ ์ฑ ์ค์: ์ธ์ ๊ณต์ (Redis)
โข ๋๊ท๋ชจ ์๋น์ค, ๋ง์ดํฌ๋ก์๋น์ค: JWT ํ ํฐ
โข ํ์ด๋ธ๋ฆฌ๋: ์ค์ํ ์ ๋ณด๋ ํ ํฐ, ์์ ๋ฐ์ดํฐ๋ Redis
๋ก๋ ๋ฐธ๋ฐ์๊ฐ ์ ๋๋ก ์๋ํ๋ ค๋ฉด ๊ฐ ์๋ฒ์ ์ํ๋ฅผ ์ง์์ ์ผ๋ก ๋ชจ๋ํฐ๋งํด์ผ ํด. ๋ฌธ์ ๊ฐ ์๋ ์๋ฒ์ ํธ๋ํฝ์ ๋ณด๋ด๋ฉด ์ ๋๋๊น! ๐ฉบ
### ๐ ํฌ์ค ์ฒดํฌ ์ ํํฌ์ค ์ฒดํฌ๋ ์๋ฒ๊ฐ ์ ์์ ์ผ๋ก ์๋ํ๋์ง ํ์ธํ๋ ๊ณผ์ ์ด์ผ. ์ฌ๋ฌ ๊ฐ์ง ๋ฐฉ๋ฒ์ด ์์ด.
๊ฐ์ฅ ๊ธฐ๋ณธ์ ์ธ ๋ฐฉ์์ด์ผ. ์ง์ ๋ ํฌํธ์ TCP ์ฐ๊ฒฐ์ ์๋ํด์ ์ฑ๊ณตํ๋ฉด ์ ์์ผ๋ก ํ๋จํด.
2. HTTP ํฌ์ค ์ฒดํฌ
ํน์ URL์ HTTP ์์ฒญ์ ๋ณด๋ด๊ณ ์๋ต ์ฝ๋๋ฅผ ํ์ธํด. ๋ณดํต 200 OK๋ฅผ ๋ฐ์ผ๋ฉด ์ ์์ด์ผ.
3. ์ปค์คํ ํฌ์ค ์ฒดํฌ
์ ํ๋ฆฌ์ผ์ด์ ์ด ์ง์ ์ํ๋ฅผ ์ฒดํฌํด์ ์๋ตํด. ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ฐ๊ฒฐ, ์ธ๋ถ API ์ํ ๋ฑ์ ์ข ํฉ์ ์ผ๋ก ํ๋จํ ์ ์์ด.
// Express.js ํฌ์ค ์ฒดํฌ ์๋ํฌ์ธํธ ์์
app.get('/health', async (req, res) => {
try {
// ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ฐ๊ฒฐ ํ์ธ
await db.ping();
// Redis ์ฐ๊ฒฐ ํ์ธ
await redis.ping();
// ๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ๋ ํ์ธ
const memUsage = process.memoryUsage();
const memPercent = (memUsage.heapUsed / memUsage.heapTotal) * 100;
if (memPercent > 90) {
return res.status(503).json({
status: 'unhealthy',
reason: 'high memory usage'
});
}
res.status(200).json({
status: 'healthy',
timestamp: new Date().toISOString(),
uptime: process.uptime()
});
} catch (error) {
res.status(503).json({
status: 'unhealthy',
error: error.message
});
}
});
ํฌ์ค ์ฒดํฌ๋ฅผ ํจ๊ณผ์ ์ผ๋ก ์ด์ํ๋ ค๋ฉด ์ ์ ํ ํ๋ผ๋ฏธํฐ ์ค์ ์ด ์ค์ํด.
| ํ๋ผ๋ฏธํฐ | ์ค๋ช | ๊ถ์ฅ๊ฐ |
|---|---|---|
| Interval | ํฌ์ค ์ฒดํฌ ์ฃผ๊ธฐ | 5-30์ด |
| Timeout | ์๋ต ๋๊ธฐ ์๊ฐ | 2-5์ด |
| Healthy Threshold | ์ ์ ํ์ ์ฐ์ ์ฑ๊ณต ํ์ | 2-3ํ |
| Unhealthy Threshold | ๋น์ ์ ํ์ ์ฐ์ ์คํจ ํ์ | 2-3ํ |
โข ๋๋ฌด ์งง์ ๊ฐ๊ฒฉ: ์๋ฒ์ ๋ถํ์ํ ๋ถํ ๋ฐ์
โข ๋๋ฌด ๊ธด ๊ฐ๊ฒฉ: ์ฅ์ ๊ฐ์ง๊ฐ ๋ฆ์ด์ ธ ์ฌ์ฉ์ ์ํฅ ์ฆ๊ฐ
โข ๋๋ฌด ๋ฎ์ ์๊ณ๊ฐ: ์ผ์์ ๋ฌธ์ ๋ก ์ ์ ์๋ฒ ์ ์ธ
โข ๋๋ฌด ๋์ ์๊ณ๊ฐ: ๋ฌธ์ ์๋ ์๋ฒ๊ฐ ๊ณ์ ํธ๋ํฝ ๋ฐ์
์๋ฒ๊ฐ ๋ค์ ์ ์ํ๋๋ฉด ์๋์ผ๋ก ํธ๋ํฝ์ ๋ฐ์ ์ ์๊ฒ ํด์ผ ํด. ์ด๊ฒ ๋ฐ๋ก ์๋ ๋ณต๊ตฌ ๋ฉ์ปค๋์ฆ์ด์ผ.
# Nginx ์๋ ๋ณต๊ตฌ ์ค์
upstream backend {
server backend1.example.com max_fails=3 fail_timeout=30s;
server backend2.example.com max_fails=3 fail_timeout=30s;
server backend3.example.com max_fails=3 fail_timeout=30s;
}
# 3๋ฒ ์คํจํ๋ฉด 30์ด ๋์ ์ ์ธ
# 30์ด ํ ์๋์ผ๋ก ๋ค์ ์๋
์๋ฒ ์ฅ์ ๊ฐ ๋ฐ์ํ์ ๋ ์ด๋ป๊ฒ ๋์ํ ์ง ๋ฏธ๋ฆฌ ๊ณํ์ ์ธ์๋๋ ๊ฒ ์ค์ํด.
- โ ๋ชจ๋ํฐ๋ง ์๋ฆผ: ์๋ฒ ์ฅ์ ์ ์ฆ์ ์๋ฆผ ๋ฐ๊ธฐ
- โ ์๋ ํ์ผ์ค๋ฒ: ๋ฌธ์ ์๋ฒ ์๋ ์ ์ธ
- โ ๋ฐฑ์ ์๋ฒ: ์๋น ์๋ฒ ํญ์ ์ค๋น
- โ ๋ก๊ทธ ์์ง: ์ฅ์ ์์ธ ๋ถ์์ ์ํ ๋ก๊ทธ ๋ณด๊ด
- โ ๋กค๋ฐฑ ๊ณํ: ๋ฐฐํฌ ๋ฌธ์ ์ ๋น ๋ฅธ ๋กค๋ฐฑ
- โ ๋ฌธ์ํ: ์ฅ์ ๋์ ์ ์ฐจ ๋ฌธ์ํ
๋จ์ํ ๋ถํ๋ฅผ ๋ถ์ฐํ๋ ๊ฒ์ ๋์ด์ ํธ๋ํฝ์ ๋๋ํ๊ฒ ๊ด๋ฆฌํ๋ ๊ณ ๊ธ ๊ธฐ๋ฒ๋ค์ ์์๋ณด์! ๐
### ๐ฏ ์ฝํ ์ธ ๊ธฐ๋ฐ ๋ผ์ฐํ์์ฒญ์ ๋ด์ฉ์ ๋ถ์ํด์ ์ ์ ํ ์๋ฒ๋ก ๋ณด๋ด๋ ๊ฑฐ์ผ. ์๋ฅผ ๋ค์ด ์ด๋ฏธ์ง๋ ์ด๋ฏธ์ง ์๋ฒ๋ก, API๋ API ์๋ฒ๋ก ๋ณด๋ด๋ ์์ด์ง.
# Nginx ์ฝํ
์ธ ๊ธฐ๋ฐ ๋ผ์ฐํ
server {
listen 80;
server_name example.com;
# ์ด๋ฏธ์ง ์์ฒญ์ ์ด๋ฏธ์ง ์๋ฒ๋ก
location ~* \.(jpg|jpeg|png|gif|ico|svg)$ {
proxy_pass http://image_servers;
}
# API ์์ฒญ์ API ์๋ฒ๋ก
location /api/ {
proxy_pass http://api_servers;
}
# ์ ์ ํ์ผ์ CDN์ผ๋ก
location /static/ {
proxy_pass http://cdn_servers;
}
# ๋๋จธ์ง๋ ์น ์๋ฒ๋ก
location / {
proxy_pass http://web_servers;
}
}
ํธ๋ํฝ์ ํ๋ฆ์ ์ ์ดํด์ ๋คํธ์ํฌ ์์์ ํจ์จ์ ์ผ๋ก ์ฌ์ฉํ๋ ๊ธฐ๋ฒ์ด์ผ. ๋์ญํญ ์ ํ, ์ฐ์ ์์ ์ค์ ๋ฑ์ ํ ์ ์์ด.
# Nginx ์๋ ์ ํ ์ค์
http {
# IP๋น ์ด๋น 10๊ฐ ์์ฒญ์ผ๋ก ์ ํ
limit_req_zone $binary_remote_addr zone=mylimit:10m rate=10r/s;
# ๋์ญํญ ์ ํ (์ด๋น 1MB)
limit_rate 1m;
server {
location /download/ {
limit_req zone=mylimit burst=20;
limit_rate 500k; # ๋ค์ด๋ก๋๋ 500KB/s๋ก ์ ํ
}
location /api/ {
limit_req zone=mylimit burst=5 nodelay;
}
}
}
์๋ก์ด ๋ฒ์ ์ ๋ฐฐํฌํ ๋ ์ผ๋ถ ์ฌ์ฉ์์๊ฒ๋ง ๋จผ์ ๋ณด์ฌ์ฃผ๋ ๊ฑฐ์ผ. ๋ฌธ์ ๊ฐ ์์ผ๋ฉด ์ ์ง์ ์ผ๋ก ํ๋ํ์ง. ๐ค
# Nginx ์นด๋๋ฆฌ ๋ฐฐํฌ (10% ํธ๋ํฝ๋ง ์ ๋ฒ์ ์ผ๋ก)
upstream backend_v1 {
server backend-v1-1.example.com;
server backend-v1-2.example.com;
}
upstream backend_v2 {
server backend-v2-1.example.com;
}
split_clients "${remote_addr}" $backend_version {
10% v2;
* v1;
}
server {
location / {
proxy_pass http://backend_$backend_version;
}
}
1๋จ๊ณ (5%): ๋ด๋ถ ์ง์๊ณผ ๋ฒ ํ ํ ์คํฐ์๊ฒ๋ง
2๋จ๊ณ (10%): ์ผ๋ฐ ์ฌ์ฉ์ ์ค 10%์๊ฒ ๋ ธ์ถ
3๋จ๊ณ (25%): ๋ฌธ์ ์์ผ๋ฉด 25%๋ก ํ๋
4๋จ๊ณ (50%): ์ ๋ฐ์ ์ฌ์ฉ์์๊ฒ ๋ ธ์ถ
5๋จ๊ณ (100%): ์ ์ฒด ์ฌ์ฉ์์๊ฒ ๋ฐฐํฌ
๊ฐ ๋จ๊ณ๋ง๋ค ๋ชจ๋ํฐ๋งํ๊ณ ๋ฌธ์ ๋ฐ์ ์ ์ฆ์ ๋กค๋ฐฑ!
์ฌ์ฉ์์ ์์น์ ๋ฐ๋ผ ๊ฐ์ฅ ๊ฐ๊น์ด ์๋ฒ๋ก ์ฐ๊ฒฐํด์ฃผ๋ ๊ฑฐ์ผ. ์๋ต ์๋๊ฐ ๋นจ๋ผ์ง๊ณ ์ฌ์ฉ์ ๊ฒฝํ์ด ์ข์์ง์ง. ๐บ๏ธ
# Nginx GeoIP ๊ธฐ๋ฐ ๋ผ์ฐํ
http {
geoip_country /usr/share/GeoIP/GeoIP.dat;
map $geoip_country_code $backend {
default us_servers;
KR kr_servers;
JP jp_servers;
CN cn_servers;
EU eu_servers;
}
server {
location / {
proxy_pass http://$backend;
}
}
}
์๋ฒ์ ์ค์๊ฐ ์ํ์ ๋ฐ๋ผ ๊ฐ์ค์น๋ฅผ ์๋์ผ๋ก ์กฐ์ ํ๋ ๊ฑฐ์ผ. CPU ์ฌ์ฉ๋ฅ ์ด ๋์ผ๋ฉด ๊ฐ์ค์น๋ฅผ ๋ฎ์ถ๊ณ , ์ฌ์ ๋ก์ฐ๋ฉด ๋์ด๋ ์์ด์ง.
// Node.js ๋์ ๊ฐ์ค์น ์กฐ์ ์์
class DynamicLoadBalancer {
constructor() {
this.servers = [
{ url: 'server1', weight: 5, currentLoad: 0 },
{ url: 'server2', weight: 5, currentLoad: 0 },
{ url: 'server3', weight: 5, currentLoad: 0 }
];
}
async updateWeights() {
for (let server of this.servers) {
const metrics = await this.getServerMetrics(server.url);
// CPU ์ฌ์ฉ๋ฅ ์ ๋ฐ๋ผ ๊ฐ์ค์น ์กฐ์
if (metrics.cpuUsage > 80) {
server.weight = Math.max(1, server.weight - 1);
} else if (metrics.cpuUsage < 50) {
server.weight = Math.min(10, server.weight + 1);
}
server.currentLoad = metrics.cpuUsage;
}
}
getNextServer() {
// ๊ฐ์ค์น ๊ธฐ๋ฐ ๋๋ค ์ ํ
const totalWeight = this.servers.reduce((sum, s) => sum + s.weight, 0);
let random = Math.random() * totalWeight;
for (let server of this.servers) {
random -= server.weight;
if (random <= 0) return server;
}
}
}
// 10์ด๋ง๋ค ๊ฐ์ค์น ์
๋ฐ์ดํธ
setInterval(() => balancer.updateWeights(), 10000);
๋ฌธ์ ๊ฐ ์๋ ์๋ฒ๋ก์ ์์ฒญ์ ์ผ์์ ์ผ๋ก ์ฐจ๋จํด์ ์ฐ์ ์ฅ์ ๋ฅผ ๋ฐฉ์งํ๋ ํจํด์ด์ผ. ์ ๊ธฐ ํ๋ก์ ์ฐจ๋จ๊ธฐ์ฒ๋ผ ์๋ํ์ง. โก
// ์ํท ๋ธ๋ ์ด์ปค ๊ตฌํ ์์
class CircuitBreaker {
constructor(threshold = 5, timeout = 60000) {
this.failureCount = 0;
this.threshold = threshold;
this.timeout = timeout;
this.state = 'CLOSED'; // CLOSED, OPEN, HALF_OPEN
this.nextAttempt = Date.now();
}
async call(fn) {
if (this.state === 'OPEN') {
if (Date.now() < this.nextAttempt) {
throw new Error('Circuit breaker is OPEN');
}
this.state = 'HALF_OPEN';
}
try {
const result = await fn();
this.onSuccess();
return result;
} catch (error) {
this.onFailure();
throw error;
}
}
onSuccess() {
this.failureCount = 0;
this.state = 'CLOSED';
}
onFailure() {
this.failureCount++;
if (this.failureCount >= this.threshold) {
this.state = 'OPEN';
this.nextAttempt = Date.now() + this.timeout;
}
}
}
// ์ฌ์ฉ ์์
const breaker = new CircuitBreaker(5, 60000);
async function callAPI() {
try {
return await breaker.call(() => fetch('http://api.example.com'));
} catch (error) {
// ํด๋ฐฑ ๋ก์ง
return getCachedData();
}
}
โข ์ ์ง์ ์ ์ฉ: ์๋ก์ด ๊ธฐ๋ฒ์ ์์ ๊ท๋ชจ๋ก ํ ์คํธ ํ ํ๋
โข ๋ชจ๋ํฐ๋ง ํ์: ์ค์๊ฐ ๋ฉํธ๋ฆญ ์์ง๊ณผ ์๋ฆผ ์ค์
โข ํด๋ฐฑ ์ค๋น: ํญ์ ๋์ ๊ฒฝ๋ก ๋ง๋ จ
โข ๋ฌธ์ํ: ์ค์ ๊ณผ ์์ฌ๊ฒฐ์ ๊ณผ์ ๊ธฐ๋ก
โข ์ ๊ธฐ ๊ฒํ : ํธ๋ํฝ ํจํด ๋ณํ์ ๋ฐ๋ผ ์ ๋ต ์กฐ์
๋ก๋ ๋ฐธ๋ฐ์๋ฅผ ์ค์ ํ๋ค๊ณ ๋์ด ์๋์ผ. ์ง์์ ์ผ๋ก ๋ชจ๋ํฐ๋งํ๊ณ ์ต์ ํํด์ผ ํด! ๐
### ๐ ํต์ฌ ๋ชจ๋ํฐ๋ง ์งํ์ด๋ค ์งํ๋ค์ ๋ด์ผ ํ ๊น? ์ค์ํ ๊ฒ๋ค๋ง ์ถ๋ ค๋ดค์ด.
| ์งํ | ์ค๋ช | ์ ์ ๋ฒ์ |
|---|---|---|
| ์๋ต ์๊ฐ | ์์ฒญ๋ถํฐ ์๋ต๊น์ง ๊ฑธ๋ฆฐ ์๊ฐ | < 200ms |
| ์ฒ๋ฆฌ๋ (TPS) | ์ด๋น ์ฒ๋ฆฌํ๋ ํธ๋์ญ์ ์ | ์๋น์ค๋ง๋ค ๋ค๋ฆ |
| ์๋ฌ์จ | ์ ์ฒด ์์ฒญ ์ค ์๋ฌ ๋น์จ | < 0.1% |
| ๋์ ์ฐ๊ฒฐ ์ | ํ์ฌ ํ์ฑ ์ฐ๊ฒฐ ๊ฐ์ | ์๋ฒ ์ฉ๋์ 70% ์ดํ |
| ์๋ฒ CPU | ๊ฐ ์๋ฒ์ CPU ์ฌ์ฉ๋ฅ | < 70% |
| ์๋ฒ ๋ฉ๋ชจ๋ฆฌ | ๊ฐ ์๋ฒ์ ๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ๋ฅ | < 80% |
| ๋คํธ์ํฌ ๋์ญํญ | ๋คํธ์ํฌ ์ฌ์ฉ๋ | < 80% |
์ข์ ๋๊ตฌ๋ฅผ ์ฌ์ฉํ๋ฉด ๋ชจ๋ํฐ๋ง์ด ํจ์ฌ ์ฌ์์ ธ. ์ธ๊ธฐ ์๋ ๋๊ตฌ๋ค์ ์๊ฐํ ๊ฒ.
์คํ์์ค ๋ชจ๋ํฐ๋ง ์คํ์ ์ ์์ด์ผ. Prometheus๋ก ๋ฉํธ๋ฆญ์ ์์งํ๊ณ Grafana๋ก ์๊ฐํํด.
2. ELK Stack (Elasticsearch + Logstash + Kibana)
๋ก๊ทธ ์์ง๊ณผ ๋ถ์์ ํนํ๋์ด ์์ด. ๋์ฉ๋ ๋ก๊ทธ๋ ๋น ๋ฅด๊ฒ ๊ฒ์ํ ์ ์์ง.
3. Datadog
์ ๋ฃ์ง๋ง ๊ฐ๋ ฅํ ํด๋ผ์ฐ๋ ๋ชจ๋ํฐ๋ง ์๋น์ค์ผ. ์ค์ ์ด ์ฝ๊ณ ๊ธฐ๋ฅ์ด ํ๋ถํด.
4. New Relic
APM(Application Performance Monitoring)์ ๊ฐ์์ผ. ์ ํ๋ฆฌ์ผ์ด์ ์ฑ๋ฅ์ ๊น์ด ์๊ฒ ๋ถ์ํ ์ ์์ด.
๋ก๋ ๋ฐธ๋ฐ์ ์ฑ๋ฅ์ ๋์ด์ฌ๋ฆฌ๋ ๋ฐฉ๋ฒ๋ค์ด์ผ. ํ๋์ฉ ์ฒดํฌํด๋ณด์! โ
โ๏ธ Keep-Alive ํ์ฑํ: TCP ์ฐ๊ฒฐ ์ฌ์ฌ์ฉ์ผ๋ก ์ค๋ฒํค๋ ๊ฐ์
โ๏ธ HTTP/2 ์ฌ์ฉ: ๋ฉํฐํ๋ ์ฑ์ผ๋ก ๋์ ์์ฒญ ์ฒ๋ฆฌ
โ๏ธ ์์ถ ํ์ฑํ: Gzip, Brotli๋ก ์ ์ก ๋ฐ์ดํฐ ํฌ๊ธฐ ๊ฐ์
โ๏ธ CDN ํ์ฉ: ์ ์ ์ฝํ ์ธ ๋ CDN์ผ๋ก ๋ถ์ฐ
์๋ฒ ๋ ๋ฒจ ์ต์ ํ:
โ๏ธ ์ปค๋ฅ์ ํ๋ง: ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ฐ๊ฒฐ ์ฌ์ฌ์ฉ
โ๏ธ ์บ์ฑ ์ ๋ต: Redis, Memcached๋ก ์์ฃผ ์ฐ๋ ๋ฐ์ดํฐ ์บ์ฑ
โ๏ธ ๋น๋๊ธฐ ์ฒ๋ฆฌ: ๋ฌด๊ฑฐ์ด ์์ ์ ๋ฐฑ๊ทธ๋ผ์ด๋์์ ์ฒ๋ฆฌ
โ๏ธ ์ฟผ๋ฆฌ ์ต์ ํ: ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ฟผ๋ฆฌ ์ฑ๋ฅ ๊ฐ์
๋ก๋ ๋ฐธ๋ฐ์ ๋ ๋ฒจ ์ต์ ํ:
โ๏ธ ์ ์ ํ ์๊ณ ๋ฆฌ์ฆ ์ ํ: ํธ๋ํฝ ํจํด์ ๋ง๋ ์๊ณ ๋ฆฌ์ฆ ์ฌ์ฉ
โ๏ธ ํฌ์ค ์ฒดํฌ ์ต์ ํ: ๊ฐ๊ฒฉ๊ณผ ์๊ณ๊ฐ ์กฐ์
โ๏ธ ํ์์์ ์ค์ : ์ ์ ํ ํ์์์์ผ๋ก ๋ฆฌ์์ค ๋ญ๋น ๋ฐฉ์ง
โ๏ธ ๋ฒํผ ํฌ๊ธฐ ์กฐ์ : ๋คํธ์ํฌ ๋ฒํผ ํฌ๊ธฐ ์ต์ ํ
# Nginx ์ฑ๋ฅ ์ต์ ํ ์ค์ ์์
http {
# Keep-Alive ์ค์
keepalive_timeout 65;
keepalive_requests 100;
# ์์ถ ์ค์
gzip on;
gzip_vary on;
gzip_min_length 1024;
gzip_types text/plain text/css application/json application/javascript;
# ๋ฒํผ ํฌ๊ธฐ ์ค์
client_body_buffer_size 128k;
client_max_body_size 10m;
# ํ๋ก์ ์ค์
proxy_buffering on;
proxy_buffer_size 4k;
proxy_buffers 8 4k;
proxy_connect_timeout 60s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
# ์
์คํธ๋ฆผ Keep-Alive
upstream backend {
server backend1.example.com;
server backend2.example.com;
keepalive 32;
}
server {
location / {
proxy_pass http://backend;
proxy_http_version 1.1;
proxy_set_header Connection "";
}
}
}
์ค์ ์ด์ ์ ์ ์ผ๋ง๋ ๋ง์ ํธ๋ํฝ์ ๊ฐ๋นํ ์ ์๋์ง ํ ์คํธํด๋ด์ผ ํด. ๋ถํ ํ ์คํธ ๋๊ตฌ๋ค์ ์๊ฐํ ๊ฒ! ๐ช
GUI ๊ธฐ๋ฐ์ ๊ฐ๋ ฅํ ๋ถํ ํ ์คํธ ๋๊ตฌ์ผ. ๋ณต์กํ ์๋๋ฆฌ์ค๋ ์ฝ๊ฒ ๋ง๋ค ์ ์์ด.
Gatling
Scala ๊ธฐ๋ฐ์ ๊ณ ์ฑ๋ฅ ๋ถํ ํ ์คํธ ๋๊ตฌ์ผ. ์ฝ๋๋ก ์๋๋ฆฌ์ค๋ฅผ ์์ฑํ๊ณ ๋ฉ์ง ๋ฆฌํฌํธ๋ฅผ ์ ๊ณตํด.
k6
JavaScript๋ก ์๋๋ฆฌ์ค๋ฅผ ์์ฑํ๋ ํ๋์ ์ธ ๋๊ตฌ์ผ. ๊ฐ๋ฐ์ ์นํ์ ์ด๊ณ CI/CD ํตํฉ์ด ์ฌ์.
Artillery
Node.js ๊ธฐ๋ฐ์ ๊ฐ๋จํ๊ณ ๊ฐ๋ ฅํ ๋๊ตฌ์ผ. YAML๋ก ์๋๋ฆฌ์ค๋ฅผ ์์ฑํ ์ ์์ด.
// k6 ๋ถํ ํ
์คํธ ์คํฌ๋ฆฝํธ ์์
import http from 'k6/http';
import { check, sleep } from 'k6';
export let options = {
stages: [
{ duration: '2m', target: 100 }, // 2๋ถ๊ฐ 100๋ช
๊น์ง ์ฆ๊ฐ
{ duration: '5m', target: 100 }, // 5๋ถ๊ฐ 100๋ช
์ ์ง
{ duration: '2m', target: 200 }, // 2๋ถ๊ฐ 200๋ช
๊น์ง ์ฆ๊ฐ
{ duration: '5m', target: 200 }, // 5๋ถ๊ฐ 200๋ช
์ ์ง
{ duration: '2m', target: 0 }, // 2๋ถ๊ฐ 0๋ช
๊น์ง ๊ฐ์
],
thresholds: {
http_req_duration: ['p(95)<500'], // 95%์ ์์ฒญ์ด 500ms ์ดํ
http_req_failed: ['rate<0.01'], // ์๋ฌ์จ 1% ์ดํ
},
};
export default function() {
let response = http.get('http://example.com/api/users');
check(response, {
'status is 200': (r) => r.status === 200,
'response time < 500ms': (r) => r.timings.duration < 500,
});
sleep(1);
}
์ด๋ก ๋ง ๋ฐฐ์ฐ๋ฉด ์ฌ๋ฏธ์์์? ์ค์ ๊ธฐ์ ๋ค์ด ์ด๋ป๊ฒ ๋ก๋ ๋ฐธ๋ฐ์ฑ์ ํ์ฉํ๋์ง ์์๋ณด์! ๐
### ๐ ๋ํ ์ด์ปค๋จธ์ค ์ฌ์ดํธํ ๋ํ ์ผํ๋ชฐ์ ๋ธ๋ํ๋ผ์ด๋ฐ์ด ๋์ ์ฌ๋ก์ผ. ํ์ ํธ๋ํฝ์ 50๋ฐฐ๋ฅผ ์ฒ๋ฆฌํด์ผ ํ์ด.
โข ํ์ 10,000 TPS โ ๋ธ๋ํ๋ผ์ด๋ฐ์ด 500,000 TPS
โข ์ ์ธ๊ณ ์ฌ์ฉ์ ๋์ ์ ์
โข ๊ฒฐ์ ์์คํ ์์ ์ฑ ํ์
ํด๊ฒฐ ๋ฐฉ์:
1. ๋ค์ธต ๋ก๋ ๋ฐธ๋ฐ์ฑ ๊ตฌ์กฐ
โข GSLB๋ก ์ง์ญ๋ณ ํธ๋ํฝ ๋ถ์ฐ
โข L7 ๋ก๋ ๋ฐธ๋ฐ์๋ก ์๋น์ค๋ณ ๋ผ์ฐํ
โข L4 ๋ก๋ ๋ฐธ๋ฐ์๋ก ์ต์ข ์๋ฒ ๋ถ์ฐ
2. ์คํ ์ค์ผ์ผ๋ง
โข CPU ์ฌ์ฉ๋ฅ 70% ์ด์ ์ ์๋์ผ๋ก ์๋ฒ ์ถ๊ฐ
โข ํธ๋ํฝ ๊ฐ์ ์ ์๋์ผ๋ก ์๋ฒ ์ ๊ฑฐ
โข ์ต์ 50๋ โ ์ต๋ 500๋ ์๋ฒ ์ด์
3. ์บ์ฑ ์ ๋ต
โข ์ํ ์ ๋ณด๋ CDN์ ์บ์ฑ
โข ์ฅ๋ฐ๊ตฌ๋๋ Redis์ ์บ์ฑ
โข API ์๋ต์ Varnish๋ก ์บ์ฑ
๊ฒฐ๊ณผ:
โ 99.99% ๊ฐ์ฉ์ฑ ๋ฌ์ฑ
โ ํ๊ท ์๋ต ์๊ฐ 200ms ์ ์ง
โ ์๋ฒ ๋น์ฉ 30% ์ ๊ฐ (ํจ์จ์ ์ธ ์ค์ผ์ผ๋ง)
โ ๋งค์ถ ๋ชฉํ 120% ๋ฌ์ฑ
์ ์ธ๊ณ ์๋ฐฑ๋ง ๋ช ์ด ๋์์ ํ๋ ์ดํ๋ ์จ๋ผ์ธ ๊ฒ์์ ์ฌ๋ก์ผ.
โข ์ค์๊ฐ ๊ฒ์ ๋ฐ์ดํฐ ๋๊ธฐํ
โข ์ง์ญ๋ณ ๋ ์ดํด์ ์ต์ํ
โข ํผํฌ ํ์ ํธ๋ํฝ ์ง์ค
ํด๊ฒฐ ๋ฐฉ์:
1. ์ง์ญ๋ณ ๊ฒ์ ์๋ฒ ํด๋ฌ์คํฐ
โข ๋ถ๋ฏธ, ์ ๋ฝ, ์์์ ๊ฐ ์ง์ญ์ ์๋ฒ ํด๋ฌ์คํฐ
โข GSLB๋ก ์ฌ์ฉ์๋ฅผ ๊ฐ์ฅ ๊ฐ๊น์ด ํด๋ฌ์คํฐ๋ก ์ฐ๊ฒฐ
โข ๊ฐ ํด๋ฌ์คํฐ ๋ด์์ L4 ๋ก๋ ๋ฐธ๋ฐ์ฑ
2. ์ธ์ ๊ณ ์ ์ ๋ต
โข ๊ฒ์ ์ธ์ ์ค์๋ ๊ฐ์ ์๋ฒ ์ ์ง
โข ์๋ฒ ์ฅ์ ์์๋ง ๋ค๋ฅธ ์๋ฒ๋ก ์ด๋
โข ๊ฒ์ ์ํ๋ Redis์ ์ค์๊ฐ ๋ฐฑ์
3. ๋์ ์๋ฒ ํ ๋น
โข ๊ฒ์ ๋ชจ๋๋ณ๋ก ์๋ฒ ํ ๋ถ๋ฆฌ
โข ์ธ๊ธฐ ๋ชจ๋์ ๋ ๋ง์ ์๋ฒ ํ ๋น
โข ๋งค์น๋ฉ์ดํน ์ ์๋ฒ ๋ถํ ๊ณ ๋ ค
๊ฒฐ๊ณผ:
โ ํ๊ท ๋ ์ดํด์ 50ms ์ดํ
โ ๋์ ์ ์์ 500๋ง ๋ช ์ฒ๋ฆฌ
โ ์๋ฒ ์ฅ์ ๋ก ์ธํ ๊ฒ์ ์ค๋จ 0๊ฑด
โ ์ฌ์ฉ์ ๋ง์กฑ๋ 95% ์ด์
์ค์๊ฐ ํผ๋์ ๋ฉ์์ง์ ์ ๊ณตํ๋ ์์ ๋ฏธ๋์ด์ ์ฌ๋ก์ผ.
โข ์ค์๊ฐ ํผ๋ ์ ๋ฐ์ดํธ
โข ์ด๋ฏธ์ง/๋น๋์ค ๋์ฉ๋ ํธ๋ํฝ
โข ๋ถ๊ท์นํ ํธ๋ํฝ ํจํด
ํด๊ฒฐ ๋ฐฉ์:
1. ๋ง์ดํฌ๋ก์๋น์ค ์ํคํ ์ฒ
โข ํผ๋, ๋ฉ์์ง, ๋ฏธ๋์ด ์๋น์ค ๋ถ๋ฆฌ
โข ๊ฐ ์๋น์ค๋ง๋ค ๋ ๋ฆฝ์ ์ธ ๋ก๋ ๋ฐธ๋ฐ์
โข API Gateway๋ก ํตํฉ ๊ด๋ฆฌ
2. ์ฝํ ์ธ ๊ธฐ๋ฐ ๋ผ์ฐํ
โข ์ด๋ฏธ์ง/๋น๋์ค๋ ๋ฏธ๋์ด ์๋ฒ๋ก
โข API ์์ฒญ์ ์ ํ๋ฆฌ์ผ์ด์ ์๋ฒ๋ก
โข WebSocket ์ฐ๊ฒฐ์ ์ค์๊ฐ ์๋ฒ๋ก
3. ์ง๋ฅํ ์บ์ฑ
โข ์ธ๊ธฐ ์ฝํ ์ธ ๋ ์ฃ์ง ์บ์์ ์ ์ฅ
โข ์ฌ์ฉ์๋ณ ํผ๋๋ Redis์ ์บ์ฑ
โข ๋ฏธ๋์ด ํ์ผ์ CDN์ผ๋ก ๋ฐฐํฌ
๊ฒฐ๊ณผ:
โ ํผ๋ ๋ก๋ฉ ์๊ฐ 1์ด ์ด๋ด
โ ๋ฏธ๋์ด ์ ์ก ๋น์ฉ 60% ์ ๊ฐ
โ ์ผ์ผ ํ์ฑ ์ฌ์ฉ์ 1์ต ๋ช ์ฒ๋ฆฌ
โ ์์คํ ๊ฐ์ฉ์ฑ 99.95%
โข ๊ณ์ธตํ๋ ์ ๊ทผ: ๋จ์ผ ๋ก๋ ๋ฐธ๋ฐ์๋ณด๋ค ์ฌ๋ฌ ๊ณ์ธต์ผ๋ก ๋ถ์ฐ
โข ์บ์ฑ ํ์ฉ: ๋ก๋ ๋ฐธ๋ฐ์ฑ๋ง์ผ๋ก๋ ๋ถ์กฑ, ์บ์ฑ ์ ๋ต ํ์
โข ๋ชจ๋ํฐ๋ง ์ค์: ์ค์๊ฐ ๋ฉํธ๋ฆญ์ผ๋ก ๋น ๋ฅธ ๋์
โข ํ ์คํธ ํ์: ์ค์ ์ํฉ ์ ์ ์ถฉ๋ถํ ๋ถํ ํ ์คํธ
โข ์ ์ง์ ํ์ฅ: ํ ๋ฒ์ ๋ชจ๋ ๊ฑธ ๋ฐ๊พธ์ง ๋ง๊ณ ๋จ๊ณ์ ์ผ๋ก
์์ฆ์ ๋๋ถ๋ถ ํด๋ผ์ฐ๋์์ ์๋น์ค๋ฅผ ์ด์ํ์์? ํด๋ผ์ฐ๋ ํ๊ฒฝ์์์ ๋ก๋ ๋ฐธ๋ฐ์ฑ์ ์ข ๋ค๋ฅธ ์ ๊ทผ์ด ํ์ํด. โ๏ธ
### ๐ AWS ๋ก๋ ๋ฐธ๋ฐ์ฑAWS๋ ์ธ ๊ฐ์ง ํ์ ์ ๋ก๋ ๋ฐธ๋ฐ์๋ฅผ ์ ๊ณตํด. ๊ฐ๊ฐ์ ํน์ง์ ์์๋ณด์!
ํน์ง:
โข HTTP/HTTPS ํธ๋ํฝ ์ ์ฉ
โข ๊ฒฝ๋ก ๊ธฐ๋ฐ, ํธ์คํธ ๊ธฐ๋ฐ ๋ผ์ฐํ
โข Lambda ํจ์ ์ง์ ํธ์ถ ๊ฐ๋ฅ
โข ์ปจํ ์ด๋ ๊ธฐ๋ฐ ์ ํ๋ฆฌ์ผ์ด์ ์ ์ต์
์ฌ์ฉ ์ฌ๋ก:
โข ๋ง์ดํฌ๋ก์๋น์ค ์ํคํ ์ฒ
โข ์ปจํ ์ด๋ ๊ธฐ๋ฐ ์ ํ๋ฆฌ์ผ์ด์
โข ์๋ฒ๋ฆฌ์ค ์ ํ๋ฆฌ์ผ์ด์
๊ฐ๊ฒฉ: ์๊ฐ๋น ์๊ธ + ์ฒ๋ฆฌ๋ ๊ธฐ๋ฐ ์๊ธ
ํน์ง:
โข L4 ๋ก๋ ๋ฐธ๋ฐ์
โข ์ด๋น ์๋ฐฑ๋ง ์์ฒญ ์ฒ๋ฆฌ
โข ๊ณ ์ IP ์ฃผ์ ์ง์
โข ๊ทน๋๋ก ๋ฎ์ ๋ ์ดํด์
์ฌ์ฉ ์ฌ๋ก:
โข ๊ฒ์ ์๋ฒ
โข IoT ์ ํ๋ฆฌ์ผ์ด์
โข ์ค์๊ฐ ์คํธ๋ฆฌ๋ฐ
๊ฐ๊ฒฉ: ์๊ฐ๋น ์๊ธ + ์ฒ๋ฆฌ๋ ๊ธฐ๋ฐ ์๊ธ (ALB๋ณด๋ค ์ ๋ ด)
ํน์ง:
โข ๋ฐฉํ๋ฒฝ, IDS/IPS ๋ฑ ๊ฐ์ ์ดํ๋ผ์ด์ธ์ค ๋ฐฐํฌ
โข ํธ๋ํฝ์ ํฌ๋ช ํ๊ฒ ์ ๋ฌ
โข ๋ณด์ ๊ฒ์ฌ ํ ์๋ ๋ชฉ์ ์ง๋ก ์ ๋ฌ
์ฌ์ฉ ์ฌ๋ก:
โข ๋คํธ์ํฌ ๋ณด์ ์๋ฃจ์
โข ํธ๋ํฝ ๊ฒ์ฌ ๋ฐ ํํฐ๋ง
๊ฐ๊ฒฉ: ์๊ฐ๋น ์๊ธ + ์ฒ๋ฆฌ๋ ๊ธฐ๋ฐ ์๊ธ
Microsoft Azure๋ ๋ค์ํ ๋ก๋ ๋ฐธ๋ฐ์ฑ ์ต์ ์ ์ ๊ณตํด.
โข L4 ๋ก๋ ๋ฐธ๋ฐ์
โข ๋ด๋ถ ๋ฐ ์ธ๋ถ ํธ๋ํฝ ์ง์
โข ๊ณ ๊ฐ์ฉ์ฑ ๋ฐ ๋ฎ์ ๋ ์ดํด์
Azure Application Gateway
โข L7 ๋ก๋ ๋ฐธ๋ฐ์
โข WAF (Web Application Firewall) ํตํฉ
โข SSL ์ข ๋ฃ ๋ฐ URL ๊ธฐ๋ฐ ๋ผ์ฐํ
Azure Traffic Manager
โข DNS ๊ธฐ๋ฐ ๊ธ๋ก๋ฒ ๋ก๋ ๋ฐธ๋ฐ์
โข ์ง๋ฆฌ์ ๋ผ์ฐํ
โข ์ฌํด ๋ณต๊ตฌ ์ง์
GCP๋ ํตํฉ๋ ๋ก๋ ๋ฐธ๋ฐ์ฑ ์๋ฃจ์ ์ ์ ๊ณตํด.
โข ๊ธ๋ก๋ฒ L7 ๋ก๋ ๋ฐธ๋ฐ์
โข ์๋ ์ค์ผ์ผ๋ง
โข Cloud CDN ํตํฉ
TCP/UDP Load Balancing
โข ์ง์ญ๋ณ ๋๋ ๊ธ๋ก๋ฒ L4 ๋ก๋ ๋ฐธ๋ฐ์
โข ๊ณ ์ฑ๋ฅ TCP/UDP ํธ๋ํฝ ์ฒ๋ฆฌ
Internal Load Balancing
โข VPC ๋ด๋ถ ํธ๋ํฝ ๋ถ์ฐ
โข ๋ง์ดํฌ๋ก์๋น์ค ๊ฐ ํต์ ์ต์ ํ
์ปจํ ์ด๋ ์ค์ผ์คํธ๋ ์ด์ ํ๊ฒฝ์์์ ๋ก๋ ๋ฐธ๋ฐ์ฑ๋ ์ค์ํด!
# Kubernetes Service ์ ์ (LoadBalancer ํ์
)
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
type: LoadBalancer
selector:
app: my-app
ports:
- protocol: TCP
port: 80
targetPort: 8080
sessionAffinity: ClientIP # ์ธ์
๊ณ ์
sessionAffinityConfig:
clientIP:
timeoutSeconds: 3600
# Ingress ๋ฆฌ์์ค (L7 ๋ก๋ ๋ฐธ๋ฐ์ฑ)
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: my-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
nginx.ingress.kubernetes.io/ssl-redirect: "true"
spec:
rules:
- host: example.com
http:
paths:
- path: /api
pathType: Prefix
backend:
service:
name: api-service
port:
number: 8080
- path: /web
pathType: Prefix
backend:
service:
name: web-service
port:
number: 80
โข ๋น์ฉ ๊ด๋ฆฌ: ํธ๋ํฝ ์์ ๋ฐ๋ผ ๋น์ฉ์ด ๊ธ์ฆํ ์ ์์ด
โข ๋ฆฌ์ ์ ํ: ์ฌ์ฉ์์ ๊ฐ๊น์ด ๋ฆฌ์ ์ ํ์ด ์ค์
โข ํฌ์ค ์ฒดํฌ ์ค์ : ์ ์ ํ ํฌ์ค ์ฒดํฌ๋ก ๋ถํ์ํ ๋น์ฉ ๋ฐฉ์ง
โข ๋ณด์ ๊ทธ๋ฃน: ๋ฐฉํ๋ฒฝ ๊ท์น ์ ๋๋ก ์ค์
โข ๋ก๊น ํ์ฑํ: ๋ฌธ์ ํด๊ฒฐ์ ์ํ ๋ก๊ทธ ์์ง ํ์
๋ก๋ ๋ฐธ๋ฐ์๋ ๋ชจ๋ ํธ๋ํฝ์ด ์ง๋๊ฐ๋ ๊ด๋ฌธ์ด์ผ. ๋ณด์์ด ์ ๋ง ์ค์ํ์ง! ๐
### ๐ SSL/TLS ์ข ๋ฃHTTPS ํธ๋ํฝ์ ์ํธํ/๋ณตํธํ๋ฅผ ๋ก๋ ๋ฐธ๋ฐ์์์ ์ฒ๋ฆฌํ๋ ๊ฑฐ์ผ. ๋ฐฑ์๋ ์๋ฒ์ ๋ถ๋ด์ ์ค์ผ ์ ์์ด.
# Nginx SSL ์ข
๋ฃ ์ค์
server {
listen 443 ssl http2;
server_name example.com;
# SSL ์ธ์ฆ์ ์ค์
ssl_certificate /etc/nginx/ssl/example.com.crt;
ssl_certificate_key /etc/nginx/ssl/example.com.key;
# SSL ํ๋กํ ์ฝ ๋ฐ ์ํธํ ์ค์
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
# HSTS ํค๋
add_header Strict-Transport-Security "max-age=31536000" always;
# ๋ฐฑ์๋๋ก ํ๋ก์ (HTTP)
location / {
proxy_pass http://backend;
proxy_set_header X-Forwarded-Proto https;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
์ฅ์ :
โ
๋ฐฑ์๋ ์๋ฒ CPU ๋ถํ ๊ฐ์
โ
์ธ์ฆ์ ๊ด๋ฆฌ ์ค์ํ
โ
์ต์ ๋ณด์ ํ๋กํ ์ฝ ์ฝ๊ฒ ์ ์ฉ
๋จ์ :
โ ๋ก๋ ๋ฐธ๋ฐ์์ ๋ฐฑ์๋ ๊ฐ ํธ๋ํฝ์ ์ํธํ๋์ง ์์
โ ๋ก๋ ๋ฐธ๋ฐ์๊ฐ ๋จ์ผ ์ฅ์ ์ ์ด ๋ ์ ์์
๋ก๋ ๋ฐธ๋ฐ์ ๋ ๋ฒจ์์ DDoS ๊ณต๊ฒฉ์ ๋ฐฉ์ดํ ์ ์์ด.
1. ์๋ ์ ํ (Rate Limiting)
โข IP๋น ์ด๋น ์์ฒญ ์ ์ ํ
โข ์๊ณ๊ฐ ์ด๊ณผ ์ ์ผ์์ ์ฐจ๋จ
2. ์ฐ๊ฒฐ ์ ํ
โข IP๋น ๋์ ์ฐ๊ฒฐ ์ ์ ํ
โข ๋น์ ์์ ์ธ ์ฐ๊ฒฐ ํจํด ๊ฐ์ง
3. ์ง๋ฆฌ์ ์ฐจ๋จ
โข ํน์ ๊ตญ๊ฐ/์ง์ญ ์ฐจ๋จ
โข ํ์ดํธ๋ฆฌ์คํธ ๊ธฐ๋ฐ ์ ๊ทผ ์ ์ด
4. ํจํด ๋ถ์
โข ๋น์ ์์ ์ธ ํธ๋ํฝ ํจํด ๊ฐ์ง
โข ๋จธ์ ๋ฌ๋ ๊ธฐ๋ฐ ์ด์ ํ์ง
# Nginx DDoS ๋ฐฉ์ด ์ค์
http {
# ์ฐ๊ฒฐ ์ ํ
limit_conn_zone $binary_remote_addr zone=conn_limit:10m;
limit_conn conn_limit 10;
# ์์ฒญ ์๋ ์ ํ
limit_req_zone $binary_remote_addr zone=req_limit:10m rate=10r/s;
limit_req zone=req_limit burst=20 nodelay;
# ํ์์์ ์ค์
client_body_timeout 10s;
client_header_timeout 10s;
server {
# ํน์ User-Agent ์ฐจ๋จ
if ($http_user_agent ~* (bot|crawler|spider)) {
return 403;
}
# ํน์ ๊ตญ๊ฐ ์ฐจ๋จ (GeoIP ํ์)
if ($geoip_country_code = CN) {
return 403;
}
location / {
# ์์ฒญ ํฌ๊ธฐ ์ ํ
client_max_body_size 1m;
proxy_pass http://backend;
}
}
}
SQL ์ธ์ ์ , XSS ๊ฐ์ ์น ๊ณต๊ฒฉ์ ๋ง์์ฃผ๋ ๋ฐฉํ๋ฒฝ์ด์ผ.
โข SQL Injection: ๋ฐ์ดํฐ๋ฒ ์ด์ค ๊ณต๊ฒฉ
โข XSS (Cross-Site Scripting): ์ ์ฑ ์คํฌ๋ฆฝํธ ์ฝ์
โข CSRF (Cross-Site Request Forgery): ์์กฐ๋ ์์ฒญ
โข Path Traversal: ๋๋ ํ ๋ฆฌ ํ์ ๊ณต๊ฒฉ
โข Command Injection: ์์คํ ๋ช ๋ น์ด ์คํ
โข File Upload Attack: ์ ์ฑ ํ์ผ ์ ๋ก๋
๋ก๋ ๋ฐธ๋ฐ์ ๋ ๋ฒจ์์ ์ธ์ฆ์ ์ฒ๋ฆฌํ ์๋ ์์ด.
# Nginx ๊ธฐ๋ณธ ์ธ์ฆ ์ค์
server {
location /admin {
auth_basic "Restricted Area";
auth_basic_user_file /etc/nginx/.htpasswd;
proxy_pass http://backend;
}
# JWT ํ ํฐ ๊ฒ์ฆ (lua ๋ชจ๋ ํ์)
location /api {
access_by_lua_block {
local jwt = require "resty.jwt"
local token = ngx.var.http_authorization
if not token then
ngx.status = 401
ngx.say("Missing token")
return ngx.exit(401)
end
local jwt_obj = jwt:verify("your-secret", token)
if not jwt_obj.verified then
ngx.status = 401
ngx.say("Invalid token")
return ngx.exit(401)
end
}
proxy_pass http://backend;
}
}
โข ์ต์ ๊ถํ ์์น: ํ์ํ ์ต์ํ์ ๊ถํ๋ง ๋ถ์ฌ
โข ์ ๊ธฐ์ ์ธ ์ ๋ฐ์ดํธ: ๋ก๋ ๋ฐธ๋ฐ์ ์ํํธ์จ์ด ์ต์ ๋ฒ์ ์ ์ง
โข ๋ก๊ทธ ๋ชจ๋ํฐ๋ง: ์์ฌ์ค๋ฌ์ด ํ๋ ์ค์๊ฐ ๊ฐ์ง
โข ๋ฐฑ์ ๊ณํ: ์ค์ ํ์ผ ์ ๊ธฐ์ ๋ฐฑ์
โข ์นจํฌ ํ ์คํธ: ์ ๊ธฐ์ ์ธ ๋ณด์ ์ทจ์ฝ์ ์ ๊ฒ
โข ์ํธํ ํต์ : ๊ฐ๋ฅํ ๋ชจ๋ ๊ตฌ๊ฐ์์ ์ํธํ ์ฌ์ฉ
์ค์ ๋ก ์ด์ํ๋ค ๋ณด๋ฉด ์์์น ๋ชปํ ๋ฌธ์ ๋ค์ด ์๊ฒจ. ์์ฃผ ๊ฒช๋ ๋ฌธ์ ๋ค๊ณผ ํด๊ฒฐ ๋ฐฉ๋ฒ์ ๊ณต์ ํ ๊ฒ! ๐ง
### ๐ ์์ฃผ ๋ฐ์ํ๋ ๋ฌธ์ ๋ค์ฆ์:
โข ํ ์๋ฒ๋ง CPU 100%
โข ๋ค๋ฅธ ์๋ฒ๋ค์ ์ฌ์ ๋ก์
โข ์ ์ฒด ์๋ต ์๊ฐ ์ฆ๊ฐ
์์ธ:
โข ์ธ์ ๊ณ ์ ์ค์ ์ผ๋ก ํน์ ์ฌ์ฉ์๋ค์ด ํ ์๋ฒ์ ๋ชฐ๋ฆผ
โข ๊ฐ์ค์น ์ค์ ์ค๋ฅ
โข ํฌ์ค ์ฒดํฌ ์คํจ๋ก ์ผ๋ถ ์๋ฒ ์ ์ธ๋จ
ํด๊ฒฐ:
โข ์ธ์ ๊ณ ์ ๋์ ์ธ์ ๊ณต์ ๋ฐฉ์ ์ฌ์ฉ
โข ๊ฐ์ค์น ์ฌ์กฐ์
โข ํฌ์ค ์ฒดํฌ ๋ก๊ทธ ํ์ธ ๋ฐ ์๊ณ๊ฐ ์กฐ์
์ฆ์:
โข ๊ฐ๋์ฉ 504 Gateway Timeout ์๋ฌ
โข ํน์ ์๊ฐ๋์ ์ง์ค
โข ์ฌ์๋ํ๋ฉด ์ฑ๊ณต
์์ธ:
โข ๋ฐฑ์๋ ์๋ฒ ์ฒ๋ฆฌ ์๊ฐ ์ด๊ณผ
โข ๋ก๋ ๋ฐธ๋ฐ์ ํ์์์ ์ค์ ์ด ๋๋ฌด ์งง์
โข ๋คํธ์ํฌ ์ง์ฐ
ํด๊ฒฐ:
โข ํ์์์ ๊ฐ ์ฆ๊ฐ
โข ๋ฐฑ์๋ ์ฑ๋ฅ ์ต์ ํ
โข ๋๋ฆฐ ์ฟผ๋ฆฌ ์ฐพ์์ ๊ฐ์
์ฆ์:
โข ๋ก๊ทธ์ธ ํ ๋ค์ ๋ก๊ทธ์ธ ํ๋ฉด์ผ๋ก
โข ์ฅ๋ฐ๊ตฌ๋ ๋ด์ฉ ์ฌ๋ผ์ง
โข ์ฌ์ฉ์ ๋ถ๋ง ์ฆ๊ฐ
์์ธ:
โข ์ธ์ ์ด ์๋ฒ ๋ก์ปฌ์ ์ ์ฅ๋์ด ์์
โข ๋ก๋ ๋ฐธ๋ฐ์๊ฐ ์์ฒญ์ ๋ค๋ฅธ ์๋ฒ๋ก ๋ณด๋
ํด๊ฒฐ:
โข Redis ๊ฐ์ ์ค์ ์ธ์ ์ ์ฅ์ ์ฌ์ฉ
โข JWT ํ ํฐ ๊ธฐ๋ฐ ์ธ์ฆ์ผ๋ก ์ ํ
โข ์ธ์ ๊ณ ์ ์ค์ (์์ ๋ฐฉํธ)
์ฆ์:
โข ์ ์ ์๋ฒ๊ฐ ์ ์ธ๋จ
โข ๋๋ ๋ฌธ์ ์๋ ์๋ฒ๊ฐ ๊ณ์ ํธ๋ํฝ ๋ฐ์
์์ธ:
โข ํฌ์ค ์ฒดํฌ ์๋ํฌ์ธํธ๊ฐ ์ค์ ์๋น์ค ์ํ๋ฅผ ๋ฐ์ํ์ง ๋ชปํจ
โข ์๊ณ๊ฐ ์ค์ ์ค๋ฅ
ํด๊ฒฐ:
โข ํฌ์ค ์ฒดํฌ ์๋ํฌ์ธํธ ๊ฐ์ (DB ์ฐ๊ฒฐ, ์ธ๋ถ API ์ํ ๋ฑ ์ฒดํฌ)
โข ์๊ณ๊ฐ ์กฐ์
โข ํฌ์ค ์ฒดํฌ ๋ก๊ทธ ๋ชจ๋ํฐ๋ง
๋ฌธ์ ๊ฐ ์๊ฒผ์ ๋ ์ด๋ป๊ฒ ์์ธ์ ์ฐพ์๊น?
# 1. ๋ก๋ ๋ฐธ๋ฐ์ ๋ก๊ทธ ํ์ธ
tail -f /var/log/nginx/access.log
tail -f /var/log/nginx/error.log
# 2. ์๋ฒ๋ณ ํธ๋ํฝ ๋ถํฌ ํ์ธ
awk '{print $1}' /var/log/nginx/access.log | sort | uniq -c | sort -rn
# 3. ์๋ต ์๊ฐ ๋ถ์
awk '{print $NF}' /var/log/nginx/access.log | \
awk '{sum+=$1; count++} END {print "Average:", sum/count}'
# 4. ์๋ฌ์จ ํ์ธ
awk '{print $9}' /var/log/nginx/access.log | \
grep -E "^[45]" | wc -l
# 5. ์ค์๊ฐ ์ฐ๊ฒฐ ์ ํ์ธ
netstat -an | grep :80 | wc -l
์ ๊ธฐ์ ์ผ๋ก ํ์ธํด์ผ ํ ํญ๋ชฉ๋ค์ด์ผ.
โ๏ธ ๋ชจ๋ ์๋ฒ ํฌ์ค ์ฒดํฌ ์ํ ํ์ธ
โ๏ธ ์๋ฌ ๋ก๊ทธ ๊ฒํ
โ๏ธ ์๋ต ์๊ฐ ๋ชจ๋ํฐ๋ง
โ๏ธ ํธ๋ํฝ ๋ถํฌ ํ์ธ
์ฃผ๊ฐ ์ฒดํฌ๋ฆฌ์คํธ:
โ๏ธ ์๋ฒ ๋ฆฌ์์ค ์ฌ์ฉ๋ฅ ํธ๋ ๋ ๋ถ์
โ๏ธ ๋ก๊ทธ ํ์ผ ์ ๋ฆฌ ๋ฐ ์์นด์ด๋น
โ๏ธ ๋ณด์ ํจ์น ํ์ธ
โ๏ธ ๋ฐฑ์ ์ํ ํ์ธ
์๊ฐ ์ฒดํฌ๋ฆฌ์คํธ:
โ๏ธ ๋ถํ ํ ์คํธ ์ค์
โ๏ธ ์ค์ ํ์ผ ๋ฆฌ๋ทฐ
โ๏ธ ์ฉ๋ ๊ณํ ๊ฒํ
โ๏ธ ์ฌํด ๋ณต๊ตฌ ๊ณํ ํ ์คํธ
์, ์ฌ๊ธฐ๊น์ง ์ฝ์๋ค๋ฉด ์ ๋ง ๋๋จํด! ๐ ๋ก๋ ๋ฐธ๋ฐ์ฑ๊ณผ ํธ๋ํฝ ๊ด๋ฆฌ์ ๋ํด ๊ฝค ๋ง์ ๊ฑธ ๋ฐฐ์ ์ ๊ฑฐ์ผ.
ํต์ฌ๋ง ๋ค์ ์ ๋ฆฌํด๋ณผ๊ฒ:
1. ๋ก๋ ๋ฐธ๋ฐ์ฑ์ ๋ชฉ์
โข ์๋ฒ ๋ถํ ๋ถ์ฐ์ผ๋ก ์ฑ๋ฅ ํฅ์
โข ๊ณ ๊ฐ์ฉ์ฑ ํ๋ณด
โข ํ์ฅ์ฑ ์ ๊ณต
2. ์ฃผ์ ์๊ณ ๋ฆฌ์ฆ
โข ๋ผ์ด๋ ๋ก๋น: ๋จ์ํ๊ณ ํจ๊ณผ์
โข ์ต์ ์ฐ๊ฒฐ: ๋์ ๋ถํ ๋ถ์ฐ
โข IP ํด์: ์ธ์ ์ ์ง
3. ์ธ์ ๊ด๋ฆฌ
โข ์ธ์ ๊ณ ์ : ๊ฐ๋จํ์ง๋ง ์ ํ์
โข ์ธ์ ๊ณต์ : ์์ ์ ์ด์ง๋ง ๋ณต์ก
โข JWT ํ ํฐ: ํ๋์ ์ด๊ณ ํ์ฅ์ฑ ์ข์
4. ๋ชจ๋ํฐ๋ง
โข ํต์ฌ ์งํ ์ถ์
โข ์ค์๊ฐ ์๋ฆผ ์ค์
โข ์ ๊ธฐ์ ์ธ ๋ถํ ํ ์คํธ
5. ๋ณด์
โข SSL/TLS ์ข ๋ฃ
โข DDoS ๋ฐฉ์ด
โข WAF ์ ์ฉ
๋ก๋ ๋ฐธ๋ฐ์ฑ์ ๋จ์ํ ํธ๋ํฝ์ ๋ถ์ฐํ๋ ๊ฒ ์ด์์ด์ผ. ์ฌ์ฉ์ ๊ฒฝํ์ ๊ฐ์ ํ๊ณ , ์์คํ ์์ ์ฑ์ ๋์ด๊ณ , ๋น์ฆ๋์ค ์ฑ์ฅ์ ์ง์ํ๋ ํต์ฌ ์ธํ๋ผ์ง. ๐
์ฒ์์๋ ๋ณต์กํด ๋ณด์ด์ง๋ง ํ๋์ฉ ์ฐจ๊ทผ์ฐจ๊ทผ ์ ์ฉํ๋ค ๋ณด๋ฉด ์ด๋์ ์ ๋ฌธ๊ฐ๊ฐ ๋์ด ์์ ๊ฑฐ์ผ. ์์ ๊ท๋ชจ๋ก ์์ํด์ ์ ์ง์ ์ผ๋ก ํ์ฅํ๋ ๊ฒ ์ข์. ๊ทธ๋ฆฌ๊ณ ํญ์ ๋ชจ๋ํฐ๋งํ๊ณ ์ต์ ํํ๋ ๊ฑธ ์์ง ๋ง!
โข ๊ณผ๋ํ ์ต์ ํ ์ฃผ์: ํ์ํ ๋งํผ๋ง ๋ณต์กํ๊ฒ
โข ๋ฌธ์ํ ํ์: ์ค์ ๊ณผ ์์ฌ๊ฒฐ์ ๊ณผ์ ๊ธฐ๋ก
โข ํ๊ณผ ๊ณต์ : ์ง์์ ํผ์๋ง ๊ฐ์ง์ง ๋ง๊ธฐ
โข ์ง์์ ํ์ต: ๊ธฐ์ ์ ๊ณ์ ๋ฐ์ ํด
โข ์คํ ์ ์ : ์๋ก์ด ๊ธฐ๋ฒ์ ๋๋ ค์ํ์ง ๋ง๊ธฐ
์ด์ ๋น์ ๋ ๋ก๋ ๋ฐธ๋ฐ์ฑ ์ ๋ฌธ๊ฐ์ ๊ธธ์ ํ ๊ฑธ์ ๋ค๊ฐ์ฐ์ด! ์ค์ ํ๋ก์ ํธ์ ์ ์ฉํ๋ฉด์ ๋ ๋ง์ ๊ฑธ ๋ฐฐ์ฐ๊ฒ ๋ ๊ฑฐ์ผ. ํ์ดํ ! ๐ช
๊ถ๊ธํ ์ ์ด ์๊ฑฐ๋ ๋์์ด ํ์ํ๋ฉด ์ธ์ ๋ ์ง ์ปค๋ฎค๋ํฐ์ ๋ฌผ์ด๋ณด๊ฑฐ๋ ์ ๋ฌธ๊ฐ์ ๋์์ ๋ฐ์. ํผ์ ๊ณ ๋ฏผํ์ง ๋ง๊ณ ํจ๊ป ์ฑ์ฅํ์! ๐ฑ
๊ด๋ จ ํค์๋
๋๊ธ ์์ฑ
์ด ๊ธ์ ๋ํ ์ฌ๋ฌ๋ถ์ ์๊ฐ์ ๋ค๋ ค์ฃผ์ธ์
๋ก๊ทธ์ธ์ด ํ์ํฉ๋๋ค
๋๊ธ์ ์์ฑํ๋ ค๋ฉด ๋จผ์ ๋ก๊ทธ์ธํด์ฃผ์ธ์.
๋๊ธ 0
์ง์์ธ์ ์ฒ - ์ง์ ์ฌ์ฐ๊ถ ๋ณดํธ ๊ณ ์ง
์ง์ ์ฌ์ฐ๊ถ ๋ณดํธ ๊ณ ์ง
- ์ ์๊ถ ๋ฐ ์์ ๊ถ: ๋ณธ ์ปจํ ์ธ ๋ ์ฌ๋ฅ๋ท์ ๋ ์ AI ๊ธฐ์ ๋ก ์์ฑ๋์์ผ๋ฉฐ, ๋ํ๋ฏผ๊ตญ ์ ์๊ถ๋ฒ ๋ฐ ๊ตญ์ ์ ์๊ถ ํ์ฝ์ ์ํด ๋ณดํธ๋ฉ๋๋ค.
- AI ์์ฑ ์ปจํ ์ธ ์ ๋ฒ์ ์ง์: ๋ณธ AI ์์ฑ ์ปจํ ์ธ ๋ ์ฌ๋ฅ๋ท์ ์ง์ ์ฐฝ์๋ฌผ๋ก ์ธ์ ๋๋ฉฐ, ๊ด๋ จ ๋ฒ๊ท์ ๋ฐ๋ผ ์ ์๊ถ ๋ณดํธ๋ฅผ ๋ฐ์ต๋๋ค.
- ์ฌ์ฉ ์ ํ: ์ฌ๋ฅ๋ท์ ๋ช ์์ ์๋ฉด ๋์ ์์ด ๋ณธ ์ปจํ ์ธ ๋ฅผ ๋ณต์ , ์์ , ๋ฐฐํฌ, ๋๋ ์์ ์ ์ผ๋ก ํ์ฉํ๋ ํ์๋ ์๊ฒฉํ ๊ธ์ง๋ฉ๋๋ค.
- ๋ฐ์ดํฐ ์์ง ๊ธ์ง: ๋ณธ ์ปจํ ์ธ ์ ๋ํ ๋ฌด๋จ ์คํฌ๋ํ, ํฌ๋กค๋ง, ๋ฐ ์๋ํ๋ ๋ฐ์ดํฐ ์์ง์ ๋ฒ์ ์ ์ฌ์ ๋์์ด ๋ฉ๋๋ค.
- AI ํ์ต ์ ํ: ์ฌ๋ฅ๋ท์ AI ์์ฑ ์ปจํ ์ธ ๋ฅผ ํ AI ๋ชจ๋ธ ํ์ต์ ๋ฌด๋จ ์ฌ์ฉํ๋ ํ์๋ ๊ธ์ง๋๋ฉฐ, ์ด๋ ์ง์ ์ฌ์ฐ๊ถ ์นจํด๋ก ๊ฐ์ฃผ๋ฉ๋๋ค.
์์ง ๋๊ธ์ด ์์ต๋๋ค.