본문으로 건너뛰기

NVMe FDP (Flexible Data Placement)

[!tldr] 업무 관점 takeaway 우리 미션의 핵심 HW 기술. Host가 SSD에 write 명령을 보낼 때 "이 데이터는 RUH #X에 놔라"는 힌트를 추가하는 NVMe 표준 (TP4146, 2022). 같은 RUH끼리 같은 RU(Reclaim Unit)에 모여 lifetime이 정렬 → [[Garbage-Collection|GC]] 복사 최소화 → [[WAF]] ~1.0. 우리는 [[LMCache-개요|LMCache]]의 KV Cache lifetime을 RUH에 매핑하는 [[기여-포인트-맵|Backend [1]·[9]]]를 만든다.


한 줄 정의

NVMe의 데이터 배치 힌트 표준. Host가 write 시 placement identifier를 함께 보내면 SSD가 같은 식별자끼리 같은 [[NAND-Flash-기초|NAND]] RU에 배치 → 수명 분리로 GC 비용 절감.


4가지 핵심 개념

개념영문설명
Reclaim Unit (RU)Reclaim UnitSSD 내부 "데이터 그룹" 단위 = 기존 Superblock. GC가 RU 단위로 발생
Reclaim Group (RG)Reclaim GroupRU들의 모음. NAND Die 기반으로 묶임
Reclaim Unit Handle (RUH)RUHHost가 사용하는 "라벨" / 포인터. "이 데이터는 RUH #2"라고 힌트
Placement Handle (PH)PHHost write 명령 시의 인덱스. 관계: PH → RUH → RU

추가: Endurance Group (EG) — 수명 함께 관리되는 NAND 블록 집합. 보통 SSD 전체.


기존 SSD vs FDP SSD

기존 (CNS — Conventional Namespace SSD)

Host → LBA만 제공

SSD 내부: Append Point 1개

Superblock 내부:
[A(짧)][B(김)][C(짧)][D(김)][E(짧)] (섞임)

짧은 게 지워지면 → 빈칸이 군데군데 → GC 시 긴 것까지 복사.

FDP SSD

Host → LBA + RUH 힌트 제공

SSD 내부: RUH 수만큼 Append Point

RU #0 (RUH #0): [A(짧)][C(짧)][E(짧)] (수명 짧음만)
RU #1 (RUH #1): [B(김)][D(김)] (수명 김만)

RU #0이 모두 지워지면 → valid copy 0 → 그냥 erase → WAF ~1.0.

자세한 Append Point 그림: [[NAND-Flash-기초]].


FDP의 결정적 특성

특성함의
하위 호환FDP 모르는 앱도 동작. 아는 앱만 추가 혜택
Read/TRIM 변경 없음Write 명령에만 placement handle 추가
WAF 보장 가능잘 매핑하면 ~1.0 달성 가능 ([[CacheLib-FDP-사례

Linux Kernel 지원

구성요소상태
Linux Kernel5.13+ I/O Passthru, 5.19+ 안정
xNVMev0.7+ Full Support
QEMUv8.0+ FDP Emulation (WAF 시뮬레이션 X, 기능 검증용)
nvme-cliUpstream (FDP 명령/로그 페이지)
FioRU/RUH 지원, io_uring trim 개선 중
SPDKv23.05+
CacheLibOngoing (Meta)

FDP hint 전달 경로 2가지

경로 A — I/O Passthru (저지연)
App → io_uring_cmd → NVMe Driver → FDP SSD
파일시스템 우회, NVMe 디바이스 직접 접근

경로 B — File System / Block IO
App → VFS → FS → Block Layer → NVMe → FDP SSD
─ Application-driven: 앱이 힌트 부여 (LMCache에 적합)
─ Filesystem-driven: FS가 자동 분리 (예: f2fs)

LMCache 관점에서는 앱이 KV 수명을 가장 잘 안다 → Application-driven 경로 + io_uring_cmd 조합이 정답. ([[io_uring]], [[기여-포인트-맵|기여 포인트 [2][8]]])


FIO로 효과 측정

ioengine=io_uring_cmd
fdp=1
fdp_pli=<placement identifier list>

WAF 측정: [[WAF#측정-방법|WAF 페이지의 nvme fdp stats]] 참조.


QEMU 에뮬레이션 (실제 SSD 없이 실험 가능)

-device "nvme-subsys,id=nvme-subsys0,fdp=on,fdp.runs=96M,fdp.nrg=1,fdp.nruh=16"
-device "nvme,id=nvme0,serial=deadbeef,subsys=nvme-subsys0"
-drive "id=fdp-1,file=data.img,format=raw,if=none"
-device "nvme-ns,id=fdp-1,drive=fdp-1,nsid=1,fdp.ruhs=1-15"
  • fdp.runs — RU 크기
  • fdp.nrg — Reclaim Group 수
  • fdp.nruh — RUH 수

⚠️ 기능 검증만 가능, WAF는 시뮬레이션 안 됨 (실 SSD 필요).


LMCache RUH 매핑 전략 (설계 후보)

KV Cache 종류 → RUH 매핑
─────────────────────────────────────────
Prefix Cache (long-lived) → RUH #0 (long bucket)
중간 컨텍스트 (medium) → RUH #1
Single-query KV (short-lived) → RUH #2 (short bucket)
임시 버퍼 → RUH #3 (very short)

매핑 기준 후보:

  • 접근 빈도 (LFU bucket)
  • 생성 시간 (FIFO bucket)
  • 세션 / 모델 단위
  • 사용자 명시 (pin 여부 등)

[[LMCache-Local-Disk-Backend|LRU 정책]]이 이미 lifetime bucket을 만들어주고 있으므로, 그걸 그대로 RUH ID로 사용하는 게 자연스럽다.


의외의 연결

[!note] FDP RUH = lifetime-aware allocator 결국 FDP는 NAND 안에서 동작하는 lifetime-aware free space allocator다. [[KV-Cache]] 워크로드는 lifetime이 명백히 나뉘므로 ideal workload. "풀고 싶은 문제와 푸는 도구가 너무 잘 맞는 케이스".

[!note] FDP는 ZNS의 실패에서 배웠다 [[데이터-배치-기술-역사]] 참조. ZNS는 좋았지만 호환성 깨서 죽음. FDP는 "hint만 추가, 안 쓰면 평소대로" 라는 하위 호환을 지켜서 살아남음.


관련 페이지

  • [[NAND-Flash-기초]] — RU/Append Point가 풀고자 하는 NAND 제약
  • [[WAF]] — FDP가 줄이는 핵심 지표
  • [[Garbage-Collection]] — FDP가 줄이는 메커니즘
  • [[HC-SSD]] — FDP 효과가 더 큰 미디어
  • [[CacheLib-FDP-사례]] — 실측 (WAF 3.5 → 1.0)
  • [[데이터-배치-기술-역사]] — Streams/ZNS와의 비교
  • [[io_uring]] — FDP hint 전달의 정석 경로
  • [[기여-포인트-맵]] — [1][9][10][11] 우리 작업 영역