[팁] 리눅스 커널 5.1 부터 도입된 io_uring 에 대해 - 리무스BBS
io_uring 에 대해
시스템 프로그래밍에서의 IO 담당 함수들
select
- 이게 제일 오래된 함수이다. 소켓의 파일 디스크립터 (fd) 들을 배열로 만들고, 해당 fd 에 read / write 플래그를 줘서 변화가 있는지를 루프를 돌면서 체크한다.
- 일명 level trigger 라는 방식이다.
- fd 들이 많은 대용량의 사이트에서는 루프를 돌면서 체크한다는 것 때문에 오버헤드가 발생한다.
- fd 숫자의 제한이 생긴다.
- 리눅스 select, poll, epoll — 하프연구소 (tistory.com)
poll
- 조금 더 발전된 방식으로, fd 에 대해서 폴링을 하는 함수인데, 지정된 소켓 (fd)의 변화가 생기면 해당 데이터를 return 하는 방식으로 처리된다.
- 루프를 도는 방식에서, 이벤트가 발생하면 처리하는 형태로 select 처럼 이벤트가 발생했는지 loop를 돌면서 확인하지 않아도 된다.
- 특정 시간이 지나면 이벤트가 없다는 리턴을 하므로, 주기적 처리도 가능하다.
- 일명 edge trigger 방식이다.
epoll
- 서버에서 poll 의 결과를 wait 하는 시간동안 프로세스가 sleep 하고 있는 문제점을 없애기 위해, 처리할 내용이 발생했을 경우 event 를 발생시킨다.
- 서버는 다른 일을 하다가, 이벤트가 발생했을 경우에 처리하고 돌아오는 방식이므로 프로세스가 wait 할 필요가 없다.
- SYSV 계열에서 시작되어 이후 linux 에 적용됨
kqueue
- BSD 계열 버전의 epoll. FreeBSD 등등에서 사용했음.
iocp
- 윈도우 개념의 이벤트 처리 방식이다. 데이터 copy 가 문제가 되므로, 커널과 프로그램 사이에 지정된 영역에 데이터를 주고받는 곳을 지정하고, 거기에서 직접 데이터를 읽고 쓴다.
- 위의 리눅스 계열의 이벤트 처리에 비해 데이터 copy 의 오버헤드가 발생하지 않으므로 속도가 상대적으로 빠를 수 있다.
- 윈도우 서버에서 사용하는 MMORPG 서버는 대부분 이 기술로 만들어져 있다고 보면 무방.
io_uring

- 리눅스 계열에서는 이벤트 내용을 트리거 받고, 데이터를 복사해가는 구조였으므로, IOCP 에 비해 손해를 보는 경향이 있었는데, 이 부분을 IO Uring 이라는 구조를 통해 개선하였다.
- 페이스북의 엔지니어가 만든 구조임.
- SQ 와 CQ (Send Queue, Completion Queue) 라는 형태의 커널과 사용자가 공유하는 두 개의 원형 큐를 사용한다.
- SQ에 쌓인 일을 커널이 처리한 후, CQ에 쌓는다. 이때 커널의 업무처리는 커널 레벨에서 처리하므로, 사용자에게 부담이 없다.
- CQ에 쌓인 결과물을 사용자 프로그램이 직접 처리하므로, IOCP와 유사하게 데이터를 복사하지 않고 직접 사용이 가능하다.
- 이외에 CQ에 데이터가 쌓일 때 이벤트가 발생하므로, 기존의 장점을 대부분 수용할 수 있다.
기능에 대한 소감
- 커널과 사용자 메모리 space 가 점차 보안을 위해 엄격하게 분리되고 있는 추세에 특정 목적을 위해 뚫어 놓은 커널/사용자 공유 영역
- 대용량 서버의 시스템 효율화를 위해 좋은 기능
- 기존 시스템의 마이그레이션이 크게 어렵지 않음
- epoll 기반의 서비스였다면, request 와 response 처리 부분만 약간 바꿈으로서 가능할 듯