LLM 애플리케이션은 스레드 기반 동시성의 약점을 노출합니다. 스레드 기반 방식은 스트리밍 응답 대기 시 자원 점유, 스레드 생성 및 컨텍스트 스위칭의 높은 비용, 그리고 대규모 동시 연결에서의 확장성 문제(슬롯 고갈, 자원 증식, 성능 오버헤드)를 야기합니다. 이는 LLM 통신이 기존 백그라운드 작업과 근본적으로 다르기 때문입니다.
동시성 모델에서 파이버(Fibers)는 스레드와 차별화됩니다. 스레드가 운영체제에 의해 선점적으로 스케줄링되고 I/O 시 블록킹되며 OS 자원을 필요로 하는 반면, 파이버는 사용자 공간에서 관리되며 I/O 경계에서 자발적으로 제어권을 양보합니다. Ruby의 GVL(Global VM Lock) 환경에서 파이버는 단일 스레드가 epoll
, kqueue
같은 I/O 멀티플렉싱을 통해 수천 개의 I/O 작업을 효율적으로 모니터링할 수 있게 하여, ‘연결당 스레드’ 모델의 비효율성을 해소합니다.
파이버는 스레드 대비 20배 빠른 할당, 10배 빠른 컨텍스트 스위칭, 15배 높은 처리량을 제공하며, 더 적은 OS 자원 사용과 효율적인 스케줄링으로 압도적인 확장성을 자랑합니다. 이러한 특성 덕분에 비동기 방식은 LLM 통신에서 발생하는 자원 비효율성 및 확장성 문제를 효과적으로 해결합니다.
Ruby의 비동기 생태계는 투명성이 강점입니다. async
gem을 활용하면 Python처럼 async/await
키워드 없이도 기존 Ruby 코드가 자동으로 확장성을 얻습니다. Net::HTTP
와 같은 라이브러리가 네트워크 I/O 중에 자동으로 파이버에 제어권을 양보하여, RubyLLM
이 별도의 수정 없이도 동시 LLM 대화를 처리할 수 있게 합니다. Falcon
, async-job
, async-cable
등 관련 비동기 라이브러리들이 생태계를 구성합니다. Rails 애플리케이션 마이그레이션은 간단한 젬 및 설정 파일 수정으로 가능하며, 기존 작업 코드를 변경할 필요가 거의 없습니다. 또한, LLM 작업에만 async-job
을 사용하고 다른 작업에는 기존 큐 어댑터를 유지하는 유연한 접근 방식도 가능합니다.
비동기 방식은 I/O 바운드 작업, API 호출, WebSocket, SSE, LLM 애플리케이션과 같은 스트리밍 작업에 최적입니다. 반면, CPU 집약적 작업에는 스레드가 더 적합합니다.