๐ŸŒ Multiplexing NonBlocking IO ๋„คํŠธ์›Œํฌ ์•„ํ‚คํ…์ฒ˜ ์กฐ์‚ฌ - YangJJune/U-Compass GitHub Wiki

ThreadPool์˜ ํšจ์œจ์ ์ธ ๊ฐœ์ˆ˜๋ฅผ ์—ฐ๊ตฌํ•˜๋ ค ํ•œ ์ด์œ ?

  • ์‹ค์‹œ๊ฐ„ ์œ„์น˜ ๊ณต์œ ์˜ ๋น ๋ฅธ ์†๋„์™€ ํšจ์œจ์„ ์œ„ํ•œ 7์ฃผ๊ฐ„์ด์—ˆ๋‹ค.
  • ์ง€๋‚œ ์‹œ๊ฐ„์— ThreadPool์˜ ๊ฐœ์ˆ˜๊ฐ€ ๋ฌด์ž‘์ • ๋งŽ๋‹ค๊ณ  ์ข‹์€ ๊ฒƒ์ด ์•„๋‹ˆ๋ผ๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์—ˆ๊ณ , ์ด์— ๋”ฐ๋ผ ํšจ์œจ์ ์ธ Thread์˜ ๊ฐœ์ˆ˜์— ๋Œ€ํ•ด ๊ณต๋ถ€๋ฅผ ํ•˜๋˜ ์ค‘ ํฅ๋ฏธ๋กœ์šด ๋‚ด์šฉ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์—ˆ๋‹ค.
  • ๋ฐ”๋กœ Multi-Process / Multi-Thread / Multi-Plex ํ”„๋กœ๊ทธ๋ž˜๋ฐ์ด์—ˆ๋‹ค

Multi-Processing

image

  • ์—ฌ๋Ÿฌ ๊ฐœ์˜ ๋…๋ฆฝ๋œ ํ”„๋กœ์„ธ์Šค๋ฅผ ๋™์‹œ์— ์‹คํ–‰ํ•˜๋Š” ๊ฒƒ์ด๋‹ค
  • ๋”ฐ๋ผ์„œ ์‹œ์Šคํ…œ ์ž์›์„ ๋…๋ฆฝ์ ์œผ๋กœ ํ• ๋‹น๋ฐ›๋Š”๋‹ค
    • CPU ์ž์› ๋ถ„ํ• ์€ OS์— ์˜ํ•ด ์ด๋ฃจ์–ด์ง„๋‹ค
    • ๋”ฐ๋ผ์„œ ํ”„๋กœ์„ธ์Šค ๊ฐ„์˜ ๋ฐ์ดํ„ฐ ์ „๋‹ฌ์—๋Š” IPC (ํŒŒ์ดํ”„, ํ, ์†Œ์ผ“ ๋“ฑ)๊ฐ€ ํ•„์š”ํ•˜๋‹ค
  • ์ปจํ…์ŠคํŠธ ์Šค์œ„์นญ ๋ฐœ์ƒ ์‹œ ๊ต‰์žฅํžˆ ์ผ์ด ํฌ๋‹ค
    • Memory Address Space ์˜ ๋ณ€๊ฒฝ์ด ํ•„์š”ํ•˜๊ธฐ ๋•Œ๋ฌธ(๋ฉ”๋ชจ๋ฆฌ ์ฃผ์†Œ, ๋งตํ•‘, ํŽ˜์ด์ง€ ํ…Œ์ด๋ธ” ๋“ฑ)

Multi-Threading

image

  • ๋ชจ๋“  ์“ฐ๋ ˆ๋“œ๊ฐ€ ํ”„๋กœ์„ธ์Šค์˜ ๋ฉ”๋ชจ๋ฆฌ ๊ณต๊ฐ„์„ ๊ณต์œ ํ•œ๋‹ค
    • ๋”ฐ๋ผ์„œ ๋ชจ๋“  ์“ฐ๋ ˆ๋“œ๋Š” ๊ฐ™์€ ๋ฉ”๋ชจ๋ฆฌ ์˜์—ญ์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋‹ค
    • ๋ฉ”๋ชจ๋ฆฌ ๊ณต๊ฐ„์„ ๊ณต์œ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋ฐ์ดํ„ฐ ์ „๋‹ฌ์ด ์šฉ์ดํ•˜๋‹ค
  • I/O ์ž‘์—…์ด ์ง„ํ–‰๋˜๋Š” ๋™์•ˆ ๋‹ค๋ฅธ ์“ฐ๋ ˆ๋“œ์—์„œ๋Š” ์ž‘์—…์„ ์ง„ํ–‰ํ•˜๋Š” ๋“ฑ์˜ ํšจ์œจ์„ ๋ฐœํœ˜ํ•  ์ˆ˜ ์žˆ๋‹ค
  • ์ปจํ…์ŠคํŠธ ์Šค์œ„์นญ ๋ฐœ์ƒ ์‹œ ์ผ์ด ํ”„๋กœ์„ธ์Šค์— ๋น„ํ•ด ๋น„๊ต์  ์ ๋‹ค

