Skip to content
isdnetworks
Go back

๋ฐฑ ์ดˆ์ฏค ์ง€๋‚˜๋ฉด ๋Š๊ธฐ๋˜ ์—ฐ๊ฒฐ

(์ˆ˜์ •๋จ)

์‹œ์„ธ ํ™”๋ฉด์ด ๊ฐ€๋” ๋ฉˆ์ถ˜๋‹ค๋Š” ์–˜๊ธฐ๊ฐ€ ๋“ค์–ด์™”๋‹ค. ์ƒˆ๋กœ๊ณ ์นจํ•˜๋ฉด ๋‹ค์‹œ ๋‚˜์˜ค๋Š”๋ฐ ์—ด์–ด ๋‘๊ณ  ๋ณด๊ณ  ์žˆ์œผ๋ฉด ์ž˜ ๋‚˜์™€์„œ ์žฌํ˜„์ด ์•ˆ ๋๋‹ค.

Table of contents

Open Table of contents

์ฆ์ƒ โ€” ์žฌํ˜„์ด ์•ˆ ๋๋‹ค

์•ž์— ๋‘๊ณ  ์ง€์ผœ๋ณด๋ฉด ๋ฉˆ์ถ”์ง€ ์•Š์•˜๋‹ค.

๋ฉˆ์ท„๋‹ค๋Š” ์‚ฌ๋žŒ์€ ์žˆ๋Š”๋ฐ ์žฌํ˜„์ด ์•ˆ ๋˜๋‹ˆ ๋กœ๊ทธ๋ฅผ ๋ณผ ์‹œ์ ๋„ ๋ชป ์žก๋Š”๋‹ค. ๋ฌด์—‡์„ ๋ด์•ผ ํ• ์ง€ ์ •ํ•˜๋ ค๋ฉด ์–ด๋–ค ์กฐ๊ฑด์—์„œ ๋‚˜๋Š”์ง€๋ถ€ํ„ฐ ์ขํ˜€์•ผ ํ–ˆ๋‹ค.

๋ฌธ์˜๋ฅผ ๋‹ค์‹œ ์ฝ์œผ๋‹ˆ ๊ณตํ†ต์ ์ด ์žˆ์—ˆ๋‹ค.

ํ™”๋ฉด์„ ์—ด์–ด ๋‘๊ณ  ๋‹ค๋ฅธ ์ผ์„ ํ•˜๋‹ค๊ฐ€ ๋Œ์•„์˜ค๋ฉด ๋ฉˆ์ถฐ ์žˆ๋‹ค
๊ฑฐ๋ž˜๊ฐ€ ํ™œ๋ฐœํ•œ ์ข…๋ชฉ์—์„œ๋Š” ์•ˆ ๊ทธ๋ ‡๋‹ค

๋‘˜ ๋‹ค ๊ทธ๋™์•ˆ ์•„๋ฌด๊ฒƒ๋„ ์•ˆ ํ˜๋ €๋‹ค๋Š” ๋œป์œผ๋กœ ์ฝํ˜”๋‹ค.

์กฐ์‚ฌ โ€” ์กฐ๊ฑด ์ขํžˆ๊ธฐ

๊ฑฐ๋ž˜๊ฐ€ ์—†๋Š” ์ข…๋ชฉ์„ ์—ด์–ด ๋‘๊ณ  ์‹œ๊ณ„๋ฅผ ๋ดค๋‹ค.

0:00   ์—ฐ๊ฒฐ ์„ฑ๊ณต, ์ดˆ๊ธฐ ๋ฐ์ดํ„ฐ ์ˆ˜์‹ 
0:12   ์ฒด๊ฒฐ ํ•˜๋‚˜ ์ˆ˜์‹ 
...
1:40   (์•„๋ฌด๊ฒƒ๋„ ์•ˆ ์˜ด)
1:47   ์—ฐ๊ฒฐ ์ข…๋ฃŒ

๋งˆ์ง€๋ง‰ ํ”„๋ ˆ์ž„์œผ๋กœ๋ถ€ํ„ฐ 100์ดˆ์ฏค ๋’ค์— WebSocket ์ด ๋Š๊ธด๋‹ค.

๊ฑฐ๋ž˜๊ฐ€ ํ™œ๋ฐœํ•˜๋ฉด ๊ณ„์† ๋ฐ์ดํ„ฐ๊ฐ€ ํ๋ฅด๋‹ˆ 100์ดˆ๋ฅผ ์ฑ„์šธ ์ผ์ด ์—†๋‹ค. ๊ทธ๋ž˜์„œ ์ง€์ผœ๋ณด๊ณ  ์žˆ์„ ๋•Œ๋Š” ์žฌํ˜„์ด ์•ˆ ๋๋‹ค.

