본문으로 건너뛰기
Version: 0.0.15

Mooncake

무엇인가

Mooncake는 LLM 서빙 시스템입니다. MASS 환경에서 중요한 질문은 MASS가 Mooncake 내부 런타임 구성 요소를 대체하느냐가 아니라, Mooncake가 모델 서빙에 필요한 공유 파일을 어디에 둘 것인가입니다.

MASS에서 왜 중요한가

  • 모델 가중치, 토크나이저, 프롬프트 코퍼스, 평가 데이터셋, 로그, 내보낸 trace를 위한 공유 스토리지
  • 여러 서빙 노드가 같은 아티팩트를 함께 사용해야 할 때의 중앙화된 데이터 접근 경로
  • 단일 호스트 수명보다 오래 유지되어야 하는 대형 서빙 자산의 지속 스토리지

MASS와 함께 사용하는 방법

  1. 모델 아티팩트와 그 외 배포가 공유할 지속 데이터 크기에 맞춰 MASS 볼륨을 생성합니다.
  2. 각 서빙 노드에 그 볼륨을 마운트하거나, Mooncake를 실행하는 플랫폼 계층을 통해 노출합니다.
  3. 공유 모델 저장소, 설정 파일, 프롬프트 데이터셋, 출력 아티팩트를 MASS 경로에 저장합니다.
  4. 모든 서빙 노드가 같은 위치에서 같은 자산을 해석하도록 Mooncake 설정을 해당 공유 경로로 맞춥니다.
  5. 노드 로컬 hot cache나 임시 scratch 영역은 upstream Mooncake 배포가 권장하는 로컬 매체에 두고, MASS는 서빙 시스템 주변의 공유 영속 계층으로 사용합니다.

MASS-Mooncake 통합 가이드

사전 요구 사항

Mooncake의 DAOS 백엔드를 빌드하고 실행하려면 Mooncake를 빌드하고 실행하는 호스트에 full mass-client 패키지가 설치되어 있어야 합니다. 이 패키지는 CMake가 사용하는 DAOS 클라이언트 라이브러리, 헤더 및 mass.pc pkg-config 모듈을 제공합니다.

mass-client 설치

MangoBoost 패키지 저장소를 설정하고 클라이언트를 설치하는 방법은 mass-client 설치 가이드를 참고하십시오. Ubuntu 또는 RHEL/Rocky Linux 9의 full client 패키지를 사용하십시오. RHEL/Rocky Linux 10 패키지는 thin client이므로 이 가이드에 필요한 DAOS 개발 파일을 포함하지 않습니다.

Mooncake 소스 트리를 준비하고 공통 빌드 의존성을 설치합니다.

cd /path/to/Mooncake
sudo bash dependencies.sh

빌드를 구성하기 전에 Mooncake 통합 패치를 소스 트리에 적용합니다.

MOONCAKE_SRC=/path/to/Mooncake
PATCH_FILE=/path/to/downloaded/mooncake.patch

cd "$MOONCAKE_SRC"
git apply --check "$PATCH_FILE"
git apply "$PATCH_FILE"

패치를 적용하면 mass-client의 pkg-config 메타데이터가 DAOS 헤더 및 라이브러리 경로를 자동으로 해결합니다. 별도의 PKG_CONFIG_PATH 또는 DAOS_ROOT 설정은 필요하지 않습니다.

pkg-config --exists mass
pkg-config mass --cflags --libs

cmake -S . -B build \
-DCMAKE_BUILD_TYPE=Release \
-DWITH_STORE=ON \
-DUSE_DAOS=ON

cmake --build build -j"$(nproc)"
sudo cmake --install build

Mooncake에서 MASS 사용하도록 설정

Mooncake용 MASS 볼륨을 생성하거나 기존 볼륨을 선택한 후, 모든 Mooncake 호스트에 동일한 POSIX/UNS 경로로 마운트합니다. 이 경로는 DAOS pool과 container로 해석될 수 있어야 합니다 (예: /mnt/mass/mooncake). 어댑터는 이 경로로 DAOS 이름을 확인하고, 객체 I/O는 libdfs를 통해 직접 수행합니다.

