본문으로 건너뛰기

Architecture Review

변경 검증 가이드 (다음 fetch 후):

git log eaa2bfee..HEAD -- lmcache/v1/storage_backend/ lmcache/v1/cache_engine.py lmcache/v1/cache_controller/

커밋이 잡히면 본 문서의 결론 중 어떤 게 깨질지 점검 필요:

  • local_disk_backend.py 변경 → "1 chunk = 1 file", use_odirect, LocalDiskWorker 우선순위(PREFETCH > DELETE > PUT) 항목 재확인
  • abstract_backend.py 변경 → put/get/prefetch 블로킹/비블로킹 가정 재확인
  • storage_manager.py 변경 → LRU eviction → async offloading 트리거 흐름 재확인
  • cache_engine.py chunk 크기 관련 변경 → 256 token 청크 ↔ FDP RU 정렬 논의 영향
  • cache_controller/ 변경 → Clear/Lookup/Move API 의 의미 변동 여부

┌─────────────────────────────────────────┐ │ Application (User) │ └──────────────────┬──────────────────────┘ │ HTTP Request ┌──────────────────▼──────────────────────┐ │ vLLM (Inference Engine) │ │ ┌─────────────┐ ┌────────────────┐ │ │ │ Scheduler │ │ GPU Worker │ │ │ └──────┬──────┘ └───────┬────────┘ │ └─────────┼───────────────────┼───────────┘ │ (LMCache 연동) │ ┌─────────▼───────────────────▼───────────┐ │ LMCache Layer │ │ ┌──────────────────────────────────┐ │ │ │ Cache Index (Token DB) │ │ │ └──────────────────────────────────┘ │ │ ┌──────────────────────────────────┐ │ │ │ Storage Manager │ │ │ └───┬──────────────┬───────────────┘ │ │ │ │ │ │ ┌───▼───┐ ┌───▼──────────┐ │ │ │ CPU │ │ LocalDisk │ │
│ │ DRAM │ │ Backend │ │ │ └───────┘ └───┬──────────┘ │ └────────────────────┼───────────────────┘ │ ┌────────────────────▼───────────────────┐ │ Storage Stack │ │ ┌──────────────────────────────────┐ │ │ │ File System (ext4/xfs) │ │ │ └──────────────────────────────────┘ │ │ ┌──────────────────────────────────┐ │ │ │ Block Layer (I/O Scheduler) │ │ │ └──────────────────────────────────┘ │ │ ┌──────────────────────────────────┐ │ │ │ NVMe Driver │ │ │ └──────────────────────────────────┘ │ │ ┌──────────────────────────────────┐ │ │ │ NVMe SSD (FDP/HC-SSD) │ │ │ └──────────────────────────────────┘ │ └────────────────────────────────────────┘

리뷰목적-> LMCache가 NVMe에 어떤 방식으로 I/O를 내려보내는지 이해하기 위함

Architecture Overview Review LMCache 전체 구조(LMCache가 어떻게 생겼지?)

Q1. LMCache의 4개 스토리지 티어를 빠른 순서대로 나열해볼 수 있어? 그리고 각각 어떤 역할인지 한 줄씩 말해봐.

GPU Memory, CPU DRAM, Local storage, Remote storage GPU Memory - 현재 추론에 실제로 사용 중인 'Active Working Set.' CPU DRAM - Hot cache 역할. GPU Memory overflow 시 offloading, GPU<->CPU 전송 속도를 높이기 위해 Pinned Memory로 씀 Local Storage - CPU DRAM에서 다 못담는 대용량 KV Cache를 위한 확장 티어. LRU 정책에 의해 Local storage에 kv cache 저장됨. Remote Storage - 영구 보관. 용량 큼. 가장 느림.

Q2. KV Cache가 NVMe에 write되는 건 어떤 상황에서 발생해? (힌트: 어떤 컴포넌트가 트리거야?)

CPU DRAM이 가득 참 -> Memory Allocator가 LRU Eviction 실행 (Q. DRAM이 가득 찬거 어떤방식으로 캐치?) -> Async Offloading이 비동기로 NVMe write 즉 [Memory allocator]가 판단. [Async offloading]이 실제로 nvme write

Q3. Storage Mode랑 Transport Mode의 차이를 한 문장으로 설명해봐.

Storage Mode는 KV Cache를 여러 계층에서 저장, 즉 KV Cache를 재활용 하는 것이고, Transport Mode는 Prefill과 Decode 가 다른 서버에서 이루어질때 KV cache를 전송하는 모드이다.

Q4. Cache Index가 256토큰 단위로 청크를 나눈다고 했는데, 이게 FDP 설계할 때 왜 중요한 정보야?

청크단위로 storage에 전송되니까! FDP에는 RU (Reclaim Unit)이라는 개념이 있다. SSD가 GC할 때 한 번에 정리하는 단위. 이 크기랑 write단위가 안 맞으면 불필요한 데이터까지 같이 지워지고 다시 써야해서 WAF가 올라감 즉, LMCache write단위와 RU크기를 맞춰주면 GC효율이 올라감.

256토큰 청크 단위로 NVMe에 I/O가 발생하기 때문에, FDP의 RU 크기를 이 청크 크기에 맞게 정렬하면 WAF를 줄이고 GC 효율을 높일 수 있다

Q5. Controller의 API 중에서 FDP ON/OFF 비교 실험할 때 제일 유용하게 쓸 수 있는 API는 뭐고, 왜 그렇게 생각해?

