닮아 보여도 목적이 다른 두 방식
모델 하나에 요청 하나를 보내는 시연을 넘어서면 운영에서 두 방식이 나타나. 서로 관련돼 보이지만 최적화하는 대상이 다르고, 맞지 않는 방식을 쓰면 자원만 낭비해.
- 프로세스 하나에 여러 모델 — 한 서비스가 대화용 7B 모델과 작은 임베딩 모델, 이미지 이해용 VLM처럼 서로 다른 모델을 함께 제공해. 프로세스의 공통 비용은 아끼지만 모델끼리 통합 메모리를 놓고 경쟁해.
- 모델 하나의 묶음 추론 — 같은 모델로 들어오는 여러 프롬프트를 한 묶음으로 처리해. 처리량은 늘지만 요청마다 기다리는 시간도 늘어. 전체 계산 효율과 개별 지연 시간을 맞바꾸는 방식이야.
이 레슨에서는 두 방식의 차이와 각각 언제 맞는지 살펴봐.
여러 모델 — 메모리 장부
프로세스 하나에 여러 모델을 두면 모든 가중치가 통합 메모리에 동시에 머물러. foundations.lesson4에서 모델마다 한 어림셈을 그대로 더하면 돼. 7B Q4 약 5GB와 작은 임베딩 모델 약 1GB, 2B VLM 약 2GB를 함께 두면 상주 메모리가 약 8GB고, 현재 생성 중인 모델의 KV 캐시가 더해져. 모델 하나만 쓸 때보다 장부가 더 중요해. 어느 모델이든 갑자기 온전한 추론 예산을 요구할 수 있거든.
잘 작동하는 방식은 시작할 때 모든 모델을 불러와 계속 상주시킨 뒤 요청 종류에 맞춰 보내는 거야. 요청이 올 때 불러오고 놀 때 내리는 방식은 좋지 않아. 큰 모델을 불러오는 데 드는 몇 초가 개별 추론 시간보다 훨씬 길 수 있어.
묶음 추론 — 처리량이 지연 시간보다 중요할 때
같은 모델에 동시 프롬프트가 많다면 묶음으로 GPU 호출 한 번에 더 많은 토큰을 처리해 계산 자원당 처리량을 크게 높일 수 있어. 대신 각 요청은 첫 토큰을 보기 전에 묶음을 채우는 시간이 끝날 때까지 기다려야 해.
mlx-lm에는 일부 PyTorch 서빙 기술처럼 다듬어진 일급 묶음 생성 기능이 아직 없어. 그래서 현실적인 방식은 FastAPI 같은 서비스층에서 비동기로 요청을 모은 뒤 mlx-lm으로 프롬프트마다 추론하는 거야. 짧은 프롬프트가 동시에 많이 들어오는 작업이라면 MLX 위의 더 높은 수준 서빙 기술을 살펴보거나 mlx-lm의 묶음 API가 성숙할 때까지 기다려.
상황별 선택
- 모델 하나, 사용자 한 명 — prod.lesson1의 단순한 FastAPI 서비스면 되고 묶음 처리는 필요 없어.
- 여러 모델, 프로세스 하나, 낮은 동시성 — 시작할 때 모두 불러와 요청 종류에 따라 보내. 대신 가용성을 위해 통합 메모리를 계속 쓴다는 점을 받아들여야 해.
- 모델 하나, 매우 높은 동시성 — Ollama나 맞춤 묶음 래퍼 같은 묶음 서빙을 살펴봐. 더 높은 처리량을 얻는 대신 요청별 지연 시간이 늘어.
- 여러 모델과 높은 동시성 — Mac 한 대의 서빙 규모를 넘어섰다는 신호일 때가 많아. 역할 하나씩 맡긴 여러 Mac이 더 경제적인지 따져 봐.