Multi-Plexing

image

  • ์œ„ ๋„์‹๋„๋Š” select()๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ IO Multiplexing์„ ํ•˜๋Š” ํ”Œ๋กœ์šฐ๋ฅผ ๋‚˜ํƒ€๋‚ธ ๊ฒƒ์ด๋‹ค.
  • ์—„๋ฐ€ํžˆ ์ด์•ผ๊ธฐํ•˜๋ฉด ์œ„์˜ Multi-Processing, Multi-Threading๊ณผ ์ง์ ‘์ ์œผ๋กœ ์—ฎ์–ด์„œ ํ‘œํ˜„ํ•˜๊ธฐ ๋ณด๋‹ค๋Š” IO์—์„œ Multiplexing์„ ํ•  ์ˆ˜ ์žˆ๊ณ , ์ด ๋•Œ ์œ„์˜ 2๊ฐœ์˜ ๊ธฐ๋ฒ•๊ณผ ๋น„๊ตํ•˜์—ฌ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค๊ณ  ํ‘œํ˜„ํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ์ œ๋Œ€๋กœ ๋œ Multiplexing ๊ฐœ๋…์œผ๋กœ ๋“ค์–ด๊ฐ€๊ธฐ ์ „์— Synchronous, Asynchronous, Blocking IO์™€ Non-blocking IO์— ๋Œ€ํ•ด ์•Œ์•„๋ณด๋„๋ก ํ•œ๋‹ค.

Synchronous IO - ๋™๊ธฐ

image

  • ๋ชจ๋“  ์ž‘์—…์ด ์ผ๋ จ์˜ ์ˆœ์„œ๋ฅผ ๋”ฐ๋ฅธ๋‹ค โ†’ ์ž‘์—…์˜ ์ˆœ์„œ ๋ณด์žฅ
  • ์ž‘์—… ์™„๋ฃŒ๋ฅผ user space์—์„œ ํŒ๋‹จํ•œ๋‹ค
  • ์ผ๋ จ์˜ pipeline์„ ์œ ์ง€ํ•˜๋Š” ๊ตฌ์กฐ์—์„œ ํšจ์œจ์ ์ด๋‹ค

Asynchronous IO

image

  • kernel์— I/O ์ž‘์—…์„ ์š”์ฒญํ•ด๋‘๊ณ  ๋‹ค๋ฅธ ์ž‘์—…์„ ์ง„ํ–‰ํ•œ๋‹ค โ†’ ์ž‘์—…์˜ ์ˆœ์„œ ๋ณด์žฅ X
  • ์ž‘์—… ์™„๋ฃŒ๋ฅผ kernel space์—์„œ ํ†ต๋ณดํ•œ๋‹ค
  • ๊ฐ ์ž‘์—…์ด ๋…๋ฆฝ์ ์ด๊ฑฐ๋‚˜, ์ž‘์—…๋ณ„ ์ง€์—ฐ์ด ํฐ ๊ฒฝ์šฐ ํšจ์œจ์ ์ด๋‹ค

Blocking

  • ์š”์ฒญํ•œ ์ž‘์—…์ด ๋ชจ๋‘ ์™„๋ฃŒ๋  ๋•Œ๊นŒ์ง€ ๊ธฐ๋‹ค๋ ธ๋‹ค๊ฐ€ ์™„๋ฃŒ๋  ๋•Œ ์‘๋‹ต๊ณผ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ˜ํ™˜๋ฐ›๋Š”๋‹ค.
  • ์š”์ฒญํ•œ ์ž‘์—… ๊ฒฐ๊ณผ๋ฅผ ๊ธฐ๋‹ค๋ฆฐ๋‹ค.

Non-blocking

  • ์ž‘์—… ์š”์ฒญ ์ดํ›„ ๊ฒฐ๊ณผ๋Š” ๋‚˜์ค‘์— ํ•„์š”ํ•  ๋•Œ ์ „๋‹ฌ๋ฐ›๋Š”๋‹ค.
  • ์š”์ฒญํ•œ ์ž‘์—… ๊ฒฐ๊ณผ๋ฅผ ๊ธฐ๋‹ค๋ฆฌ์ง€ ์•Š๋Š”๋‹ค.

