Search

์„ฑ๋Šฅ ์ตœ์ ํ™”

Nginx ์„ฑ๋Šฅ ์ตœ์ ํ™”

๊ฐœ์š”

Nginx ์„ฑ๋Šฅ ์ตœ์ ํ™”๋Š” ์›Œ์ปค ํ”„๋กœ์„ธ์Šค ํŠœ๋‹, gzip ์••์ถ•, ์บ์‹ฑ, ์—ฐ๊ฒฐ ๊ด€๋ฆฌ ๋“ฑ์„ ํ†ตํ•ด ๋” ์ ์€ ๋ฆฌ์†Œ์Šค๋กœ ๋” ๋งŽ์€ ์š”์ฒญ์„ ๋น ๋ฅด๊ฒŒ ์ฒ˜๋ฆฌํ•˜๋„๋ก ์„ค์ •ํ•˜๋Š” ๊ฒƒ์ด๋‹ค.
Nginx๋Š” ๊ธฐ๋ณธ ์„ค์ •๋งŒ์œผ๋กœ๋„ ๊ฝค ๋น ๋ฅด์ง€๋งŒ, ๋ช‡ ๊ฐ€์ง€ ์ตœ์ ํ™”๋ฅผ ์ ์šฉํ•˜๋ฉด 2~10๋ฐฐ ์ด์ƒ ์„ฑ๋Šฅ์„ ๋Œ์–ด์˜ฌ๋ฆด ์ˆ˜ ์žˆ์–ด์š”!
์„ฑ๋Šฅ ์ตœ์ ํ™”๋Š” ํฌ๊ฒŒ ์„ธ ๊ฐ€์ง€ ๊ด€์ ์—์„œ ์ ‘๊ทผํ•ด์š”:
1.
๋” ๋งŽ์€ ๋™์‹œ ์ ‘์† ์ฒ˜๋ฆฌ (์›Œ์ปค, ์—ฐ๊ฒฐ ๊ด€๋ฆฌ)
2.
๋” ๋น ๋ฅธ ์‘๋‹ต ์ „๋‹ฌ (์••์ถ•, ์บ์‹ฑ)
3.
๋” ์ ์€ ๋ฆฌ์†Œ์Šค ์‚ฌ์šฉ (๋ฒ„ํผ, ํƒ€์ž„์•„์›ƒ)

์ตœ์ ํ™” ์˜์—ญ ์ „์ฒด ๋งต

mindmap
  root((Nginx<br/>์„ฑ๋Šฅ ์ตœ์ ํ™”))
    ์›Œ์ปค ํŠœ๋‹
      worker_processes
      worker_connections
      multi_accept
    ์••์ถ•
      gzip
      gzip_types
      gzip_min_length
    ์บ์‹ฑ
      ๋ธŒ๋ผ์šฐ์ € ์บ์‹ฑ
      ํ”„๋ก์‹œ ์บ์‹ฑ
      expires
    ์—ฐ๊ฒฐ ๊ด€๋ฆฌ
      keepalive
      timeout
      TCP ์ตœ์ ํ™”
    ๋ฒ„ํผ
      proxy_buffer
      client_body_buffer
    ์ •์  ํŒŒ์ผ
      sendfile
      tcp_nopush
      open_file_cache
Mermaid
๋ณต์‚ฌ

1. ์›Œ์ปค ํ”„๋กœ์„ธ์Šค ์ตœ์ ํ™”

graph TD
    A["Master Process<br/>(์„ค์ • ๊ด€๋ฆฌ)"] --> B["Worker 1"]
    A --> C["Worker 2"]
    A --> D["Worker 3"]
    A --> E["Worker 4"]

    B --> B1["์ตœ๋Œ€ 1024 ์—ฐ๊ฒฐ"]
    C --> C1["์ตœ๋Œ€ 1024 ์—ฐ๊ฒฐ"]
    D --> D1["์ตœ๋Œ€ 1024 ์—ฐ๊ฒฐ"]
    E --> E1["์ตœ๋Œ€ 1024 ์—ฐ๊ฒฐ"]

    F["์ด ๋™์‹œ ์—ฐ๊ฒฐ = 4 ร— 1024 = 4,096"]

    style A fill:#FFD700
    style F fill:#90EE90
