46.6kデモを予約するログイン無料で始める

私たちは8年を費やしてベクトルデータベースを高速化しました。そして、それをやめました。

May 12, 202613 min read

コストは重要です。これまでも常にそうでした。しかし、順序があります。コストを削減できるのは、性能基準を満たした後だけです。安くても誤った結果を返すシステムは役に立ちません。負荷がかかった状態でレイテンシを抑えられないシステムも同じです。

Milvus は 2019 年に、シンプルな信念のもとでオープンソース化されました。それは、ベクトルデータベースはアプリケーションの中に隠れた機能ではなく、中核的なデータインフラになるというものです。8 年以上にわたり、その信念は私たちを一つの方向へ導いてきました。ベクトル検索をより高速に、より予測可能にすることです。 インデックス圧縮、セグメントスケジューリング、HNSW チューニング、プリフェッチ戦略 — ほぼすべての主要な最適化は同じ目的に向けられていました。データをローカルキャッシュに入れ、より高速に検索することです。

その取り組みは今も基盤です。常時稼働のサービングは、高 QPS・低レイテンシのベクトル検索ワークロードに適したアーキテクチャです。あるコレクションが常にクエリされているなら、インデックスをメモリ上に常駐させておくことは無駄ではありません。それはプロダクト体験を提供するためのコストです。

その後、私たちはコストに目を向けました。 階層型ストレージは役立ちました — ホットセグメントはメモリに、コールドデータはディスクとオブジェクトストレージに置くことで、実際の節約が生まれました。しかし、ノードは停止しませんでした。月に 5 時間しか動かないワークロードでも、残りの 715 時間分の料金を支払い続けていたのです。

このギャップは、新しい Zilliz Vector Lakebase が解決するために設計された問題の一つです。より大きな変化は、単に「ベクトル検索を安くする」ことではありません。永続的なセマンティックデータが、複数のコンピュートライフサイクルを支えられるようにすることです。レイテンシとスループットが重要な場合は常時稼働のサービングを使い、データをクエリ可能な状態に保つ必要はあるが、専用マシンを月中ずっと稼働させる必要はない場合はオンデマンドコンピュートを使う、ということです。

常時稼働サービングモデルの背後にある物理的制約

S3 の読み取りレイテンシは 1 リクエストあたり 20〜50 ms です。HNSW のグラフ探索は、1 クエリあたり数百のノードにアクセスします。この 2 つの数字を合わせれば、結論は明らかです。クエリを提供するには、ベクトルインデックスはローカルメモリ上に存在しなければなりません。これは設計上の欠陥ではなく、物理的制約です。

具体的に考えてみましょう。1 億ベクトル、768 次元、float32。生のベクトルデータは約 286 GB です。HNSW グラフ(M=48)は、近傍リンクとしてさらに約 55 GB を追加します — 合計でおよそ 340 GB です。

従来の Milvus QueryNode モデル:

┌──────────────────────────────────────────────────────────────┐
│                  Traditional Milvus architecture             │
│                                                              │
│  100M × 768-dim float32 → ~340 GB split across 3 QueryNodes  │
│                                                              │
│  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐        │
│  │ QueryNode 1  │  │ QueryNode 2  │  │ QueryNode 3  │        │
│  │ 128GB RAM    │  │ 128GB RAM    │  │ 128GB RAM    │        │
│  │ + NVMe       │  │ + NVMe       │  │ + NVMe       │        │
│  │ seg 0-99     │  │ seg 100-199  │  │ seg 200-299  │        │
│  │ (~113 GB)    │  │ (~113 GB)    │  │ (~113 GB)    │        │
│  └──────┬───────┘  └──────┬───────┘  └──────┬───────┘        │
│         │ load()          │ load()          │ load()         │
│         └─────────────────┼─────────────────┘                │
│                           ▼                                  │
│               ┌───────────────────────┐                      │
│               │  S3 (source of truth) │                      │
│               │  340 GB full dataset  │                      │
│               └───────────────────────┘                      │
│  Collection queryable only when all 340 GB are loaded        │
│  Node fails → its segments go dark → reload from S3          │
└──────────────────────────────────────────────────────────────┘