Mooncake master를 offload 활성화 상태로 시작합니다.

mooncake_master --enable_offload=true

각 Mooncake client를 시작하기 전에 다음 distributed backend 환경 변수를 설정합니다.

export MOONCAKE_OFFLOAD_STORAGE_BACKEND_DESCRIPTOR=distributed
export MOONCAKE_DISTRIBUTED_FS_TYPE=daos
export MOONCAKE_DISTRIBUTED_ROOT_DIR=/mnt/mass/mooncake

각 client도 offload 활성화 옵션으로 시작합니다. 이 설정을 사용하면 Mooncake Store가 DAOS 어댑터를 통해 MASS에 offload된 객체를 저장합니다. MASS backend를 사용할 client에만 MOONCAKE_OFFLOAD_STORAGE_BACKEND_DESCRIPTOR=distributed를 설정하고, 다른 client는 기본 로컬 backend를 계속 사용할 수 있습니다.

벤치마크를 실행하기 전에 Mooncake client를 시작합니다. 환경에 맞게 host 주소, MASS 경로 및 offload 디렉터리를 조정하십시오.

MOONCAKE_DISTRIBUTED_FS_TYPE=daos \
MOONCAKE_DISTRIBUTED_ROOT_DIR=/mnt/poc-home/vllm-kv \
MOONCAKE_DISTRIBUTED_HEALTH_CHECK=true \
MOONCAKE_OFFLOAD_FILE_STORAGE_PATH=/var/tmp/mooncake-offload-stub \
MOONCAKE_OFFLOAD_HEARTBEAT_INTERVAL_SECONDS=2 \
UCX_IB_RCACHE_MAX_REGIONS=256 UCX_RCACHE_MAX_REGIONS=256 \
/opt/Mooncake/bin/mooncake_client \
--master_server_address=127.0.0.1:50051 \
--metadata_server=P2PHANDSHAKE \
--host=211.250.100.47 --port=50052 \
--protocol=rdma \
--global_segment_size="32 GB" \
--local_buffer_size="1 GB" \
--enable_offload=true

벤치마크

Storage KV

store_kv_bench.py는 Mooncake Store의 end-to-end 경로를 측정합니다. DAOS Adapter microbenchmark와 달리 Store 할당 및 metadata 작업, 객체 배치, Transfer Engine 트래픽, 선택한 put 또는 get API를 모두 포함합니다. KV 작업을 검증하고 Mooncake 애플리케이션에서 관찰되는 처리량과 latency를 측정할 때 사용합니다.

스크립트는 다음 경로에 있습니다.

/opt/Mooncake/mooncake-store/benchmarks/store_kv_bench.py

Mooncake를 다른 위치에 설치했다면 경로를 조정하십시오. 실제 파일명은 storage_kv_bench.py가 아니라 store_kv_bench.py입니다. 설치한 Mooncake 버전에서 지원하는 옵션은 python3 store_kv_bench.py --help로 확인할 수 있습니다.

사전 요구 사항

  • 이 페이지 앞부분의 MASS-Mooncake 통합을 완료하고 full mass-client 패키지와 DAOS 지원 Mooncake 빌드를 준비합니다.
  • 참여하는 모든 Mooncake 호스트에 같은 MASS 볼륨을 마운트합니다.
  • offload와 metadata service가 활성화된 Mooncake master를 시작합니다.
  • 각 벤치마크 프로세스에 고유하고 접근 가능한 --local-hostname endpoint를 사용합니다. RDMA device는 자동으로 탐색됩니다.

예를 들어 MASS backend를 설정하고 embedded HTTP metadata service와 함께 master를 시작합니다.

export MOONCAKE_OFFLOAD_STORAGE_BACKEND_DESCRIPTOR=distributed
export MOONCAKE_DISTRIBUTED_FS_TYPE=daos
export MOONCAKE_DISTRIBUTED_ROOT_DIR=/mnt/mass/mooncake

mooncake_master \
--enable_offload=true \
--offload-backend distributed \
--distributed-fs-type daos \
--distributed-root-dir /mnt/mass/mooncake \
--enable_http_metadata_server=true \
--http_metadata_server_host=0.0.0.0 \
--http_metadata_server_port=8080

