๐ Multiplexing NonBlocking IO ๋คํธ์ํฌ ์ํคํ ์ฒ ์กฐ์ฌ - YangJJune/U-Compass GitHub Wiki
ThreadPool์ ํจ์จ์ ์ธ ๊ฐ์๋ฅผ ์ฐ๊ตฌํ๋ ค ํ ์ด์ ?
- ์ค์๊ฐ ์์น ๊ณต์ ์ ๋น ๋ฅธ ์๋์ ํจ์จ์ ์ํ 7์ฃผ๊ฐ์ด์๋ค.
- ์ง๋ ์๊ฐ์ ThreadPool์ ๊ฐ์๊ฐ ๋ฌด์์ ๋ง๋ค๊ณ ์ข์ ๊ฒ์ด ์๋๋ผ๋ ๊ฒ์ ํ์ธํ ์ ์์๊ณ , ์ด์ ๋ฐ๋ผ ํจ์จ์ ์ธ Thread์ ๊ฐ์์ ๋ํด ๊ณต๋ถ๋ฅผ ํ๋ ์ค ํฅ๋ฏธ๋ก์ด ๋ด์ฉ์ ํ์ธํ ์ ์์๋ค.
- ๋ฐ๋ก Multi-Process / Multi-Thread / Multi-Plex ํ๋ก๊ทธ๋๋ฐ์ด์๋ค
Multi-Processing
- ์ฌ๋ฌ ๊ฐ์ ๋ ๋ฆฝ๋ ํ๋ก์ธ์ค๋ฅผ ๋์์ ์คํํ๋ ๊ฒ์ด๋ค
- ๋ฐ๋ผ์ ์์คํ
์์์ ๋
๋ฆฝ์ ์ผ๋ก ํ ๋น๋ฐ๋๋ค
- CPU ์์ ๋ถํ ์ OS์ ์ํด ์ด๋ฃจ์ด์ง๋ค
- ๋ฐ๋ผ์ ํ๋ก์ธ์ค ๊ฐ์ ๋ฐ์ดํฐ ์ ๋ฌ์๋ IPC (ํ์ดํ, ํ, ์์ผ ๋ฑ)๊ฐ ํ์ํ๋ค
- ์ปจํ
์คํธ ์ค์์นญ ๋ฐ์ ์ ๊ต์ฅํ ์ผ์ด ํฌ๋ค
- Memory Address Space ์ ๋ณ๊ฒฝ์ด ํ์ํ๊ธฐ ๋๋ฌธ(๋ฉ๋ชจ๋ฆฌ ์ฃผ์, ๋งตํ, ํ์ด์ง ํ ์ด๋ธ ๋ฑ)
Multi-Threading
- ๋ชจ๋ ์ฐ๋ ๋๊ฐ ํ๋ก์ธ์ค์ ๋ฉ๋ชจ๋ฆฌ ๊ณต๊ฐ์ ๊ณต์ ํ๋ค
- ๋ฐ๋ผ์ ๋ชจ๋ ์ฐ๋ ๋๋ ๊ฐ์ ๋ฉ๋ชจ๋ฆฌ ์์ญ์ ์ ๊ทผํ ์ ์๋ค
- ๋ฉ๋ชจ๋ฆฌ ๊ณต๊ฐ์ ๊ณต์ ํ๊ธฐ ๋๋ฌธ์ ๋ฐ์ดํฐ ์ ๋ฌ์ด ์ฉ์ดํ๋ค
- I/O ์์ ์ด ์งํ๋๋ ๋์ ๋ค๋ฅธ ์ฐ๋ ๋์์๋ ์์ ์ ์งํํ๋ ๋ฑ์ ํจ์จ์ ๋ฐํํ ์ ์๋ค
- ์ปจํ ์คํธ ์ค์์นญ ๋ฐ์ ์ ์ผ์ด ํ๋ก์ธ์ค์ ๋นํด ๋น๊ต์ ์ ๋ค
Multi-Plexing
- ์ ๋์๋๋ select()๋ฅผ ์ฌ์ฉํ์ฌ IO Multiplexing์ ํ๋ ํ๋ก์ฐ๋ฅผ ๋ํ๋ธ ๊ฒ์ด๋ค.
- ์๋ฐํ ์ด์ผ๊ธฐํ๋ฉด ์์ Multi-Processing, Multi-Threading๊ณผ ์ง์ ์ ์ผ๋ก ์ฎ์ด์ ํํํ๊ธฐ ๋ณด๋ค๋ IO์์ Multiplexing์ ํ ์ ์๊ณ , ์ด ๋ ์์ 2๊ฐ์ ๊ธฐ๋ฒ๊ณผ ๋น๊ตํ์ฌ ์ฌ์ฉํ ์ ์๋ค๊ณ ํํํ ์ ์๋ค.
- ์ ๋๋ก ๋ Multiplexing ๊ฐ๋ ์ผ๋ก ๋ค์ด๊ฐ๊ธฐ ์ ์ Synchronous, Asynchronous, Blocking IO์ Non-blocking IO์ ๋ํด ์์๋ณด๋๋ก ํ๋ค.
Synchronous IO - ๋๊ธฐ
- ๋ชจ๋ ์์ ์ด ์ผ๋ จ์ ์์๋ฅผ ๋ฐ๋ฅธ๋ค โ ์์ ์ ์์ ๋ณด์ฅ
- ์์ ์๋ฃ๋ฅผ user space์์ ํ๋จํ๋ค
- ์ผ๋ จ์ pipeline์ ์ ์งํ๋ ๊ตฌ์กฐ์์ ํจ์จ์ ์ด๋ค
Asynchronous IO
- kernel์ I/O ์์ ์ ์์ฒญํด๋๊ณ ๋ค๋ฅธ ์์ ์ ์งํํ๋ค โ ์์ ์ ์์ ๋ณด์ฅ X
- ์์ ์๋ฃ๋ฅผ kernel space์์ ํต๋ณดํ๋ค
- ๊ฐ ์์ ์ด ๋ ๋ฆฝ์ ์ด๊ฑฐ๋, ์์ ๋ณ ์ง์ฐ์ด ํฐ ๊ฒฝ์ฐ ํจ์จ์ ์ด๋ค
Blocking
- ์์ฒญํ ์์ ์ด ๋ชจ๋ ์๋ฃ๋ ๋๊น์ง ๊ธฐ๋ค๋ ธ๋ค๊ฐ ์๋ฃ๋ ๋ ์๋ต๊ณผ ๊ฒฐ๊ณผ๋ฅผ ๋ฐํ๋ฐ๋๋ค.
- ์์ฒญํ ์์ ๊ฒฐ๊ณผ๋ฅผ ๊ธฐ๋ค๋ฆฐ๋ค.
Non-blocking
- ์์ ์์ฒญ ์ดํ ๊ฒฐ๊ณผ๋ ๋์ค์ ํ์ํ ๋ ์ ๋ฌ๋ฐ๋๋ค.
- ์์ฒญํ ์์ ๊ฒฐ๊ณผ๋ฅผ ๊ธฐ๋ค๋ฆฌ์ง ์๋๋ค.
IBM I/O Model
- ํ๋ฅผ ๋ณด๋ ๋ฒ์ โBlocking ํ๋ฉด์ Asynchronous ํ ๋ชจ๋ธ์ I/O ๋ฉํฐํ๋ ์ฑ์ด๋คโ๋ ์์ผ๋ก ๋ณด๋ฉด ๋๋ค.
- Synchronous Blocking I/O โ Blocking I/O
- Synchronous Non-Blocking I/O โ Non-Blocking I/O
- Asynchronous Blocking I/O โ I/O Multiplexing
- Asynchronous Non-Blocking I/O โ Asynchronous I/O
Blocking I/O
Non-Blocking I/O
I/O Multiplexing
-
ํ๋ก์ธ์ค์์ ํน์ ํ์ผ์ ์ ๊ทผํ ๋๋ ํ์ผ ๋์คํฌ๋ฆฝํฐ(์ดํ FD, File Descriptor)๋ผ๋ ์ถ์์ ์ธ ๊ฐ์ ์ฌ์ฉํ๋ค. ์ด๋, ์ด FD๋ค์ ๊ฐ์ํ์ฌ I/O Multiplexing์ ํ ์ ์๋ค
-
์ ๊ตฌ์กฐ๋ kernel์ I/O ์์ฒญ์ ๋ฐ์ผ๋ฉฐ ์ฒ๋ฆฌ๋ฅผ ์์ํจ๊ณผ ๋์์ user process์๊ฒ ๋ฏธ์๋ฃ ์ํ๋ฅผ ๋ฐํํ๊ณ user process๋ ๋ฐ์ดํฐ๊ฐ ์ค๋น๋๋ค๋ ์๋์ด ์ฌ ๋๊น์ง ๋๊ธฐํ๋ ๋ชจ์ต์ ๋ณด์ฌ์ฃผ๊ณ ์๋ค
-
์ด์ด์, kernel์ ์๋ต์ ๊ธฐ๋ค๋ฆฌ๋ค ๋ณด๋ฉด kernel์์ ๊ฒฐ๊ณผ ๊ฐ์ด ์ค๋น๋์๋ค๋ callback ์ ํธ๊ฐ ์ค๊ณ user process๋ ์์ ์ buffer๋ก ๋ฐ์ดํฐ๋ฅผ ๋ณต์ฌํด์ค๋ ๋ชจ์ต์ ๋ณด์ฌ์ฃผ๋๋ฐ, ์ด๋ select ํธ์ถ ๊ฒฐ๊ณผ๊ฐ ์ ์๋ฏธํ ๊ฐ์ผ๋ก ๋์ฌ ๋๊น์ง user process์์ loop๋ฅผ ๋๋ฆฌ๋ฉฐ ๋๊ธฐํ๋ ๋ฐฉ์์ด๋ค.
-
select / poll / epoll(Linux์ ์ฉ) / kqueue(maxOS์ ์ฉ)
-
Select
- ์ต๋ 1024๊ฐ์ FD๋ฅผ ๊ฐ์ํ๋ค
- FD ๊ฐ์ ์ ํ
- ๊ฐ์ ๋์์ด ๋์ด๋ ์๋ก ๋๋ ค์ง O(N)
- ์ต๋ 1024๊ฐ์ FD๋ฅผ ๊ฐ์ํ๋ค
-
Poll
- Select์ ๊ฐ์ ๋ฒ์
- FD ๊ฐ์ ์ ํ ์์
- ์ฌ์ ํ ๋งค๋ฒ FD ๋ฆฌ์คํธ๋ฅผ ์ปค๋์ ์ ๋ฌํด์ผํ๋ฏ๋ก ๊ฐ์ ๋์์ด ๋์ด๋ ์๋ก ๋๋ ค์ง O(N)
- Select์ ๊ฐ์ ๋ฒ์
-
epoll
- Linux 2.6 ์ดํ ๋์ ๋ ๊ณ ์ฑ๋ฅ ์ด๋ฒคํธ ๊ธฐ๋ฐ I/O ๋ฉํฐํ๋ ์ฑ ๋ฉ์ปค๋์ฆ
- ์ด๋ฒคํธ ๊ธฐ๋ฐ์ผ๋ก ๋์ํ๋ฉฐ, ๋น๋๊ธฐ์ ์ผ๋ก ์ฐ๊ฒฐ์ ์ฒ๋ฆฌํ๋ค. O(1)
- ๋์ ์ฑ๋ฅ
- ํจ์จ์ ์ธ ๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ
- ๋น๋๊ธฐ ์ฒ๋ฆฌ โ I/O๊ฐ ์๋ฃ๋ ์์ผ๋ง ์ฒ๋ฆฌ
-
kqueue
- ์ปค๋ ๋ด์ ์ด๋ฒคํธ ํ๋ฅผ ๊ด๋ฆฌํ๋ฉฐ, ์ด๋ฒคํธ ๊ธฐ๋ฐ์ผ๋ก ๋์
- epoll๊ณผ ์ ์ฌํ๊ฒ ๋น๋๊ธฐ I/O ๋ชจ๋ธ์ ๊ตฌํํ์ฌ, ์ฐ๊ฒฐ๋ ์์ผ์ ์ด๋ฒคํธ๋ฅผ ๊ฐ์ํ๊ณ ํด๋น ์ด๋ฒคํธ๊ฐ ๋ฐ์ํ ๋ ์ฒ๋ฆฌํ๋ค
- BSD ๊ณ์ด ์ด์์ฒด์ ์์๋ง ์ฌ์ฉ ๊ฐ๋ฅ
Asynchronous I/O
- Asynchronous I/O ํ๊ฒฝ์์ user process๋ system call ์ดํ I/O ์ฒ๋ฆฌ์ ์ ๊ฒฝ ์ฐ์ง ์๊ณ ์๋ค๊ฐ ์์ ์ด ์๋ฃ๋๋ฉด kernel๋ก๋ถํฐ signal, thread ๊ธฐ๋ฐ callback ๋ฑ์ผ๋ก ๊ฒฐ๊ณผ๋ฅผ ๋ง์น event์ฒ๋ผ ์ ๋ฌ๋ฐ๊ฒ ๋ฉ๋๋ค. ๊ทธ๋ ๊ธฐ์ ์๋ต์ด ์ค๊ธฐ ์ ๊น์ง user process๋ I/O์ ๋ ๋ฆฝ์ ์ธ ๋ค๋ฅธ processing์ด ๊ฐ๋ฅํ ๊ตฌ์กฐ์ ๋๋ค.
๊ตฌํ
select
import socket
import select
import time
server = socket.socket()
server.bind(('0.0.0.0', 3388))
server.listen()
server.setblocking(False)
# ์๋ฒ ์์ผ ์ ์ฅ
sockets = [server]
while True:
# ๋ณํ๊ฐ ์์ ๋ ๊น์ง ๋๊ธฐ (๋ฌดํ๋ฃจํ)
readable, _, _ = select.select(sockets, [], [])
print(readable)
for sock in readable:
# ์๋ฒ ์์ผ๊ณผ ๋์ผํ ๊ฐ์ฒด์ธ๊ฐ? (์์ผ์ธ๊ฐ?)
if sock is server:
# ์๋ก์ด ํด๋ผ์ด์ธํธ ์์ผ ์ถ๊ฐ
client, _ = server.accept()
client.setblocking(False)
sockets.append(client)
# ๋ฐ์ดํฐ์ธ๊ฐ? (์ด๋ฏธ ์ฐ๊ฒฐ๋ ์์ผ์ผ๋ก๋ถํฐ ์จ ๋ฐ์ดํฐ)
else:
data = sock.recv(1024)
if data:
sock.sendall(data)
else:
sockets.remove(sock)
sock.close()
time.sleep(1)
poll
import socket
import select
import time
server = socket.socket()
server.bind(('0.0.0.0', 3388))
server.listen()
server.setblocking(False)
# poll ๊ฐ์ฒด ์์ฑ
poller = select.poll()
# ์๋ฒ์์ผ์ fd -> socket ๋งคํ
fd_to_socket = {server.fileno(): server}
# ์๋ฒ ์์ผ์ ์ฝ๊ธฐ ์ด๋ฒคํธ์ ๋ฑ๋ก
poller.register(server, select.POLLIN)
print(f"Server listening")
while True:
events = poller.poll(1000) # timeout: 1000ms
print(events)
for fd, event in events:
sock = fd_to_socket[fd]
# ์๋ฒ ์์ผ๊ณผ ๋์ผํ๊ฐ? (์์ผ ๊ฐ์ฒด์ธ๊ฐ?)
if sock is server:
# ์ ํด๋ผ์ด์ธํธ ์ฐ๊ฒฐ
client_sock, addr = server.accept()
print(f"New connection from {addr}")
client_sock.setblocking(False)
#ํด๋ผ ์์ผ fd์ ๊ฐ์ฒด ์ฐ๊ฒฐ
fd_to_socket[client_sock.fileno()] = client_sock
poller.register(client_sock, select.POLLIN)
elif event & select.POLLIN:
# ๋ฐ์ดํฐ ์์
data = sock.recv(1024)
if data:
print(f"Received: {data.decode()}")
sock.sendall(data) # ์์ฝ
else:
# ์ฐ๊ฒฐ ์ข
๋ฃ
print("Client disconnected")
poller.unregister(fd)
fd_to_socket.pop(fd)
sock.close()
epoll
import socket
import select
import time
server = socket.socket()
server.bind(('0.0.0.0', 3388))
server.listen()
server.setblocking(False)
# epoll ๊ฐ์ฒด ์์ฑ
epoll = select.epoll()
# epoll์ ์๋ฒ ์์ผ ๋ฑ๋ก (์ฝ๊ธฐ ์ด๋ฒคํธ)
epoll.register(server.fileno(), select.EPOLLIN)
# ํ์ผ ๋์คํฌ๋ฆฝํฐ โ ์์ผ ๋งคํ
fd_to_socket = {server.fileno(): server}
print(f"Server listening...")
try:
while True:
# ์ด๋ฒคํธ ๊ฐ์ง (timeout: 1์ด)
events = epoll.poll(1)
for fd, event in events:
sock = fd_to_socket[fd]
# ์๋ฒ ์์ผ์ ์ด๋ฒคํธ ๋ฐ์ โ ์ ์ฐ๊ฒฐ
if sock is server:
client_sock, addr = server.accept()
print(f"New connection from {addr}")
client_sock.setblocking(False)
fd_to_socket[client_sock.fileno()] = client_sock
epoll.register(client_sock.fileno(), select.EPOLLIN)
# ํด๋ผ์ด์ธํธ ์์ผ์ ์ฝ๊ธฐ ์ด๋ฒคํธ
elif event & select.EPOLLIN:
data = sock.recv(1024)
if data:
print(f"Received: {data.decode().strip()}")
sock.sendall(data) # ์์ฝ
else:
print("Client disconnected")
epoll.unregister(fd)
sock.close()
del fd_to_socket[fd]
# ํด๋ผ์ด์ธํธ ์์ผ ์๋ฌ or ์ข
๋ฃ
elif event & (select.EPOLLHUP | select.EPOLLERR):
print("Client connection closed (error)")
epoll.unregister(fd)
sock.close()
del fd_to_socket[fd]
finally:
epoll.unregister(server.fileno())
epoll.close()
server.close()
์ ์ฌํ ์๋น์ค์ ๊ตฌํ ์ฌ๋ก
Discord
- ์ค์๊ฐ ์์ฑ/๋ฉ์์ง ์๋น์ค
- ํด๋ผ์ด์ธํธ-์๋ฒ ๋คํธ์ํน ์ํคํ
์ฒ ์ฌ์ฉ
- 1000๋ช ์ด ์ด๊ณผํ๋ฉด P2P ์ํคํ ์ฒ๊ฐ ๋น์ฉ์ด ๋ง์ด ๋ค๊ธฐ ๋๋ฌธ\
- ๊ฐ ๋์ค์ฝ๋ ์ปค๋ฎค๋ํฐ๋ฅผ Guild๋ผ ์นญํ๋ค
- ๊ทธ๋ฆฌ๊ณ Guild Process๊ฐ Guild์ ์กฐ์จ๊ณผ ๋ผ์ฐํ ์ ๋ด๋นํ๋ค
- ๋ชจ๋ ์ฌ์ฉ์๋ Session Process๋ฅผ ๊ฐ๊ณ , Guild Proccess๋ ์ ๋ฉ์์ง, ์ด๋ฒคํธ ๋๋ ์
๋ฐ์ดํธ๋ฅผ ๋ฐ์ผ๋ฉด ํด๋น ์ ๋ณด๋ฅผ ๊ด๋ จ Session Process๋ก ์ ๋ฌํ๋ค
- Session Process๋ ํด๋น ์ ๋ฐ์ดํธ๋ฅผ Discord ํด๋ผ์ด์ธํธ๋ก ํธ์ํ๋ค
- ์ด๋ ๋ง์ ์ฌ์ฉ์์ ๋ถํ๊ฐ ๊ฑธ๋ฆด ์๋ก Guild Process์ ๋ ํฐ ๋ถ๋ด์ ์ฃผ์๋ค
- BEAM์ด ํจ๊ณผ์ ์ด๋ผ๊ณ ๋ ํ๋ ๊ถ๊ทน์ ์ธ ์๋จ์ด ๋์ง๋ ๋ชปํ์๋ค๊ณ ํ๋ค
- ๊ทธ๋์ ์ต์ ํ๋ฅผ ์งํํ๋ค๊ณ ํ๋ค
- ๋ถํ์ํ ์์
์ ์ค์ด๊ธฐ
- ex) ์ฌ์ฉ์๊ฐ ๊ธธ๋๋ฅผ ์ด ๋๊น์ง ์ฒ๋ฆฌ ๋ฐ ๋ฐ์ดํฐ ์ ์ก์ skipํ๋ค
- ๋ฆด๋ ์ด ์ต์ ํ
- Relay๋ ๋ง๋ํ ํธ๋ํฝ์ ์ฒ๋ฆฌํ๊ธฐ ์ํด ์ฌ์ฉํ๋ BEAM ๊ธฐ๋ฐ ํ๋ก์ธ์ค
- ex) ๋ชจ๋ ์ ์ ํํ ๋ฉ์์ง ๋ณด๋ด๊ธฐ
- ์ด๋ฅผ ์ฒ๋ฆฌํ๊ธฐ ์ํด ์ฌ๋ฌ ํ๋ก์ธ์ค๋ฅผ ๋์์ ์์ ์ ๋ถ์ฐ
- ๊ทธ๋ฌ๋ Relay ์์ฒด์ ๋ง๋ํ RAM์ด ์๋ชจ๋์ด ํ์ํ ์์์ ๋ฉค๋ฒ๋ง ์ถ์ ํ๋๋ก ๋ฆด๋ ์ด ์ต์ ํ
- Relay๋ ๋ง๋ํ ํธ๋ํฝ์ ์ฒ๋ฆฌํ๊ธฐ ์ํด ์ฌ์ฉํ๋ BEAM ๊ธฐ๋ฐ ํ๋ก์ธ์ค
- ์๋ฒ ์๋ต์ฑ ์ ์ง
- Helper Process
- BEAM ํ๋ก์ธ์ค ๊ฐ ๋น ๋ฅธ ๋ฐ์ดํฐ ๊ณต์ ๋ฅผ ์ํ ์ธ๋ฉ๋ชจ๋ฆฌ ๋ฐ์ดํฐ๋ฒ ์ด์ค ETS ํ์ฉ
- ๋๋ฆฐ ์์
์ ๊ฒฝ์ฐ ๋น๋๊ธฐ ์์
์ ์ํด Helper Process๊ฐ ์์ฑ๋๋ค
- ex) ๊ธธ๋ ๋ง์ด๊ทธ๋ ์ด์ ์ ์ฒ๋ฆฌ
- Helper Process
- Manifold Offload
- ํฌ์์์ ๊ธธ๋์์ ๋ณ๋์ "sender" ํ๋ก์ธ์ค๋ก ๋ถ์ฐํ์ฌ ๊ธธ๋ ์์ ๋ถํ๋ฅผ ๋์ฑ ์ค์ด๊ณ ๊ธธ๋ ํ๋ก์ธ์ค๋ฅผ ๋คํธ์ํฌ ๋ฐฑํ๋ ์ ๋ก๋ถํฐ ๋ณดํธ
- Garbage Collection์ด Trickyํ๋ค
- ๋ถํ์ํ ์์
์ ์ค์ด๊ธฐ
Slack
- ์ค์๊ฐ ๋ฉ์์ง์ ์ ์ก / ์์ ์ ์ํ ์ํคํ ์ฒ ๊ตฌ์กฐ
- ํฌ๊ฒ ๋ณด๋ฉด ์ด์ ์ฃผ์ฐจ์์ ์งํํ Star / Tree ํ ํด๋ก์ง์์ ์ ์ ์๋ค
- Client, Edge Region, Main Region์ผ๋ก ํฌ๊ฒ ๊ตฌ๋ถ๋๋ค.
- Client
- ์ค์ ์ ์ ์ ํด๋ผ์ด์ธํธ (PC, Web, App)์ด ๊ตฌ๋๋๋ ๊ณต๊ฐ
- ์ ์ ์ ์ ๋ ฅ์ ๋ฐ๊ฑฐ๋ ์๋ฒ๋ก๋ถํฐ์ ๋ฉ์์ง๋ฅผ ์์ ํ๋ค
- Edge Region
- Envoy : Lyft์์ ๊ฐ๋ฐํ ๊ณ ์ฑ๋ฅ L4/L7 Proxy ์๋ฒ
- ๋ก๋๋ฐธ๋ฐ์ฑ
- TLS ์ข ๋ฃ
- ํธ๋ํฝ ๊ด์ฐฐ ๋ฐ ์ ์ด ๋ฑ
- Gateway Server
- ํด๋ผ์ด์ธํธ์ ๋ชจ๋ ์์ฒญ์ ํ ๊ณณ์ผ๋ก ๋ฐ์, ์ ์ ํ ๋ด๋ถ ์๋น์ค๋ก ์ ๋ฌํ๋ ์ค์ ํต์ ์ง์
- Slack ์์๋ Channel Server๋ก ๊ฐ๊ธฐ ์ ์ ๋ชจ๋ ์์ฒญ์ ๋ฐ๋ ์ญํ
- Envoy : Lyft์์ ๊ฐ๋ฐํ ๊ณ ์ฑ๋ฅ L4/L7 Proxy ์๋ฒ
- Main Region
- ์ค์ง์ ์ธ ๊ธฐ๋ฅ์ด ๊ตฌ๋๋๋ ๋ด๋ถ ์๋น์ค
- ์ค์ง์ ์ธ ๋ฐ์ดํฐ๊ฐ ์ ์ฅ๋๋ค
- Client
์ฐธ๊ณ ์๋ฃ
[https://velog.io/@euisuk-chung/ํ์ด์ฌ-Multiprocessing-Multithreading-์์-๋ถํ -๋ฐ-ํ ๋น](https://velog.io/@euisuk-chung/%ED%8C%8C%EC%9D%B4%EC%8D%AC-Multiprocessing-Multithreading-%EC%9E%90%EC%9B%90-%EB%B6%84%ED%95%A0-%EB%B0%8F-%ED%95%A0%EB%8B%B9)
https://blog.naver.com/n_cloudplatform/222189669084
https://medium.com/@rrakshith007/io-multiplexing-and-its-advantages-8c75584079d1
https://blog.quastor.org/p/slack-sends-millions-messages-real-time