io_uring은 syscall을 최대한 줄이고, 모든 I/O를 async하게 수행하고, 유저와 커널이 공유하는 ring buffer를 통해서 I/O를 교환한다.
두 개의 queue를 ring buffer로 사용하는데 SQ = submission queue에는 유저 프로그램이 이런 io를 해달라고 요청을 적는 공간이고 CQ = completion queue에는 커널이 I/O 끝났다고 완료 결과를 적는 공간이다. mmap으로 유저와 커널이 syscall 없이도 공유할 수 있다.
유저 스페이스에서 SQ entry들을 SQ에 push하면
한 번의 syscall로 커널에 요청 처리 시작을 알리고
커널이 I/O를 수행하게 된다.
완료되면 CQE가 CQ에 기록되고
유저는 CQ에서 바로 읽어서 결과를 확인할 수 있기 때문에 syscall가 필요 없다.
전통적인 기존의 I/O는 요청마다 syscall을 호출해야했다. syscall은 유저모드에서 커널모드로 넘어가는 context switch가 발생하는데 이 context switch로 인한 overhead는 I/O 인텐시브한 고성능 서버에서는 bottelneck의 메인 원인이 된다.
그래서 io_uring은 SQ에 메모리 write로 요청만 넣고 syscall은 batch로 한 번만 호출해서 syscall 횟수를 드라마틱하게 줄였다.
기존 서버에서 대량의 파일 디스크립터를 모니터링하고 이벤트를 확인하는 표준 방식이었던 epoll은
I/O 이벤트를 확인할 때마다 매번 epoll_wait를 호출해서 syscall을 많이 발생시키고,
내부에서 RBtree나 ready list 등으로 대량의 fd를 관리하는데
fd의 상태가 바뀔 때마다 epoll 내부 자료구조를 매번 수정해야하기 때문에 오버헤드가 컸다.
그래서 io_uring은 이벤트 완료를 CQ에 메모리 write으로 들여서 epoll_wait 같은 syscal을 아예 없애는 방법으로 속도를 높였다.
'[ Laboratory ] > Advanced Operating System' 카테고리의 다른 글
| race condition (0) | 2025.11.29 |
|---|---|
| lock free vs wait free (0) | 2025.11.20 |
| interrupt vs polling (0) | 2025.11.20 |
| ABI stability (0) | 2025.11.17 |
| 리눅스 eBPF, kfunc (0) | 2025.11.17 |
| 리눅스 cgroup (0) | 2025.11.17 |
| 리눅스 페이지 캐시 정책 (1) | 2025.11.14 |