각 벤치마크 프로세스를 시작하는 shell에도 backend 환경 변수를 유지합니다.

설정 검증

먼저 작은 write-and-read 검증을 실행합니다. 예제의 주소를 클라이언트에서 접근 가능한 값으로 바꾸십시오.

python3 /opt/Mooncake/mooncake-store/benchmarks/store_kv_bench.py \
--scenario verify_write \
--local-hostname 10.0.0.21:50071 \
--metadata-server http://10.0.0.10:8080/metadata \
--master-server 10.0.0.10:50051 \
--protocol rdma \
--global-segment-size 1073741824 \
--local-buffer-size 268435456 \
--nr-objects 64 \
--value-size 1048576 \
--pattern 0xA5 \
--verify \
--summary-json /tmp/store-kv-verify.json

TCP만 사용해 검증하려면 --protocol tcp를 지정하고 TCP network에서 접근할 수 있는 주소를 사용합니다.

verify_write는 모든 객체를 쓴 다음 다시 읽습니다. 프로세스가 status 0으로 종료되고 console에 실패한 KV나 verification failure가 없으며 summary JSON에 "ok": true가 있으면 성공입니다.

처리량 워크로드 실행

다음 예제는 동시 job 8개를 사용하여 16 MiB 객체 512개를 씁니다. Mooncake Store에 12 GiB memory segment를 제공하고 2 GiB local Transfer Engine buffer를 사용합니다.

python3 /opt/Mooncake/mooncake-store/benchmarks/store_kv_bench.py \
--scenario write_perf \
--local-hostname 10.0.0.21:50071 \
--metadata-server http://10.0.0.10:8080/metadata \
--master-server 10.0.0.10:50051 \
--protocol rdma \
--global-segment-size 12884901888 \
--local-buffer-size 2147483648 \
--io-api plain \
--numjobs 8 \
--iodepth 1 \
--batch-size 8 \
--nr-objects 512 \
--value-size 16777216 \
--pattern 0xA5 \
--summary-json /tmp/store-kv-write.json

read를 측정하려면 scenario를 read_perf로 바꾸고 --verify를 추가합니다. 기본적으로 read_perfprepare_write 단계에서 dataset을 만든 후 별도의 read_perf 단계에서 읽습니다.

python3 /opt/Mooncake/mooncake-store/benchmarks/store_kv_bench.py \
--scenario read_perf \
--local-hostname 10.0.0.21:50071 \
--metadata-server http://10.0.0.10:8080/metadata \
--master-server 10.0.0.10:50051 \
--protocol rdma \
--global-segment-size 12884901888 \
--local-buffer-size 2147483648 \
--numjobs 8 --iodepth 1 --batch-size 8 \
--nr-objects 512 --value-size 16777216 \
--pattern 0xA5 --verify \
--summary-json /tmp/store-kv-read.json

시간 기반 mixed workload에는 mixed_rw를 사용하고 0보다 큰 runtime과 read 비율을 지정합니다. --prepare-objects는 최초 readable dataset 크기를 정하고 --write-objects는 write에 사용할 수 있는 object ID를 제한합니다.

python3 /opt/Mooncake/mooncake-store/benchmarks/store_kv_bench.py \
--scenario mixed_rw --runtime 60 --rwmixread 70 \
--prepare-objects 512 --write-objects 4096 \
--local-hostname 10.0.0.21:50071 \
--metadata-server http://10.0.0.10:8080/metadata \
--master-server 10.0.0.10:50051 \
--protocol rdma \
--global-segment-size 12884901888 \
--local-buffer-size 2147483648 \
--numjobs 8 --iodepth 1 --batch-size 8 \
--nr-objects 512 --value-size 16777216 \
--pattern 0xA5 --verify \
--summary-json /tmp/store-kv-mixed.json

설정