๋Š๊ธฐ๋Š” ์‹œ์ ์ด ์ผ์ •ํ•˜๋‹ค๋Š” ๊ฒƒ์ด ๋‹ค์Œ ๋‹จ์„œ์˜€๋‹ค. ๊ฐ’์ด ๊ณ ์ •๋ผ ์žˆ๋‹ค๋ฉด ์–ด๋”˜๊ฐ€์— ๊ทธ ๊ฐ’์„ ๊ฐ€์ง„ ์„ค์ •์ด ์žˆ๋‹ค.

์›์ธ โ€” ๋กœ๊ทธ์— ์•„๋ฌด๊ฒƒ๋„ ์—†์—ˆ๋‹ค

์„œ๋ฒ„ ๋กœ๊ทธ๋ฅผ ๋ดค๋Š”๋ฐ ์˜ค๋ฅ˜๋„ ์—†๊ณ  ๋Š๊ฒผ๋‹ค๋Š” ๊ธฐ๋ก๋„ ์—†์—ˆ๋‹ค.

WebSocket connection closed: 1006

๋ธŒ๋ผ์šฐ์ € ์ฝ˜์†”์—๋Š” 1006 ์ด ์ฐํ˜€ ์žˆ์—ˆ๋‹ค.

1006 ์€ ๋‹ซํž˜ ํ”„๋ ˆ์ž„์„ ๋ชป ๋ฐ›์•˜๋‹ค๋Š” ๋œป์ด๋‹ค. RFC 6455 ๋Š” ์ด ๊ฐ’์„ ์–ด๋А ์ชฝ ๋์ ๋„ Close ํ”„๋ ˆ์ž„์— ์‹ค์–ด์„œ๋Š” ์•ˆ ๋˜๋Š” ์˜ˆ์•ฝ ์ฝ”๋“œ๋กœ ๋‘๊ณ , Close ํ”„๋ ˆ์ž„์„ ์ฃผ๊ณ ๋ฐ›์ง€ ์•Š์€ ์ฑ„ ๋น„์ •์ƒ์œผ๋กœ ๋‹ซํ˜”์Œ์„ ๋‚˜ํƒ€๋‚ด๋Š” ์šฉ๋„๋กœ ์ •ํ•œ๋‹ค. ์–‘์ชฝ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ์„œ๋กœ ๋Š์ง€ ์•Š์•˜๊ณ  ์ค‘๊ฐ„์—์„œ ๋ˆ„๊ฐ€ ๋Š์—ˆ๋‹ค๋Š” ์ด์•ผ๊ธฐ๊ฐ€ ๋œ๋‹ค.

๋กœ๊ทธ๊ฐ€ ๋น„์–ด ์žˆ๋‹ค๋Š” ์‚ฌ์‹ค ์ž์ฒด๊ฐ€ ๋‹จ์„œ์˜€๋‹ค. ์šฐ๋ฆฌ๊ฐ€ ๋Š์—ˆ์œผ๋ฉด ์šฐ๋ฆฌ ์ชฝ์— ๋‚จ์•˜์„ ๊ฒƒ์ด๋‹ค.

์ œ์•ฝ โ€” ๊ฒฝ๋กœ๋งˆ๋‹ค ์œ ํœด ์ œํ•œ

๊ฒฝ๋กœ์— ๋ฌด์—‡์ด ์žˆ๋Š”์ง€ ์…Œ๋‹ค.

๋ธŒ๋ผ์šฐ์ € โ†’ CDN โ†’ ๋กœ๋“œ๋ฐธ๋Ÿฐ์„œ โ†’ nginx โ†’ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜

CDN ๊ณผ ๋กœ๋“œ๋ฐธ๋Ÿฐ์„œ์™€ nginx ๊ฐ€ ์ €๋งˆ๋‹ค ์œ ํœด ์—ฐ๊ฒฐ ์ œํ•œ์„ ๊ฐ–๊ณ  ์žˆ์—ˆ๋‹ค.

# nginx
proxy_read_timeout 60s;    # ๊ธฐ๋ณธ๊ฐ’

proxy_read_timeout ๋ง๊ณ  ๋กœ๋“œ๋ฐธ๋Ÿฐ์„œ ์ชฝ์—๋„ ๊ธฐ๋ณธ ์œ ํœด ์ œํ•œ์ด ์žˆ์—ˆ๋‹ค.

