FDP SSD for LMCache — PoC 검증 계획
이 문서의 목적: 서동주님이 작성하신 FDP PoC 브랜치를 우리 사내 평가 서버(smrc)에서 빌드·실행·측정해 FDP가 LMCache 워크로드에서 실제로 효과가 있는지를 정량적으로 확인하고, 그 결과로 upstream 기여 항목을 도출하기 위한 작업 계획입니다.
작성: Nayeon (Storage SW) · 대상 독자: 팀 전체 (LMCache/FDP 사전 지식 없이 읽을 수 있게 작성)
0. 한 장 요약 (TL;DR)
- 무엇을: LLM 추론 캐시 엔진 LMCache 가 KV 캐시를 SSD에 저장할 때, FDP SSD 기능으로 "수명이 비슷한 데이터끼리 같은 영역에 쓰기"를 적용한 PoC가 있다.
- 왜: 이렇게 하면 SSD 내부 가비지 컬렉션(GC) 시 불필요한 복사가 줄어 WAF(쓰기 증폭) 가 감소하고 SSD 수명·테일 레이턴시가 좋아진다는 가설.
- 이번 작업: 이 PoC를 사내 FDP 지원 SSD 서버에서 돌려, FDP 끄고/켜고를 같은 워크로드로 비교해 WAF·p99 지연·TTFT·캐시 적중률 4개 지표로 효과를 측정한다.
- 산출: 측정 결과 + upstream에 올릴 후속 개선 항목(파일 backend FDP 적용, placement 정책 모듈화 등) 정리.
1. 용어 정리 (먼저 읽어주세요)
| 용어 | 뜻 |
|---|---|
| LMCache | LLM 서빙에서 KV 캐시를 GPU→CPU→디스크→원격으로 계층 저장/재사용하는 오픈소스 엔진. vLLM 등과 연동된다. |
| KV 캐시 | LLM이 토큰을 생성할 때 재사용하는 attention key/value 텐서. 같은 프롬프트를 다시 처리할 때 이걸 디스크에서 불러오면 연산을 건너뛸 수 있다. |
| FDP (Flexible Data Placement) | NVMe SSD 표준 기능. 호스트(소프트웨어)가 각 쓰기를 어느 내부 영역에 둘지 힌트를 줄 수 있다. 수명이 비슷한 데이터를 같은 영역에 모으는 데 쓴다. |
| Placement Handle / RUH | FDP에서 "데이터를 담을 내부 묶음" 단위. SSD가 제공하는 핸들 개수(N)는 보통 최대 128개로 제한된다. 소프트웨어는 쓰기마다 핸들 번호를 지정한다. |
| WAF (Write Amplification Factor) | SSD가 실제로 NAND에 쓴 양 ÷ 호스트가 요청한 쓰기 양. 1에 가까울수록 좋다. GC가 데이터를 옮겨 쓰면 WAF가 커지고 수명이 줄어든다. |
| Preconditioning (사전 조건화) | SSD를 깨끗한 상태가 아니라 실사용처럼 가득 찬 "지속 상태" 로 만든 뒤 측정하는 과정. 깨끗한 SSD는 GC가 거의 안 일어나 WAF 효과가 안 보이기 때문. |
| raw_block backend | LMCache가 파일시스템을 거치지 않고 블록 디바이스에 직접 KV를 쓰는 고성능 저장 경로. io_uring_cmd(NVMe 패스스루)를 사용한다. |
| io_uring_cmd | 리눅스 비동기 I/O 인터페이스로 NVMe 명령을 직접 보내는 방식. FDP 핸들 같은 세밀한 힌트를 디바이스에 전달할 수 있다. |
| smrc | 사내 평가 서버. FDP를 지원하는 NVMe SSD가 장착되어 있다(확정). |
| tensormesh | 실제 LLM 서빙 트래픽을 재현하는 워크로드. 최종 측정 목표. |
| 측정 harness | 측정을 자동으로 돌려주는 독립 실행 스크립트. 실제 서비스 스택이 아니라, 합성 KV 쓰기 패턴을 만들어 LMCache에 흘려보내고 FDP 모드별로 WAF·지연을 캡처한다. PoC에는 benchmarks/fdp_waf_stress/ 라는 자체 harness가 들어있어, 실제 LLM 트래픽 없이도 FDP off/on 비교를 돌릴 수 있다. |
2. 배경 — 왜 LMCache에 FDP인가
(아래는 FDP 제안서 — 서동주/한대규님 — 내용을 정리한 것입니다.)
2.1 LMCache의 저장 I/O 특성
| 특성 | 설명 |
|---|---|
| 대용량 I/O | KV 청크 한 개가 수 MB ~ 수십 MB (모델·토큰 수에 비례) |
| 덮어쓰기 없음 | 한 번 쓰고 여러 번 읽는 WORM(Write Once Read Many) 패턴 |
| 순차 접근 | LLM의 자기회귀 특성상 앞 토큰부터 순서대로 프리픽스 캐시를 읽음 |
2.2 FDP SSD가 주는 이점
| 이점 | 설명 |
|---|---|
| 호스트 주도 데이터 배치 | 쓰기마다 어느 묶음(스트림)에 둘지 호스트가 지정 |
| WAF 감소·내구성 향상 | 수명이 비슷한 데이터를 같은 영역에 모아, GC 시 불필요한 내부 복사를 줄여 NAND 마모 감소 |
| 예측 가능한 지연시간 | GC 간섭이 줄어 p99 같은 테일 레이턴시 스파이크 완화, 멀티테넌트 간 간섭 감소 |
| ZNS와의 차이 | ZNS와 달리 배치가 100% 호스트 제어는 아님. 펌웨어가 내부적으로 스트림을 섞을 수 있음 |
2.3 핵심 과제 — "무엇을 같은 묶음에 둘 것인가"
데이터 수명을 어떻게 분류하느냐가 관건이다. 제안서는 세 가지 배치 시나리오를 제시한다.
① 프롬프트별 배치 (Per-Prompt) 같은 프롬프트에서 나온 KV 청크들은 함께 hot/cold가 되므로 같은 묶음에 둔다.
스트림 번호 = prompt_id % 핸들수(N)
제약: 핸들 수가 제한(≤128), 다른 프롬프트가 우연히 같은 묶음에 섞일 수 있음.
② 단계 인식 배치 (Phase-aware)
- 디코드 단계 KV = 해당 요청 동안만 쓰는 단명 데이터
- 프리필 단계 KV = 여러 요청에 재사용되는 장수명 데이터 → 둘을 다른 스트림으로 분리.
③ vLLM 워커별 배치 (Per-Worker) Tensor Parallelism>1이면 전체 지연은 가장 느린 랭크가 결정. 워커별로 스트림을 나눠 랭크 간 성능 격리를 개선.
Worker 0 → 묶음 0, Worker 1 → 묶음 1, Worker 2 → 묶음 2, ...
2.4 I/O 인터페이스 선택지
| 방식 | 장점 | 단점 |
|---|---|---|
| 파일시스템 (write hint) | LMCache 변경 최소, 기존 FS 사용 | FS가 스트림을 섞을 수 있음, NVMe 스트림 패싱 upstream 미반영 |
| Raw Block (io_uring_cmd) | 명시적 배치 가능, NVMe 패스스루로 고성능 | 커스텀 스토리지 엔진 필요, NVMe/커널 전문 지식 요구 |
3. 검증 대상 — FDP PoC 브랜치
- 브랜치:
DongDongJu/LMCache:fdp-waf-agentic-replay-poc(서동주님이 NVIDIA PoC용으로 작성) - 규모: dev 기준 약 39 커밋 / 95 파일
- 구성 (사전 코드 분석 단계1에서 확인):
- raw_block 저장 경로 인프라 (대부분 upstream dev에 이미 반영된 기능과 동등)
- FDP / io_uring_cmd 코어 (핵심 3 커밋) — 위 ①②③ placement 정책 일부 포함
- FDP 부하/WAF 측정 harness — FDP 끄고/켜고 비교 모드(
mixed/separated/no_fdp)를 갖춘 벤치 스크립트 포함
즉, 이 PoC는 "FDP를 적용하는 코드"와 "효과를 재는 측정 도구"를 함께 들고 있어, 우리 서버에서 빌드만 되면 비교 측정을 바로 돌릴 수 있는 상태다.
3.1 "무엇을 같은 묶음에 둘 것인가" — 어디까지 실제 구현됐나
2.3절의 3개 배치 시나리오가 모두 LMCache 본체에 들어있는 것은 아니다. 묶음에 쓰는 장치(통로) 와 무엇을 어느 묶음에 둘지 정하는 정책 을 나눠 보면:
| 항목 | 구현 위치 | 상태 |
|---|---|---|
| 묶음에 쓰는 통로 (핸들 번호를 실제 NVMe 쓰기 명령에 주입) | LMCache backend 코어 + Rust FFI | ✅ 완전 구현 — "지정한 묶음에 진짜로 쓴다"가 동작 |
| ③ 워커별 정책 (Worker N → 묶음 N) | LMCache backend 코어 | ✅ backend에 내장 — 하드웨어 단에서 실제 발화 |
① 프롬프트별 정책 (prompt_id % N) | 측정 harness 전용 | ⚠️ backend에는 없음 — harness가 묶음을 미리 정해 표시 |
| ② 단계별 정책 (프리필/디코드 분리) | 측정 harness 전용 | ⚠️ backend에는 없음 — harness 우회 |
측정 가능성: 셋 다 효과 측정은 가능하다. WAF는 어느 계층이 묶음을 정하든 nvme smart-log로 재므로, 정책이 harness에 있어도 off/on 비교가 성립한다. 다만 ①②의 측정값은 "harness가 묶음을 정했을 때의 효과"이지 "LMCache 본체에 정책이 내장된 상태"의 값은 아니다 — 이 내장화가 5단계 upstream 작업의 핵심 빈자리다.
현재까지 파악된 빈자리 (upstream 개선 후보):
- 파일시스템 backend의 FDP 적용은 미구현
- placement 정책 중 prompt/phase 인식은 본체가 아닌 측정 harness에만 존재 (위 표 ①②)
- SSD의 RUH 디스크립터 자동 조회 기능 미포함
4. 검증 계획 — 5단계
| 단계 | 내용 | 담당 | 위치 |
|---|---|---|---|
| 1 | PoC 코드 분석 — 구조 지도, 구현 완성도 audit | Nayeon | 로컬 (완료) |
| 2 | 환경 audit — FDP 파라미터·toolchain·권한 수집 | Codex | smrc 서버 / 현재 세션 |
| 3 | 빌드 + 동작 확인 — PoC 빌드, 회귀 테스트, FDP 경로 1회 발화 입증 | Codex | smrc 서버 / 현재 세션 |
| 4 | 워크로드 측정 — FDP off vs on 정량 비교 | Codex | smrc 서버 / 현재 세션 |
| 5 | 개선 도출 — 측정 기반 upstream PR 항목 정리 | Nayeon | 로컬 |
진행 방식: 사내 서버에서 돌리는 단계(2~4)는 복사·붙여넣기로 실행 가능한 스크립트를 미리 만들어 드리고, 실행 결과(로그/JSON)를 받아 정리합니다.
단계 2 — 환경 audit (먼저 실행)
목적: 측정에 필요한 입력값(SSD 용량, FDP 핸들 수, 쓰기 대역폭, 권한) 확정.
실행: precheck.sh 한 번 실행 → 결과 tarball 회수 (읽기 전용, 디바이스를 건드리지 않음).
수집 항목:
- 커널/디바이스 식별 (
nvme list,id-ctrl,id-ns→ 용량 C) - FDP 파라미터 (
nvme fdp configs→ 핸들 수 N,fdp status,fdp stats기준선) - WAF 기준선 (
nvme smart-log→ 누적 쓰기량) - toolchain (rustc/cargo/maturin/liburing — 빌드 가능 여부)
- 권한 (raw block 접근,
blkdiscard가능 여부 — 측정 반복에 필요)
단계 3 — 빌드 + 동작 확인
PoC 빌드 → raw_block 회귀 테스트 → 작은 데이터 1회 write 후 nvme fdp stats 변화량으로 "FDP 쓰기 경로가 실제 디바이스에 도달했다" 를 입증.
단계 4 — 측정 (효과 확인의 본체)
→ 5절에서 상세.
단계 5 — 개선 도출
측정 결과로 후속 작업 분할: placement 정책 모듈화 / 파일 backend write hint 적용 / raw_block 메타데이터 통로 / 한대규님 라인과의 통합 등.
5. FDP 효과를 어떻게 측정하나 (단계 4 상세)
5.1 핵심 아이디어
같은 워크로드(tensormesh)를 FDP 끈 상태와 켠 상태로 각각 돌리고, 아래 4개 지표를 비교한다.
| 지표 | 의미 | 측정 방법 |
|---|---|---|
| WAF | 쓰기 증폭 (낮을수록 좋음) | nvme smart-log 의 data_units_written ÷ 호스트 쓰기량 |
| p99 read latency | 읽기 테일 지연 | LMCache 로드 경로 타이머 |
| TTFT | 첫 토큰까지 시간 | tensormesh harness 출력 |
| Hit ratio | 캐시 적중률 | LMCache lookup hit ÷ total |
5.1.5 측정 순서 — PoC harness 먼저, tensormesh 나중
PoC는 자체 측정 harness(benchmarks/fdp_waf_stress/)를 들고 있어, 실제 LLM 트래픽 없이도 FDP off/on WAF 비교를 한 번에 돌릴 수 있다. 반면 tensormesh(실 워크로드) 연결은 harness가 자식 LMCache를 띄우는 구조라 별도 통합 작업이 필요하다. 따라서 측정은 2단계로 나눈다:
- 1차 — PoC 자체 harness (먼저):
--mode no_fdp / separated / mixed로 R1/R2/R3 WAF 비교를 즉시 확보. 통합 작업 없이 FDP 효과의 1차 신호를 얻는다. - 2차 — tensormesh 연결 (나중): 1차에서 효과가 확인되면, 실 워크로드(TTFT·hit ratio 포함)로 검증을 확장.
이유: 1차 harness는 통합 비용이 거의 없어 "효과가 있나/없나"를 가장 빨리 가른다. 효과가 없으면 tensormesh 통합 비용을 들이기 전에 방향을 재검토할 수 있다.
5.2 실행 순서 (Run matrix)
| ID | 내용 |
|---|---|
| R0 | 사전 조건화: 디스크를 비운 뒤 지속 상태가 될 때까지 채움 (매 측정 전 반복) |
| R1 | 기준: FDP off + tensormesh |
| R2 | FDP on (프롬프트별 배치, prompt_id % N) — 동일 시드 |
| R3 | (선택) 단계 인식 배치 (프리필/디코드 분리) |
| R4 | (선택) 워커별 배치 (워커 ≥ 2) |
5.3 ⚠️ 측정 파라미터는 아직 확정 전
사전 조건화 시간·채우는 양·각 run 길이·반복 횟수 같은 구체 숫자는 디바이스 사양과 시간 예산이 정해져야 계산됩니다. 임의로 정하지 않고 아래 규칙으로 산출합니다.
| 파라미터 | 결정 방법 | 입력 출처 |
|---|---|---|
| 사전 조건화 시간 | SSD 용량의 약 1.5~2배를 써야 지속 상태 도달 → 용량 ÷ 쓰기대역폭 | 단계 2 (용량·대역폭) |
| 채우는 양 | 지속 상태 목적이면 거의 전체 용량을 채운 뒤 랜덤 덮어쓰기 | 단계 2 (용량) |
| run 길이(ramp/steady) | 캐시 적중률·WAF 카운터가 안정될 때까지 — 1회 예비 실행으로 결정 | 단계 4 예비 run |
| 반복 횟수 | (서버 점유 가능 시간) ÷ (1 run 시간). 예산 미정이면 우선 1회 | 시간 예산 (미정) |
| 핸들 수 N | nvme fdp configs 의 RUH 개수 | 단계 2 |
주의: 깨끗한 SSD에서 측정하면 GC가 거의 없어 WAF 차이가 안 보입니다. 반드시 사전 조건화(R0)를 거친 지속 상태에서 측정해야 합니다. (제안서 "평가 시 고려사항" 참조)
5.4 측정 결과 (예시 형태)
측정 후 채워질 표 — 현재는 자리표시입니다.
| 지표 | FDP off | FDP on | 변화 |
|---|---|---|---|
| WAF | (R1) | (R2) | ↓ ? |
| p99 read | |||
| TTFT | |||
| Hit ratio |
결론 문장 예: "FDP on에서 WAF가 A→B로 감소, p99 read −C%."
6. 일정 · 리스크
대략 일정: 단계 1 완료. 단계 23은 서버 접속 후 11.5일, 단계 4 측정은 시간 예산에 따라 가변, 단계 5 정리 1~2일.
| 리스크 | 완화책 |
|---|---|
| PoC가 아직 머지 안 된 NVMe 인프라(PR #3274)에 의존 | 해당 PR 브랜치를 중간 베이스로 끼워 빌드, 또는 일반 I/O 경로만 측정 |
| PoC 브랜치가 최신 dev와 멀어 빌드 실패 | rebase / 핵심 커밋만 cherry-pick / baseline 시점으로 일시 downgrade |
blkdiscard 권한 부재로 측정 반복 불가 | 단계 2에서 권한 사전 확인, 없으면 서버 관리자에 요청 |
| 워크로드 비결정성으로 결과 노이즈 | 동일 시드, 사전 조건화 동일화, 예산 허용 시 여러 번 평균 |
7. 참고
- FDP 제안서 (서동주/한대규님): "FDP SSD for LMCache" — 본 문서 2·5절의 근거
- LMCache raw_block 저장 경로 / NVMe FDP 관련 upstream PR: #3274 (io_uring_cmd 인프라)
문의: Nayeon (Storage SW). 단계 2 환경 audit 스크립트(precheck.sh)는 준비되어 있으니, smrc 접속 가능 시점에 공유드립니다.