Mermaid
๋ณต์‚ฌ
# ์ „์—ญ ์„ค์ • worker_processes auto; # CPU ์ฝ”์–ด ์ˆ˜๋งŒํผ ์ž๋™ ์„ค์ • worker_rlimit_nofile 65535; # ์›Œ์ปค๋‹น ์—ด ์ˆ˜ ์žˆ๋Š” ํŒŒ์ผ ์ˆ˜ events { worker_connections 4096; # ์›Œ์ปค๋‹น ๋™์‹œ ์—ฐ๊ฒฐ ์ˆ˜ multi_accept on; # ํ•œ ๋ฒˆ์— ์—ฌ๋Ÿฌ ์—ฐ๊ฒฐ ์ˆ˜๋ฝ use epoll; # Linux ์ด๋ฒคํŠธ ์ฒ˜๋ฆฌ (๊ฐ€์žฅ ํšจ์œจ์ ) }
Plain Text
๋ณต์‚ฌ
์„ค์ •
๊ธฐ๋ณธ๊ฐ’
๊ถŒ์žฅ๊ฐ’
์„ค๋ช…
worker_processes
1
auto
CPU ์ฝ”์–ด ์ˆ˜์™€ ๋™์ผํ•˜๊ฒŒ
worker_connections
512
1024~4096
์„œ๋ฒ„ ๊ทœ๋ชจ์— ๋”ฐ๋ผ ์กฐ์ •
multi_accept
off
on
ํ•œ ๋ฒˆ์— ์—ฌ๋Ÿฌ ์—ฐ๊ฒฐ ๋™์‹œ ์ˆ˜๋ฝ
use
์ž๋™
epoll
Linux์—์„œ ๊ฐ€์žฅ ํšจ์œจ์ ์ธ ๋ฐฉ์‹
worker_rlimit_nofile
์‹œ์Šคํ…œ ๊ธฐ๋ณธ
65535
ํŒŒ์ผ ๋””์Šคํฌ๋ฆฝํ„ฐ ์ œํ•œ
์ตœ๋Œ€ ๋™์‹œ ์—ฐ๊ฒฐ ์ˆ˜ = worker_processes ร— worker_connections ์˜ˆ: 4์ฝ”์–ด ร— 4096 = 16,384๊ฐœ ๋™์‹œ ์—ฐ๊ฒฐ!

2. Gzip ์••์ถ•

gzip ์••์ถ•์„ ์‚ฌ์šฉํ•˜๋ฉด ์‘๋‹ต ํฌ๊ธฐ๋ฅผ 30~70% ์ค„์ผ ์ˆ˜ ์žˆ์–ด์š”!
graph LR
    A["์›๋ณธ ์‘๋‹ต<br/>100KB"] -->|gzip ์••์ถ•| B["์••์ถ•๋œ ์‘๋‹ต<br/>30KB"]
    B -->|๋„คํŠธ์›Œํฌ ์ „์†ก| C["๐Ÿ‘ค ๋ธŒ๋ผ์šฐ์ €"]
    C -->|์ž๋™ ํ•ด์ œ| D["์›๋ณธ 100KB<br/>ํ‘œ์‹œ"]

    style A fill:#FFB3B3
    style B fill:#90EE90
