스레드와 파이버의 공존: UringMachine을 통한 Ruby I/O 성능 최적화 실험

Threads vs Fibers - Can't We Be Friends? - Noteflakes

작성자
발행일
2025년 12월 19일

핵심 요약

  • 1 Ruby의 io_uring 인터페이스인 UringMachine을 통해 스레드와 파이버를 결합했을 때의 성능 향상을 벤치마크로 입증했습니다.
  • 2 버퍼링된 쓰기 시 파이버 스케줄러가 블로킹되는 문제를 해결하여 Ruby 4.0에 반영하는 성과를 거두었습니다.
  • 3 멀티 스레드 기반 파이버 실행 환경에서 특정 임계점까지는 성능이 선형적으로 증가하나, 그 이상의 스레드 투입은 효율이 저하됨을 확인했습니다.

도입

이 글은 Ruby에서 io_uring을 활용하는 UringMachine 젬의 개발 과정과 성능 실험 결과를 다룹니다. 저자는 파이버가 I/O 작업에 유리하고 스레드가 병렬 처리에 유리하다는 일반론을 넘어, 두 기술을 결합했을 때 발생하는 실제적인 성능 변화와 한계를 탐구합니다. 특히 Ruby 4.0 릴리스에 포함된 파이버 스케줄러 개선 사항과 향후 로드맵을 공유합니다.

UringMachine과 Ruby 4.0 기여

  • 버퍼링된 쓰기 작업 시 파이버 스케줄러의 #io_write 훅이 호출되지 않고 블로킹되는 문제를 발견하여 수정안을 제출했으며, 이는 Ruby 4.0에 병합되었습니다.

  • writevsendv와 같은 벡터화된 I/O 메서드를 추가하여 저수준 API의 효율성을 높였습니다.

스레드와 파이버의 결합 벤치마크

  • 단일 스레드에서 파이버만 사용하는 방식은 I/O를 위해 커널에 진입할 때 GVL(Global VM Lock)을 해제하므로 CPU 자원이 100% 활용되지 않는 구간이 발생합니다.

  • 실험 결과, 2개 이상의 스레드에서 각각 파이버를 실행했을 때 단일 스레드 대비 최대 1.77배의 성능 향상을 보였습니다.

  • 하지만 스레드 수가 늘어날수록 GVL 경합과 컨텍스트 스위칭 비용으로 인해 성능 향상 폭이 줄어들거나 오히려 저하되는 임계점이 존재함을 확인했습니다.

향후 계획: 사이드카 스레드 및 버퍼 관리

  • 주 스레드는 파이버 로직을 처리하고, 별도의 보조(Sidecar) 스레드가 커널 I/O를 전담하는 구조를 실험할 예정입니다.

  • BufferPool API를 도입하여 메모리 할당을 최소화하고 io_uring의 버퍼 링 기능을 투명하게 관리할 계획입니다.

결론

이번 연구는 Ruby의 동시성 모델이 스레드와 파이버 중 하나를 선택하는 문제가 아니라, 워크로드에 맞춰 두 기술을 적절히 조합해야 함을 시사합니다. Ruby 4.0의 출시와 함께 더욱 강력해진 I/O 생태계가 기대되며, 향후 OpenSSL 통합 등을 통해 실무적인 웹 서버 환경에서의 활용 가능성을 높여갈 것으로 보입니다.

댓글 0

로그인이 필요합니다

댓글을 작성하거나 대화에 참여하려면 로그인이 필요합니다.

로그인 하러 가기

아직 댓글이 없습니다

첫 번째 댓글을 작성해보세요!