실험 전 → 이전 캐시 데이터가 남아있으면 안 되잖아. 깨끗하게 초기화해야 해 실험 중 → NVMe에 KV Cache가 실제로 내려갔는지 확인해야 해 실험 후 → 비동기 write가 다 끝난 시점을 알아야 정확한 측정이 가능해

이걸 Controller API랑 연결하면: | 상황 | 필요한 API | | 실험 전 캐시 초기화 | Clear | | NVMe에 캐시 있는지 확인 | Lookup | | 비동기 write 완료 확인 | Health & Finish Check | | 특정 캐시 강제로 NVMe로 내려보내기 | Move |

비동기 write이므로 write 발생과 write 완료 시점이 다름 *

========================================================================================

Storage backend(local) Review LMCache <-> Storage 경계 (I/O가 어떻게 NVMe로 내려갈까?)

Q1. Local Storage에서 KV Cache 청크 하나가 디스크에 어떤 형태로 저장돼? 그리고 이게 FDP 설계할 때 왜 문제가 될 수 있어? 파일1개. 256token = 1chunk = 1file 대량의 small I/O 발생

Q2. use_odirect 옵션이 뭐고, 우리가 FDP 실험할 때 이걸 켜야 하는 이유가 뭐야? OS의 Page Cache를 거치지 않고 NVMe (ssd)에 직접 I/O하는 것. 정확도. Page cache를 거치면 NVMe를 거치지 않고 cache hit 발생할 수도 있으니까 정확도가 떨어짐.

CPU DRAM ├── LMCache가 관리하는 영역 → KV Cache 저장 (Pinned Memory) └── OS가 관리하는 영역 → Page Cache (파일 읽기/쓰기 임시 버퍼) 둘 다 물리적으로는 같은 DRAM 칩이지만 누가 관리하느냐가 달라.

LMCache CPU DRAM = LMCache가 직접 할당해서 KV Cache를 담는 공간 Page Cache = OS가 파일 I/O를 빠르게 하려고 자동으로 쓰는 버퍼

Q3. put(), get(), prefetch() 세 가지 오퍼레이션의 차이를 설명해봐. 특히 블로킹/비블로킹 관점에서!

put() : write. cpu dram이 부족할 때 비동기적으로 이루어짐. get() : read. blocking으로 이루어짐. 지금 당장 필요한 데이터기 때문에! 추론이 이 데이터를 받아야 진행할 수 있으니까 기다릴 수 밖에 없음 -> 결과적으로 TTFT에 영향을 줌 prefetch() : storage에 있는 걸 cpu로 미리 불러오는 것. 비동기적으로 이루어짐.

Q4. LocalDiskWorker의 우선순위가 PREFETCH > DELETE > PUT 순서인데, 왜 이런 순서로 설계했을까?

read가 가장 중요함 왜냐면 TTFT 최소화 목적. 빨리 불러와야 빨리 디코딩 하고 사용자에게 빨리 응답할 수 있음.

Q5. Multi-Path 설정이 뭔지 설명하고, FDP 검증 실험할 때 이걸 어떻게 활용하면 좋을지 말해봐.

multi device일 때 특정 gpu에 특정 disk를 할당할 수 있는 설정. GPU와 disk가 맵핑되어있으니까 kv cache 데이터가 흩어지지 않아서 분석하기 쉽다? 각 NVMe에 I/O가 섞이지 않으므로

  1. WAF 측정이 정확해짐
  2. I/O 패턴 분석이 GPU별로 깔끔하게 나뉨
  3. FDP 스트림이 다른 GPU의 Write에 오염되지 않음.

"GPU마다 NVMe를 1:1로 매핑해서 KV Cache I/O가 섞이지 않게 분리할 수 있어. FDP 실험할 때 GPU별로 FDP ON/OFF를 나눠서 동시에 비교 실험하거나, WAF·I/O 패턴을 GPU 단위로 정확하게 측정할 수 있어."

========================================================================================

Async Loading Review LMCache 내부 I/O 동작 (I/O 패턴이 어떻게 생겼는지)

Q1.async_loading의 핵심 목적이 뭐야? 한문장으로 설명하면?

GPU를 놀지 않게 하려고 GPU 추론 연산과 데이터를 가져오는거랑 동시에 할 수 있게 함. "Scheduler 측 lookup"과 "Worker 측 prefetch / retrieval"을 분리. 이 분리 덕분에 overlap이 가능.

Q2.Scheduler랑 Worker가 어떻게 통신해? 그리고 Worker는 LMCache의 어떤 컴포넌트야?

ZMQ((ZeroMQ) = 빠른 메시지 전송을 위한 통신 라이브러리) 비동기로 통신. Worker는 KV Cache I/O요청을 받아서 백엔드에 위임하고 결과를 돌려주는 중간 서버

Q3. 캐시 히트가 났을 때랑 미스났을 때 각각 어떤 일이 벌어져?

lookup -> Cache hit 발생하면 -> 결과 전달 lookup -> Cache miss 발생하면 -> 생성된 chunk 저장

Q4. LocalDiskWorker의 현재 구조가 진짜 async I/O가 아니다 라고 했는데, 왜 그렇고 io_uring으로 바꾸면 뭐가 좋아져?

Q5. FDP/HC-SSD Backend를 새로 만들 때 async_loading을 지원하려면 반드시 구현해야 하는 인터페이스가 뭐야? 그리고 왜 그게 필요해?