Llama-Server가 멀쩡한 KV 캐시를 날려버리는 문제와 해결 방법
Llama-Server is Throwing Away Your Perfectly Good KV Caches, and How to Fix It
핵심 요약
llama-server의 KV 캐시 복구 시 발생하는 재연산 문제를 체크포인트 메타데이터를 담은 '사이드카' 파일로 해결했습니다.
- KV 캐시 복구 문제 — 서버 재시작 후 복구된 캐시가 첫 요청 시 무시되고 재연산되는 현상 발생
- 근본 원인 — 프로세스 메모리에만 존재하는 체크포인트 메타데이터가 디스크 저장 시 누락됨
- 사이드카 해결책 — 체크포인트 정보를 별도 파일로 저장하여 복구 시 재연산 없이 즉시 로드
- 성능 개선 — 복구 후 쿼리 응답 속도가 약 720배 향상됨
2026년 7월 6일 수정: markole이 정확히 지적했듯이, 버그를 어떻게 발견하고 테스트하고 고쳤는지 굳이 알고 싶은 사람이 아니라면, LLM이 생성한 빽빽한 요약본을 읽을 필요 없게 그냥 핵심만 딱 적어주는 게 커뮤니티에 더 도움이 됨. 이 친구가 핵심을 잘 짚었음: "그냥 '야, llama.cpp에서 kv 캐시 슬롯 제대로 저장하고 싶으면 여기 diff 파일 써라'라고 했으면 좋았을 텐데." 그래서 여기 올림: https://github.com/TheTom/llama-cpp-turboquant/pull/206/changes.
왜 이걸 업스트림에 PR 안 보냈냐고? 솔직히 말하면 AI 도움을 좀 받았는데, 난 그게 아무 문제 없다고 보거든. 근데 GGML 쪽은 아님. 자기들 규칙 안 지키는 사람한테 엄청나게 적대적이더라고. 그래서 굳이 귀찮게 안 하려고.
서론
디스크에서 2.49GB짜리 상태를 1.23초 만에 복구하는 걸 지켜봤는데, 바로 날려버리더라. llama-server의 슬롯 저장/복구 기능은 저사양 하드웨어에서 긴 컨텍스트를 다룰 때 딱 필요한 기능임. 세션을 디스크에 파킹해뒀다가 나중에 다시 불러와서 프리필(prefill) 비용을 또 낼 필요가 없게 만드는 거니까. 복구 자체는 완벽하게 작동함. 근데 프로세스를 재시작하면 이 기능이 사실상 무용지물임. 복구 후 첫 번째 쿼리가 재구성된 상태를 전부 폐기하고 처음부터 다시 프리필을 돌려버리거든. 원인은 프로세스 메모리에만 존재하는 메타데이터 한 조각 때문이었음.
테스트 환경: Qwopus3.6-27B Q6_K (하이브리드 아키텍처), 2× Tesla P100 레이어 분할, turbo4 KV 양자화.
발견 과정
고컨텍스트 벤치마크를 돌릴 때 복구는 기계적으로 완벽해 보였음. 2.49GB가 1.23초 만에 VRAM으로 돌아왔으니까. 근데 바로 다음 /completion 요청에서 forcing full prompt re-processing due to lack of cache data라는 로그가 찍히면서 전체 재프리필이 돌아감 (100K 컨텍스트 기준 약 17.5분 소요). 저장 빠르고, 복구 빠른데, 결국 다 갖다 버리는 꼴임.
(이 발견 당시에는 검증 때와는 약간 다른 설정을 썼음. 아래의 모든 수치는 패치된 빌드에서 제어된 검증을 거친 결과임.)
근본 원인
llama_state_seq_save_file은 토큰과 물리적 KV 셀은 직렬화하는데, 프로세스 메모리에만 존재하는 체크포인트 메타데이터 리스트인 slot.prompt.checkpoints는 저장하지 않음. 콜드 재시작 후 첫 요청은 항상 약간의 롤백이 필요함. 프롬프트 끝부분을 다시 토큰화하면 BPE 경계가 바뀔 수 있어서, 로짓을 생성하려면 최소한 토큰 하나는 다시 처리해야 하거든. 재사용 경로는 커버링 체크포인트(covering checkpoint), 즉 롤백 대상 지점과 같거나 그 이전 지점에 있는 체크포인트를 통해서만 롤백이 가능함. 체크포인트 리스트가 비어 있으니 서버는 아무것도 못 찾고 포기한 뒤 전부 다시 계산하는 거임.
실패한 수정안 (v1)
뻔한 해결책은 복구 시점에 복구된 상태로부터 체크포인트를 합성하는 거였음. 근데 실패했고, 그 실패가 교훈을 줌. 합성된 체크포인트는 끝부분(tip), 즉 100K 실행 기준 100,042 위치에 놓이는데, 롤백 대상은 그보다 앞인 100,034 위치거든. 체크포인트는 자기 위치와 같거나 그 이후의 롤백만 처리할 수 있어서, 끝부분 체크포인트는 항상 발생하는 롤백에 아무런 도움이 안 됨. 불변의 법칙: 끝부분 이전의 체크포인트가 필요한데, 그건 저장 시점에만 존재함.
성공한 수정안 (v2: 사이드카)
에 117줄 추가: 시점에 체크포인트 리스트를 버전이 지정된 사이드카 파일()로 저장하고, 시점에 다시 불러오게 함. 이제 롤백이 실제 저장된 체크포인트에 안착하고, 마지막 토큰 몇 개만 다시 처리하면 끝남. 만약 사이드카 파일이 없으면(예를 들어 예전 빌드로 저장된 상태 파일인 경우), 서버는 v1 방식의 끝부분 합성으로 돌아감. 이건 정확히 이어 붙이는 재개는 커버하고, 나머지는 패치 전처럼 전체 재프리필을 돌리는 식으로 우아하게 처리됨. 크래시는 안 남.


