-
강의 과제) Windows I/O Model, select, IOCP (수정 필요)TIL-sparta 2024. 6. 3. 23:47
학습 키워드: I/O, Windows I/O Model, Select Model, file descriptor, IOCP
Windows I/O Model
1) What is I/O?:
I/O(Input/Output)란, 장치 간 데이터 흐름에 관여하는 것, 즉 키보드와 마우스, 모니터, 프린터, 마이크, 스피커 등 흔히 사용되는 외부 입 출력 장치부터, 하드 디스크, 물리/논리적 네트워크 포트, 그에 관여하는 프로그램이나 운영체제의 I/O 모델 등을 통틀어 일컫습니다. 네트워크 통신 또한 I/O 작업에 포함되기 때문에 I/O를 올바르게 이해하고 다룰 수 있다면 서버를 효율적으로 설계할 수 있게 됩니다.
2) Windows I/O Model:
모든 운영체제는 주변 장치와의 데이터의 흐름을 제어하기 위한 I/O 모델이 존재합니다. Windows I/O Model은 다음과 같은 특징이 있습니다.
- I/O 작업의 계층화: lowest-level (장치와 직접 소통하는 최하위 단계 드라이버), intermediate, 그리고 highest-level (최상위 단계 드라이버, file system driver를 말함) 드라이버로 분류됩니다.
- I/O Manager라는 I/O system 컴포넌트를 통해 모든 계층의 kernel-mode 드라이버에 일관된 인터페이스를 제공합니다.
- 드라이버에 대한 모든 I/O 요청은 I/O 요청 패킷(IRP, I/O Request Packet)을 통해 이루어집니다. IRP의 생성 및 폐기는 I/O Manager가 담당합니다. 네트워크 서버의 경우
메인 thread에서WSASend나 WSARecv 등의 소켓 I/O API를 호출했을 때 IRP가 생성됩니다.
3) Select Model:
Select model은 win32 API의 winsock2 라이브러리에 속한 select 함수를 사용하는 I/O 모델입니다. select 함수는 운영체제의 커널 서비스를 이용하기 위한 system call(=syscall)에 해당하며, 하나 이상의 소켓의 상태를 확인하기 위하여 파라미터로 소켓을 가리키는 socket handle(혹은 file descriptor)이 담긴 비트 배열 fd_set(읽기: readfds, 쓰기: writefds, 오류: exceptfds)을 넘겨받아 소켓들의 상태를 확인하여 비트 값을 전환하고, 최종적으로 읽기나 쓰기 준비가 완료된 소켓 핸들의 수를 반환하거나, timeout 시 0을, 에러 발생 시 SOCKET_ERROR를 반환합니다.
소켓(socket)은 두 장치 간의 TCP/IP 통신(two-way-communication)에서 TCP 레이어가 데이터의 목적지인 application을 식별할 수 있도록 logical port에 bind되어 통신의 endpoint로 사용되는 파일 혹은 객체를 의미합니다. Windows의 경우 소켓은 커널 객체이며, 소켓 핸들을 통해 다뤄집니다.File descriptor(FD)는 실행중인 프로세스가 파일을 다룰 때 사용하는 개념입니다. 커널 내에 존재하는 open 상태의 파일을 관리하는 file table에서 해당 파일을 특정할 수 있는 고유한 값을 의미합니다. 네트워크 I/O에서는 소켓 또한 소켓 핸들을 select()에 이용할 수 있습니다. 이를 통해 열린 파일(혹은 소켓)의 상태를 조작할 수 있습니다.
위 이미지는 async-blocking 형태로 구현된 select 모델의 flow 예시입니다. I/O 작업은 비동기로 진행되고, select() 함수 호출에 따라 thread가 block된 채로 I/O 작업의 결과가 반환되기를 기다리다가, I/O 작업의 완료 이후 select() 또한 완료되어 thread가 재개되는 것을 볼 수 있습니다.
4) IOCP (I/O Completion Ports):
Multiprocessor 시스템에서 적은 수의 thread로 많은 양의 비동기 I/O 요청을 처리하기 위해 사용되는 효율적인 threading 모델입니다. Thread pool 등을 이용해서 생성한 thread들이 IOCP에 bind된 상태로 대기하며 입/출력 보고를 기다리게 하는 구조입니다.
- CreateIoCompletionPort: 프로세스가 IOCP를 생성하면 시스템에서 I/O 요청의 처리를 담당하는 worker thread 들을 담아둘 queue (worker queue, LIFO)를 생성합니다. 이후 한 개 이상의 파일 핸들(단순 파일만이 아닌 network endpoint, TCP socket, named pipe, 또는 mail slot 등의 overlapped I/O endpoint를 말함)을 해당 포트에 연결합니다. 연결된 핸들 중 하나에 대한 비동기 I/O 작업이 완료되면 프로세스가 해당 핸들의 I/O 작업 완료 알림을 받게되며, IOCP는 completion 패킷을 담는 queue (completion queue, FIFO)에 I/O completion 패킷을 담아 대기 시킵니다. 파라미터로 전달되는 NumberOfConcurrentThreads 값을 통해 IOCP에서 동시에 실행될 수 있는 최대 worker thread 수를 제한합니다. 이 값을 concurrency value라고 부르는데, 가상 이상적인 방식은 concurrency value를 컴퓨터의 CPU 수 만큼으로 지정하여 하나의 CPU가 한 개의 thread만을 사용하도록 제한시켜 context switching을 최소화하는 방식입니다. Transaction에 긴 계산이 필요한 경우 더 높은 값을 할당(보통 CPU의 수 x2)하여 각 패킷의 완료 시간을 희생하는 대신 동시에 더 많은 양의 패킷을 처리할 수 있도록 설정할 수 있습니다.
- GetQueuedCompletionStatus: 생성된 thread에서 이 함수를 처음 호출한 경우, 해당 thread가 지정된 I/O completion port와 연결됩니다. 하나의 thread는 최대 하나의 completion port와 연결되지만, 하나의 completion port는 여러 개의 thread와 연결될 수 있습니다. 함수 호출 시 thread가
completion queue를 감시하며다음 completion 패킷을 기다립니다. Completion 패킷이 completion queue에 추가될 때 마다 시스템이 해당 포트에서 실행 중인 thread의 개수를 세고, 이 개수가 concurrency 값 보다 작을 경우 worker queue에 대기 중인 thread들 중 하나(LIFO, queue에 가장 마지막에 추가된 thread)가 completion 패킷을 처리합니다. - PostQueuedCompletionStatus: Thread가 completion queue에 completion 패킷을 배치할 때 사용합니다. 이 방식을 통해 프로세스의 다른 thread로부터 통신을 받을 수 있습니다. 외부에서 발생한 이벤트를 비동기 I/O 작업 없이 다른 worker thread에 알리는 방식으로 사용할 수 있습니다.
5) Why IOCP over Select:두 모델 중 IOCP가 선호되는 이유는 IOCP의 경우 적은 수의 thread와 LIFO worker queue를 통한 작업 분배로 많은 양의 I/O 작업을 처리할 수 있는 구조여서 context switching이 적고 CPU 점유율이 낮습니다. 반면에 select 모델은 소켓이 준비 상태인지를 확인하기 위해 주어진 fd_set 배열 전체를 순회하는 O(n)의 시간 복잡도를 가지고 있기 때문에 관리해야할 FD의 개수가 늘어날수록 성능이 저하되는 문제가 있으며, 관리 가능한 FD의 수가 1024개로 제한되어 있어서 게임 서버처럼 수천 개의 연결을 관리해야하는 서버를 구현하는데 사용하기에는 적합하지 않습니다. 또한, 주어진 fd_set 내에서 에러가 발생했을 때, 정확히 어느 위치에서 발생했는지를 알기 위해서는 배열을 한 번 더 순회해야하는 문제가 있습니다.
--
REFERENCES:
> Microsoft, "Overview of the Windows I/O Model"
> MicrosoftPressStore, "Understanding the Windows I/O System"
> Microsoft, "Windows Kernel-Mode I/O Manager"
> Microsoft, "Types of Windows Drivers"
> Microsoft, "select function"
> 80000coding, "파일 디스크립터"
> Oracle, "What Is a Socket?"
> "다중입출력" by REAKWON
> "Beej's Guide to Network Programming" by Beej, 7.3 참고
> Microsoft, "Input and output"
> Microsoft, "I/O Completion Ports"
> "IO Multiplexing 기본 개념부터 심화까지 -1부-", by 네이버 클라우드 플랫폼
https://developer.ibm.com/articles/l-async/
> IBM, "Boost application performance using asynchronous I/O"
> StackOverflow, "Socket and file descriptors"
> Joinc, "IOCP"
> "Operating System Concepts, 9/E" by Abraham Silberschatz, Peter B. Galvin, and Greg Gagne
728x90'TIL-sparta' 카테고리의 다른 글
프로그래머스) 무인도 여행 풀이 (Java) (2) 2024.06.06 [TIL] 프로그래머스) 두 큐 합 같게 만들기 풀이 (Java) (2) 2024.06.04 [TIL] 프로그래머스) k진수에서 소수 개수 구하기 풀이 (Java) (0) 2024.06.02 [TIL] 프로그래머스) 2개 이하로 다른 비트 (Java) (0) 2024.06.01 [TIL] 스파르타) 팀 프로젝트 - 풋살 온라인 시작 (D-7), Prisma generator (0) 2024.05.31