๐Ÿ›‘ ๋ฌธ์ œ ์ƒํ™ฉ: ๋ฐฐํฌ ํ™˜๊ฒฝ์—์„œ ์•Œ๋ฆผ์ด ์‹ค์‹œ๊ฐ„์œผ๋กœ ์˜ค์ง€ ์•Š๋Š”๋‹ค?!

๋ฐฐํฌ ํ›„ ์•Œ๋ฆผ ์„œ๋น„์Šค๊ฐ€ ์ œ๋Œ€๋กœ ๋™์ž‘ํ•˜์ง€ ์•Š๋Š”๋‹ค๋Š” ์ œ๋ณด๋ฅผ ๋ฐ›์•˜๋‹ค. ๋กœ์ปฌ ํ™˜๊ฒฝ์—์„œ๋Š” ๋ฉ€์ฉกํ–ˆ๋Š”๋ฐ, ๋ฐฐํฌ ํ™˜๊ฒฝ์—์„œ๋Š” ์•Œ๋ฆผ์ด ์˜ค์ง€ ์•Š์•˜๋‹ค. ๋กœ์ปฌ์—์„œ๋Š” Spring Boot WAS๊ฐ€ SSE ์š”์ฒญ์„ ๋ฐ”๋กœ ์ฒ˜๋ฆฌํ–ˆ์ง€๋งŒ, ๋ฐฐํฌ ํ™˜๊ฒฝ์—์„œ๋Š” Nginx๊ฐ€ ์ค‘๊ฐ„์— ๋ผ์–ด ์žˆ์—ˆ๋‹ค.

'์ด๊ฑฐ Nginx๊ฐ€ ๋ฌธ์ œ์ผ ์ˆ˜๋„ ์žˆ๊ฒ ๋‹ค...' ์‹ถ์–ด์„œ ์„ค์ • ํŒŒ์ผ์„ ์ƒ…์ƒ…์ด ๋“ค์—ฌ๋‹ค๋ณด๊ธฐ๋กœ ํ–ˆ๋‹ค.

AS-IS ์„ค์ •

# Default server configuration
server {
    listen 80 default_server;
    listen [::]:80 default_server;

    server_name _;

    # HTTP ์š”์ฒญ์„ HTTPS๋กœ ๋ฆฌ๋””๋ ‰์…˜
    location / {
        return 301 https://$host$request_uri;
    }
}