IBM I/O Model

image

  • ํ‘œ๋ฅผ ๋ณด๋Š” ๋ฒ•์€ โ€œ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

image

Non-Blocking I/O

image

I/O Multiplexing

image

  • ํ”„๋กœ์„ธ์Šค์—์„œ ํŠน์ • ํŒŒ์ผ์— ์ ‘๊ทผํ•  ๋•Œ๋Š” ํŒŒ์ผ ๋””์Šคํฌ๋ฆฝํ„ฐ(์ดํ•˜ 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)
  • Poll

    • Select์˜ ๊ฐœ์„  ๋ฒ„์ „
      • FD ๊ฐœ์ˆ˜ ์ œํ•œ ์—†์Œ
      • ์—ฌ์ „ํžˆ ๋งค๋ฒˆ FD ๋ฆฌ์ŠคํŠธ๋ฅผ ์ปค๋„์— ์ „๋‹ฌํ•ด์•ผํ•˜๋ฏ€๋กœ ๊ฐ์‹œ ๋Œ€์ƒ์ด ๋Š˜์–ด๋‚ ์ˆ˜๋ก ๋А๋ ค์ง O(N)
  • epoll

    • Linux 2.6 ์ดํ›„ ๋„์ž…๋œ ๊ณ ์„ฑ๋Šฅ ์ด๋ฒคํŠธ ๊ธฐ๋ฐ˜ I/O ๋ฉ€ํ‹ฐํ”Œ๋ ‰์‹ฑ ๋ฉ”์ปค๋‹ˆ์ฆ˜
    • ์ด๋ฒคํŠธ ๊ธฐ๋ฐ˜์œผ๋กœ ๋™์ž‘ํ•˜๋ฉฐ, ๋น„๋™๊ธฐ์ ์œผ๋กœ ์—ฐ๊ฒฐ์„ ์ฒ˜๋ฆฌํ•œ๋‹ค. O(1)
      • ๋†’์€ ์„ฑ๋Šฅ
      • ํšจ์œจ์ ์ธ ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ
      • ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ โ†’ I/O๊ฐ€ ์™„๋ฃŒ๋œ ์†Œ์ผ“๋งŒ ์ฒ˜๋ฆฌ
  • kqueue

    • ์ปค๋„ ๋‚ด์˜ ์ด๋ฒคํŠธ ํ๋ฅผ ๊ด€๋ฆฌํ•˜๋ฉฐ, ์ด๋ฒคํŠธ ๊ธฐ๋ฐ˜์œผ๋กœ ๋™์ž‘
    • epoll๊ณผ ์œ ์‚ฌํ•˜๊ฒŒ ๋น„๋™๊ธฐ I/O ๋ชจ๋ธ์„ ๊ตฌํ˜„ํ•˜์—ฌ, ์—ฐ๊ฒฐ๋œ ์†Œ์ผ“์˜ ์ด๋ฒคํŠธ๋ฅผ ๊ฐ์‹œํ•˜๊ณ  ํ•ด๋‹น ์ด๋ฒคํŠธ๊ฐ€ ๋ฐœ์ƒํ•  ๋•Œ ์ฒ˜๋ฆฌํ•œ๋‹ค
    • BSD ๊ณ„์—ด ์šด์˜์ฒด์ œ์—์„œ๋งŒ ์‚ฌ์šฉ ๊ฐ€๋Šฅ

Asynchronous I/O

image

  • 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)

image

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()

image

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()

image

์œ ์‚ฌํ•œ ์„œ๋น„์Šค์˜ ๊ตฌํ˜„ ์‚ฌ๋ก€

Discord

  • ์‹ค์‹œ๊ฐ„ ์Œ์„ฑ/๋ฉ”์‹œ์ง€ ์„œ๋น„์Šค
  • ํด๋ผ์ด์–ธํŠธ-์„œ๋ฒ„ ๋„คํŠธ์›Œํ‚น ์•„ํ‚คํ…์ฒ˜ ์‚ฌ์šฉ
    • 1000๋ช…์ด ์ดˆ๊ณผํ•˜๋ฉด P2P ์•„ํ‚คํ…์ฒ˜๊ฐ€ ๋น„์šฉ์ด ๋งŽ์ด ๋“ค๊ธฐ ๋•Œ๋ฌธ\

