๋ ๊ฐ์ ์ฅ์น๊ฐ ๋ณธ๊ฒฉ์ ์ธ ๋ฐ์ดํฐ ํต์ ์ ์์ํ๊ธฐ ์ , ์ฐ๊ฒฐ ์ค์ ๋ฐ ๋ฐ์ดํฐ ๊ตํ ๊ท์น(ํต์ ์๋, ๋ณด์ ์ค์ ๋ฑ)์ ํ์ํ๋ ์ฌ์ ๋๊ธฐํ ๊ณผ์
๊ธฐ์กด์ HTTP๋ ์์ฒญ์ ๋ณด๋ด์ผ ์๋ต์ด ์ค๋ connectionless์ stateless ๋ฐฉ์ ์๋ก์ด ์ ๋ณด๋ฅผ ๋ฐ์์ค๋ ค๋ฉด ๋จผ์ ์์ฒญ์ ๋ณด๋ด์ผ๋ง ํฉ๋๋ค. ์ง์์ ์ผ๋ก ๋ฐ์์ฌ ์๋ก์ด ์ ๋ณด๊ฐ ์๋์ง ํ์ธํด์ผ ํ๋ ๊ฒฝ์ฐ์๋ ๊ณ์ ์์ฒญ์ ๋ณด๋ด์ผ ํฉ๋๋ค.
๋ ์จ๋ ์ฐจํธ ๊ฐ์ ์ค์๊ฐ ์ ๋ณด๋ฅผ ๋ชจ๋ํฐ๋ง ํ๋ ค๋ฉด ์ฃผ๊ธฐ์ ์ผ๋ก ์์ฒญ์ ๋ณด๋ด์ ๋ฐ์ดํฐ๋ฅผ ๊ฐฑ์ ํด์ผ ํฉ๋๋ค.
์ด๋ฌํ ๋จ์ ์ ๋ณด์ํ๊ธฐ ์ํด ์น์์ผ์ด ํ์ํฉ๋๋ค.
์น์์ผ์ Transport protocol์ ์ผ์ข ์ผ๋ก ์๋ฐฉํฅ ์ํต์ ์ํ ๊ท์ฝ์ ๋๋ค.
์์ฒญ์ ๋จผ์ ๋ณด๋ด์ง ์์ผ๋ฉด ๋ฐ์ดํฐ๋ฅผ ๋ฐ์์ฌ ์ ์์๋ ๊ธฐ์กด์ ๋ฐฉ์์์ ๋ฒ์ด๋ ์ค์๊ฐ ์๋ฐฉํฅ ์ํต์ด ๊ฐ๋ฅํ๊ฒ ํด์ค๋๋ค.
์ฑํ ์ด๋ ๊ฒ์, ์ฆ๊ถ๊ฑฐ๋ ๋ฑ ์ค์๊ฐ ์๋น์ค์์ ๋ง์ด ์ฌ์ฉ๋ฉ๋๋ค.
https://curiousjinan.tistory.com/entry/websocket-deep-dive-ep1
- WebSocket ์์ฒด (ํ๋กํ ์ฝ ๋ ๋ฒจ)
- HTTP๋ก ์์ํด์ Upgrade: websocket ํค๋๋ก ํ ๋ฒ ํธ๋์ ฐ์ดํฌํ๊ณ , ๊ทธ ๋ค๋ก๋ ๊ฐ์ TCP ์ปค๋ฅ์ ์ ๊ณ์ ์ด์ด๋ ์ฑ **์๋ฐฉํฅ(full-duplex)**์ผ๋ก ๋ฐ์ดํฐ๋ฅผ ์ฃผ๊ณ ๋ฐ๋ ํ๋กํ ์ฝ์ ๋๋ค.
- HTTP์ฒ๋ผ ๋งค๋ฒ ์์ฒญ-์๋ต์ด ์๋๋ผ, ์๋ฒ๊ฐ ๋จผ์ ํด๋ผ์ด์ธํธ์ ๋ฐ์ดํฐ๋ฅผ ๋ฐ์ด๋ฃ์ ์ ์์ด์(new_message๊ฐ ๊ทธ๋ ๊ฒ ์ต๋๋ค). ์ด๊ฒ ์ฑํ ์ด "polling ์ ํ๊ณ ์ค์๊ฐ"์ธ ์ด์ ์ ๋๋ค.
- ์ฐ๊ฒฐ์ด ์ํ๋ฅผ ๊ฐ์ง(stateful) ์ฐ๊ฒฐ์ด๋ผ๋ ๊ฒ ํต์ฌ โ HTTP ์์ฒญ์ ๋งค๋ฒ ๋ ๋ฆฝ์ ์ด์ง๋ง, WebSocket ์ฐ๊ฒฐ์ "์ด ์์ผ์ด ๊ณง ์ด ์ ์ "๋ผ๋ ๋งคํ์ด ์๋ฒ ๋ฉ๋ชจ๋ฆฌ์ ์๊น๋๋ค. ์ด๊ฒ ์ฐ๋ฆฌ๊ฐ ๊ณ์ ์๊ธฐํ "๋ ธ๋๊ฐ ์ฌ๋ฌ ๊ฐ๋ฉด ์ด ๋งคํ์ด ๋ ธ๋๋ง๋ค ๋ฐ๋ก ๋ ผ๋ค"๋ ๋ฌธ์ ์ ๊ทผ๋ณธ ์์ธ์ด์์.
- Socket.IO๊ฐ ๊ทธ ์์ ์น๋ ๊ฒ๋ค WebSocket ์์ฒด๋ ์ ์์ค์ด๋ผ Socket.IO๊ฐ ์ค๋ฌด์ ํ์ํ ๊ฒ๋ค์ ์ถ๊ฐ๋ก ์ ๊ณตํฉ๋๋ค.
- ์๋ ์ฌ์ฐ๊ฒฐ: ์ฐ๊ฒฐ ๋๊ธฐ๋ฉด ์ง์ ๋ฐฑ์คํ๋ก ์์์ ์ฌ์๋. ์ฐ๋ฆฌ ์ค๊ณ์ "1์ดโ2์ดโ4์ด..." ์ฌ์ฐ๊ฒฐ ๋ก์ง์ด ์ด๊ฑธ ๊ทธ๋๋ก ์.
- Room: ์์ผ์ ๊ทธ๋ฃน์ผ๋ก ๋ฌถ์ด์ io.to(roomName).emit()์ผ๋ก ํ ๋ฒ์ ๋ณด๋ผ ์ ์๋ ๊ธฐ๋ฅ. ๊ทผ๋ฐ ์ง๋๋ฒ์ ํ์ธํ๋ฏ ์ฐ๋ฆฌ SRS๋ ์ด๊ฑธ ๋ฉ์์ง ๋ฐฐ๋ฌ์ ์ ์ฐ๊ณ (์ฌ์ฉ์ ๊ธฐ๋ฐ), ํ์ดํ/์ฝ์์ฒ๋ผ "์ง๊ธ ๋ณด๊ณ ์๋ ์ฌ๋๋ค๋ผ๋ฆฌ"๋ง ์ฐ๋ ์ฉ๋๋ก ์ขํ๋จ์ฃ โ ์ด๊ฒ๋ Room์ด ๋ญ์ง ์์์ผ ๊ทธ ์ค๊ณ ๊ฒฐ์ ์ด ์ ๊ทธ๋ ๊ฒ ๋๋์๋์ง ์ดํด๊ฐ ๋ฉ๋๋ค.
- Adapter (์ฐ๋ฆฌ๋ Redis/Valkey adapter): Socket.IO ์๋ฒ๊ฐ ์ฌ๋ฌ ๊ฐ(๋ฉํฐ๋ ธ๋)์ผ ๋, ๋ ธ๋1์ด ๊ฐ์ง ์์ผ ๋ชฉ๋ก์ ๋ ธ๋2๋ ๋ชจ๋ฆ ๋๋ค. Adapter๊ฐ Valkey pub/sub์ผ๋ก "๋๊ฐ ์ด๋ room์ ์๋์ง, emit ๋ช ๋ น์ ๋ค๋ฅธ ๋ ธ๋์๋ ์ ํ"ํด์ฃผ๋ ์ญํ . ์ด๊ฒ ์์ผ๋ฉด sticky session(๊ฐ์ ์ ์ ๋ฅผ ํญ์ ๊ฐ์ ๋ ธ๋๋ก) ๊ฐ์ ํด์ผ ํ๋๋ฐ, ๊ทธ๋ผ ๋ก๋๋ฐธ๋ฐ์ฑ์ด ๋ง๊ฐ์ง๊ณ ๋ ธ๋ ํ๋ ์ฃฝ์ผ๋ฉด ๊ทธ ๋ฐฉ ์ ์ฒด๊ฐ ๋๊น๋๋ค.
- Heartbeat (ping/pong): TCP ์ฐ๊ฒฐ์ด ์ฃฝ์๋์ง ์๋ฒ๊ฐ ์ฃผ๊ธฐ์ ์ผ๋ก ํ์ธํ๋ ๋ฉ์ปค๋์ฆ. ์ฐ๋ฆฌ ์ค๊ณ์์ "ํด๋ผ์ด์ธํธ๊ฐ ๋ฐ๋ก heartbeat ์ ๋ณด๋ด๋ ๋จ"์ด๋ผ๊ณ ํ ๊ฒ ์ด๊ฑฐ โ Socket.IO๊ฐ ๊ธฐ๋ณธ์ผ๋ก ํด์ค๋๋ค.
- ๋ค์์คํ์ด์ค: ์ฐ๋ฆฌ๋ ์ ์ผ์ง๋ง, ํ๋์ ์ฐ๊ฒฐ ์์ ์ฌ๋ฌ ๋ ผ๋ฆฌ์ ์ฑ๋์ ๋ถ๋ฆฌํ๋ ๊ธฐ๋ฅ๋ ์์ต๋๋ค (์ฐธ๊ณ ๋ก๋ง).
- ์ด๊ฒ ์ ์ค๊ณ์ ์ง์ ์ํฅ์ ์คฌ๋์ง
- room vs ์ฌ์ฉ์ ๊ธฐ๋ฐ ๋ฐฐ๋ฌ: Room์ด "์ง๊ธ joinํ ์ฌ๋์๊ฒ๋ง ๊ฐ๋ค"๋ ๊ฑธ ์์์ผ, SRS์ "์ฑํ ๋ฐฉ ์ ์ฅ ์์๋ง Room Join" + "๋ฉ์์ง๋ Room ๊ธฐ๋ฐ ์๋ ์ฌ์ฉ์ ๊ธฐ๋ฐ"์ด๋ผ๋ ๋ฌธ์ฅ์ด ์ ์ง์ ์ด๋ฃจ๋์ง ์ดํด๋ฉ๋๋ค. Room์ ์๋ Idle ์ ์ ๋ ๋ฉ์์ง๋ฅผ ๋ฐ์์ผ ํ๋๊น, ๋ฉ์์ง๋ room์ผ๋ก ๋ชป ๋ณด๋ด๊ณ ์ฐธ์ฌ์ ๊ฐ๊ฐ์ธ์ ์์ผ์ผ๋ก ์ง์ ์ด์ผ ํ๋ ๊ฑฐ์ฃ .
- ๋ฉํฐ๋ ธ๋์์ ์ํ๋ฅผ ์ด๋ ๋์ง: ์์ผ์ด "์ด ๋ ธ๋์ ๋ฉ๋ชจ๋ฆฌ์๋ง ์กด์ฌ"ํ๋ค๋ ๊ฑธ ์์์ผ, ์ ์ฐ๊ฒฐ ์ํยท์ ์ฌ ๋ชฉ๋กยทrate limit์ ์ ๋ถ Valkey๋ก ๋นผ์ผ ํ๋์ง๊ฐ ์์ฐ์ค๋ฝ๊ฒ ๋์ต๋๋ค.
- ์ฌ์ฐ๊ฒฐ ์ ์ ์ค ์ฒ๋ฆฌ: WebSocket์ด ๋๊ธฐ๋ฉด ๊ทธ ์ฌ์ด ์๋ฒ๊ฐ ๋ณด๋ธ ๋ฉ์์ง๋ ๊ทธ๋ฅ ์ฌ๋ผ์ง๋ค๋ ๊ฑธ ์์์ผ, "์ฌ์ฐ๊ฒฐ ๊ฐญ ์ฑ์ฐ๊ธฐ"(lastMessageId ๊ธฐ๋ฐ ๋๊ธฐํ)๊ฐ ์ ํ์ ์๊ตฌ์ฌํญ์ธ์ง ์ดํด๋ฉ๋๋ค.