옵션설명기본값
--scenario검증, fill, read/write 성능, mixed I/O, metadata, 삭제 또는 replay 중 실행할 workload입니다.필수
--local-hostname이 Store client의 접근 가능한 주소입니다. 동시에 실행하는 각 프로세스에는 고유 endpoint가 필요합니다.127.0.0.1:50071
--metadata-serverTransfer Engine metadata service URL 또는 P2PHANDSHAKE입니다.http://127.0.0.1:8080/metadata
--master-serverMooncake master 주소입니다.127.0.0.1:50051
--protocol, --device-name전송 protocol입니다. RDMA device는 자동으로 탐색되며 device 선택을 재정의할 때만 --device-name을 사용합니다.tcp, 비어 있음
--global-segment-size이 프로세스가 global Store pool에 제공하는 memory 크기(byte)입니다.64 MiB
--local-buffer-sizelocal Transfer Engine buffer용으로 예약하는 크기(byte)입니다.32 MiB
--io-apiplain은 일반 Store API를, zcopy는 registered buffer를 사용합니다.plain
--numjobs, --iodepth동시성 설정입니다. worker lane 수는 numjobs × iodepth입니다.1, 1
--batch-size하나의 batch request로 제출하는 KV object 수입니다.1
--nr-objectsobject-count 기반 단계에서 사용하는 object 수입니다.128
--runtime실행 시간(초)입니다. 0이면 object-count 기반으로 실행하며 mixed_rw에는 필수입니다.0
--value-sizevalue 크기(byte)입니다. write workload에서는 512 byte의 배수여야 합니다.4 KiB
--pattern, --verify고정 payload를 재사용하고 필요하면 읽은 데이터를 검증합니다. --verify에는 --pattern이 필요합니다.비어 있음, 비활성화
--summary-jsonphase 및 overall 결과를 저장하는 machine-readable 파일입니다.미설정

처리량을 비교할 때는 --pattern을 사용합니다. 지정하지 않으면 payload 생성이 timed path에 포함되어 Python 측 처리량을 제한할 수 있습니다. --io-api zcopy를 사용할 때는 value-size × batch-size × numjobs × iodepth--local-buffer-size를 넘지 않도록 하고, 설치된 Mooncake 빌드가 registered buffer allocation을 지원하는지 먼저 확인합니다.

공개 스크립트는 하나의 Store client process를 실행하며 여러 호스트에 rank를 시작하거나 결과를 집계하지 않습니다. 다중 호스트 테스트에서는 각 호스트에 하나 이상의 프로세스를 시작하고 모든 프로세스에 고유한 --local-hostname 주소나 port를 할당합니다. 서로 다른 --object-id-start 범위나 --key-prefix 값을 사용하여 key 충돌을 방지하고, 프로세스마다 별도의 summary 파일을 저장한 후 모든 프로세스가 끝나면 phase 결과를 집계합니다.

결과 해석

console과 summary JSON은 request와 KV 수, 성공한 byte, duration, requests/s, KVs/s, MiB/s, p50/p95/p99 latency, miss, verification failure 및 error count를 보여 줍니다. read_perfmixed_rw에서는 overall에 dataset 준비 단계도 포함되므로 이름이 지정된 main phase를 비교합니다.

Store 처리량과 MASS persistence 처리량은 서로 다른 측정값입니다. 성공한 Store put은 MASS로의 비동기 offload가 drain되기 전에 반환될 수 있습니다. Mooncake의 offload 또는 master metric으로 queue가 비었는지 확인하고 persistence를 별도로 측정하십시오. 진행 상황을 확인하기 위해 생성된 모든 객체를 재귀적으로 나열하거나 stat하지 마십시오. 대규모 namespace scan은 workload를 왜곡하고 mounted filesystem에 불필요한 부하를 줄 수 있습니다.

참고

  • MASS는 배포 주변의 공유 영속 자산에 가장 적합합니다. Mooncake 구성 요소가 가장 뜨거운 캐시 계층에서 호스트 로컬 메모리나 로컬 NVMe를 기대한다면 그 계층은 로컬에 유지하세요.
  • 실제 운영과 같은 모델 크기와 클라이언트 동시성으로 모델 로드 시간과 steady-state 처리량을 검증하세요.
  • 컨테이너나 Kubernetes에서 배포한다면 MASS 기반 볼륨을 파드에 마운트하고, 복제본 간 컨테이너 내부 경로를 일관되게 유지하세요.