[서버-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를 대기하지 않기 때문에 너무 많은 요청이 왔을 때 페이지 락 제한에 대비할 수 있다.