コレクションがクエリ可能になる前に、すべてのセグメントに常駐ノードが必要です。340 GB のデータ、3 台の 128 GB マシンが 24 時間 365 日稼働します。頻繁にクエリされるコレクションでは、これはうまく機能します。その後、AI が需要パターンを変えました。

プロダクトチームは2週間のA/B実験を実行し、その後それらのembeddingは二度とクエリされません。SaaSプロダクトでは、ユーザーの90%が先週ログインしていません。RAGナレッジベースでは、ドキュメントの80%が過去1か月間取得されていません。そのデータは無用ではありません — いつでもクエリされる可能性があります — しかし、クエリされることはまれです。従来のデータベースはこれを階層化で処理します。ホットデータはメモリに、コールドデータはディスクに置き、必要に応じてページインします。ベクトルデータベースにはそのような概念がありませんでした。コレクション全体をロードするか、クエリできないかのどちらかでした。

AI生成embeddingが広く普及する前は、その二択は問題ではありませんでした。ほとんどのベクトルワークロードは、インデックスをメモリに常駐させることが理にかなっている明確なオンライン serving システムか、独自のパイプラインを許容できるオフライン実験のどちらかでした。AIはその中間領域を変えました。

私たちは顧客との会話の中で、この変化を目にし始めました。embeddingはもはや本番環境のRAGチャットボットを動かすだけのものではありませんでした。あるグローバルGPUリーダーは、自動運転データ — カメラフレーム、走行セッション、天候、位置情報、タイムスタンプ、その他のメタデータ — をembedding化し、エンジニアが数百億のベクトルからまれな運転シナリオを探索できるようにしていました。ある教育テクノロジー企業は、多言語の盗用検出にセマンティック検索を使用しており、試験期間中にはワークロードが少数のドキュメントからバッチで10,000+ドキュメントにまで急増する可能性がありました。

これがVector Lakebaseの文脈です。AIチームは、永続的で発見可能な状態を保つ必要がある非構造化データを蓄積していますが、アクセスパターンは均一ではありません。継続的な serving が必要な経路もあります。同じ基盤データに対して、時折の検索、探索、またはバッチ発見が必要な経路もあります。それらすべての経路を常時稼働の serving として扱うと、あまりにも多くのインフラがアイドル状態になります。

あるユーザーが私たちのコミュニティSlackに投稿しました:

"私のembeddingはすでにS3にあります。つまり、たまにクエリを実行するだけのために、3時間かけてそれらをインポートし、128 GB RAMのマシンを3台24/7で稼働させ続け、年間$24,000を支払う必要があると言っているのですか?"

彼は正しかったのです。問題はデータがどこにあるかでも、インデックスが十分に高速かどうかでもありませんでした。彼はコールドデータのアクセスパターンに対してホットデータの料金を支払っていたのです: 0.7%がアクティブで、100%が課金対象。

市場はすでに、オブジェクトストレージファーストの経済性がベクトルワークロードにとって重要であることを証明し始めていました。そして、オブジェクトストレージ上でステートレスなコンピュートを維持することは、多くのユーザーが望む方向性でした。しかし、私たちにとってより難しい問いは、そのコストモデルを完全なベクトルデータベースにどう持ち込むかでした。フィルタ付き検索、データベースセマンティクス、運用上の分離、そしてワークロードがホットになったときに常時稼働 serving へと戻る経路を備えた形で、です。

それが私たちのVector Lakebaseのテーゼです。セマンティックデータを永続的に保持し、コンピュート層がワークロードに合わせられるようにする。オンデマンド検索はそのアーキテクチャの一つの表現です。それを正しく実現するには、4つの技術的障壁を乗り越える必要がありました。

Lakebaseオンデマンド検索への4つの障壁

Lakebaseオンデマンド検索モデルでは、QueryNodesがオンデマンドで起動し、クエリを処理し、その後解放されます。データは信頼できる唯一の情報源としてオブジェクトストレージに残ります。コンピュートはクエリセッション間でゼロまでスケールします。これは単純に聞こえますが、実用可能にするには、コールドスタートレイテンシ、スキャン量、取得時のI/O増幅、コントロールプレーンの固定費に対処する必要がありました。

コールドスタートが遅すぎた

