• 서버는 클라이언트에 의해 입력과 출력 처리를 많이 진행하게 된다

  • 이에, 입력 출력 처리를 효율적으로 사용할 수 있도록 돕는 것이 IOCP 이다.

  • 아래는 IOCP를 이해하기 위한 기초 개념들을 정리해 두었다.

입력 및 출력 I/O 개념

  • 컴퓨터와 같은 정보 처리 시스템과 다른 컴퓨터 시스템, 주변 장치 또는 인간 작업자와 같은 외부 세계 간의 통신을 지칭함

  • I/O란 서로 다른 두 물체 간 정보를 전송하는 것

image

  • 파일 버퍼링 : 버퍼링되지 않은 파일 입출력(I/O)의 애플리케이션 제어에 대한 고려 사항
    ( 버퍼링되지 않은 파일 입출력(I/O) : 데이터를 읽거나 쓸 때 별도의 메모리 버퍼를 사용하지 않고 직접적으로 파일에 접근하는 방식 )

  • 파일 캐싱 : Windows는 디스크에서 읽은 파일 데이터와 디스크에 쓴 파일 데이터를 캐시함 ( 캐시 : 컴퓨터 내부의 임시 저장 공간으로, 데이터나 연산 결과를 저장하여 반복적인 데이터 접근 시 성능을 향상시키는 기술 )

  • 동기 및 비동기 I/O : 입력/출력(I/O) 동기화에는 동기 I/O와 비동기 I/O의 두 가지 유형이 있음
    ( 비동기 I/O는 오버랩(Overlapped) I/O라고도 함 )

  • 보류 중인 I/O 작업 취소 : 느리거나 차단된 I/O 요청을 사용자가 취소할 수 있도록 하면 애플리케이션의 유용성과 견고성이 향상될 수 있음

  • 경고 가능한 I/O : 애플리케이션 스레드가 경고 가능한 상태에 있을 때만 비동기 I/O 요청을 처리하는 방법

  • I/O 완료 포트(IOCP) : 멀티프로세서 시스템에서 여러 개의 비동기 I/O 요청을 처리하기 위한 효율적인 스레딩 모델
    ( 멀티프로세서는 한 컴퓨터 시스템 내에서 두 개 이상의 CPU가 장착되어 있는 구조를 말함 )

동기 및 비동기 I/O

image

  • 입력/출력(I/O) 동기화에는 동기 I/O와 비동기 I/O의 두 가지 유형이 있음
    (비동기 I/O는 중첩 I/O(Overlapped I/O)라고도 불림)

  • 동기 파일 I/O에서 스레드는 I/O 작업을 시작하고 I/O 요청이 완료될 때까지 즉시 대기 상태에 들어감

  • 비동기 파일 I/O를 수행하는 스레드는 적절한 함수를 호출하여 커널에 I/O 요청을 보냄

  • 요청이 커널에 의해 수락되면 호출 스레드는 커널이 스레드에 I/O 작업이 완료되었음을 알릴 때까지 다른 작업을 계속 처리

  • I/O 요청이 많은 시간이 걸릴 것으로 예상되는 상황에서 비동기 I/O는 일반적으로 처리 효율성을 최적화하는 좋은 방법
    (예: 대규모 데이터베이스의 새로 고침 또는 백업 또는 느린 통신 링크)

  • 빠른 I/O 작업의 경우 커널 I/O 요청과 커널 신호를 처리하는 오버헤드로 인해 비동기 I/O가 덜 유익할 수 있으며, 특히 많은 빠른 I/O 작업을 해야 하는 경우 더욱 그럼

커널 (kernel)

image

  • 커널은 운영체제 중 항상 메모리에 올라가 있는 운영체제의 핵심 부분

  • 하드웨어와 응용 프로그램 사이에서 인터페이스를 제공하는 역할을 하며 컴퓨터 자원들을 관리하는 역할

  • 스스로 실행되는 프로세스가 아니라 호출되어 실행되어지는 단순한 함수/데이터의 집합

