I/O Multiplexing (입출력 다중화)

kafkaaaa·2023년 9월 27일
1
post-thumbnail

하나의 프로세스로 여러 디바이스를 처리할 수 있다면 좀 더 간단하게 해결할 수 있다는 생각에서 출발한 개념이 I/O Multiplexing(입출력 다중화) 이며,
Linux에서는 select, poll 같은 system call 함수를 지원한다.

I/O 작업은 user space에서 직접 수행할 수 없고,
user process가 kernel에 I/O 작업을 요청하고 응답을 받는 구조이다.
kernel로부터 응답을 어떤 순서로 받는지, (동기/비동기) 혹은
기다렸다가 받는지 (blocking / non-blocking)에 따라 여러 모델로 분류된다.


📌 Multiplexing & Demultiplexing

- Multiplexing (다중화)

  • 하나의 고속 통신 회선을 다수의 단말기가 공유할 수 있도록 하는 것.

  • 다수의 프로세스를 생성하지 않고도 여러 클라이언트에게 서비스를 제공할 수 있는 기술.

  • 다수의 신호들을 단일 데이터 링크로 동시에 전송하게 하는 기술.

  • MUX (Multiplexer)

    • 다수의 스트림을 하나의 스트림으로 결합하는 기기.
    • 여러 입력 中 하나를 선택해 출력으로 내보내는 논리 회로.
  • DEMUX (Demultiplexer)

    • 하나의 스트림을 다수의 스트림으로 분리하는 기기.
    • 하나의 입력을 여러 개의 출력 中 하나를 선택하여 내보내는 논리 회로.
  • Transport(전송)계층에서 다중화란, Application 계층의 여러 소켓에서 전송되는 데이터를 하나로 모으는 것.

    • 전송 계층의 Segment, 네트워크 계층의 Packet
  • Demultiplexing (역다중화)는 반대로, 전송 받은 Segment를 적절한 소켓에 분배해 주는 것.



📌 I/O Multiplexing

  • 입출력 다중화

  • 하나의 통신 채널을 통해서 둘 이상의 데이터를 전송하기 위한 기술.

  • 물리적 장치의 효율성을 높이기 위해,
    최소한의 물리적 요소만을 이용하여 최대한의 데이터를 전달하기 위해 사용되는 기술.

  • 각 파일을 처리할 때 마다 개별 I/O 통로를 만들어 프로세스(스레드)를 만들면 IPC, 동기화, 스레드, Context Switching 등의 Overhead 단점.

  • 따라서 하나의 채널을 통해 여러 데이터를 송/수신 하여 프로세스 개수를 최소한으로 유지하는 I/O Multiplexing.

  • 💡 I/O Multiplexing이 필요한 경우

    • TCP Client가 다수의 Descriptor를 처리해야 하는 경우
    • TCP Client가 다수의 Socket을 동시에 처리해야 하는 경우
    • TCP Server가 Listening Socket과 Connected Socket을 모두 처리해야 하는 경우
    • Server가 TCP와 UDP를 동시에 지원해야 하는 경우
    • Server가 여러 서비스 혹은 프로토콜을 처리해야 하는 경우