340 GBのHNSWインデックス。S3からロードすると4分以上。4分のコールドスタートは、あらゆるオンデマンドのユースケースを台無しにします。ユーザーがクエリを実行して4分待つ — それは遅延ではなく、壊れたプロダクトです。

解決策は、インデックスを利用可能なまま圧縮することでした。私たちはRabitQ (Gao & Long, 2024)に基づく1+3ビットのmatryoshka量子化を構築しました。マトリョーシカ人形のように入れ子になった2つの層です。

1ビット層が最初にロードされます — 340 GBではなく13 GBです。検索はその上ですぐに実行されます: RabitQは1ビット距離に対して証明可能な誤差範囲を提供するため、候補を安全に枝刈りでき、真のtop-kに含まれるものが落とされないことを保証できます。最初のクエリで85–90%の再現率。

1ビット検索の実行中に、3ビットレイヤーがバックグラウンドでダウンロードされます。準備ができると、これは精緻化パスとして使われます。1ビット段階を生き残った候補が、完全な1+3ビット精度で再スコアリングされます。再現率は95%以上になります。2つのレイヤーは代替手段ではありません。内側のレイヤーがフィルタリングを行い、外側のレイヤーが結果を改善します。

生の量子化スループットは、大規模環境ではボトルネックになります。GPUで高速化されたインデックス構築と、AVX512 / ARM SVE クエリカーネルにより、距離計算スループットは量子化オーバーヘッドが無視できる水準まで高まります。さらに2つの改善によって再現率が向上します。各ベクトルがグローバルな係数を共有するのではなく、それぞれの量子化誤差を最小化するベクトルごとの最適スケーリング。そして、分散に基づく次元間の非一様なビット割り当てにより、情報密度の高い次元により多くのビットを割り当てます。どちらも、インデックスサイズを増やさずに量子化誤差を直接削減します。

最初の障害はクリアしました。しかし完全な量子化を行っても、1億ベクトルのスキャンは依然として高コストです。

1億ベクトルのスキャン

1ビットインデックスは小さいものの、1億ベクトルに対する距離計算は依然として線形です。オンデマンドモデルでは、これが積み重なります。計算時間が長いほど、QueryNode が常駐する時間も長くなり、エラスティックに解放できる時間枠が狭まります。

グローバルインデックスプルーニングを伴う IVF クラスタリング(バケット数はデータ量に応じてスケール):

┌──────────────────────────────────────────────────────────────┐
│                  Global Index + IVF pruning                  │
│                                                              │
│  100M vectors → IVF clustering (N buckets, N scales with     │
│                                  data volume)                │
│                                                              │
│  ┌───┬───┬───┬───┬───┬───┬───┬───┬─── ··· ───┬───┐           │
│  │ 1 │ 2 │ 3 │ 4 │ 5 │ 6 │ 7 │ 8 │        │  N   │           │
│  └───┴───┴───┴───┴───┴───┴───┴───┴─── ··· ───┴───┘           │
│    ▲           ▲                   ▲                         │
│    █           █                   █  ← scan only ~3%        │
│                                                              │
│  Query q → find nearest centroids → search those buckets     │
│                                                              │
│  Data scanned:  ~3% of total                                 │
│  S3 I/O:        pull ~3% of data                             │
│  Compute:       distance calc on ~3% only                    │
└──────────────────────────────────────────────────────────────┘

IVF は新しいものではありませんが、私たちのものには2つの違いがあります。

第一に、スケールです。ほとんどの IVF 実装は、インデックス構築時にすべてを一度にメモリへロードする必要があるため、10億ベクトル規模では破綻します。私たちは、クラスタリング作業をノード間でシャーディングする分散インデックス構築を実装しました。これにより、数十億ベクトルを含む任意の規模で IVF が可能になります。

第二に、Lakebase との相互作用です。クエリ時には、関連するバケットだけが S3 から取得されます。クラスタの約3%をプローブし、データの約3%を取得し、QueryNode メモリには約3%だけを保持します。データセットの3%だけをロードしたノードは、クエリ完了後ほぼ即座に回収できます。