스레드 (Thread)

image

  • 스레드란 프로그램(프로세스) 실행의 단위이며, 하나의 프로세스는 여러개의 스레드로 구성이 가능

  • 하나의 프로세스를 구성하는 스레드들은 프로세스에 할당된 메모리, 자원 등을 공유함

  • 프로세스와 같이 실행, 준비, 대기 등의 실행 상태를 가지며, 실행 상태가 변할때마다 스레드 문맥교환(context switching)을 수행

  • 스레드별로 자신만의 스택과 레지스터를 가짐

스레드 풀링(Thread Pooling)

image

  • 스레드 풀은 애플리케이션의 비동기 작업을 효과적으로 실행하기 위한 스레드 모음이며, 스레드 풀의 이러한 스레드는 작업자(Worker) 스레드라 칭함

  • 스레드 풀링이란 할당된 일을 마친 스레드를 소멸시키지 않고, 스레드 풀에 저장해 뒀다가 필요할 때 다시 꺼내 쓰는 개념
    ( 스레드의 생성과 소멸은 시스템에 많은 부담을 줌 )

  • 애플리케이션은 스레드 풀을 사용하여 애플리케이션 스레드 수를 줄이고 작업자 스레드를 관리함

  • 작업 처리에 사용되는 스레드를 제한된 개수만큼 정해 놓고 작업 대기열(Task Queue)에 들어오는 작업들을 하나씩 스레드가 맡아 처리하는 것

문맥 교환(Context Switching)

  • 프로그래밍에서 문맥(Context)(동작, 작업들의 집합)을 (정의, 관리, 실행)하도록 하는 (최소한의 상태, 재료, 속성)을 포함하는 (객체, 구조체, 정보)를 뜻함

  • 프로세스 또는 스레드 의 상태를 저장하여 나중에 복원하고 실행을 재개할 수 있도록 한 다음, 이전에 저장된 다른 상태를 복원하는 작업으로, 이를 통해 여러 프로세스가 단일 중앙 처리 장치 (CPU)를 공유할 수 있음

  • 한 프로세스에서 다른 프로세스로 전환하려면 레지스터와 메모리 맵을 저장하고 로드하고,
    다양한 테이블과 목록을 업데이트하는 등 관리를 수행하는 데 일정 시간이 필요함

IOCP(Input/Ouptput Completion Port)

  • Windows NT 버전 3.5 이상, AIX 및 Solaris 10 이상의 운영 체제 에서 지원하는 기능

  • 소켓이나 파일의 입출력(I/O)을 최소한의 스레드를 사용해서 처리하는 기법

  • IOCP는 스레드 풀링(Thread Pooling) + 비동기 I/O(=Overlapped I/O)와 같은 개념들을 이용해서 작동

  • 커널이 요청한 Overlapped(비동기) 작업의 완료를 실시간으로 알려주는 대신,
    작업 결과를 IOCP 대기열(Queue)에 넣고 나중에 사용자가 지정한 방법으로 통지하는 방식

사용 이유

  • 작업을 스레드에 분산하여 최신 멀티프로세서 호스트를 활용가능

  • I/O 작업 처리를 효과적으로 예약함으로써 응답성과 처리량을 극대화

  • 비동기 소켓 프로그래밍에서 효율적인 작업 처리를 위해 사용

  • 대규모 서버 애플리케이션에서 성능과 확장성을 확보하기 위해 흔히 사용

기능

  • Windows OS가 직접 효율적인 스레드 풀링 제공으로 Context Switching을 줄임

  • 애플리케이션 스레드 수를 줄이고 작업자(Worker) 스레드를 관리하는 데 사용

  • I/O 서비스를 요청하는 프로세스는 I/O 서비스 완료 알림을 받지 않고 대신 I/O 완료 포트의 메시지 대기열을 확인하여 I/O 요청 상태를 확인

  • 커널 차원에서 I/O 처리를 스케줄링( 프로세스들에게 CPU 등의 자원을 적절히 배정 )하여 CPU 사용량을 최적화
    ( 스레드 간 작업 전환 시의 발생하는 Context Switching에 대해서도 풀의 스레드를 상황에 맞춰 조절함으로 회피가능 )

  • CPU에 무리가 가는 스레드의 잦은 생성과 파괴 작업을 피하는 대신 상태만 활성화/비활성화함으로 오버헤드를 줄임