image

  • ๊ฐ ๋””์Šค์ฝ”๋“œ ์ปค๋ฎค๋‹ˆํ‹ฐ๋ฅผ Guild๋ผ ์นญํ•œ๋‹ค
  • ๊ทธ๋ฆฌ๊ณ  Guild Process๊ฐ€ Guild์˜ ์กฐ์œจ๊ณผ ๋ผ์šฐํŒ…์„ ๋‹ด๋‹นํ•œ๋‹ค
  • ๋ชจ๋“  ์‚ฌ์šฉ์ž๋Š” Session Process๋ฅผ ๊ฐ–๊ณ , Guild Proccess๋Š” ์ƒˆ ๋ฉ”์‹œ์ง€, ์ด๋ฒคํŠธ ๋˜๋Š” ์—…๋ฐ์ดํŠธ๋ฅผ ๋ฐ›์œผ๋ฉด ํ•ด๋‹น ์ •๋ณด๋ฅผ ๊ด€๋ จ Session Process๋กœ ์ „๋‹ฌํ•œ๋‹ค
    • Session Process๋Š” ํ•ด๋‹น ์—…๋ฐ์ดํŠธ๋ฅผ Discord ํด๋ผ์ด์–ธํŠธ๋กœ ํ‘ธ์‹œํ•œ๋‹ค
    • ์ด๋Š” ๋งŽ์€ ์‚ฌ์šฉ์ž์˜ ๋ถ€ํ•˜๊ฐ€ ๊ฑธ๋ฆด ์ˆ˜๋ก Guild Process์— ๋” ํฐ ๋ถ€๋‹ด์„ ์ฃผ์—ˆ๋‹ค
      • BEAM์ด ํšจ๊ณผ์ ์ด๋ผ๊ณ ๋Š” ํ•˜๋‚˜ ๊ถ๊ทน์ ์ธ ์ˆ˜๋‹จ์ด ๋˜์ง€๋Š” ๋ชปํ•˜์˜€๋‹ค๊ณ  ํ•œ๋‹ค

image

  • ๊ทธ๋ž˜์„œ ์ตœ์ ํ™”๋ฅผ ์ง„ํ–‰ํ–ˆ๋‹ค๊ณ  ํ•œ๋‹ค
    • ๋ถˆํ•„์š”ํ•œ ์ž‘์—…์„ ์ค„์ด๊ธฐ
      • ex) ์‚ฌ์šฉ์ž๊ฐ€ ๊ธธ๋“œ๋ฅผ ์—ด ๋•Œ๊นŒ์ง€ ์ฒ˜๋ฆฌ ๋ฐ ๋ฐ์ดํ„ฐ ์ „์†ก์„ skipํ•œ๋‹ค
    • ๋ฆด๋ ˆ์ด ์ตœ์ ํ™”
      • Relay๋Š” ๋ง‰๋Œ€ํ•œ ํŠธ๋ž˜ํ”ฝ์„ ์ฒ˜๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉํ•˜๋Š” BEAM ๊ธฐ๋ฐ˜ ํ”„๋กœ์„ธ์Šค
        • ex) ๋ชจ๋“  ์œ ์ €ํ•œํ…Œ ๋ฉ”์‹œ์ง€ ๋ณด๋‚ด๊ธฐ
        • ์ด๋ฅผ ์ฒ˜๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด ์—ฌ๋Ÿฌ ํ”„๋กœ์„ธ์Šค๋ฅผ ๋„์›Œ์„œ ์ž‘์—…์„ ๋ถ„์‚ฐ
        • ๊ทธ๋Ÿฌ๋‚˜ Relay ์ž์ฒด์— ๋ง‰๋Œ€ํ•œ RAM์ด ์†Œ๋ชจ๋˜์–ด ํ•„์š”ํ•œ ์†Œ์ˆ˜์˜ ๋ฉค๋ฒ„๋งŒ ์ถ”์ ํ•˜๋„๋ก ๋ฆด๋ ˆ์ด ์ตœ์ ํ™”
    • ์„œ๋ฒ„ ์‘๋‹ต์„ฑ ์œ ์ง€
      • Helper Process
        • BEAM ํ”„๋กœ์„ธ์Šค ๊ฐ„ ๋น ๋ฅธ ๋ฐ์ดํ„ฐ ๊ณต์œ ๋ฅผ ์œ„ํ•œ ์ธ๋ฉ”๋ชจ๋ฆฌ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ETS ํ™œ์šฉ
        • ๋А๋ฆฐ ์ž‘์—…์˜ ๊ฒฝ์šฐ ๋น„๋™๊ธฐ ์ž‘์—…์„ ์œ„ํ•ด Helper Process๊ฐ€ ์ƒ์„ฑ๋œ๋‹ค
          • ex) ๊ธธ๋“œ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜์˜ ์ฒ˜๋ฆฌ
    • Manifold Offload
      • ํŒฌ์•„์›ƒ์„ ๊ธธ๋“œ์—์„œ ๋ณ„๋„์˜ "sender" ํ”„๋กœ์„ธ์Šค๋กœ ๋ถ„์‚ฐํ•˜์—ฌ ๊ธธ๋“œ ์ž‘์—… ๋ถ€ํ•˜๋ฅผ ๋”์šฑ ์ค„์ด๊ณ  ๊ธธ๋“œ ํ”„๋กœ์„ธ์Šค๋ฅผ ๋„คํŠธ์›Œํฌ ๋ฐฑํ”„๋ ˆ์…”๋กœ๋ถ€ํ„ฐ ๋ณดํ˜ธ
      • Garbage Collection์ด Trickyํ–ˆ๋‹ค

