프로젝트마다 모델을 띄우다가, LLM 서버를 하나로 합쳤다

DGX Spark 한 대에 vLLM 서버를 세우고, 프로젝트마다 모델을 띄우는 대신 하나로 분리해 첫날 모니터링까지 붙인 기록

하려던 것

집에 NVIDIA DGX Spark(GB10) 한 대가 있다. 통합 메모리 128GB에 CPU와 GPU가 그 메모리를 같이 쓰는 구조다.

LLM이 필요한 게 두 개가 됐다. 공시 요약 서비스의 배치와, 맥미니에서 한 시간에 한 번 도는 감시 배치. 둘 다 각자 모델을 띄우고 있으면 낭비다.

“같은 모델 띄우려는 건데, 하나만 있어도 되려나? 2개의 다른 프로젝트에서 사용할 건데.”

하나면 된다고 했다. 그래서 모델 서빙만 하는 프로젝트를 따로 팠다. vLLM 하나 띄우고 OpenAI 호환 API로 열어 두면 누가 부르든 상관없다. 도메인 로직은 각 서비스가 자기 프롬프트를 들고 오고, 서버는 모델만 서빙한다.

굳이 프로젝트를 하나 더 만드는 게 맞나 싶었는데, 반대로 생각하니 분명했다. 모델을 바꾸거나 엔진 설정을 만질 때마다 두 애플리케이션 저장소를 같이 고쳐야 한다면 그게 더 이상하다.

어떻게 시켰나

하루에 커밋 세 개로 끝났다. vLLM 서빙, 임베딩 서비스(multilingual-e5-large, 8001 포트), 그리고 보안 정리와 로그 수집.

임베딩을 같이 올린 건 나중에 검색 기능을 붙일 때 쓰려는 것이다. 지금 쓰는 데는 없는데 어차피 같은 장비에 올릴 거라 미리 세웠다. 쓰는 데가 없는 걸 미리 세우는 게 좋은 판단인지는 모르겠다.

모니터링은 처음부터 같이 붙였다. 서버를 따로 빼면 문제가 생겼을 때 어느 쪽 문제인지 가릴 방법이 있어야 한다. 그게 분리의 대가다. vLLM 상태와 로그를 밖에서 볼 수 있냐고 물었고, Prometheus·Grafana를 얹었다. 로그는 별도로 모은다.

어디서 막혔나

붙였다고 바로 보이는 게 아니었다. 로그인은 됐는데 대시보드가 하나도 없었고, 임베딩을 호출해봐도 그래프에 안 잡혔다.

“그라파나 대시보드에서 방금 임베딩 테스트 호출한 건 안 잡히는데, 지표 수집 잘되고 있는 건가? 이건 또 따로 해야 해?”

따로 해야 했다. exporter를 붙이는 것, 스크레이프 대상에 등록하는 것, 대시보드를 만드는 것이 각각 별개 작업이다. 셋 다 해야 숫자가 나온다.

어떻게 풀었나

대시보드까지 직접 만들고 나서야 지표가 보이기 시작했다. 지금 서빙 설정은 이렇다.

--model nvidia/Gemma-4-31B-IT-NVFP4
--quantization modelopt
--max-model-len 8192
--gpu-memory-utilization 0.85

NVFP4 양자화본을 골랐다. 통합 메모리를 CPU와 나눠 쓰는 구조라 가중치가 작을수록 좋을 것 같았고, 실제로 잘 올라온다.

gpu-memory-utilization은 0.85로 뒀다. 보통 이 정도면 보수적인 값이다.

남은 문제

느리다. 단일 스트림에서 초당 7토큰쯤 나온다. 31B 모델이라 이 정도인가 싶다가도, NVFP4로 4비트까지 줄였는데 이건 좀 아닌 것 같다. GPU 사용률을 보면 노는 시간이 꽤 있다. 연산이 부족한 게 아니라 다른 데서 막혀 있는 것 같은데 아직 뭔지 모르겠다.

컨텍스트 8192도 짧다. 공시 원문은 만 자 넘는 게 흔한데 이걸로 될지 모르겠다. 한국어는 토큰당 글자 수가 적어서 만 자면 8천 토큰을 넘길 수 있다. 잘리면 뒷부분이 통째로 빠지는 건데, 공시는 중요한 수치가 뒤에 나오는 경우가 많다.

사소한 것 하나 더. 로컬과 원격의 작업 디렉터리 이름을 정하다가 한쪽은 단수형, 한쪽은 복수형이 됐다. 오타에서 시작된 구분이라 헷갈리지 말자고 메모까지 남겼다. 지금은 별일 아닌데 이런 게 나중에 문다는 걸 몇 번 겪었다.

배운 점