기타 Lobsters · 2026-09-19

블로킹 걸리면 영혼 체인지? io_uring의 정신 나간 성능 최적화 패치 제안

핵심 요약
  • 리눅스 io_uring 메인테이너 옌스 악스보가 블로킹 발생 시 스레드 간 신원을 맞바꿔버리는 파격적인 RFC 패치를 제안했습니다.
  • 기존 방식은 블로킹되지 않을 작업까지 워커 스레드로 넘겨 성능 손실이 컸는데, 이를 해결하기 위해 실제 멈추는 순간에만 '영혼 체인지'를 하겠다는 발상입니다.
  • 스케줄러 훅을 통해 블로킹 직전 워커 스레드와 TID 및 시그널 설정을 교환하며, 발상은 단순하나 커널 구조상 매우 위험하고 급진적인 시도로 평가받습니다.
요약 리눅스 커널의 고성능 비동기 I/O 서브시스템인 io_uring은 논블로킹(non-blocking) 실행을 핵심으로 설계되었습니다. 하지만 커널 내 많은 시스템 콜(예: fdatasync, statx, 일부 openat 경로 등)은 본래 비동기 처리를 고려해 개발되지 않았기 때문에, 실행 도중 스레드가 멈추는(블로킹) 현상을 막는 것이 오랜 과제였습니다. 현재 리눅스 커널에서는 블로킹 가능성이 있는 작업을 아예 별도의 워커 스레드로 넘겨 처리하도록 하고 있습니다. 하지만 이 방식은 실제로는 블로킹 없이 바로 처리될 수 있는 작업임에도 불구하고 불필요한 스레드 기상과 컨텍스트 스위칭 오버헤드를 발생시켜, 고성능을 추구하는 io_uring의 장점을 깎아먹는 원인이 되었습니다. 모든 시스템 콜 경로를 논블로킹으로 뜯어고치는 것은 현실적으로 매우 어렵고 오랜 시간이 걸리는 작업입니다. 이에 io_uring의 메인테이너인 옌스 악스보(Jens Axboe)는 파격적이면서도 다소 모험적인 '스레드 신원 맞바꾸기(Thread-identity switcheroo)' RFC 패치를 제안했습니다. 이 방식은 작업을 일단 원래 스레드에서 그대로 실행하되, 스케줄러에 새 플래그(PF_IO_HANDOFF)를 도입해 스레드가 실제로 블로킹되려는 순간을 감지합니다. 블로킹 직전 io_uring은 풀에서 워커 스레드를 하나 가져와 두 스레드의 정체성(스레드 ID, 시그널 핸들러 설정 등)을 통째로 맞바꿉니다. 그 결과 원래 호출 스레드의 역할을 넘겨받은 워커 스레드가 유저 공간으로 복귀해 다음 링 큐를 처리하고, 정작 멈추게 된 원래 스레드는 워커 신분이 되어 평소처럼 블로킹되었다가 깨어난 뒤 작업을 마치고 워커 풀에 합류하게 됩니다. 실제로 블로킹이 발생할 때만 비용을 치르도록 하는 기발한 해법이지만, 스레드 신원을 바꾸는 방식인 만큼 커널 내부적으로 많은 복잡성과 잠재적 위험을 동반하는 시도로 평가받고 있습니다.
Sponsored · 광고