1ビット量子化と組み合わせることで、2つの障壁は相乗的に縮小されます。340 GB → 13 GB(量子化)→ クエリあたり約400 MB(IVF プルーニング)。コールドスタートではクラスタ重心と1ビットインデックスメタデータだけをロードします — 5〜10秒です。以降の各クエリでは、13 GB全体ではなく、関連するバケットだけを取得します。

第二の障害もクリアしました。

Retrieve が S3 I/O を増幅していた

ベクトル検索が返すのは ID であり、生データではありません。元のベクトルやスカラー項目を取得するには2回目の読み取りが必要になり、ストレージネイティブなクエリパスでは、その1回1回が S3 のポイント読み取りになります。

問題はストレージ形式にありました。標準的な Parquet ファイルは 64 MB の行グループを使用します。単一のベクトルレコードは約 3 KB です。それを読み取るには行グループ全体をダウンロードする必要があります。有用なデータは 3 KB、実際の I/O は 64 MB — 約20,000倍の増幅です。ローカルディスクでは許容できますが、S3 では過酷です。

Storage V2 はその半分に取り組みました。幅広い列と幅狭い列を分離し、ベクトルとスカラー フィールドを独立して格納し、行グループを 1 MB に縮小しました — 増幅は 64 分の 1 です。問題は、Parquet のブロックレベル圧縮が大きな行グループに依存していることです。行グループを小さくすると、圧縮率が低下し、ファイルは大きくなります。Parquet では、小さな行グループと高い圧縮率は両立しません。そこで Vortex の出番です。

Spiral が開発し Linux Foundation がホストする Vortex は、強制的な行グループ構造のない完全に設定可能なレイアウト、Delta → RLE → BitPacking のネストされたエンコーディングを通じた圧縮データへの直接ポイント クエリ(解凍不要)、そして BtrBlocks アルゴリズムに基づき、圧縮率、エンコード速度、デコード速度のバランスを取る自動エンコーディング選択を備えています。

ベンチマーク: 300 万行、128 次元ベクトル、S3、256 の同時リーダー、読み取りごとに 10 行バッチ。

指標ParquetLanceVortex
ポイント読み取りスループット (reads/s)162464620
読み取りごとの S3 バイト数 (MB)9.440.0060.07
行ごとの S3 GET 数~2~5~2
フルスキャン スループット (MB/s)6387301,548
書き込みスループット (MB/s)216247244

Parquet は読み取りごとに 9.44 MB、つまり行グループ全体をダウンロードします。Lance は 512 バイト単位で読み取ることでこれを 0.006 MB まで削減しますが、その代償として IOPS が発生します。行ごとの S3 GET 数は、他が ~2 であるのに対し ~5 です。Vortex は行ごとに ~2 GET のまま 0.07 MB に収まり、IOPS のペナルティなしに Parquet よりトラフィックを 135 分の 1 に削減します。フルスキャン スループットは Parquet の 2.4 倍で、書き込みは同等です。

3 つ目の障害が解消されました。

コントロール プレーンのコストはゼロまでスケールしなかった

最初の 3 つの変更はクエリ パスにありました。4 つ目はコントロール プレーンに隠れていました。

すべての QueryNode がアイドル状態でも、各 Milvus インスタンスは Coordinator と etcd を稼働させ続けます。N 個のテナントは N セットを意味します。QueryNode はゼロまでスケールできますが、この 2 つのコンポーネントはできません — ステートフルであり、常駐している必要があります。100 万テナントでは、コントロール プレーンのオーバーヘッドが QueryNode のコストを上回ります。

Lakebase のコントロール プレーンはこれを O(N) から O(1) に変えます。

従来の Milvus: コントロール プレーン コスト O(N)

 ┌──────────────────────────────────────────────────────────────┐
 │                     Shared infrastructure                    │
 │        Kafka / Pulsar (shared)        Index Pool (shared)    │
 └──────────────────────────────────────────────────────────────┘
           |                     |                     |
       Tenant A              Tenant B              Tenant C
  ┌──────────────────┐  ┌──────────────────┐  ┌──────────────────┐
  │  Coordinator     │  │  Coordinator     │  │  Coordinator     │
  │  etcd            │  │  etcd            │  │  etcd            │
  ├──────────────────┤  ├──────────────────┤  ├──────────────────┤
  │  QueryNode       │  │  QueryNode       │  │  QueryNode       │
  │  (dedicated)     │  │  (dedicated)     │  │  (dedicated)     │
  └────────┬─────────┘  └────────┬─────────┘  └────────┬─────────┘
           └─────────────────────┼─────────────────────┘
                                 ↓
                              ┌──────┐
                              │  S3  │
                              └──────┘

