본문으로 건너뛰기

다중 접속 서버의 구현 방식

1. 블로킹 TCP 서버의 한계​

1.1 문제점​

  • 다수의 클라이언트가 연결하는 경우에는 문제가 발생합니다.
  • 처음 연결한 클라이언트가 연결을 종료하기 전까지는 다른 클라이언트의 연결은 listen 큐에 들어가 대기해야 합니다.
  • 따라서 다수의 요청을 처리할 수 없다는 문제가 있습니다.

1.2 해결 방안 개요​

다중 접속 서버는 다수의 클라이언트가 동시에 접속할 수 있는 서버입니다. 구현 방식은 크게 다음과 같습니다:

  • 멀티 프로세싱: fork() 함수를 사용해 자식 프로세스를 생성하는 방식
  • 멀티 스레딩: 스레드를 사용해 다수의 클라이언트 요청을 처리하는 방식
  • I/O 멀티플렉싱: select() 함수를 사용해 다수의 소켓을 모니터링하고, 이벤트가 발생한 소켓을 처리하는 방식

2. 멀티 프로세싱 기반 다중 접속 서버​

2.1 동작 방식​

  1. 연결 수락 과정
    • 부모 프로세스는 리스닝 소켓으로 accept 함수를 호출해서 연결 요청을 수락합니다.
    • 이때 얻는 소켓의 파일 디스크립터(클라이언트와 연결된 연결 소켓)를 자식 프로세스를 생성해 넘겨줍니다.
  2. 서비스 제공
    • 자식 프로세스는 전달받은 파일 디스크립터를 바탕으로 서비스를 제공합니다.
    • 핵심은 하나의 연결이 생성될 때마다 프로세스를 생성해서 해당 클라이언트에 대해 서비스를 제공하는 방식입니다.

2.2 장점​

  • 프로그램 흐름이 단순하기 때문에 이해하기 쉽습니다.
  • 안정적인 동작이 가능합니다. 운영 체제에서 프로세스는 서로 독립된 실행 객체로 존재합니다.
  • 서로 독립된 메모리 공간을 갖고 각 프로세스는 서로 영향을 미치지 않기 때문에 독립적으로 수행이 가능합니다.

2.3 단점​

  • 프로세스 복사가 필요하기 때문에 리소스를 많이 사용합니다.
  • 병렬로 처리해야 하는 수만큼 프로세스를 생성해야 합니다.
  • 서로 다른 독립적인 메모리 공간을 갖기 때문에 프로세스간 정보 교환이 어렵습니다.

3. 멀티 스레딩 기반 다중 접속 서버​

3.1 개요​

Blocking 소켓에서 다중 클라이언트의 접속 처리를 하지 못하는 문제점을 해결하기 위해서 등장한 모델이 연결된 클라이언트별로 각각 스레드를 할당하는 방식입니다.

3.2 동작 방식​

  1. 연결 수락
    • 메인 스레드는 리스닝 소켓으로 accept 함수를 호출해서 연결 요청을 수락합니다.
    • 이때 얻는 소켓의 파일 디스크립터(클라이언트와 연결된 연결 소켓)를 별도 워커 스레드를 생성해 넘겨줍니다.
  2. 서비스 제공
    • 워커 스레드는 전달받은 파일 디스크립터를 바탕으로 서비스를 제공합니다.
    • 핵심은 연결이 하나 생성될 때마다 프로세스가 아닌 스레드를 생성해서 해당 클라이언트에게 서비스를 제공하는 것입니다.
  3. 스레드 풀 활용
    • 매번 스레드를 생성하는 것이 아니라 미리 생성해 놓은 스레드 풀에서 스레드를 가져와 사용할 수도 있습니다.

3.3 장점​

  • 프로세스 복사 비용보다 스레드 생성 비용이 적습니다.
  • 서로 공유하는 메모리가 있기 때문에 스레드간 정보 교환이 쉽습니다.

3.4 단점​

  • 하나의 프로세스 내에 다수의 스레드가 존재하기 때문에 하나의 스레드에서 발생한 문제가 프로세스 전체에 영향을 미쳐 나머지 다수의 스레드에 영향을 끼칠 수 있습니다.
  • 멀티프로세싱 방식보다는 비용이 적게 들지만 스레드 관리에 여전히 많은 리소스가 필요합니다.
  • 일정 크기의 스레드를 생성해 풀로 관리하며 운영할 수 있지만 요청마다 스레드를 무한정 생성할 수 없기 때문에 많은 수의 요청을 동시에 처리할 수 없습니다(C10k problem을 해결하지 못합니다).
  • 커넥션별로 스레드를 생성하기때문에 스레드가 기하급수적으로 많아질 수도 있습니다. 이때 스레드간의 컨텍스트 스위칭 하는 과정에서 CPU 시간과 리소스를 소모합니다.
  • 다중 연결을 처리할 수 있는 가장 기본적인 서버 구조이나, 요청이 증가하면 선형적으로 서버의 부하가 걸리는 구조라는 치명적인 문제가 있습니다.

4. 멀티플렉싱 기반 다중 접속 서버​

4.1 개요​

  • 커널(kernel)에서는 하나의 스레드가 여러 개의 소켓(파일)을 핸들링할 수 있는 select, poll, epoll, io_uring과 같은 시스템 콜(system call)을 제공하고 있습니다.

4.2 구현 방식​

  • Java에서는 NIO(New I/O) 패키지를 통해 멀티플렉싱 기반의 다중 접속 서버를 구현할 수 있습니다.
  • 하나의 스레드로 여러 연결을 동시에 처리할 수 있어 자원 효율성이 높습니다.

4.3 장점​

  • 단일 스레드로 다중 연결 처리 가능
  • C10k problem 해결
  • 컨텍스트 스위칭 최소화
  • 시스템 자원 효율적 사용

4.4 단점​

  • 구현 복잡도가 높음
  • CPU 집약적 작업에 취약
  • 비동기 프로그래밍 모델 적응 필요