📌 I/O Models

  • UNIX에서 I/O Models은 크게 5가지로 구분

  • #1. Blocking

    • 가장 기본적인 형태 (Socket의 Default Type)
    • recvfrom() 으로 데이터를 받을 때 까지 계~속 작업을 block하고 기다림.
    • read()시에 Data가 입력될 때 까지 해당 pthread(POSIX-thread)를 block시키고 scheduling 수행
  • #2. Non-blocking

    • 각각의 Server가 한 가지 일만 수행(최소한의 I/O만 수행)하고,
    • 거의 모든 자원을 특정 Job이 독점하는 경우에 적합


  • #3. I/O Multiplexing

    • select() 함수를 호출해서 여러 소켓 중 data ready 상태가 된 소켓이 있을 때 까지 대기.

    • select() 결과로 read() 함수를 호출할 수 있는 소켓의 목록이 반환되면 해당 소켓에 대해 read() 함수 호출.

    • 여러 소켓을 동시에 확인하여 하나 이상의 소켓이 준비될 때 까지 대기.

    • (개념적으로) 여러 스레드가 Blocking I/O를 실행하는 것으로 구현되어 있음

    • 📌 select ( )

      • I/O Multiplexing 서버를 구현할 때 사용하는 가장 대표적인 함수
      • 이벤트(입출력, 예외)별로 감시할 파일들을 fd_set 이라는 File State Table (=File Descriptor 배열)에 등록하고 , 이 중에서 이벤트 발생 시 fd_set을 확인하는 방식으로 작동함 (0=변화X, 1=변화O)
      • FD 배열 중 입출력이 준비된 파일이 발생하면 FD의 수를 반환하고, 해당 파일에 대해 입출력 수행.
      • 즉, 한 곳에 여러 FD를 모아놓고 상태를 계속 관찰하는 함수
      #include <sys/select.h>
      int select (int nfds, fd_set *readset, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
      • nfds: FD 개수

      • readfds: 파일에 읽을 데이터가 있는지 관심있는 파일 목록(fd_set)

      • writefds: 파일에 데이터를 쓸 수 있는지 여부에 관심있는 파일 목록(fd_set)

      • exceptfds: 파일에 예외가 발생했는지 여부에 관심있는 파일 목록(fd_set)

      • timeout: 무한 대기 상태를 막기 위함. (NULL=무한정 block, 0=polling)

      • return값

        • 1이상: 이벤트가 발생한 FD 개수
        • 0: timeout
        • -1: error

        📌 fd_set


        fd_set은 위 그림과 같이 0과 1로된 bit 배열이며 1이면 해당 FD(파일)이 읽을 데이터가 있다는 표시.

        📌 <fd_set을 조작하는 매크로 함수들>

        • void FD_ZERO(fd_set *set) : fd_set의 모든 비트를 0으로 초기화 시킴.
        • void FD_SET(int fd, fd_set *set) : fd_set에 fd를 추가 (감시 대상 추가)
        • void FD_CLR(int fd, fd_set *set) : fd_set에서 fd 제거 (감시 대상에서 제거)
        • int FD_ISSET(int fd, fd_set *set) : fd_set에 있는 fd가 준비되었는지 확인 (비트 1인지 확인)

  • 😊 장점

    • 단일 프로세스(스레드)에서 여러 파일의 입출력 처리가 가능하여 동시에 수만 개의 커넥션도 처리 가능.
      이를 바탕으로 🧷C10k problem을 해결할 수 있음
    • POSIX 표준을 따르기 때문에 -> 이식성이 좋음
    • client 요청마다 처리하기 위한 별도의 thread를 만들지 않아 context switching 하는 overhead 발생 X
  • 😥 단점

    • select 함수를 호출해서 전달된 정보는 커널에 등록되지 않은 것이라서 호출할 때 마다 매번 관련 정보를 전달해야 함.
    • select 함수의 리턴값이 이벤트가 발생한 FD의 '개수' 이기 때문에 어떤 FD에서 이벤트가 발생했는지 확인하려면 fd_set 테이블 전체를 검사해야 함.
    • 검사할 수 있는 FD 개수에 제한이 있음 (최대 1024개)
    • select 함수를 호출할 때 마다 데이터를 복사해야 함
      (select 함수를 호출한 후 이벤트를 처리할 때 fd_set 테이블 변경이 필요하기 때문에 미리 복사가 필요함)



  • #4. Signal-Driven I/O

    • SIGIO 시그널을 이용한 방법
    • I/O가 가능해진 시점에 시그널을 발생시키고, I/O를 요청한 Process, Thread가 Catching하는 방식
  • #5. Asynchronous I/O

    • POSIX의 aio()를 이용한 방법
    • Real TIme Application을 지원하고자 만들어진 방법
    • 시스템 간 호환성이 가장 떨어지는 방법.
    • 프로그래밍적 장점, 퍼포먼스적 장점이 적음.

  • Synchronous I/O Model

    • Blocking, Nonblocking, I/O Multiplexing, Signal-Driven
    • I/O 작업이 끝날 때 까지 read() 계열 System Call에 의해 해당 User Process가 Block 됨.
  • Asynchronous I/O Model

    • I/O를 요청한 User Process를 Block시키지 않음.

👀 더 알아볼 것

  • poll

    • poll도 select와 마찬가지로 Multiplexing을 구현하는 System Call.
    • 작동 원리는 select와 유사하지만 차이점은..
      • select방식 처럼 표준 입력,출력,에러를 따로 감시할 필요가 없다.
      • select에서는 timeval 구조체를 이용하여 timeout 값을 설정하지만, poll 방식은 다른 구조체 필요 X
      • (단점) 일부 UNIX 시스템은 poll 지원 X
  • epoll (event poll)

    • select와 poll의 단점을 해결할 수 있는 Multiplexing 지원
    • kernel에 관찰 대상에 대한 정보를 한 번만 전달하고, 대상의 범위나 내용에 변경이 있을 때만 알려줌
    • 비슷한 역할을 하는 System Call로 🧷Windows의 IOCP, FreeBSD의 Kqueue가 있음.
    • select, poll과 차이점은..
      • 상태 변화를 확인하기 위한 전체 FD대상 반복분 필요 X
      • 커널에서 상태 정보를 유지하기 때문에 관찰 대상의 정보(fd_set)를 매번 전달할 필요 X
      • (단점) Linux의 select 기반 서버를 -> Windows의 select 기반 서버로 변경하는 것은 비교적 간단하지만,
        Linux의 epoll 기반 서버를 -> Windows의 IOCP 기반으로 변경하는 것은 어렵다.


Ref

https://ko.wikipedia.org/wiki/%EB%8B%A4%EC%A4%91%ED%99%94_(%ED%86%B5%EC%8B%A0)
https://engineering.linecorp.com/ko/blog/do-not-block-the-event-loop-part1
https://www.joinc.co.kr/w/Site/system_programing/File/select
https://reakwon.tistory.com/117
https://dad-rock.tistory.com/412
https://incredible-larva.tistory.com/entry/IO-Multiplexing-%ED%86%BA%EC%95%84%EB%B3%B4%EA%B8%B0-1%EB%B6%80
https://plummmm.tistory.com/68
https://www.techtarget.com/searchnetworking/definition/multiplexing
https://dev-nicitis.tistory.com/26

profile
일모도원

0개의 댓글

관련 채용 정보