Lakebase: コントロール プレーン コスト O(1)

  ┌───────────────────────────────────────────────────────────────┐
  │               共有コントロールプレーン(リージョンごと)        │
  │                                                               │
  │  ┌──────────────────┐  ┌──────────┐  ┌───────────────────┐    │
  │  │ 共有             │  │ Catalog  │  │   WAL Service     │    │
  │  │ Coordinator      │  │  ≠ etcd  │  │  → S3, ≠ Kafka    │    │
  │  │                  │  │          │  │                   │    │
  │  └──────────────────┘  └──────────┘  └───────────────────┘    │
  │                                                               │
  │  ┌───────────────────────────────────────────────────────┐    │
  │  │              Index Service(GPUビルドプール)          │    │
  │  └───────────────────────────────────────────────────────┘    │
  └─────────────────────────────┬─────────────────────────────────┘
           ┌────────────────────┼─────────────────────┐
      Tenant A NS           Tenant B NS           Tenant C NS
    ┌────────────┐         ┌────────────┐         ┌───────────┐
    │ QueryNode  │         │   (アイドル)│         │ QueryNode │
    │ QueryNode  │         │  scale = 0 │         └────┬──────┘
    └──────┬─────┘         └────────────┘              │
           └─────────────────────┬─────────────────────┘
                                 ↓
                              ┌──────┐
                              │  S3  │
                              └──────┘

Lakebaseは、旧来のテナントごとのモデルの各要素を置き換えます。コーディネーターはテナント間で共有され、テナントごとのコーディネーターを置き換えます。Catalogはインスタンスごとのetcdを置き換え、2 GBのストレージ上限を取り除きます。WAL ServiceはローカルディスクなしでS3に直接書き込みます — 実測スループットは750 MB/s、Kafkaの5.8倍 — Kafka/Pulsarを置き換えます。Index Serviceはテナント間で共有されるGPUビルドプールであり、インスタンスごとのGPU割り当てを置き換えます。

「ゼロへのスケール」は、「QueryNodeが解放できる」という意味ではなくなり、「インスタンス全体がアイドル時にほぼコストゼロになる」という意味になります。

┌──────────────────────────────────────────────────────────────┐
│              マルチテナント × Lakebase On-demand Search       │
│                                                              │
│  S3ストレージ層                  コンピュート(オンデマンド) │
│  ┌──────────────┐                                            │
│  │Tenant A data │ ◄──── クエリ ──── QueryNode A(アクティブ) │
│  ├──────────────┤                                            │
│  │Tenant B data │                  (アイドル、QueryNodeなし)│
│  ├──────────────┤                                            │
│  │Tenant C data │                  (アイドル、QueryNodeなし)│
│  ├──────────────┤                                            │
│  │Tenant N data │ ◄──── クエリ ──── QueryNode N(アクティブ) │
│  └──────────────┘                                            │
│                                                              │
│  100万テナント、1%がアクティブ → データの99%はコンピュートコストゼロ │
└──────────────────────────────────────────────────────────────┘

従来、マルチテナンシーとは、個別のコレクションやパーティションを通じてテナント間でクラスターを共有することを意味していました。しかし、そのクラスターには厳しい上限がありました。etcdの2 GBメタデータ制限、コーディネーターのスループット、そして固定されたQueryNode容量です。これらの制限を超えてスケールするには、より多くのクラスターが必要になり、それはより多くのオーバーヘッドを意味しました。

Lakebaseはその上限を変えます。Catalogはetcdをスケーラブルなメタデータストアで置き換え、共有コーディネーターはテナントごとのオーバーヘッドなしで、はるかに多くのテナントを処理します。S3はストレージの伸縮性を提供します。その結果、単一のクラスターで、隔離された多数のテナントにサービスを提供できるようになります。そして、実際にクエリを受け取っているテナントだけがコンピュートを消費します。残りはストレージ分だけを支払います。

