Llama-Server가 멀쩡한 KV 캐시를 버리는 이유와 해결 방법
요약
Llama-Server의 KV 캐시 저장/복구 기능이 프로세스 재시작 시 메타데이터 유실로 인해 무용지물이 되는 문제를 분석하고 해결책을 제시합니다. 체크포인트 메타데이터를 사이드카 파일로 영속화하여 재시작 후에도 효율적인 롤백과 프리필 비용 절감이 가능하도록 개선했습니다.
핵심 포인트
- Llama-Server의 KV 캐시 복구 시 메타데이터 누락으로 인한 재프리필 문제 발견
- 체크포인트 리스트가 메모리에만 존재하여 콜드 재시작 시 활용 불가
- 단순 체크포인트 합성 방식의 한계와 롤백 메커니즘의 불일치 확인
- 사이드카 파일(.ckpt)을 통한 체크포인트 영속화로 문제 해결
서론
저는 1.23초 만에 디스크로부터 2.49 GB의 상태 복구 (state restore)를 지켜보았습니다 — 그리고 그것이 바로 버려지는 것을 보았습니다. llama-server의 슬롯 저장/복구 (slot save/restore) 기능은 저사양 하드웨어에서 긴 문맥 (long-context) 작업을 수행할 때 정확히 필요한 것을 약속합니다: 세션을 디스크에 보관했다가, 나중에 프리필 비용 (prefill tax)을 다시 지불하지 않고 다시 불러오는 것입니다. 그리고 복구 자체는 완벽하게 작동합니다. 하지만 프로세스 재시작을 거치면서 이 기능은 기능적으로 무용지물이 되었습니다: 복구 후 첫 번째 쿼리가 재수화된 (rehydrated) 상태 전체를 폐기하고 처음부터 다시 프리필 (re-prefill)을 수행했기 때문입니다. 그 이유는 프로세스 메모리에만 존재하는 단 하나의 메타데이터 조각 때문인 것으로 밝혀졌습니다.
테스트베드: Qwopus3.6-27B Q6_K (하이브리드 아키텍처), 2× Tesla P100 레이어 분할 (layer-split), turbo4 KV 양자화 (quantization).
발견
높은 문맥 (high-context) 벤치마킹 중에, 복구는 기계적으로 완벽해 보였습니다 — 1.23초 만에 2.49 GB가 VRAM으로 돌아왔습니다 — 하지만 다음 /completion 요청 시 캐시 데이터 부족으로 인해 전체 프롬프트 재처리 (re-processing)가 강제되었고, 전체 재프리필 (re-prefill)이 실행되었습니다 (100K 문맥에서 약 17.5분 소요). 빠르게 저장하고, 빠르게 복구하지만, 모두 버려버리는 것입니다.
(해당 발견 실행은 검증 실행과 약간 다른 설정을 사용했습니다; 아래의 모든 주요 수치는 패치된 빌드에서의 통제된 검증 실행 결과입니다.)
근본 원인
llama_state_seq_save_file은 토큰과 물리적 KV 셀 (physical KV cells)을 직렬화(serialize)하지만, 프로세스 메모리에만 존재하는 체크포인트 메타데이터 리스트인 slot.prompt.checkpoints는 직렬화하지 않습니다. 콜드 재시작 (cold restart) 후, 첫 번째 요청은 항상 작은 롤백 (rollback)을 필요로 합니다: 프롬프트 꼬리 부분을 다시 토큰화 (re-tokenizing)하면 BPE 경계가 이동할 수 있으며, 로짓 (logits)을 생성하기 위해 최소 하나 이상의 토큰이 재처리되어야 합니다. 재사용 경로는 롤백 대상과 일치하거나 그 이전의 체크포인트를 통해서만 롤백을 수행합니다. 체크포인트 리스트가 비어 있으면, 서버는 아무것도 찾지 못하고 포기한 뒤 모든 것을 다시 계산합니다.
작동하지 않은 해결책 (v1)
명백한 해결책: 복구 시점에 복구된 상태로부터 체크포인트를 합성하는 것입니다. 이는 실패했으며, 그 실패는 시사하는 바가 큽.
합성된 체크포인트(synthesized checkpoint)는 팁(tip) — 즉, 최종 위치(100K 실행 시 100,042번째) — 에 위치하는 반면, 롤백(rollback)은 더 이전 위치(100,034번째)를 대상으로 합니다. 체크포인트는 자신의 위치와 같거나 그 이후의 롤백에 대해서만 역할을 수행할 수 있으므로, 팁 체크포인트는 항상 발생하는 바로 그 롤백 상황에서는 무용지물입니다. 불변의 법칙(invariant): 팁 이전의 체크포인트가 필요하며, 이는 오직 저장(save) 시점에만 존재합니다.
성공한 해결책 (v2: 사이드카 (sidecar))
tools/server/server-context.cpp 파일의 117행: SLOT_SAVE에서 체크포인트 목록을 버전 관리되는 사이드카 파일(<state>.ckpt)로 영속화(persist)하고, SLOT_RESTORE에서 이를 다시 로드합니다. 이제 롤백은 실제로 영속화된 체크포인트에 도달하며, 오직 마지막 몇 개의 테일 토큰(tail tokens)만 다시 처리됩니다. 만약 사이드카 파일이 없다면 — 예를 들어, 이전 빌드에서 저장된 상태 파일인 경우 — 서버는 v1 방식의 팁 합성(tip synthesis)으로 폴백(fallback)하며, 이는 정확한 추가(append) 재개를 지원하면서도 그 외의 경우에는 패치 전 동작으로 우아하게 저하(degrade gracefully)됩니다: 즉, 전체 재-프리필(re-prefill)을 수행하지만, 출력은 정확하며 크래시(crash)는 발생하지 않습니다.
주요 결과
지표 성능 데이터
- 100K 베이스라인 전체 프리필(full prefill): 722.4초(실제 시간) / 719,975ms(API 시간) (138.9 t/s)
- 저장(Save): 1,777ms (2.56 GB 상태 + 299.3 MB 사이드카)
- 콜드 재시작(Cold restart) → 1,592ms 내에 100,043개 토큰 복구
- 복구 후 델타 쿼리(Delta query): 1,000ms(API 시간) / 2.72초(실제 시간) — 95% 깊이의 카나리 사실(canary fact) 회상 성공
- 동일 빌드 A/B 테스트 (사이드카 숨김): 720.1초 전체 재-프리필; 정확한 출력, 크래시 없음
- 헤드라인: 델타 프리필 약 720배 개선 / 엔드-투-엔드(end-to-end) 재개 약 167배 개선
A/B 테스트 행이 중요한 증거입니다: 동일한 바이너리, 동일한 상태 파일, 오직 사이드카만 제거했을 때 — 사이드카가 없으면 720.1초, 있으면 1.0초가 걸렸습니다. 사이드카가 효과의 전부입니다.
실시간 회귀 테스트(Live regression) 또한 전반적으로 통과했습니다: 실시간 프리픽스 재사용(prefix reuse)은 변경되지 않았으며(action=save가 명시적으로 호출되지 않는 한 사이드카 파일은 작성되지 않음), 복구된 세션은 정확한 회상 능력을 갖춘 완전히 캐시된 멀티 턴(multi-turn) 대화를 유지했으며, 분기된 연속성을 가진 일시 정지 후 재개(park-and-resume) 상황에서도 사이드카 체크포인트를 통해 정상적으로 서비스되었습니다.
결론 및 뉘앙스 (Conclusion & Nuance)
llama-cpp-turboquant 포크(fork)에 대한 PR(Pull Request)로 수정 사항이 반영되었습니다 (커밋 eaf98e612, +117 라인): TheTom/llama-cpp-turboquant#206. 근본적인 버그는 업스트림(upstream) llama.cpp 마스터(master) 브랜치에도 존재하며 — Dense 모델과 SWA(Sliding Window Attention) 모델 모두에서 확인되었습니다 — 해당 브랜치에서는 아직 수정되지 않은 상태로 남아 있습니다.
이 하이브리드 아키텍처(hybrid architecture)에서 사이드카(sidecar) 크기는 컨텍스트(context) 크기에 독립적입니다: 순환 상태(recurrent state) 체크포인트당 약 149.6 MiB이며, 두 개의 체크포인트는 컨텍스트가 1K일 때나 100K일 때 모두 299.3 MB입니다. 순수 SWA(Pure-SWA) 체크포인트 페이로드(payload)는 다르게 확장될 수 있으며 아직 측정되지 않았습니다. 별도로: 하이브리드 모델에서 -np 2 --kv-unified 옵션 사용 시 듀얼 슬롯(dual-slot) 캐시가 삭제되는 현상은 기존에 존재하던 동작임이 밝혀졌으며, 패치가 적용되지 않은 빌드에서도 재현되었고 이번 패치와는 무관합니다.
https://gist.github.com/apollo-mg/6defe7c0e3aba47727c758df03360b3e
제출자: /u/apollo_mg
[링크] [댓글]
AI 자동 생성 콘텐츠
본 콘텐츠는 r/LocalLLaMA의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기