์ด ๊ฐ’๋“ค์€ ๊ทธ ์‹œ๊ฐ„ ๋™์•ˆ ์•„๋ฌด๊ฒƒ๋„ ์•ˆ ํ๋ฅด๋ฉด ๋Š๋Š”๋‹ค๋Š” ๋œป์ด๋‹ค. ์—ฐ๊ฒฐ์„ ์œ ์ง€ํ•˜๋Š” ๋ฐ๋„ ์ž์›์ด ๋“œ๋‹ˆ ๋…ธ๋Š” ์—ฐ๊ฒฐ์„ ์ •๋ฆฌํ•˜๋Š” ๊ฒƒ์€ ๋‹น์—ฐํ•œ ๋™์ž‘์ด๋‹ค.

๋ฌธ์ œ๋Š” ์‹ค์‹œ๊ฐ„ ๋ฐ์ดํ„ฐ ์—ฐ๊ฒฐ์ด ์›๋ž˜ ๊ฐ€๋” ์กฐ์šฉํ•œ ์„ฑ์งˆ์ด๋ผ๋Š” ์ ์ด์—ˆ๋‹ค. ๊ฑฐ๋ž˜๊ฐ€ ์—†์œผ๋ฉด ๋ณด๋‚ผ ๊ฒƒ์ด ์—†๋Š”๋ฐ ๊ทธ๊ฒƒ์ด ๋Š์„ ์ด์œ ๊ฐ€ ๋œ๋‹ค.

์—ฌ๋Ÿฟ์ด ๊ฒฝ๋กœ์— ๊ฑธ์ณ ์žˆ์œผ๋ฉด ๊ทธ์ค‘ ๊ฐ€์žฅ ์งง์€ ๊ฐ’์ด ์‹ค์ œ ํ•œ๊ณ„๊ฐ€ ๋œ๋‹ค.

์กฐ์น˜ โ€” ์ฃผ๊ธฐ ์‹ ํ˜ธ๋กœ ์ฑ„์šฐ๊ธฐ

์กฐ์šฉํ•ด๋„ ๋ฌด์–ธ๊ฐ€๋ฅผ ๋ณด๋‚ด๋ฉด ๋œ๋‹ค.

ping ๊ณผ pong ์ด ๊ทธ ์šฉ๋„๋ผ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋ฐ์ดํ„ฐ๊ฐ€ ์•„๋‹ˆ๋ผ ํ”„๋กœํ† ์ฝœ ์ˆ˜์ค€์—์„œ ์˜ค๊ฐ„๋‹ค. ํด๋ผ์ด์–ธํŠธ ์ฝ”๋“œ๊ฐ€ ๋”ฐ๋กœ ์ฒ˜๋ฆฌํ•  ํ•„์š”๊ฐ€ ์—†๋‹ค. ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋ฉ”์‹œ์ง€๋กœ ๋นˆ ํ‹ฑ์„ ๋ณด๋‚ด๋Š” ๋‹ค๋ฅธ ๋ฐฉ๋ฒ•๋„ ์žˆ์—ˆ์ง€๋งŒ ์ œ์–ด ํ”„๋ ˆ์ž„ ์ชฝ์„ ๊ณจ๋ž๋‹ค. ์ด์œ ๋Š” ํด๋ผ์ด์–ธํŠธ ๊ตฌํ˜„๋งˆ๋‹ค ๋นˆ ํ‹ฑ ์ฒ˜๋ฆฌ๋ฅผ ๋‹ค์‹œ ์งœ์•ผ ํ•ด์„œ๋‹ค.

const HEARTBEAT_INTERVAL = 30000;

wss.on('connection', function (ws) {
    ws.isAlive = true;

    ws.on('pong', function () {
        this.isAlive = true;
    });
    ...
});

setInterval(function () {
    wss.clients.forEach(function (ws) {
        if (ws.isAlive === false) {
            // ์ง€๋‚œ ์ฃผ๊ธฐ์— pong ์ด ์•ˆ ์™”๋‹ค. ์ฃฝ์€ ์—ฐ๊ฒฐ์ด๋‹ค
            return ws.terminate();
        }
        ws.isAlive = false;
        ws.ping();
    });
}, HEARTBEAT_INTERVAL);

HEARTBEAT_INTERVAL 30์ดˆ๋Š” ๊ฐ€์žฅ ์งง์€ proxy_read_timeout 60์ดˆ์˜ ์ ˆ๋ฐ˜์œผ๋กœ ์žก์•˜๋‹ค.

์ œํ•œ๋ณด๋‹ค ์งง์•„์•ผ ํ•˜๊ณ  ํ•œ ๋ฒˆ ๋†“์ณ๋„ ๊ดœ์ฐฎ๊ฒŒ ์ ˆ๋ฐ˜ ์ดํ•˜๋กœ ๋‘๋Š” ํŽธ์ด ์•ˆ์ „ํ•˜๋‹ค. ์ด ์ฝ”๋“œ๋Š” ์ฃฝ์€ ์—ฐ๊ฒฐ์„ ์ •๋ฆฌํ•˜๋Š” ์—ญํ• ๋„ ํ•œ๋‹ค.

