[서버-10] IOCP에서 Page Locking에 대해서
#서버 프로그래밍IOCP Page Locking의 장점과 단점
IOCP는 기본적으로 Overlapped I/O 방식을 사용한다. 이 Overlapped I/O를 사용하면 커널 영역과 유저 영역의 버퍼가 공유가 된다.
Page Locking
IOCP서버에서 클라이언트와 통신을 할 때 WSABUF
를 사용한다. 이때 이 버퍼는 I/O 과정에서 커널에서 직접 접근해서
읽고 쓸 수 있어야한다. 왜 그렇게 하냐면 프로세스가 가지는 메모리 영역은 기본적으로 가상 메모리이다. 가상 메모리가 가리키는 물리 메모리는 메모리 공간 부족시 디스크 부분으로 스왑 아웃
이 된다.
이때의 페이지 교체의 비용이 비싸기 때문에 WSABUF가 가리키는 메모리는 스왑아웃 시키지 않도록 페이지 락을 거는 것이다. 이런식으로 IOCP는 성능을 높일 수 있다.
Receive 할 때의 이점
기본적으로 Scatter gather
를 지원하는 NIC
은 패킷이 들어오면 DMA로 CPU를 거치지 않고 물리 메모리에 바로 데이터를 입력한다.
이때 WSARecv
를 하면은 물리메모리 공간을 Page Lock을 하고 데이터를 입력한다.
이렇게 하면 물리메모리 공간과 가상 메모리 공간이 일치가 되면서 가상 메모리에 바로 데이터가 입력이 되는 효과를 받을 수 있다.
만약 페이지 락을 안하고 DMA로 받으면 어떻게 되는가.
가상 메모리에서 클라이언트가 보낸 데이터를 가져올 때 물리 메모리의 페이지가 디스크로 내려갔다면 다시 페이지 교체를 해서 가져와야 된다.
복사 관점에서 보면 일반 I/O는 디스크에서 OS 버퍼로 OS버퍼에서 사용자 버퍼로 복사되지만. Overlapped I/O는 사용자 버퍼로 바로 복사가 되는 것이다.
따라서 최고의 성능을 위한 IOCP의 Overlapped I/O는 위와 같이 작동한다.
Page Locking의 문제점
그러나 만약에 동시에 너무 많은 I/O가 발생하여 물리 메모리 전체에 락이 걸렸다고 하자. 그럼 OS는 다른 프로세스에 할당해줄 공간이 없어서 실행을 못 시킨다.
일부 페이지를 내리고 디스크에서 페이지를 가져와야 되는데 전부 락이 걸렸으니 방법이 없다.
그래서 운영체제는 Locked Page Limit
라는 것을 두어 한 프로세스가 페이지에 락을 걸 수 있는 양에 한계를 두었다.
보통 이 제한은 RAM의 8분의 1정도라고 한다. 이 제한에 도달하면 IOCP는 ERROR_INSUFFICIENT_RESOURCES
에러를 내며 실패하게 된다.
위의 문제점 때문에 Zero Byte Recv
라는 방법을 사용하기도 한다.
Zero Byte Recv
IOCP 환경에서 비동기 I/O를 할 때에 수신 버퍼 크기를 0
으로 설정하는 기법이다.
이 기법은 데이터 수신 자체를 목적으로 하는 것이 아니라 I/O 작업의 완료를 기다리면서 페이지 락을 피하는 것이다.
0바이트로 WSARecv
를 호출하면 실제 데이터를 복사하지 않기 때문에 Page-Locking이 발생하지 않는다.
이런식으로 0바이트 수신 WSARecv로 IOCP Queue에 넣은 다음에 실제 데이터를 받는다. 물론 GetQueuedCompletionStatus 함수로 IOCP 큐에서 가져올 때는 TransferredBytes
가 0이므로 이때는 연결을 끊으면 안된다.
모든 소켓의 버퍼에 미리 락을 걸고 Recv를 대기하지 않기 때문에 너무 많은 요청이 왔을 때 페이지 락 제한에 대비할 수 있다.