LMCache 코드 구조 분석 — Overview & storage_backend 진입
변경 검증 가이드 (다음 fetch 후):
git log eaa2bfee..HEAD -- lmcache/v1/ lmcache/v1/storage_backend/ lmcache/v1/distributed/l2_adapters/ docs/design/v1/distributed/l2_adapters/커밋이 잡히면 다음을 재확인:
abstract_backend.py라인 번호(27/325/424) — 인터페이스 위치 변경되면 §4.1 인용 끊김storage_backend/__init__.py— 빌트인 vs plugin 로딩 분기 구조 유지 여부 (§4.2)storage_backend/파일 추가/삭제 → §3 라인수 표 갱신 필요distributed/l2_adapters/새 어댑터 추가 → §5.1 진입 권장 순서 영향docs/design/v1/distributed/l2_adapters/디자인 doc 변경 → 진입 순서/근거 재검토plugins/또는raw_block/신규 파일 → §4.3, §5.2, §5.3 갱신
작성일: 2026-05-19
분석 대상: /home/ny/LMCache/
1. LMCache 최상위 레이아웃 (lmcache/)
lmcache/
├── v1/ ← 현재 활성 런타임 (모든 신규 개발은 여기)
├── integration/ ← vLLM / SGLang / TRT-LLM 어댑터
├── storage_backend/ ← 레거시 백엔드 (v1/storage_backend 로 대체됨)
├── cli/ ← 커맨드라인 도구
├── tools/ ← 보조 스크립트
├── *.so ← C++ 확장 (c_ops, lmcache_fs, lmcache_redis, native_storage_ops)
└── connections.py / logging.py / observability.py / utils.py
v1/가 본체이고, 최상위storage_backend/는 deprecated.- 분석 타깃은
lmcache/v1/storage_backend/.
2. lmcache/v1/ 내부 — 런타임의 큰 그림
| 그룹 | 모듈 | 역할 |
|---|---|---|
| 엔진 코어 | cache_engine.py, cache_interface.py, manager.py, token_database.py, metadata.py | KV 캐시 라이프사이클 오케스트레이션 |
| 스토리지 계층 | storage_backend/ | GPU→CPU→Disk→S3/Redis/NIXL 계층형 백엔드 (오늘의 타깃) |
| 메모리/할당 | memory_management.py, lazy_memory_allocator.py, pin_monitor.py | 버퍼/핀 메모리 관리 |
| GPU 연동 | gpu_connector/, compute/, ec_engine.py | 디바이스 측 KV 이동·연산 |
| 프로세스간 | multiprocess/, mp_observability/, transfer_channel/, rpc/ | 워커 ↔ 캐시 서버 IPC |
| 분산/공유 | distributed/, cache_controller/, p2p_backend | 노드 간 KV 공유, disagg prefill |
| 서버/API | server/, api_server/, internal_api_server/, offload_server/, lookup_client/ | 컨트롤 플레인 |
| 운영 | health_monitor/, check/, basic_check.py, periodic_thread.py, event_manager.py | 헬스/모니터링 |
| 플랫폼/플러그인 | platform/, plugin/, system_detection.py, standalone/ | 환경 적응 |
| 설정/공통 | config.py, config_base.py, exceptions/, protocol.py, utils/ | 설정·예외·프로토콜 |
설계 문서(docs/design/v1/)는 distributed, gpu_connector, mp_observability, multiprocess, platform 만 존재하며, storage_backend/ 디자인 doc 디렉토리는 아직 없음. 즉 코드와 docstring 위주로 파야 함.
3. lmcache/v1/storage_backend/ 구조 (라인수 기준)
storage_backend/
├── abstract_backend.py 460 ← 공통 인터페이스 (StorageBackendInterface)
├── storage_manager.py 1371 ← 백엔드 오케스트레이션 (계층 관리)
├── __init__.py 316 ← 백엔드 팩토리/등록
│
├── local_cpu_backend.py 886 ← L1: pinned CPU 메모리
├── local_disk_backend.py 673 ← L2: 로컬 디스크
├── remote_backend.py 625 ← L3: Redis/S3 등 원격
├── gds_backend.py 1227 ← GPUDirect Storage
├── nixl_storage_backend.py 1662 ← NIXL 백엔드
├── maru_backend.py 735
├── p2p_backend.py 788 ← 노드 간 P2P
├── pd_backend.py 1085 ← prefill/decode disaggregation
├── pd_backend_async.py 1664 ← 동상, async 버전
├── audit_backend.py 233 ← 데코레이터 (정합성 검증)
│
├── connector/ ← 원격 백엔드용 transport (redis, s3 등)
├── naive_serde/ ← 직렬화/역직렬화
├── cache_policy/ ← eviction 정책 (LRU 등)
├── job_executor/ ← 비동기 작업 실행기
├── dax/ ← DAX(persistent memory) 경로
├── raw_block/ ← 블록 디바이스 직접 I/O
├── plugins/ ← 외부 백엔드 플러그인
├── native_clients/ ← C++ 확장 클라이언트 래퍼
│
├── batched_message_sender.py 222
├── resp_client.py 227 ← RESP(Redis 프로토콜)
├── path_sharder.py 115 ← 디스크 경로 샤딩
└── storage_backend_listener.py 19
4. plugins/ vs 빌트인 백엔드 차이
한 줄 요약: plugins/ = 동적으로 로드되는 "꽂아 쓰는" 백엔드, 나머지 = 코어에 하드코딩된 빌트인 백엔드.
4.1 인터페이스 계층 (abstract_backend.py)
StorageBackendInterface ← 공통 추상 (put/get/lookup …) # line 27
├─ AllocatorBackendInterface ← 자체 메모리 할당까지 책임 # line 325
│ ↑ 빌트인 백엔드들 (CPU/Disk/Remote/GDS/NIXL …) 이 이쪽을 상속
└─ StoragePluginInterface ← plug-and-play 용 베이스 # line 424
↑ plugins/* 가 이쪽을 상속
추가 인자: config, metadata, local_cpu_backend, loop
StoragePluginInterface docstring 그대로:
"implement when you want to add a storage backend in a configurable or plug and play fashion."
4.2 로딩 방식 차이 (storage_backend/__init__.py)
| 함수 | 동작 | 대상 |
|---|---|---|
CreateStorageBackends() (line 111~) | if config.enable_pd: ..., if config.local_cpu: ... 처럼 플래그 분기로 import + 인스턴스화 | 빌트인 백엔드 |
storage_plugin_launcher() (line 40~) | config.storage_plugins + extra_config.storage_plugin.<name>.module_path/class_name 를 읽어 importlib.import_module(...) 로 동적 로드 | plugin 백엔드 |
즉 plugin은 import 경로가 config 에 적혀 있어 LMCache 코드를 안 건드리고도 외부 패키지 클래스를 그대로 꽂을 수 있음.
4.3 dax/, raw_block/ 와의 관계
dax/ ← DaxCore (실제 I/O 엔진, mmap/persistent memory 접근)
plugins/
└─ dax_backend.py ← DaxCore + LocalCPUBackend 를 StoragePluginInterface 로 노출
raw_block/ ← RawBlockCore (io_uring 기반 블록 디바이스 I/O)
plugins/
└─ rust_raw_block_backend.py ← RawBlockCore 를 StoragePluginInterface 로 노출
즉 dax/, raw_block/ = 로우레벨 코어, plugins/* = 그 코어를 plugin 인터페이스에 맞춰 감싼 어댑터.
4.4 연구 관점 (FDP / HC-SSD / io_uring)
이 구조라면 LMCache 본체를 fork 하지 않고도 새 백엔드 = plugin 으로 등록 가능.
- FDP / HC-SSD:
StoragePluginInterface구현으로 새 백엔드를 추가하고, 로우레벨은raw_block/처럼 별도 코어 모듈로 분리 → 기존 패턴과 일관. - io_uring:
raw_block/core.py에 이미 구현되어 있음. 신규 구현이 아니라 기존 구현 분석·활용 관점.RawBlockCore의 io_uring 사용 방식, 큐 깊이/배치 정책, plugin 어댑터(rust_raw_block_backend.py) 가 어떻게 노출하는지 파악이 우선.
5. 분석 타깃 (업데이트)
연구 방향(FDP/HC-SSD)에 가장 직접적으로 닿는 영역으로 타깃 재설정:
5.1 1순위 — lmcache/v1/distributed/l2_adapters/
L2(원격/디스크 계층) 어댑터 모듈. 디자인 문서가 같이 있는 드문 영역이라 분석 효율이 높음.
lmcache/v1/distributed/l2_adapters/
├── base.py
├── config.py
├── factory.py
├── serde_wrapper.py
│
├── dax_l2_adapter.py
├── raw_block_l2_adapter.py
├── plugin_l2_adapter.py
├── native_plugin_l2_adapter.py
├── native_connector_l2_adapter.py
├── nixl_store_l2_adapter.py
├── nixl_store_dynamic_l2_adapter.py
├── mooncake_store_l2_adapter.py
├── fs_l2_adapter.py
├── fs_native_l2_adapter.py
├── s3_l2_adapter.py
├── resp_l2_adapter.py
└── mock_l2_adapter.py
docs/design/v1/distributed/l2_adapters/
├── overall.md
├── plugin.md
├── dax.md
├── raw_block.md
├── nixl_store.md
├── l2_eviction.md
├── l2_per_user_quota.md
└── serde_wrapper.md
5.2 2순위 — lmcache/v1/storage_backend/plugins/
StoragePluginInterface 구현 레퍼런스 (2개).
plugins/
├── dax_backend.py (917 lines)
└── rust_raw_block_backend.py (585 lines)
5.3 3순위 — lmcache/v1/storage_backend/raw_block/
io_uring 기반 블록 디바이스 I/O 코어. 새 백엔드 작성 시 의존하게 될 로우레벨 엔진.
raw_block/
├── core.py
├── key_codec.py
└── __init__.py
진입 권장 순서
docs/design/v1/distributed/l2_adapters/overall.md— L2 어댑터 전체 그림distributed/l2_adapters/base.py+factory.py— 어댑터 계약과 등록 흐름docs/design/v1/distributed/l2_adapters/plugin.md+plugin_l2_adapter.py— adapter ↔ plugin 연결docs/design/v1/distributed/l2_adapters/raw_block.md+raw_block_l2_adapter.py+storage_backend/raw_block/core.py+plugins/rust_raw_block_backend.py— raw_block 라인 전체 종단- (참고)
dax.md+dax_l2_adapter.py+dax/core.py+plugins/dax_backend.py— 같은 패턴으로 dax 라인 확인