Mermaid
๋ณต์‚ฌ
http { # gzip ์••์ถ• ํ™œ์„ฑํ™” gzip on; gzip_vary on; # Vary: Accept-Encoding ํ—ค๋” ์ถ”๊ฐ€ gzip_proxied any; # ํ”„๋ก์‹œ ์‘๋‹ต๋„ ์••์ถ• gzip_comp_level 6; # ์••์ถ• ๋ ˆ๋ฒจ (1~9, 6 ๊ถŒ์žฅ) gzip_min_length 256; # ์ตœ์†Œ ํฌ๊ธฐ ์ด์ƒ๋งŒ ์••์ถ• gzip_types text/plain text/css text/xml application/json application/javascript application/xml application/xml+rss image/svg+xml font/woff2; }
Plain Text
๋ณต์‚ฌ
์„ค์ •
๊ถŒ์žฅ๊ฐ’
์„ค๋ช…
gzip_comp_level
6
1(๋น ๋ฆ„, ๋‚ฎ์€ ์••์ถ•) ~ 9(๋А๋ฆผ, ๋†’์€ ์••์ถ•), 6์ด ์ตœ์ 
gzip_min_length
256
๋„ˆ๋ฌด ์ž‘์€ ํŒŒ์ผ์€ ์••์ถ• ํšจ๊ณผ ์—†์Œ
gzip_types
ํ…์ŠคํŠธ ๊ธฐ๋ฐ˜
์ด๋ฏธ ์••์ถ•๋œ ํŒŒ์ผ(jpg, png, mp4)์€ ์ œ์™ธ
์ด๋ฏธ์ง€(jpg, png)๋‚˜ ๋™์˜์ƒ(mp4)์€ ์ด๋ฏธ ์••์ถ•๋œ ํ˜•์‹์ด๋ผ gzip ํšจ๊ณผ๊ฐ€ ๊ฑฐ์˜ ์—†์–ด์š”. ์˜คํžˆ๋ ค CPU๋งŒ ๋‚ญ๋น„ํ•ด์š”!

3. ์บ์‹ฑ ์ „๋žต

๋ธŒ๋ผ์šฐ์ € ์บ์‹ฑ

# ์ •์  ์—์…‹ โ€” ์žฅ๊ธฐ ์บ์‹ฑ (React ๋นŒ๋“œ ํŒŒ์ผ์ฒ˜๋Ÿผ ํ•ด์‹œ๊ฐ€ ์žˆ๋Š” ๊ฒฝ์šฐ) location /static/ { expires 1y; add_header Cache-Control "public, immutable"; } # ์ผ๋ฐ˜ ์ด๋ฏธ์ง€ โ€” ์ค‘๊ธฐ ์บ์‹ฑ location ~* \\.(jpg|jpeg|png|gif|ico|webp)$ { expires 30d; add_header Cache-Control "public"; } # HTML โ€” ์บ์‹ฑ ์•ˆ ํ•จ (ํ•ญ์ƒ ์ตœ์‹  ๋ฒ„์ „ ์ œ๊ณต) location ~* \\.html$ { expires -1; add_header Cache-Control "no-cache"; }
Plain Text
๋ณต์‚ฌ
ํŒŒ์ผ ์œ ํ˜•
์บ์‹ฑ ๊ธฐ๊ฐ„
์ด์œ 
JS/CSS (ํ•ด์‹œ ํฌํ•จ)
1๋…„
ํŒŒ์ผ๋ช…์— ํ•ด์‹œ โ†’ ๋‚ด์šฉ ๋ณ€๊ฒฝ ์‹œ ์ด๋ฆ„๋„ ๋ณ€๊ฒฝ
์ด๋ฏธ์ง€
30์ผ
์ž์ฃผ ์•ˆ ๋ฐ”๋€œ
HTML
์บ์‹ฑ ์•ˆ ํ•จ
ํ•ญ์ƒ ์ตœ์‹  JS/CSS๋ฅผ ์ฐธ์กฐํ•ด์•ผ ํ•จ
API ์‘๋‹ต
์บ์‹ฑ ์•ˆ ํ•จ
์‹ค์‹œ๊ฐ„ ๋ฐ์ดํ„ฐ

ํ”„๋ก์‹œ ์บ์‹ฑ (Nginx๊ฐ€ ๋ฐฑ์—”๋“œ ์‘๋‹ต์„ ์บ์‹ฑ)

http { # ์บ์‹œ ์˜์—ญ ์ •์˜ proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=my_cache:10m max_size=1g inactive=60m; server { location /api/ { proxy_pass <http://localhost:8080>; # ํ”„๋ก์‹œ ์บ์‹ฑ ์ ์šฉ proxy_cache my_cache; proxy_cache_valid 200 10m; # 200 ์‘๋‹ต์€ 10๋ถ„ ์บ์‹ฑ proxy_cache_valid 404 1m; # 404 ์‘๋‹ต์€ 1๋ถ„ ์บ์‹ฑ add_header X-Cache-Status $upstream_cache_status; } } }
Plain Text
๋ณต์‚ฌ
sequenceDiagram
    participant ์‚ฌ์šฉ์žA as ๐Ÿ‘ค ์‚ฌ์šฉ์ž A
    participant Nginx as ๐Ÿ–ฅ๏ธ Nginx (์บ์‹œ)
    participant Spring as ๐Ÿƒ Spring Boot

    ์‚ฌ์šฉ์žA->>Nginx: GET /api/products
    Nginx->>Spring: ์บ์‹œ ์—†์Œ โ†’ ๋ฐฑ์—”๋“œ ์š”์ฒญ
    Spring-->>Nginx: ์ƒํ’ˆ ๋ชฉ๋ก (200 OK)
    Nginx->>Nginx: ์บ์‹œ์— ์ €์žฅ
    Nginx-->>์‚ฌ์šฉ์žA: ์‘๋‹ต (X-Cache-Status: MISS)

    Note over Nginx: 10๋ถ„ ์ด๋‚ด ๊ฐ™์€ ์š”์ฒญ โ†’

    participant ์‚ฌ์šฉ์žB as ๐Ÿ‘ค ์‚ฌ์šฉ์ž B
    ์‚ฌ์šฉ์žB->>Nginx: GET /api/products
    Nginx-->>์‚ฌ์šฉ์žB: ์บ์‹œ์—์„œ ์ฆ‰์‹œ ์‘๋‹ต!<br/>(X-Cache-Status: HIT)

    Note over Nginx,Spring: Spring Boot์— ์š”์ฒญ ์•ˆ ๊ฐ!<br/>โ†’ ๋ฐฑ์—”๋“œ ๋ถ€ํ•˜ ๊ฐ์†Œ
Mermaid
๋ณต์‚ฌ

4. ์—ฐ๊ฒฐ ๊ด€๋ฆฌ

http { # Keep-Alive ์„ค์ • keepalive_timeout 65; # ์—ฐ๊ฒฐ ์œ ์ง€ ์‹œ๊ฐ„ keepalive_requests 100; # ํ•˜๋‚˜์˜ ์—ฐ๊ฒฐ๋กœ ์ฒ˜๋ฆฌํ•  ์ตœ๋Œ€ ์š”์ฒญ ์ˆ˜ # TCP ์ตœ์ ํ™” sendfile on; # ์ปค๋„ ๋ ˆ๋ฒจ์—์„œ ํŒŒ์ผ ์ „์†ก (๋” ๋น ๋ฆ„) tcp_nopush on; # ํŒจํ‚ท์„ ๋ชจ์•„์„œ ํ•œ ๋ฒˆ์— ์ „์†ก tcp_nodelay on; # ์ž‘์€ ํŒจํ‚ท๋„ ์ฆ‰์‹œ ์ „์†ก # ํƒ€์ž„์•„์›ƒ client_body_timeout 12; # ์š”์ฒญ ๋ฐ”๋”” ์ฝ๊ธฐ ํƒ€์ž„์•„์›ƒ client_header_timeout 12; # ์š”์ฒญ ํ—ค๋” ์ฝ๊ธฐ ํƒ€์ž„์•„์›ƒ send_timeout 10; # ์‘๋‹ต ์ „์†ก ํƒ€์ž„์•„์›ƒ }
Plain Text
๋ณต์‚ฌ
์„ค์ •
์„ค๋ช…
ํšจ๊ณผ
sendfile on
OS ์ปค๋„์—์„œ ์ง์ ‘ ํŒŒ์ผ ์ „์†ก
์ •์  ํŒŒ์ผ ์ „์†ก ์†๋„ ํ–ฅ์ƒ
tcp_nopush on
ํŒจํ‚ท์„ ๋ฌถ์–ด์„œ ์ „์†ก
๋„คํŠธ์›Œํฌ ํšจ์œจ์„ฑ ์ฆ๊ฐ€
tcp_nodelay on
์ง€์—ฐ ์—†์ด ์ฆ‰์‹œ ์ „์†ก
์‘๋‹ต ์ง€์—ฐ ๊ฐ์†Œ
keepalive_timeout
์—ฐ๊ฒฐ ์žฌ์‚ฌ์šฉ ์‹œ๊ฐ„
TCP ํ•ธ๋“œ์…ฐ์ดํฌ ์˜ค๋ฒ„ํ—ค๋“œ ๊ฐ์†Œ

5. ํŒŒ์ผ ์บ์‹œ (open_file_cache)

http { # ์ž์ฃผ ์ ‘๊ทผํ•˜๋Š” ํŒŒ์ผ ์ •๋ณด๋ฅผ ๋ฉ”๋ชจ๋ฆฌ์— ์บ์‹ฑ open_file_cache max=10000 inactive=20s; open_file_cache_valid 30s; open_file_cache_min_uses 2; open_file_cache_errors on; }
Plain Text
๋ณต์‚ฌ
์ด ์„ค์ •์€ ํŒŒ์ผ์˜ ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ(ํฌ๊ธฐ, ์ˆ˜์ •์‹œ๊ฐ„ ๋“ฑ)๋ฅผ ๋ฉ”๋ชจ๋ฆฌ์— ์บ์‹ฑํ•ด์š”. ๋งค ์š”์ฒญ๋งˆ๋‹ค ๋””์Šคํฌ์—์„œ ํŒŒ์ผ ์ •๋ณด๋ฅผ ์กฐํšŒํ•˜๋Š” ๋น„์šฉ์„ ์ค„์—ฌ์ฃผ๋Š” ๊ฑฐ์˜ˆ์š”!

์ตœ์ ํ™” ์ „ํ›„ ๋น„๊ต

ํ•ญ๋ชฉ
๊ธฐ๋ณธ ์„ค์ •
์ตœ์ ํ™” ํ›„
๊ฐœ์„ ๋ฅ 
๋™์‹œ ์—ฐ๊ฒฐ
~512
~16,384
32๋ฐฐ
HTML ์‘๋‹ต ํฌ๊ธฐ
100KB
30KB (gzip)
70% ๊ฐ์†Œ
์ •์  ํŒŒ์ผ ์ „์†ก
์ผ๋ฐ˜ read
sendfile
~2๋ฐฐ
๋ฐ˜๋ณต ์š”์ฒญ ์‘๋‹ต
๋งค๋ฒˆ ์ฒ˜๋ฆฌ
์บ์‹œ HIT
์ฆ‰์‹œ ์‘๋‹ต
์—ฐ๊ฒฐ ์ˆ˜๋ฆฝ
๋งค๋ฒˆ TCP ํ•ธ๋“œ์…ฐ์ดํฌ
Keep-Alive ์žฌ์‚ฌ์šฉ
์ง€์—ฐ ๊ฐ์†Œ

์„ฑ๋Šฅ ์ตœ์ ํ™” ์ฒดํฌ๋ฆฌ์ŠคํŠธ

flowchart TD
    A["์„ฑ๋Šฅ ์ตœ์ ํ™” ์ฒดํฌ๋ฆฌ์ŠคํŠธ"] --> B["1๏ธโƒฃ worker_processes auto โœ“"]
    A --> C["2๏ธโƒฃ gzip on โœ“"]
    A --> D["3๏ธโƒฃ ์ •์  ํŒŒ์ผ expires ์„ค์ • โœ“"]
    A --> E["4๏ธโƒฃ sendfile + tcp_nopush โœ“"]
    A --> F["5๏ธโƒฃ keepalive ์„ค์ • โœ“"]
    A --> G["6๏ธโƒฃ proxy_cache ์„ค์ • โœ“"]
    A --> H["7๏ธโƒฃ open_file_cache ์„ค์ • โœ“"]

    style B fill:#90EE90
    style C fill:#90EE90
    style D fill:#90EE90
    style E fill:#90EE90
    style F fill:#90EE90
    style G fill:#87CEEB
    style H fill:#87CEEB
Mermaid
๋ณต์‚ฌ

ํ•ต์‹ฌ ์ •๋ฆฌ

์›Œ์ปค ํŠœ๋‹: worker_processes auto + worker_connections 4096
gzip ์••์ถ•: ํ…์ŠคํŠธ ๊ธฐ๋ฐ˜ ํŒŒ์ผ 30~70% ํฌ๊ธฐ ๊ฐ์†Œ (gzip_comp_level 6)
๋ธŒ๋ผ์šฐ์ € ์บ์‹ฑ: expires + Cache-Control๋กœ ๋ฐ˜๋ณต ์š”์ฒญ ์ œ๊ฑฐ
ํ”„๋ก์‹œ ์บ์‹ฑ: ๋ฐฑ์—”๋“œ ์‘๋‹ต์„ Nginx๊ฐ€ ์บ์‹ฑํ•˜์—ฌ ๋ถ€ํ•˜ ๊ฐ์†Œ
TCP ์ตœ์ ํ™”: sendfile, tcp_nopush, keepalive๋กœ ์ „์†ก ํšจ์œจ ๊ทน๋Œ€ํ™”