Slack

  • ์‹ค์‹œ๊ฐ„ ๋ฉ”์‹œ์ง€์˜ ์ „์†ก / ์ˆ˜์‹ ์„ ์œ„ํ•œ ์•„ํ‚คํ…์ฒ˜ ๊ตฌ์กฐ
  • ํฌ๊ฒŒ ๋ณด๋ฉด ์ด์ „ ์ฃผ์ฐจ์—์„œ ์ง„ํ–‰ํ•œ Star / Tree ํ† ํด๋กœ์ง€์ž„์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค

image

  • Client, Edge Region, Main Region์œผ๋กœ ํฌ๊ฒŒ ๊ตฌ๋ถ„๋œ๋‹ค.
    • Client
      • ์‹ค์ œ ์œ ์ €์˜ ํด๋ผ์ด์–ธํŠธ (PC, Web, App)์ด ๊ตฌ๋™๋˜๋Š” ๊ณต๊ฐ„
      • ์œ ์ €์˜ ์ž…๋ ฅ์„ ๋ฐ›๊ฑฐ๋‚˜ ์„œ๋ฒ„๋กœ๋ถ€ํ„ฐ์˜ ๋ฉ”์‹œ์ง€๋ฅผ ์ˆ˜์‹ ํ•œ๋‹ค
    • Edge Region
      • Envoy : Lyft์—์„œ ๊ฐœ๋ฐœํ•œ ๊ณ ์„ฑ๋Šฅ L4/L7 Proxy ์„œ๋ฒ„
        • ๋กœ๋“œ๋ฐธ๋Ÿฐ์‹ฑ
        • TLS ์ข…๋ฃŒ
        • ํŠธ๋ž˜ํ”ฝ ๊ด€์ฐฐ ๋ฐ ์ œ์–ด ๋“ฑ
      • Gateway Server
        • ํด๋ผ์ด์–ธํŠธ์˜ ๋ชจ๋“  ์š”์ฒญ์„ ํ•œ ๊ณณ์œผ๋กœ ๋ฐ›์•„, ์ ์ ˆํ•œ ๋‚ด๋ถ€ ์„œ๋น„์Šค๋กœ ์ „๋‹ฌํ•˜๋Š” ์ค‘์•™ ํ†ต์ œ ์ง€์ 
        • Slack ์—์„œ๋Š” Channel Server๋กœ ๊ฐ€๊ธฐ ์ „์— ๋ชจ๋“  ์š”์ฒญ์„ ๋ฐ›๋Š” ์—ญํ• 
    • Main Region
      • ์‹ค์งˆ์ ์ธ ๊ธฐ๋Šฅ์ด ๊ตฌ๋™๋˜๋Š” ๋‚ด๋ถ€ ์„œ๋น„์Šค
      • ์‹ค์งˆ์ ์ธ ๋ฐ์ดํ„ฐ๊ฐ€ ์ €์žฅ๋œ๋‹ค

์ฐธ๊ณ ์ž๋ฃŒ

https://stackoverflow.com/questions/51635655/multiplexing-vs-multithreading-on-a-tcp-distributed-system

[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://www.linkedin.com/pulse/choice-between-multithreading-multi-processing-when-use-deepak-kumar-uxyvf

https://blog.naver.com/n_cloudplatform/222189669084

https://medium.com/@rrakshith007/io-multiplexing-and-its-advantages-8c75584079d1

https://discord.com/blog/how-discord-handles-push-request-bursts-of-over-a-million-per-minute-with-elixirs-genstage

https://blog.quastor.org/p/slack-sends-millions-messages-real-time

https://slack.engineering/real-time-messaging/