본문으로 건너뛰기

[vllm] vLLM 멀티모달 처리 성능 개선: MM 전처리를 위한 별도 Executor 도입

PR 링크: vllm-project/vllm#49524 상태: Merged | 변경: +31 / -20

들어가며

vLLM은 대규모 언어 모델(LLM) 서빙을 위한 고성능 추론 엔진으로, 특히 멀티모달(Multimodal) 기능 지원에 힘쓰고 있습니다. 멀티모달 모델은 텍스트뿐만 아니라 이미지와 같은 다양한 형태의 데이터를 처리할 수 있어야 합니다. 하지만 기존 vLLM 아키텍처에서는 이미지 전처리(MM preprocessing)와 토큰화(tokenization) 작업이 동일한 워커 스레드 풀(worker thread pool)을 공유하면서 병목 현상이 발생했습니다. 특히, 큰 이미지의 경우 전처리 시간이 1초 이상 소요될 수 있으며, 이 시간 동안 다른 모든 동시 요청의 토큰화 작업이 지연되는 심각한 성능 저하를 야기했습니다.

이번 PR([Perf] Isolate MM preprocessing on its own executor)은 이러한 문제를 해결하기 위해 멀티모달 이미지 전처리 작업을 위한 별도의 Executor를 도입합니다. 이를 통해 이미지 전처리 작업이 토큰화 작업과 더 이상 경합하지 않도록 분리하여, 전반적인 요청 처리 지연 시간을 크게 줄이고 동시성(concurrency)을 향상시키는 것을 목표로 합니다.

코드 변경 분석

이번 PR의 핵심은 vllm/renderers/base.py 파일에서 멀티모달 전처리 작업에 사용되는 Executor를 분리하는 것입니다. 또한, 이 변경 사항과 관련된 설정 및 테스트 코드도 함께 수정되었습니다.

1. vllm/renderers/base.py: Executor 분리

가장 중요한 변경 사항은 Renderer 클래스의 __init__ 메서드에서 발생합니다. 기존에는 토크나이저와 멀티모달 전처리 작업 모두 동일한 ThreadPoolExecutor를 공유했습니다. 하지만 이 PR에서는 멀티모달 전처리를 위한 별도의 ThreadPoolExecutor를 생성하여 _mm_executor로 할당합니다. 이 새로운 Executor는 max_workers=1로 설정되어, 멀티모달 전처리 작업이 다른 작업과 경합하지 않도록 보장합니다.

Before:

-        # Shared thread pool executor for blocking tokenizer and
-        # multimodal preprocessing operations.  The multimodal processor
-        # receives a deep-copied tokenizer (see #36557) so it is safe to
-        # run tokenization and MM preprocessing concurrently.
+        # Thread pool executor for blocking tokenizer operations.  The
+        # multimodal processor receives a deep-copied tokenizer (see #36557)
+        # so it is safe to run tokenization and MM preprocessing concurrently.
         pool_workers = config.model_config.renderer_num_workers
         self._executor = ThreadPoolExecutor(max_workers=pool_workers)
 
-        # Multimodal preprocessing is always offloaded to the thread pool
-        # to keep the asyncio event loop responsive under concurrent load.
-        self._mm_executor: Executor = self._executor
+        # Separate single-worker executor so tokenization never queues behind
+        # MM preprocessing; must stay single-worker per #38418 (P0/P1 order).
+        self._mm_executor: Executor = ThreadPoolExecutor(max_workers=1)

After: 위 diff는 _executor_mm_executor를 분리하는 과정을 보여줍니다. _executor는 기존처럼 renderer_num_workers 만큼의 워커를 가지지만, _mm_executor는 오직 1개의 워커만 가지도록 설정되었습니다. 이는 멀티모달 전처리 작업이 토큰화 작업의 흐름을 방해하지 않도록 보장하는 핵심적인 변경입니다.

또한, _clear_mm_cache_async_process_multimodal_async와 같이 멀티모달 관련 비동기 함수들이 이제 _mm_executor를 사용하도록 변경되었습니다.

Before:

-        self._clear_mm_cache_async = make_async(
-            self.clear_mm_cache, executor=self._executor
+        self._clear_mm_cache_async = make_async(
+            self.clear_mm_cache, executor=self._mm_executor
         )
         self._process_multimodal_async = make_async(
-            self._process_multimodal, executor=self._executor
+            self._process_multimodal, executor=self._mm_executor
         )

After:

         self._clear_mm_cache_async = make_async(
-            self.clear_mm_cache, executor=self._executor
+            self.clear_mm_cache, executor=self._mm_executor
         )
         self._process_multimodal_async = make_async(
-            self._process_multimodal, executor=self._executor
+            self._process_multimodal, executor=self._mm_executor
         )

2. vllm/config/model.py: ValueError 조건 완화

기존에는 멀티모달 캐시(mm_processor_cache_gb > 0)가 활성화된 상태에서 renderer_num_workers > 1인 경우 ValueError가 발생했습니다. 이는 멀티모달 캐시가 스레드 안전하지 않고 동시 렌더러 워커를 지원하지 않기 때문이었습니다. 하지만 이번 PR에서는 이 제약 조건이 완화되었습니다. 특히, 'pooling' 러너 타입의 모델에 대해서만 이 제약이 유지되고, 'generate' 러너 타입의 모델에 대해서는 이 제약이 해제됩니다. 이는 'pooling' 모델의 경우 멀티모달 전처리가 여전히 렌더러 워커에서 실행되기 때문이며, 'generate' 모델의 경우 별도의 MM Executor로 분리되었기 때문에 더 이상 문제가 되지 않기 때문입니다.

Before:

             if (
                 self.renderer_num_workers > 1
                 and self.multimodal_config.mm_processor_cache_gb > 0
+            ):
+                raise ValueError(
+                    

## 참고 자료
- https://pytorch.org/docs/stable/generated/torch.compile.html

> ⚠️ **알림:** 이 분석은 AI가 실제 코드 diff를 기반으로 작성했습니다.

댓글

관련 포스트

PR Analysis 의 다른글