Rostam: 고성능 벡터 데이터베이스 및 키-값 저장소
요약
Rostam은 단일 Go 엔진으로 구현된 고성능 벡터 데이터베이스이자 키-값 저장소입니다. Milvus와 Qdrant 대비 월등히 빠른 성능을 자랑하며, 독립형 서버, Raft 클러스터 복제, 바이너리 임베딩 등 세 가지 방식으로 활용 가능합니다. 특히 OpenAI 호환 캐싱 프록시 및 RAG 기능을 통합 제공하여 개발 편의성을 높였습니다.
핵심 포인트
- Milvus 대비 2배, Qdrant 대비 4배 빠른 쿼리 처리 성능을 입증했습니다.
- OpenAI와 호환되는 LLM 캐싱 리버스 프록시를 제공합니다.
- 별도 설정 없이 RAG 기능을 바로 사용할 수 있는 'RAG in a box' 방식을 지원합니다.
- 독립형 서버, 클러스터 복제, 임베딩 등 다양한 배포 환경을 지원합니다.
Rostam
단일 Go 엔진으로 구현된 고성능 벡터 데이터베이스 및 서브-마이크로초 키-값 저장소 — 독립형 서버로 실행하거나, Raft 클러스터에 복제하거나, 또는 서버 없이 바이너리에 직접 임베딩할 수 있습니다.
매치드 리콜(matched recall) 기준으로 Milvus와 pgvector보다 약 2배, Qdrant보다 약 4배 많은 쿼리를 처리하며, 세트 중 가장 빠른 로드 속도(1M × 768d를 282초에 로드)와 가장 높은 리콜을 측정했습니다. → 비교 방법
하나의 엔진으로 제공되는 세 가지 실행 방식:
| 독립형 서버(Standalone server) | REST, gRPC 및 바이너리 TCP 프로토콜을 지원합니다. Python 또는 모든 언어에서 접속할 수 있습니다. |
| ... |
rostam-server llm-proxy는 OpenAI와 호환되는 캐싱 리버스 프록시입니다. 한 줄만 수정하고 적격한 반복적인 chat-completions 요청(캐시 가능한 형태, 일치하는 범위, 캐시에 도달하는 프롬프트)이 들어오면, 업스트림 API를 호출하는 대신 로컬 시맨틱 캐시에서 응답을 받습니다. 정확히 바이트 단위로 동일한 매칭은 임베딩 키 없이도 기본적으로 작동하며, OpenAI와 호환되는 임베더를 지정하면 유사한 중복 프롬프트까지 매칭하도록 업그레이드됩니다.
rostam-server llm-proxy
→ LLM 캐싱 프록시에서 플래그, 캐시 범위 규칙, 그리고 캐싱되지 않는 항목에 대한 정보를 확인하세요.
박스의 RAG (RAG in a box)
rostam-server rag는 문서를 청크(chunks)로 나누고 인덱싱한 다음, 출처가 명시된 답변을 제공합니다. 별도의 벡터 스토어 설정이나 수집 파이프라인이 필요하지 않습니다:
rostam-server rag ingest ./docs
rostam-server rag ask "How does the LLM proxy decide what's cacheable?"
검색(Retrieval)은 BM25 전체 텍스트 검색으로 기본적으로 작동하며, OpenAI와 호환되는 임베더를 지정하면 기본적으로 밀집 벡터+BM25 하이브리드 융합(fusion)으로 업그레이드됩니다 (-no-hybrid는 순수 밀집 검색을 선택합니다). rag query는 LLM이 필요 없이 검색만 수행합니다.
→ RAG CLI에서 플래그, 임베디드 대 원격 모드(embedded-vs-remote mode), 지원되는 파일 유형에 대한 정보를 확인하세요.
그리고 함께 사용하거나 완전히 독립적으로 사용할 수 있는 두 가지 엔진입니다:
- 벡터 검색 엔진(vector search engine) (
vector/) — HNSW, IVF 및 Vamana 인덱스, SQ8/binary/PQ 양자화(quantization), 하이브리드 밀집+희소 융합(fusion), BM25 전체 텍스트, 그리고 재현율 절벽 현상에 빠지지 않는 정확한 필터 우선 질의 플래너를 갖춘 메타데이터 필터링을 지원합니다. 레포지토리 내 다른 어떤 것에도 의존하지 않습니다. - 키-값 저장소(key-value store) — 인프로세스 세션 캐시, 복제된 스토어 또는 TCP 서버가 하나의
Store인터페이스 뒤에 있으며, 서버 측 사용자 정의 연산(custom ops) 및 샌드박싱된 WASM 저장 프로시저를 지원합니다.
두 가지 모두 지연 시간에 민감한 영역을 위해 구축되었습니다. 읽기 작업은 zero-copy 방식이며 락(lock) 사용이 적고, 핵심 경로(hot paths)는 할당 과정이 필요 없으며, 거리 커널(distance kernels)은 수동으로 벡터화되었습니다.
상태: 베타(Beta). 활발하게 개발 및 테스트 중입니다 (경쟁 조건 안전성 확보, 벤치마크 수행 완료).
1.0 버전 출시 전에 API가 변경될 수 있습니다.
📚 docs.rostamlabs.com — 빠른 시작(quickstart), 개념(concepts), 가이드, 전체 API 레퍼런스(HTTP, gRPC, Go, Python)를 제공합니다. 이 사이트는 해당 저장소의 docs/ 트리(mkdocs.yml)에서 구축되었기 때문에 여기나 로컬에서도 읽거나 서비스할 수 있습니다.
비교 분석
VectorDBBench라는 중립적인 제3자 벤치마크 환경에서 Cohere-1M (768차원, 코사인 유사도)을 기준으로 비교했습니다. 총 6개 엔진이 27가지 케이스를 거쳐 하나의 연속 세션을 진행했으며, 모든 엔진에 HNSW의 m=16 / ef_construction=200 / k=100 값이 동일하게 고정되었고 ef 값만 변화시켰습니다.
**일치하는 재현율(matched recall)**에서 비교합니다. 이는 유일하게 공평한 비교 방식입니다. 엔진들은 동일한 ef 값이라도 서로 다른 재현율에 도달하며, 따라서 분할된 엔진이 특정 ef를 모든 세그먼트에 대해 실행하므로, 동일한 ef가 동일한 작업량을 의미하지는 않습니다.
| 매치된 재현율 (Matched recall) | Rostam | vs Milvus | vs pgvector | vs Weaviate | vs Qdrant | vs Redis |
|---|---|---|---|---|---|---|
| 0.95 | 3,161 QPS | 1.84× | 1.83× | 3.25× | — | 6.54× |
| ... | ||||||
| The lead is stable across the whole curve, so it does not depend on picking a | ||||||
| favourable operating point. Rostam also 가장 빠르게 로드합니다 (1M × 768d에 대해 282초) 동시에 테스트 세트의 어떤 멀티코어 엔진보다도 가장 적은 총 CPU를 사용하며, 가장 높은 측정된 재현율(0.9978)을 달성했습니다. |
이 모든 것을 제한하는 두 가지 주의사항이 있으며, 이는 각주가 아닙니다: 모든 수치는 동일 세션(same-session) 기준입니다. 왜냐하면 이 하드웨어는 변경되지 않은 코드에서 세션 간에 최대 **42%**까지 변동하기 때문이며; 벤치마크 클라이언트가 박스를 공유하므로, 가장 빠른 엔진에게 가장 큰 불이익을 주어 처리량 수치는 최저치(floors), 최고치가 아닙니다(not ceilings).
또 다른 측면에서 최저치입니다: 스윕은 Rostam의 JSON 와이어를 거쳐 진행되며, ef=300 지점에서 그 바이너리 쿼리 프레이밍은 동일한 박스와 코퍼스에서 +16.8% QPS 및 −19% 단일 클라이언트 p99를 측정합니다. 이것은 곡선 위의 한 점일 뿐이며, 균일한 향상을 의미하지는 않습니다. 와이어가 쿼리당 고정 비용을 절약하기 때문에, 검색 자체가 더 비싸지면 그 기여도는 줄어듭니다.
전체 ef별 곡선, 엔진별 CPU 사용량 계산, 필터 케이스, 네 쌍의 A/B 제어 및 전체 방법론(데이터가 Rostam과 반대로 잘리는 지점 포함)은 rostam-bench/vectordbbench에서 확인할 수 있습니다.
그리고 키-값(key-value) 측면
Rostam은 두 개의 엔진으로 구성되어 있으므로, KV 절반도 동일하게 측정됩니다 — 와이어를 통해 7개의 엔진이 하나의 머신, 하나의 세션에 걸쳐 테스트됩니다:
<picture> <source media="(prefers-color-scheme: dark)" srcset="docs/assets/bench/local-get-fast-dark.svg"> <img alt="Rostam, Memcached, Dragonfly 및 Aerospike에 대한 동시성별 GET 처리량. 8개 연결에서 Memcached가 선두를 달리고; Rostam은 64개부터 앞서나가며 약 730k 오퍼레이션/초를 유지합니다." src="https://raw.githubusercontent.com/rostamlabs/rostam/HEAD/docs/assets/bench/local-get-fast-light.svg" width="100%"> </picture>| GET ops/s | Rostam | Memcached | Dragonfly | Aerospike | Valkey | Redis | KeyDB |
|---|---|---|---|---|---|---|---|
| 64 conns | 726.1k | 682.9k | 532.0k | 510.6k | 239.1k | 228.3k | 206.3k |
| 256 conns | 732.4k | 681.7k | 551.6k | 516.9k | 227.9k | 219.6k | 208.8k |
p99 at 512 connections: Rostam 2.02 ms, seven개 중 최고치 (Memcached 2.32, Aerospike 2.75, Redis 4.69). Memcached가 8개 연결에서 우세하며; 동시성이 증가함에 따라 Rostam이 앞서 나갑니다.
복제 쓰기(Replicated writes) (RF=2) against Aerospike CE 8.1 at 일치하는 커밋 시맨틱스(matched commit semantics) — 둘 다 복제본이 쓰기를 받았을 때만 확인 응답(ack)을 보냄:
<picture> <source media="(prefers-color-scheme: dark)" srcset="docs/assets/bench/rf2-commit-all-dark.svg"> <img alt="복제본 확인 응답(replica-ack)을 사용하는 RF=2에서의 동시성별 복제 쓰기 처리량. 8개 연결에서 Aerospike가 약간 앞서며; Rostam은 32개에서 추월하여 128개에서는 113.6k를 기록하며, 이는 Aerospike의 85.9k에 해당합니다. 반면 Redis, Valkey 및 KeyDB는 43k 근처에서 평탄하게 유지됩니다." src="https://raw.githubusercontent.com/rostamlabs/rostam/HEAD/docs/assets/bench/rf2-commit-all-light.svg" width="100%"> </picture>| RF=2, replica-ack | 8 conns | 32 conns | 128 conns | p50 @128 |
|---|---|---|---|---|
| Rostam PB | 35.6k | 80.9k | 113.6k | 0.99 ms |
| ... | ||||
| Rostam의 우위는 확장성(scaling property)에서 나타납니다. Aerospike가 8개 연결(connections)에서 승리하며, 이때 더 나은 테일(tail) 성능을 보이지만, Rostam은 32개 및 128개 연결에서 역전하여 각각 **+42% / +32%**의 우위를 점하고, 32개 연결 이상에서는 더 나은 중앙값(median)을 보여줍니다. Redis 프로토콜 엔진은 32개 연결 이상에서 성능이 평탄해지는데, 이는 인스턴스당 최대치(per-instance ceiling)입니다. Rostam과 Aerospike를 ack-at-master로 완화하면 그 형태가 유지됩니다 (128개 연결에서 각각 157.4k 대 125.7k). |
이 테스트는 네 번의 간격으로 같은 장비(box)에서 두 번 측정되었으며, Rostam은 기준점(anchor points)에서 약 1–4% 이내로 재현되었습니다.
별도의 노드에서 실제 네트워크 환경으로 측정했을 때는 거의 동등한 수준(near-parity)으로 수렴하며, 이때도 Rostam의 테일 성능이 앞섭니다 (p99 ~8 ms 대 17–22 ms). 전체 포스처 매트릭스(full posture matrix)와 단일 부하 생성기(single load generator)가 이 비교를 완전히 무효화하는 이유에 대한 내용은 rostam-bench/netkv에서 확인할 수 있습니다.
사용 방법은 두 가지가 있습니다. 서버를 실행하고 REST, gRPC 또는 바이너리 TCP 프로토콜을 통해 어떤 언어에서도 접근할 수 있게 하거나 — 혹은 Go 라이브러리를 직접 임베드하여 서버 없이 사용할 수도 있습니다. 아래에서 시작하며, Go 임베딩 경로는 여기 더 아래에 있습니다.
설치 (Install)
# 미리 빌드된 바이너리 — 배포 체크섬을 확인한 후 설치합니다
curl -fsSL https://raw.githubusercontent.com/rostamlabs/rostam/main/install.sh | sh
...
스크립트를 셸(shell)로 파이프하기를 선호하지 않으신가요? 최신 릴리스에서 아카이브와 checksums.txt 파일을 다운로드한 다음, 추출하기 전에 검증하세요. 스크립트가 하는 모든 것은 이것이며, 플랫폼에 맞는 적절한 파일을 선택하는 것만 추가됩니다:
sha256sum -c checksums.txt --ignore-missing # Linux
shasum -a 256 -c checksums.txt --ignore-missing # macOS
릴리스 바이너리는 **순수 Go 빌드(pure-Go builds)**입니다. WASM 저장 프로시저를 제외하고는 모든 것이 작동하며, 이 경우 wasm: stored procedures require a cgo build 오류가 반환됩니다. 컨테이너 이미지는 항상 이를 포함합니다. go install은 C 컴파일러가 있는 환경에서 네이티브 빌드(cgo는 기본적으로 크로스 컴파일 시 비활성화됨)를 할 때만 이를 포함합니다.
로컬 인프로세스 임베딩(Local in-process embeddings)은 순수 Go(rembed)입니다. cgo도, ONNX Runtime도 필요 없고 설치할 것도 없기 때문에 모든 바이너리와 이미지에 내장됩니다. 모델만 지정해주면 됩니다:
docker run -p 127.0.0.1:8080:8080 -e ROSTAM_API_KEY=secret \
-e ROSTAM_EMBED_LOCAL=minilm-l6-v2 -e REMBED_CACHE=/models -v rostam-models:/models \
ghcr.io/rostamlabs/rostam:latest
가중치(Weights)는 첫 사용 시 Hugging Face Hub에서 REMBED_CACHE (기본 OS 사용자 캐시 디렉토리)로 다운로드됩니다. 이를 마운트된 볼륨에 지정하여 재시작 간에도 지속되도록 할 수 있습니다. ROSTAM_EMBED_LOCAL은 내장 카탈로그 외의 모든 Hugging Face org/model ID도 허용합니다.
모델 카탈로그 및 구성은 Local embeddings를 참조하십시오.
빠른 시작 — 서버 실행
rostam-server -http 127.0.0.1:8080 -data ./data
인증기(authenticator)가 구성되지 않은 경우, 서버는 열린 데이터 저장소를 네트워크에 제공하기보다는 도달 가능한 주소 바인딩을 거부합니다. 따라서 단순히 :8080만으로는 시작할 수 없습니다. 루프백 외의 포트를 리스닝하려면 인증 정보(auth)를 제공하거나 (-api-key 또는 -keys-file), 의도적으로 열어두려면 -insecure를 전달하십시오.
curl -s localhost:8080/v1/collections \
-d '{"name":"docs","config":{"dim":4,"metric":"cosine"}}'
curl -s localhost:8080/v1/collections/docs/points \
...
또는 컨테이너에서 실행하기
이미지는 0.0.0.0에 바인딩하므로 인증이 필요합니다. 환경 변수로 토큰을 전달하면 프로세스 테이블에 노출되지 않지만 (docker inspect에서도 여전히 Config.Env 아래에 표시됨), 다음과 같이 할 수 있습니다:
AI 자동 생성 콘텐츠
본 콘텐츠는 GitHub AI Tools의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기