솔직히 고백하자면, 지금까지 vLLM을 써본 적이 있음에도 vLLM이 정확히 무슨 일을 하고, 왜 써야 하는지를 제대로 설명하지 못한다. 그냥 "LLM을 효율적으로 실행할 수 있게 해주는 도구" 정도로만 알고 있었달까. 막상 이렇게 질문을 받으면 답을 못 한다는게 스스로도 좀 부끄러워져서, 적어도 질문에는 답할 수 있을 만큼은 제대로 파헤쳐보려고 한다.
LLM은 Large Language Model이라는 이름에 걸맞게, 보통 자체적으로 돌리려면 고성능 GPU와 큰 용량의 vRAM이 필요하다. 문제는 GPU 성능이 아무리 좋아도, 메모리 관리나 요청 처리 방식이 비효율적이면 그 좋은 자원을 제대로 활용하지 못하고 버벅거린다는 점이다.
vLLM은 바로 이 지점을 파고드는 오픈소스 추론 엔진이다. vRAM을 효율적으로 사용하고, GPU 성능을 최대한 끌어내서, 같은 자원으로 훨씬 가성비있게 LLM을 서빙할 수 있도록 도와준다. 한 줄로 정리하자면, 거대한 AI 모델을 가성비 좋게 실행할 수 있도록 도와주는 엔진인 셈이다.
그렇다면 vLLM이 구체적으로 뭘 어떻게 해주길래 가능한걸까? 이를 가능하도록 하는 vLLM의 핵심적인 특정은 크게 세 가지로 정리할 수 있다.
LLM이 답변을 생성할 때는 이전 문맥을 KV 캐시라는 형태로 메모리에 계속 저장해둬야 한다. 그런데 문제는 답변이 얼마나 길어질지, 그래서 이전 문맥을 저장하기 위해 메모리가 어느 정도 필요할지 미리 알 수 없다는 점이다. 그래서 LLM이 동작하는 과정에서 "혹시 모르니" 최대 길이만큼 메모리를 넉넉하게 미리 예약해두게 된다. 이렇게 예약된 메모리는 실제로는 대부분 다 사용하지 못하고, 사용되지 않는 메모리는 그냥 놀게 된다.
vLLM은 여기서 운영체제의 가상 메모리 관리 방식(페이징)에서 아이디어를 가져와서 적용했다. 메모리를 필요한 만큼만 잘게 나눠서 그때그때 할당하는 방식이다. 덕분에 미리 예약만 해두고 사용하지 않아 버려지는 메모리를 거의 0에 가깝게 줄일 수 있고, vRAM을 늘리지 않고도 vLLM을 도입하기 전보다 훨씬 많은 요청을 처리할 수 있게 된다.

AI 서버가 여러 요청을 동시에 처리할 때는 보통 한 번에 처리할 수 있는 요청 개수(배치 크기)가 정해져 있다. 문제는 기존 방식에서는 이 배치 안의 요청이 전부 다 끝나야 다음 요청을 받아준다는 점이다. 예를 들어 동시에 4개 요청을 처리 중인데 그 중 하나가 금방 끝나버려도, 나머지 3개가 다 끝날 때까지 그 자리는 그냥 비워둔 채로 기다린다.
vLLM은 이 낭비를 없애기 위해 요청 하나가 먼저 끝나면, 즉시 그 빈 자리에 새로운 요청을 밀어 넣어서 GPU가 쉬지 않고 계속 돌아가게 만든다. 그 결과 같은 시간 동안 처리할 수 있는 요청 수, 즉 처리량(throughput)이 증가하게 된다.

아무리 좋은 기능이 있어도 사용할 모델이 바뀔 때마다 코드를 갈아엎어야 한다면 실무에서 쓰기 부담스럽다. vLLM은 Hugging Face에 올라온 최신 오픈소스 모델 대부분을 그대로 지원하고, 다양한 하드웨어 환경에서도 잘 동작해서 어디서든 부담 없이 바로 가져다 쓸 수 있다.
이론은 이 정도로 정리하고, 실제로 vLLM 덕분에 문제를 해결했던 경험을 하나 공유하려고 한다.
인턴으로 근무할 당시, 사내 회의록을 자동으로 요약해주는 툴을 개발하는 일을 맡았던 적이 있었다. 보안이 중요한 회의에서는 외부 LLM API로 회의 내용을 보낼 수 없었기 때문에, 로컬 환경에 자체 LLM을 띄워서 처리해야 했다. 그렇다고 자체 LLM을 상시 GPU 서버를 띄워서 돌리면 비효율적이고 비용이 많이 들기 때문에, Serverless GPU를 제공하는 RunPod Worker를 활용해서 회의 내용을 요약하는 방식으로 구현했었다. 이 과정에서 예상치 못한 문제가 터졌다.
LLM(Qwen2.5-7B-Instruct-AWQ)으로 회의록 요약을 요청하면, 2~3번에 한 번 꼴로 에러 메시지 하나 없이 조용히 응답이 끊겨버렸다. RunPod의 job은 finish 상태로 정상 종료됐다고 뜨는데, 정작 결과값은 비어 있는 상황이었다. 이 정도 실패율이면 실제 보안 회의에서는 도저히 믿고 쓸 수가 없었다.
여러 자료를 찾아보다가 RunPod Serverless 환경에서 반복적으로 요청을 처리할 때 메모리 관리가 제대로 안 되고 있는 게 아닐까 하는 가설을 세웠다.
finish 상태로 끝났는데 결과는 비어있는, 지금 겪고 있는 것과 똑같은 증상의 사례가 여럿 올라와 있었다.정확한 해결 방법이나 원인을 찾을 수 있는 방법이 뚜렷하지 않아서 "vLLM을 도입해서 문제가 해결된다면 역으로 메모리 문제라는 가설이 맞는게 아닐까?" 하는 생각으로 vLLM을 도입해보기로 했다.
그리고 vLLM을 도입한 이후로 일주일 간의 시범 운영 기간 동안 동일한 문제가 재발하지 않았다. 그제서야 자체적인 LLM을 보안 회의에서 사용하도록 기능을 제공할 수 있게 되었다.
막연하게 "LLM 서빙을 효율적으로 해주는 도구"로만 알고 쓰던 vLLM을 이번에 제대로 파보면서, 왜 이렇게 많은 곳에서 표준처럼 쓰이는지 이해할 수 있었다. 특히 PagedAttention과 Continuous Batching 같은 아이디어는 알고 나니 굉장히 직관적이고 단순명료해서, 왜 이걸 진작 안 찾아봤을까 싶기도 했다. 로컬 LLM을 운영 중이거나 계획 중이라면, vLLM은 한 번쯤 제대로 들여다보고 이해한 뒤에 사용해보면 좋을 것 같다.