MinIO memkv 문서를 먼저 확인하겠습니다.Quick Start 페이지를 확인하겠습니다.vLLM 연동 페이지도 확인하겠습니다.MinIO MemKV 공식 문서(Quick Start, vLLM 연동 페이지)를 기준으로 정리했습니다. 문서에 없어서 제가 보충한 내용은 [보충]으로 표시했습니다.
MemKV 서버는 두 가지 형태가 있습니다.
| 형태 | 용도 | 스토리지 / 전송 |
|---|---|---|
| Distributed full server (Linux) | 운영용. 문서의 97.4 GiB/s 벤치마크가 이 형태입니다. | NVMe raw 디바이스 + RDMA(DC, RC fallback) |
| Single-node co-located | 개발, 엣지, GPU 개발 박스 | file 모드 + TCP (127.0.0.1) |
3.5단계 스토리지 용도라면 distributed full server가 맞습니다. 이 서버는 GPU 노드와 별도의 스토리지 노드(NVMe + RDMA NIC) 에 올리고, GPU 노드의 vLLM이 클라이언트로 접속하는 구성이 일반적입니다.
라이선스 제약은 Free 티어가 distributed 형태에서 서버 1대로 제한되고, 다중 서버 scale-out은 Enterprise가 필요합니다. 파일럿은 Free로 1대부터 시작할 수 있습니다. 라이선스(JWT)는 min.io/pricing에서 발급받습니다.
memkv setup 때 재포맷됩니다.memory.maxSize 이상이어야 하며, 부족하면 memkv start가 실행을 거부합니다.사전 점검 명령입니다. [보충]
uname -r # 6.8 이상인지
ibv_devices # RDMA 디바이스명 확인 (예: mlx5_0)
lsblk -d -o NAME,SIZE,MODEL # 전용 NVMe 식별 (OS 디스크 제외!)
grep -i huge /proc/meminfo
예를 들어 memory.maxSize를 64 GiB로 잡으면 2 MiB 페이지 32768개가 필요합니다. [보충: 계산 및 영구화]
sudo sysctl -w vm.nr_hugepages=32768
echo "vm.nr_hugepages=32768" | sudo tee /etc/sysctl.d/90-memkv.conf
바이너리 하나에 서버, admin client, 문서 사이트가 모두 들어 있습니다.
curl -LO https://dl.min.io/aistor/memkv/release/linux-amd64/memkv
chmod +x memkv
sudo mv memkv /usr/local/bin/
memkv --version
linux-arm64 빌드도 있으며 URL만 바꾸면 됩니다. .deb/.rpm 패키지로 설치했다면 NIXL 플러그인은 /usr/lib/memkv/libplugin_MEMKV.so에 이미 있습니다.
vLLM + LMCache 경로에서는 필요 없고, NIXL 경로(Dynamo KVBM 등)에서만 필요합니다.
sudo mkdir -p /opt/nvidia/nvda_nixl/lib/plugins
sudo curl -L \
https://dl.min.io/aistor/memkv/release/linux-amd64/libplugin_MEMKV.so \
-o /opt/nvidia/nvda_nixl/lib/plugins/libplugin_MEMKV.so
설치 위치는 NIXL_PLUGIN_DIR로 바꿀 수 있습니다.
sudo mkdir -p /etc/memkv
sudo install -m 0600 /path/to/minio.license /etc/memkv/minio.license
서버가 이 경로를 자동으로 인식하며, 다른 경로를 쓰려면 MEMKV_LICENSE=/path를 지정합니다.
⚠️ 지정한 드라이브의 데이터가 모두 삭제됩니다. 이미 초기화된 드라이브를 덮어쓰려면
--force가 필요합니다.
sudo memkv setup \
--drives /dev/nvme0n1 /dev/nvme1n1 /dev/nvme2n1 \
--rdma mlx5_0 \
| sudo tee /etc/memkv/config.yaml
YAML이 stdout으로 출력되므로 반드시 파일로 리다이렉트해야 합니다. 생성된 network.auth_key는 클라이언트와 공유하는 HMAC 키이니 따로 보관하세요. 전체 플래그는 CLI Reference(/operate/cli/#setup)에서 확인할 수 있습니다.
sudo memkv start --config /etc/memkv/config.yaml
curl http://localhost:9901/v1/health
# {"status":"healthy","rdma_active":true,"drives_online":3,"drives_offline":0,"drives_total":3}
포트는 데이터 플레인이 9900, admin/health가 9901(데이터 포트 + 1)입니다. rdma_active:true와 drives_online == drives_total을 확인하세요.
# /etc/systemd/system/memkv.service
[Unit]
Description=MinIO MemKV server
After=network-online.target
Wants=network-online.target
[Service]
ExecStart=/usr/local/bin/memkv start --config /etc/memkv/config.yaml
Restart=on-failure
LimitMEMLOCK=infinity
LimitNOFILE=1048576
[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload && sudo systemctl enable --now memkv
GPU 노드에 /etc/memkv/client.yaml을 만들고 MEMKV_CONFIG로 지정합니다.
servers:
- server-0.memkv.example.com:9900
rdma_devices: [mlx5_0, mlx5_1]
transport: auto # rdma_devices가 있으면 RDMA, 없으면 TCP
auth_key: <서버 config.yaml의 network.auth_key>
license: /etc/memkv/minio.license
export MEMKV_CONFIG=/etc/memkv/client.yaml
yaml의 모든 값은 MEMKV_SERVERS, MEMKV_RDMA_DEVICES, MEMKV_AUTH_KEY, MEMKV_LICENSE 같은 환경변수로 덮어쓸 수 있습니다.
GPU 개발 박스에서 빠르게 테스트할 때 쓰는 형태입니다. 운영용은 아닙니다.
sudo mkdir -p /etc/memkv /var/lib/memkv
openssl rand -hex 32 | sudo tee /etc/memkv/auth_key >/dev/null
sudo chmod 600 /etc/memkv/auth_key
AUTH=$(sudo cat /etc/memkv/auth_key)
sudo tee /etc/memkv/config.yaml >/dev/null <<EOF
network:
address: 127.0.0.1:9900
auth_key: "$AUTH"
memory:
block_size: 2 MiB
max_size: 1 GiB
storage:
mode: file
block_size: 4 MiB
drives:
- media: /var/lib/memkv/drive0.dat
max_size: 16 GiB
EOF
sudo memkv start --config /etc/memkv/config.yaml
이 경우 클라이언트는 transport: tcp, servers: [127.0.0.1:9900]로 설정합니다.
차트는 deploy/helm/memkv, 이미지는 quay.io/minio/memkv입니다. StatefulSet으로 서버 1개당 Pod 1개가 뜨고, hard pod-anti-affinity로 노드마다 하나씩 배치됩니다. 차트 소스를 어디서 받는지는 문서에 명시돼 있지 않으니 MinIO 다운로드 페이지(dl.minio.io/aistor/memkv/)나 담당 채널에서 확인이 필요합니다.
hugepages-2Mi 리소스를 인식해야 합니다) [보충]이 조건은 values.schema.json으로 설치 시점에 검증됩니다. NVMe를 쓸 스토리지 노드에는 라벨/테인트를 걸어두면 편합니다. [보충]
kubectl label node <node> memkv.minio.io/storage=true
MemKV는 raw block 디바이스에 직접 기록하므로, 기본 모드(drives.mode: blockDevice)는 드라이브마다 PVC를 하나씩 만들어 local PV에 바인딩합니다. PV의 nodeAffinity 덕분에 Pod가 해당 호스트로 자동 고정됩니다.
deploy/helm/memkv/examples/local-pv-example.yaml을 환경에 맞게 수정한 뒤 적용합니다.
kubectl apply -f deploy/helm/memkv/examples/local-pv-example.yaml
StorageClass 이름은 아래 설치 명령의 memkv-local과 맞춰야 합니다.
kubectl create namespace memkv
kubectl -n memkv create secret generic memkv-license \
--from-file=license=/path/to/minio.license
(A) 운영 권장: blockDevice
helm install memkv deploy/helm/memkv \
--namespace memkv \
--set replicaCount=2 \
--set drives.blockDevice.count=12 \
--set drives.blockDevice.storageClass=memkv-local \
--set license.existingSecret=memkv-license \
--set config.memory.maxSize="64 GiB" \
--set hugepages.amount=64Gi
replicaCount가 서버(노드) 수이고, drives.blockDevice.count는 노드당 드라이브 수입니다. Free 라이선스는 서버 1대 제한이므로 replicaCount=1로 시작하세요. [보충]
(B) hostDev 모드 (단일 테넌트, 편의용)
호스트 /dev를 Pod에 bind-mount하고 /dev/nvmeXn1을 직접 지정합니다. 차트가 Pod를 특정 노드에 고정해 주지 못하므로 nodeSelector나 affinity를 반드시 함께 지정해야 합니다.
helm install memkv deploy/helm/memkv \
--namespace memkv \
--set drives.mode=hostDev \
--set 'drives.hostDev.devices={/dev/nvme0n1,/dev/nvme1n1}' \
--set 'nodeSelector.memkv\.minio\.io/storage=true' \
--set license.existingSecret=memkv-license
(C) file 모드 (dev/kind/CI 전용)
PVC 안의 일반 파일을 mmap해서 쓰므로 NVMe나 privileged init이 필요 없고, 성능은 호스트 파일시스템에 제한됩니다. 운영용은 아닙니다.
helm install memkv deploy/helm/memkv \
--namespace memkv --create-namespace \
-f deploy/helm/memkv/ci/ci-values.yaml
kubectl -n memkv get pods -o wide # Pod가 서로 다른 노드에 배치됐는지
kubectl -n memkv get pvc -l app.kubernetes.io/instance=memkv # 전부 Bound인지
kubectl -n memkv port-forward svc/memkv-admin 9901:9901
curl http://127.0.0.1:9901/v1/health
# {"status":"healthy","rdma_active":true,"drives_online":12,"drives_offline":0,"drives_total":12}
vLLM Pod에서 접속할 서버 주소(MEMKV_SERVERS)는 StatefulSet의 Pod별 DNS 형태(memkv-0.<headless-svc>.memkv.svc:9900 등)가 될 가능성이 높습니다. 실제 서비스명은 kubectl -n memkv get svc로 확인하세요. [보충] Prometheus 메트릭과 K8s probe는 문서의 Monitoring 페이지(/operate/monitoring/)를 참고하세요.
문서상 vLLM 연결 방식은 세 가지입니다.
| 방식 | vLLM 버전 | 구조 |
|---|---|---|
| ① LMCache 플러그인 | 릴리스 버전 | vLLM → LMCacheConnectorV1 → memkv_lmcache → MemKV |
| ② Native offloading 2차 티어 | vLLM main | vLLM 자체 CPU offload 풀 뒤에 MemKV |
| ③ Direct (GPUDirect) | vLLM main | GPU 텐서 ↔ MemKV를 RDMA로 직접 이동 (CPU 풀 없음) |
릴리스 vLLM에서는 ①이 기본 경로이고, ③이 3.5단계 개념(GPU HBM → 네트워크 NVMe 직결)에 가장 가깝지만 vLLM main이 필요합니다. ②, ③은 각각 /integrate/vllm-offloading/, /integrate/vllm-gpudirect/ 페이지를 따로 확인하세요. 아래는 ① 기준입니다.
curl -LO https://dl.min.io/aistor/memkv/release/linux-amd64/memkv_lmcache-latest-cp39-abi3-linux_x86_64.whl
pip install 'lmcache>=0.5,<0.6' ./memkv_lmcache-latest-cp39-abi3-linux_x86_64.whl
lmcache.yaml)chunk_size: 256
local_cpu: True
max_local_cpu_size: 60 # GiB. 너무 작으면(한 자리 GiB) 모든 read가 MemKV로 감
enable_lazy_memory_allocator: True
lazy_memory_initial_ratio: 0.003
storage_plugins: memkv
extra_config:
storage_plugin.memkv.module_path: memkv_lmcache.backend
storage_plugin.memkv.class_name: MemKVStorageBackend
local_cpu: True와 max_local_cpu_size > 0은 필수입니다. LMCache의 CPU 풀(2단계)이 가득 차면 evict된 chunk가 MemKV로 흘러가는 구조라서, 이 풀이 곧 vLLM의 G2 역할을 합니다.
export MEMKV_SERVERS="host-a:9900,host-b:9900"
export MEMKV_AUTH_KEY="<64-hex>"
export MEMKV_TRANSPORT=auto # RDMA 사용 시. 컨테이너에서 RDMA 미노출이면 tcp
export MEMKV_LICENSE=/path/to/minio.license
export MEMKV_RDMA_DEVICES="mlx5_0,mlx5_1"
export MEMKV_STAGING_SIZE_MB=1024 # TP worker별 pinned staging 풀
export MEMKV_STAGING_SLOT_MB=16
TP=8이면 호스트당 pinned 메모리가 8 × MEMKV_STAGING_SIZE_MB만큼 필요합니다.
RDMA를 쓰려면 문서 예시에 --device=/dev/infiniband --cap-add=IPC_LOCK --ulimit memlock=-1을 추가하고 MEMKV_TRANSPORT=auto(또는 rdma)로 설정합니다.
docker run -d --name vllm-memkv \
--runtime=nvidia --net=host --shm-size=64g --ipc=host \
--device=/dev/infiniband --cap-add=IPC_LOCK --ulimit memlock=-1 \
-e MEMKV_SERVERS="host-a:9900,host-b:9900" \
-e MEMKV_AUTH_KEY="$AUTH_KEY" \
-e MEMKV_TRANSPORT=auto \
-e MEMKV_RDMA_DEVICES="mlx5_0,mlx5_1" \
-e MEMKV_LICENSE=/minio.license \
-e LMCACHE_CONFIG_FILE=/lmcache.yaml \
-v /path/to/models:/inference-models:ro \
-v /path/to/minio.license:/minio.license:ro \
-v /path/to/lmcache.yaml:/lmcache.yaml:ro \
-v /path/to/wheels:/plugins:ro \
--entrypoint bash \
vllm/vllm-openai:<tag> -lc '
pip install "lmcache>=0.5,<0.6" /plugins/memkv_lmcache-*.whl &&
vllm serve /inference-models/<model-dir> \
--host 0.0.0.0 --port 8810 \
--tensor-parallel-size <N> \
--max-model-len <max_seq_len> \
--gpu-memory-utilization 0.85 \
--enable-prefix-caching \
--kv-transfer-config "{\"kv_connector\":\"LMCacheConnectorV1\",\"kv_role\":\"kv_both\"}"
'
정상 기동 시 TP worker마다 Created dynamic backend: memkv, memkv-client license verified, MemKVStorageBackend ready (servers=[...], rdma=...) 로그가 순서대로 보입니다. 이후 chunk_size(256 토큰)보다 긴 프롬프트가 들어오면 Stored ... tokens 로그의 put_time으로 MemKV 쓰기 시간을 볼 수 있습니다.
values.yaml 전체 키는 Quick Start에 없으니 차트의 deploy/helm/README.md를 보세요.config.yaml 전체 스키마는 Configuration 페이지(/operate/configuration/)에서 확인하세요.nvidia-peermem 등 추가 조건을 해당 페이지에서 확인해야 합니다.원하시면 사용 환경(노드 수, NVMe 개수, NIC 종류, vLLM 버전)을 알려주세요. 그에 맞춰 memory.maxSize, hugepages, replicaCount와 LMCache 파라미터 값을 구체적으로 잡아드리겠습니다.
확인을 위해 문서를 다시 보겠습니다.아니요, memkv 서버 노드에는 NIXL 플러그인도, 그 경로 설정도 필요 없습니다.
NIXL 플러그인(libplugin_MEMKV.so)은 memkv 서버가 아니라 NIXL을 로드하는 쪽에 두는 클라이언트용 라이브러리입니다. 문서 개요 페이지도 이를 "Dynamo 컨테이너에 NIXL 플러그인을 넣는다"고 설명합니다. 즉 /opt/nvidia/nvda_nixl/lib/plugins/ 경로는 Dynamo/KVBM이 도는 GPU 추론 노드나 컨테이너 안의 경로입니다.
| 노드 | 필요한 것 |
|---|---|
| memkv 서버 노드 (GPU 없음) | memkv 바이너리, 라이선스, NVMe, hugepages, RDMA NIC. NIXL 플러그인은 불필요합니다. |
| GPU 추론 노드 (vLLM) | client.yaml/MEMKV_* 환경변수, 그리고 연동 방식에 따라 memkv_lmcache wheel 등 |
| GPU 추론 노드 (Dynamo + NIXL 경로) | 위 항목에 더해 NIXL 플러그인 .so |
앞서 정리에서 1-4 항목을 서버 설치 절차 안에 넣은 탓에 서버 노드에서 할 일처럼 읽혔을 수 있습니다. 서버 노드는 1-1~1-3, 1-5~1-8 단계만 따르시면 됩니다.
NIXL 플러그인은 전혀 필요 없습니다. NIXL은 Dynamo KVBM 경로에서만 쓰입니다. vLLM은 LMCache 플러그인(memkv_lmcache), native offloading 2차 티어, direct 방식 중 하나로 연결합니다.
앞에서 vLLM 연결 방식 ②(native offloading), ③(GPUDirect)에 "vLLM main이 필요하다"고 정리했습니다. 그런데 이번에 다시 확인한 개요 페이지는 세 가지 방식이 모두 stock 엔진에서 동작한다고 적고 있습니다. 문서 갱신 시점에 따라 설명이 다를 수 있어서, 실제로 쓰실 vLLM 버전의 요구사항은 /integrate/vllm-offloading/과 /integrate/vllm-gpudirect/ 페이지에서 한 번 더 확인해 주세요. 3.5단계 용도에는 GPU 텐서와 MemKV 사이를 RDMA로 직접 옮기는 ③번이 가장 맞습니다.