수행 과정

  • CreateIoCompletionPort 함수를 통해 I/O 완료 포트(IOCP)를 만들고 하나 이상의 파일 핸들을 해당 포트와 연결
    ( 파일 핸들은 디스크의 파일이나 모든 네트워크 엔드포인트 또는 TCP 소켓에 대한 읽기/쓰기를 나타냄 )

    • 변수 NumberOfConcurrentThreads 는 IOCP에서 동시에 실행해야 하는 비동기 I/O 스레드 수를 결정함
      ( 대기열에 대기 중인 완료 패킷이 있지만 포트가 동시성 한계에 도달하여 대기를 충족할 수 없는 경우가 가장 효율적
      => 가장 좋은 최대값은 컴퓨터의 CPU 수 (0으로 설정하면 자동으로 인식) )
  • 완료 포트(Completion Port)가 생성되면 운영 체제(OS)는 대기열(Queue)를 생성하고 모든 I/O 완료 패킷을 연결하여 대기시킴,
    이를 통해 I/O 완료 패킷은 애플리케이션 작업자(Worker) 스레드를 할당받아 처리될 수 있음

  • I/O 작업이 완료되면 I/O 스레드(=작업자(Worker) 스레드)는 IOCP에서 PostQueuedCompletionStatus 함수를 호출하여,
    I/O 완료 패킷을 연관된 대기열(선입선출(FIFO) 형식)로 이동하고 사용 가능한 스레드 풀로 다시 이동

  • 애플리케이션 작업자(Worker) 스레드가 사용 가능해지면 GetQueuedCompletionStatus 함수를 호출하여 IOCP 대기열에서 대기된 I/O 완료 패킷을 가져오고 추가 작업을 계속 진행

  • I/O 완료 포트에서 실행이 차단된(=작업 대기중) 스레드는 기본적으로 LIFO(Last-in-first-out) 순서로 해제되며, 가장 오래된 I/O 완료 패킷의 정보가 해당 스레드에 전달됨
    ( 최근에 사용된 스레드는 CPU 캐시에 여전히 남아있을 가능성이 높음
    => Context Switching 오버헤드를 줄이고 전체 시스템 성능을 향상가능 )

  • 더 이상 비동기 I/O 스레드가 실행되지 않고 파일 핸들이 없으면 IOCP가 시스템에서 해제됨
    ( 따라서 더 나은 성능을 위해 모든 I/O 작업 리소스를 제대로 닫아야 함 )

image

  1. I/O 완료 포트 스레드: IOCP 스레드는 특정 IOCP에 대한 알림을 기다리며 비동기 작업이 완료될 때까지 차단됨

  2. SomeAsync 메서드 호출 : 작업 스레드에서 await DoAsync()가 실행되면, 이 메서드는 IOCP에 “바인딩”되고 비동기 I/O 작업이 시작됨
    ( 이때 비동기 작업의 진행 상태를 추적하는 상태 머신이(State Machine)이 생성되고 Task가 반환됨 )

  3. 비동기 I/O 작업이 완료됨

  4. I/O 완료 신호: I/O 작업이 완료되면 IOCP가 특정 알림를 보내 차단된 IOCP 스레드 중 하나를 깨워 작업을 계속 진행하게 함

  5. 상태 머신 실행: 신호를 받은 IOCP 스레드는 상태 머신을 실행하여 Task의 결과를 설정함
    ( 이 과정에서 후속 작업(continuation)을 결정함 )

대채 프로그램

Reference

C-sharpcorner
Microsoft
TooSlowException