あのSlackユーザーに戻る

同じシナリオです。1億ベクトル、768次元float32、1日10クエリ、各1分。アクティブ時間は月に約5時間。

このワークロードにおいて重要な違いは、単にバイトがどこに存在するかではありません。誰もクエリしていない間も、コンピュートをそれらのバイトに接続したままにしておく必要があるかどうかです。

セルフホスト型 Milvus と Zilliz Cloud の階層型ストレージモデルのコールドスタート時間は、どちらも一度きりのロードコストです。一度ウォームになれば、クエリは高速です。Lakebase のオンデマンドのコールドスタートは、ノードがゼロまでスケールバックした後、各セッションの開始時に発生します。このワークロードでは、実質的に毎回です。セッション間に何も支払わないためのトレードオフが、セッションごとの 5〜10 秒です。

セルフホストのコストは主に常時稼働の EC2 で、オンデマンドの 3 × r6g.4xlarge が月額およそ $2,073、さらに Kafka が加わります。Zilliz Cloud の階層型ストレージモデルは運用負担を取り除きますが、課金モデルは同じままです。Lakebase のオンデマンド検索はモデルを変えます。実際に使う 5 時間分だけ支払います。

セルフホスト型 MilvusZilliz Cloud 階層型ストレージモデルLakebase オンデマンド検索
コンピュートのライフサイクル常時稼働常時稼働オンデマンド
アイドル時のコンピュートコストフルレートフルレート$0
コールドスタートのパターン一度きりのロード後、ウォーム状態一度きりのロード後、ウォーム状態セッション開始時に 5〜10 秒
最適な用途ホットサービングワークロードマネージドなホット/コールド階層化まれにクエリされるセマンティックデータ

年間約 $240。99% の時間でコンピュートコストはゼロ。4 つの障害、4 層の変化。

物理法則は変わっていません。S3 は今も 1 回の読み取りに 20〜50 ms かかります。

変わったのは、その物理法則を取り巻くコンピュートモデルです。階層型ストレージは、よりコールドなデータを保存するコストを削減しましたが、Lakebase のオンデマンド検索は、ほとんどアイドル状態のワークロードに対して、常時稼働コンピュートの下限を取り除きます。

その差は、節約額以上に重要です。年間 $24,000 を正当化できなかった Slack ユーザーは、移行によって単にお金を節約しただけではありません。検索が十分に安くなったため、より多くのデータをインデックスし始めました。価格が下がり、需要が増えたのです。

これが Vector Lakebase のより大きなストーリーです。セマンティックデータが単一の常時稼働サービングクラスターから独立して永続化できるようになると、チームはワークロードに合ったコンピュートの形を選べます。ホットパスには継続的なサービング、まれにクエリされるデータにはオンデマンド検索、探索や処理ジョブにはバッチコンピュートです。

Zilliz Vector Lakebase がパブリックプレビューで利用可能に

Zilliz Vector Lakebase のパブリックプレビューを開始しました。これは、Zilliz Cloud をマネージドベクトルデータベースから統合セマンティックデータプラットフォームへと進化させる大きな一歩であり、低レイテンシのベクトルサービングと、データレイクのオープン性、スケーラビリティ、経済性を組み合わせています。

Vector Lakebase Core の機能:

  • 階層型サービング は、リアルタイム性能とコストのさまざまなトレードオフに最適化
  • オンデマンド検索 は、常時稼働コンピュートなしで大規模または探索的ワークロードに対応
  • 外部データレイク検索 — 既存のレイクデータを直接インデックスして検索
  • フルスペクトラム検索 は、ベクトル、テキスト、JSON、地理空間データを横断し、ハイブリッド検索とリランキングに対応
  • 統合されたレイクネイティブストレージ は、Lance や Parquet より高速で安価なランダム読み取りを実現するオープンフォーマット Vortex を基盤に構築

現在のスタックでサービングと探索を別々のシステムに分けているなら、Vector Lakebase は検討する価値があるかもしれません。Zilliz Cloud でお試しください — 仕事用メールで新規登録すると $100 の無料クレジットが付与されます — または、ユースケースについてお問い合わせください。

Updated on Jun 15, 2026