ํด๋ผ์ด์–ธํŠธ๊ฐ€ ๋„คํŠธ์›Œํฌ ๋‹จ์ ˆ๋กœ ์‚ฌ๋ผ์ง€๋ฉด ์„œ๋ฒ„๋Š” ๊ทธ๊ฒƒ์„ ๋ฐ”๋กœ ๋ชจ๋ฅด๊ณ  ํ•œ์ฐธ ๋’ค์—์•ผ ์•Œ๊ฒŒ ๋œ๋‹ค. pong ์ด ์•ˆ ์˜จ ์—ฐ๊ฒฐ์„ ๋‹ค์Œ ์ฃผ๊ธฐ์— terminate ํ•˜๋‹ˆ ๊ทธ ์‚ฌ์ด ์Œ“์ด๋˜ ๊ฒƒ์ด ์‚ฌ๋ผ์กŒ๋‹ค.

๋Œ€์‘ โ€” ํด๋ผ์ด์–ธํŠธ ์ชฝ ๋ณต๊ตฌ

์„œ๋ฒ„๊ฐ€ ์‚ด์•„ ์žˆ์–ด๋„ ์ค‘๊ฐ„์—์„œ ๋Š๊ธฐ๋Š” ๊ฒฝ์šฐ๋Š” ๋‚จ๋Š”๋‹ค.

let retryDelay = 1000;

function connect() {
    const ws = new WebSocket(WS_URL);

    ws.onopen = function () {
        retryDelay = 1000;      // ์„ฑ๊ณตํ•˜๋ฉด ์ดˆ๊ธฐํ™”
        subscribe(currentSymbols);
    };

    ws.onclose = function () {
        setTimeout(connect, retryDelay);
        retryDelay = Math.min(retryDelay * 2, 30000);   // ์ตœ๋Œ€ 30์ดˆ
    };
}

์—ฌ๊ธฐ์„œ ๋‘ ๊ฐ€์ง€๋ฅผ ์ง€์ผฐ๋‹ค.

retryDelay ๋ฅผ ๋Š˜๋ ค ๊ฐ€๋Š” ๊ฒƒ์ด ์ฒซ์งธ๋‹ค. ์„œ๋ฒ„๊ฐ€ ์ฃฝ์–ด ์žˆ๋Š”๋ฐ ์ˆ˜์ฒœ ๊ฐœ ํด๋ผ์ด์–ธํŠธ๊ฐ€ 1์ดˆ๋งˆ๋‹ค ๋ถ™์œผ๋ฉด ์„œ๋ฒ„๊ฐ€ ์‚ด์•„๋‚˜๋Š” ์ˆœ๊ฐ„ ๋‹ค์‹œ ์ฃฝ๋Š”๋‹ค.

onopen ์—์„œ subscribe ๋ฅผ ๋‹ค์‹œ ๋ถ€๋ฅด๋Š” ๊ฒƒ์ด ๋‘˜์งธ๋‹ค. ์„œ๋ฒ„๋Š” ์ด๊ฒƒ์„ ์ƒˆ WebSocket ์œผ๋กœ ๋ณด๋ฏ€๋กœ ์ด์ „์— ๋ฌด์—‡์„ ๋ณด๊ณ  ์žˆ์—ˆ๋Š”์ง€ ๋ชจ๋ฅธ๋‹ค.

์ด๊ฒƒ์„ ๋น ๋œจ๋ฆฌ๋ฉด ์—ฐ๊ฒฐ์€ ์‚ด์•„ ์žˆ๋Š”๋ฐ ๋ฐ์ดํ„ฐ๊ฐ€ ์•ˆ ์˜ค๋Š” ์ƒํƒœ๊ฐ€ ๋œ๋‹ค. ์ฆ์ƒ์ด ์›๋ž˜ ๋ฌธ์ œ์™€ ๋˜‘๊ฐ™์•„์„œ ๊ณ ์ณค๋Š”์ง€ ์•„๋‹Œ์ง€๋„ ์•ˆ ๊ฐˆ๋ฆฐ๋‹ค.

์ •๋ฆฌ


Share this post on:

Previous Post
์ฃผ์„ ์ฒ˜๋ฆฌ๊ฐ€ ํ์ง€๋Š” ์•„๋‹ˆ๋‹ค
Next Post
๋‹จ๊ฑด ์‹คํ–‰์€ ์Šค์ฝ”ํ”„๋ฅผ ์•ˆ ๊ฑฐ์นœ๋‹ค