server {
    listen 443 ssl;
    listen [::]:443 ssl ipv6only=on;
    server_name sharespace.store;

    root /var/www/html;

    ssl_certificate /etc/letsencrypt/live/sharespace.store/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/sharespace.store/privkey.pem;
    include /etc/letsencrypt/options-ssl-nginx.conf;
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;

    location / {
        proxy_pass <http://127.0.0.1:8080>;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

# HTTP ์š”์ฒญ์„ HTTPS๋กœ ๋ฆฌ๋””๋ ‰์…˜ (ํŠน์ • ๋„๋ฉ”์ธ)
server {
    if ($host = sharespace.store) {
        return 301 https://$host$request_uri;
    }

    listen 80;
    listen [::]:80;

    server_name sharespace.store;
    return 404;
}

๋ญ”๊ฐ€ ํ‰๋ฒ”ํ•ด ๋ณด์ด๋Š” ์„ค์ •์ธ๋ฐ, ์—ฌ๊ธฐ์„œ SSE์˜ ํŠน์„ฑ์„ ๊ณ ๋ คํ•˜์ง€ ์•Š์€ ์ ์ด ๋ฌธ์ œ์˜€๋‹ค. SSE๋Š” ์ŠคํŠธ๋ฆฌ๋ฐ ๋ฐฉ์‹์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ์‹ค์‹œ๊ฐ„์œผ๋กœ ์ „์†กํ•ด์•ผ ํ•œ๋‹ค. ํ•˜์ง€๋งŒ Nginx๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฒ„ํผ๋งํ•œ๋‹ค. ์ด๋Ÿฌ๋ฉด ์‹ค์‹œ๊ฐ„ ์ „์†ก์ด ๋ง‰ํ˜€๋ฒ„๋ฆฐ๋‹ค.

์ˆ˜์ • ์‹œ์ž‘

1๏ธโƒฃ proxy_buffering ๋„๊ธฐ

SSE๋Š” ๋ฒ„ํผ๋ง์ด ํ•„์š” ์—†๋‹ค. ์˜คํžˆ๋ ค ๋ฐ์ดํ„ฐ๊ฐ€ ๋ฒ„ํผ์— ์Œ“์—ฌ ์‹ค์‹œ๊ฐ„ ์•Œ๋ฆผ์ด ์ง€์—ฐ๋  ๋ฟ์ด๋‹ค. Nginx ์„ค์ •์—์„œ /notification/sse ๊ฒฝ๋กœ์— ๋Œ€ํ•ด proxy_buffering off๋ฅผ ์ถ”๊ฐ€ํ–ˆ๋‹ค.

<aside>

โ“ proxy_buffering์ด๋ž€?

proxy_buffering์€ NGINX๊ฐ€ ๋ฐฑ์—”๋“œ ์„œ๋ฒ„๋กœ๋ถ€ํ„ฐ ๋ฐ›์€ ์‘๋‹ต ๋ฐ์ดํ„ฐ๋ฅผ ๋ฒ„ํผ์— ์ €์žฅํ•œ ํ›„, ํด๋ผ์ด์–ธํŠธ์—๊ฒŒ ์ „๋‹ฌํ•˜๋Š” ๊ธฐ๋Šฅ์ด๋‹ค. ์ด ๊ณผ์ •์—์„œ ๋ชจ๋“  ์‘๋‹ต์„ ํ•œ ๋ฒˆ์— ๋ฐ›์€ ํ›„ ํด๋ผ์ด์–ธํŠธ๋กœ ์ „์†กํ•˜๋ฏ€๋กœ, ์‹ค์‹œ๊ฐ„ ๋ฐ์ดํ„ฐ ์ „์†ก์ด ํ•„์š”ํ•œ ๊ฒฝ์šฐ์—๋Š” ์ ํ•ฉํ•˜์ง€ ์•Š๋‹ค.

๐Ÿ”ฅ SSE์™€ proxy_buffering์˜ ์ถฉ๋Œ

SSE๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ์‹ค์‹œ๊ฐ„ ์ŠคํŠธ๋ฆฌ๋ฐ ๋ฐฉ์‹์œผ๋กœ ํด๋ผ์ด์–ธํŠธ์— ์ „์†กํ•œ๋‹ค. ํ•˜์ง€๋งŒ NGINX์˜ ๋ฒ„ํผ๋ง์ด ํ™œ์„ฑํ™”๋˜์–ด ์žˆ์œผ๋ฉด ๋ฐ์ดํ„ฐ๋ฅผ ํด๋ผ์ด์–ธํŠธ๋กœ ์ฆ‰์‹œ ๋ณด๋‚ด์ง€ ์•Š๊ณ  ๋ฒ„ํผ์— ์Œ“์•˜๋‹ค๊ฐ€ ์ „์†กํ•˜๋ฏ€๋กœ, ์‹ค์‹œ๊ฐ„์„ฑ์ด ์‚ฌ๋ผ์ง„๋‹ค.

</aside>

2๏ธโƒฃ chunked_transfer_encoding ๋„๊ธฐ

Nginx๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ HTTP/1.1์˜ ์ฒญํฌ ์ „์†ก์„ ํ™œ์„ฑํ™”ํ•œ๋‹ค. ํ•˜์ง€๋งŒ SSE๋Š” ์ž์ฒด์ ์œผ๋กœ ์ŠคํŠธ๋ฆฌ๋ฐ์„ ์ฒ˜๋ฆฌํ•˜๋ฏ€๋กœ ์ฒญํฌ ์ „์†ก์„ ๋„๋Š” ๊ฒƒ์ด ๋” ์•ˆ์ •์ ์ด๋‹ค.

<aside>

โ“ chunked_transfer_encoding์ด๋ž€?

HTTP/1.1์˜ ์ฒญํฌ ์ „์†ก ๋ฐฉ์‹์œผ๋กœ, ์‘๋‹ต ๋ฐ์ดํ„ฐ๋ฅผ ์ž‘์€ ์ฒญํฌ(chunk) ๋‹จ์œ„๋กœ ๋‚˜๋ˆ„์–ด ํด๋ผ์ด์–ธํŠธ๋กœ ์ „์†กํ•˜๋Š” ๋ฐฉ์‹์ด๋‹ค. ๋ฐ์ดํ„ฐ๋ฅผ ์ „์†กํ•  ๋•Œ ๊ฐ ์ฒญํฌ์˜ ํฌ๊ธฐ๋ฅผ ๋ช…์‹œํ•˜๋ฉฐ, ๋ฐ์ดํ„ฐ๊ฐ€ ๋๋‚  ๋•Œ๊นŒ์ง€ ์ฒญํฌ๋ฅผ ๊ณ„์† ๋ณด๋‚ด๋Š” ๊ตฌ์กฐ์ด๋‹ค.

๐Ÿ”ฅ SSE์™€ chunked_transfer_encoding์˜ ๋ฌธ์ œ

SSE๋Š” ์ž์ฒด์ ์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ์ŠคํŠธ๋ฆฌ๋ฐํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ฒญํฌ ์ „์†ก ๋ฐฉ์‹์„ ์‚ฌ์šฉํ•  ํ•„์š”๊ฐ€ ์—†๋‹ค. NGINX๊ฐ€ ์ด ๋ฐฉ์‹์„ ๊ฐ•์ œ๋กœ ์ ์šฉํ•˜๋ฉด ํด๋ผ์ด์–ธํŠธ๊ฐ€ ๋ฐ์ดํ„ฐ๋ฅผ ์ œ๋Œ€๋กœ ์ฒ˜๋ฆฌํ•˜์ง€ ๋ชปํ•˜๊ฑฐ๋‚˜ ์—ฐ๊ฒฐ์ด ๋Š๊ธฐ๋Š” ๋“ฑ์˜ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋‹ค.

</aside>

3๏ธโƒฃ Connection ํ—ค๋” ์„ค์ •

SSE๋Š” ํด๋ผ์ด์–ธํŠธ์™€ ์„œ๋ฒ„ ๊ฐ„ ์žฅ์‹œ๊ฐ„ ์—ฐ๊ฒฐ์„ ์œ ์ง€ํ•ด์•ผ ํ•œ๋‹ค. ์ด๋ฅผ ์œ„ํ•ด Connection ํ—ค๋”๋ฅผ ๋น„์›Œ์„œ(๋นˆ ๋ฌธ์ž์—ด) ๋ช…์‹œ์ ์œผ๋กœ ์„ค์ •ํ–ˆ๋‹ค.

4๏ธโƒฃ ํƒ€์ž„์•„์›ƒ ์„ค์ •

๊ธฐ๋ณธ ํƒ€์ž„์•„์›ƒ์€ ๋„ˆ๋ฌด ์งง์•„์„œ SSE ์—ฐ๊ฒฐ์ด ์ž๊พธ ๋Š๊ธธ ๊ฐ€๋Šฅ์„ฑ์ด ์žˆ์—ˆ๋‹ค. ์ด๋ฅผ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•ด proxy_read_timeout๊ณผ keepalive_timeout์„ 300์ดˆ๋กœ ๋Š˜๋ ธ๋‹ค.

5๏ธโƒฃ ์บ์‹ฑ ๋ฐฉ์ง€

์‹ค์‹œ๊ฐ„ ์•Œ๋ฆผ ๋ฐ์ดํ„ฐ๋Š” ์บ์‹ฑ๋˜๋ฉด ์•ˆ ๋œ๋‹ค. ๊ทธ๋ž˜์„œ Cache-Control ํ—ค๋”๋ฅผ ํ†ตํ•ด ์บ์‹ฑ์„ ๋ฐฉ์ง€ํ–ˆ๋‹ค.