クラウド・ネイティブ・ベクター・データベース管理システムの概要
この度、弊社の最新論文「Manu: A Cloud Native Vector Database Management System」が、データベース研究のトップ国際会議であるVLDB'22](https://zilliz.com/news/Ziiliz-pioneers-vector-database-research-vldb)に採択されたことを大変光栄に思います。本記事では、ベクトルデータ管理のために構築されたクラウドネイティブデータベースであるManu (Milvus 2.0のプロジェクト名)の主要な設計思想と原則について説明します。詳しくは、過去の論文やGitHubリポジトリをご参照ください。
背景
Milvus1.0を設計した当初、我々の主な目的は単にベクトル管理をサポートし、ベクトル検索のパフォーマンスを最適化することでした。しかし、数年にわたり多くのユーザと交流するうちに、初期のフレームワークでは対応が困難であったベクターデータベースに対する一般的なビジネス要件を発見しました。
これらのニーズは、常に変化する要件、より柔軟な一貫性ポリシー、コンポーネントレベルの弾力性、よりシンプルで効率的なトランザクション処理モデルといったカテゴリーに分類することができます。
変化し続ける要件
ベクトル・データ処理に関しては、ビジネス要件はまだ完全に定義されていない。
初期の頃は、K-最近傍検索が最も必要とされていました。しかし、その後、範囲検索、様々なカスタム距離メトリックのサポート、ハイブリッド検索、マルチモーダルクエリ、その他ますます多様化するクエリセマンティクスなど、より多くの要件が表面化しています。
このため、ベクトルデータベースのアーキテクチャは、新しい要件を迅速かつ俊敏にサポートできる柔軟性が求められます。
より柔軟な一貫性ポリシー
コンテンツの推薦を例にとると、このシナリオでは適時性に対する要求が高い。新しいコンテンツは数分、あるいは数秒以内にユーザーに推薦される必要があるため、システムが推薦内容を更新するのに1日以上かかることは許されない。このようなシナリオでは、最終的な一貫性のみを提供することでビジネス成果を保証することは難しく、強い一貫性にこだわるとシステムのオーバーヘッドが大きくなります。
この問題に対処するために、我々は次の解決策を提案する。ビジネス要件に従って、ユーザーは挿入されたデータを照会できるようになるまでに許容できる最大の遅延を指定することができる。その結果、システムは特定のデータ処理メカニズムを調整し、ビジネスの最終結果を保証する。
コンポーネントレベルの弾力性
リソース要件と負荷強度は、アプリケーションによってベクトルデータベースの各コンポーネントで大きく異なります。例えば、ベクトル検索とクエリーコンポーネントは、そのパフォーマンスを確保するために大規模な計算リソースとメモリリソースを必要としますが、データアーカイブとメタデータ管理は、機能するためにわずかなリソースしか必要としません。
アプリケーションの観点から見ると、推薦システムにとって最も重要な要件は、大規模な同時クエリーを行う能力であるため、これらのシステムでは、クエリーコンポーネントのみが高い負荷を受ける。一方、分析アプリケーションでは、多くの場合、大量のオフラインデータをインポートする必要があるため、データ挿入とインデックス構築という相互に関連する2つのコンポーネントに負荷がかかる。
**リソースの利用率を向上させるためには、各機能モジュールが独立した弾力的なスケーラビリティを持つことが必要であり、これによりシステムのリソース割り当てをアプリケーションの実際のニーズにより近づけることができる。
よりシンプルで効率的なトランザクション処理モデル
厳密に言えば、トランザクション・モデルはビジネス要件というよりも、システム設計で利用できる最適化のためのスペースである。
機械学習がその記述力を進化させるにつれて、ビジネスでは1つのエンティティの複数の次元からのデータを融合して、1つの統一されたベクトルとして表現する傾向がある。例えば、ユーザープロファイリングでは、個人プロファイル、嗜好、社会的関係などの情報が融合される。その結果、ベクトル・データベースは、従来のデータベースで一般的なJOINのような操作を実装することなく、単一のテーブルだけで管理することができる。このように、**システムは単一のテーブル上で行レベルのACIDをサポートするだけでよく、複数のテーブルを含む複雑なトランザクションを行う必要がない。
目的
**Milvusの2番目のメジャーリリースとして、Manuはクラウドネイティブの分散ベクターデータベースシステムとして位置づけられている。
Manuの設計に着手するにあたり、私たちは上記の様々なビジネス要件を考慮し、分散システムに共通する要件と組み合わせました。その結果、Manuには5つの大まかな目的が生まれました:長期的な進化可能性、調整可能な一貫性、優れた弾力性、高可用性、高性能です。
長期的な進化可能性
機能性を進化させながらシステムの複雑さを管理可能なレベルにコントロールするためには、個々のコンポーネントが他のコンポーネントへの干渉を最小限に抑えながら独立して進化、追加、交換できるように、システムをうまく切り離す必要があります。
調整可能な一貫性
新しく挿入されたデータに対するクエリの可視性の遅延をユーザが指定できるように、システムはデルタ一貫性をサポートする必要があります。デルタ一貫性では、すべてのクエリが少なくともデルタ時間単位まですべての関連データを返すことが必要です。
優れた弾力性
リソースの利用効率を向上させるために、システムはコンポーネントレベルできめ細かな弾力性を実現し、コンポーネントの様々なハードウェア依存性を考慮したリソース割り当てポリシーを実現する必要があります。
高い可用性とパフォーマンス
高可用性はすべてのクラウドデータベースの基本要件であり、少数のサービスノードやコンポーネントに障害が発生しても、他のサービスに影響が及ばないこと、そしてシステムが効果的に障害復旧できることが要求される。
高性能はベクトル・データベースの決まり文句である。設計プロセスでは、システムフレームワークレベルで発生するオーバーヘッドを厳密に制御し、良好なパフォーマンスを確保する必要がある。
マニュアーキテクチャ
**Manuは4層のアーキテクチャを採用しており、読み込みと書き込み、ステートレスとステートフル、ストレージとコンピューティングの分離を可能にしています。
下図に示すように、Manuは上から順に、アクセス層、コーディネータ層、ワーカー層、ストレージ層の4つの層を持つ。また、Manuはバックボーンとしてログシステムを使用しており、分離されたコンポーネントを接続している。
Manuアーキテクチャ](https://assets.zilliz.com/architecture_33e310d093.png)
アクセス層
**アクセス・レイヤーは、ユーザー・エンドポイントとして機能するステートレス・プロキシで構成される。
これらのプロキシはクライアントからのリクエストを受け取り、対応するコンポーネントにリクエストを分配し、クライアントに返す前に結果を収集する。その上、プロキシは検索リクエストの正当性(例えば、検索するコレクションが存在するかどうか)を検証するためにメタデータのコピーをキャッシュする。
コーディネータ層
**コーディネータ層はシステムの状態を管理し、メタデータを維持し、タスクを処理するためにシステムコンポーネントを調整する。
コーディネータには4つのタイプがあり、それぞれ異なる機能のために独立して設計されている。このようにして、システム障害を分離し、コンポーネントを個別に進化させることができる。信頼性を考慮し、各コーディネーターは複数のインスタンスを持つことができる(例えば、メイン1つとバックアップ2つ)。
ルート・コーディネーター
ルート・コーディネーターは、コレクションの作成/削除などのデータ定義要求を処理し、コレクションのメタ情報(コレクションのプロパティ、各プロパティのデータ型など)を保持します。
データコーディネーター
データ更新要求をビンログに変換するためにデータノードを調整し、コレクションの詳細情報(各コレクションのセグメント一覧、各セグメントの格納パスなど)を記録する。
インデックスコーディネータ
インデックスコーディネータはデータのインデックス作成を管理する。インデックス作成タスクのためにインデックスノードを調整し、各コレクションのインデックス情報(インデックスタイプ、関連パラメータ、ストレージパスなど)を記録する。
クエリコーディネータ
クエリコーディネータはクエリノードのステータスを監視し、負荷分散のためにクエリノードへのセグメント(関連インデックスとともに)の割り当てを調整します。
ワーカーレイヤー
**ワーカー層はシステム内の複数のタスクを実行する。
すべてのワーカーノードはステートレスであり、読み取り専用のデータコピーを取得してタスクを実行し、相互に連携する必要はありません。したがって、ワーカーノードの数は負荷に応じて柔軟に調整することができます。また、Manuはタスクごとに異なるワーカーノードを使用するため、実際の負荷やQoS要件に応じて、各ノードタイプを独立して拡張することができます。
ストレージ層
**ストレージ層はシステムステータス情報、メタデータ、コレクション、関連インデックスを永続的に保存します。
Manuはシステムステータス情報とメタデータを格納するために、etcdのような可用性の高い分散KV(key-value)ストアを使用します。メタデータが更新されると、データはまずKVストアに書き込まれ、関連するコーディネータと同期されます。コレクションやインデックスのような大容量のデータは、AWS S3のようなオブジェクト・ストレージ・サービスで管理される。ワーカーノードがデータを処理する前にオブジェクトストアからデータの読み取り専用コピーを取得し、ローカルにキャッシュするため、ほとんどのデータ処理はローカルで行われるため、オブジェクトストレージに伴う高いレイテンシはパフォーマンスのボトルネックにはならない。
ログバックボーン
ログ・バックボーン](https://assets.zilliz.com/log_backbone_d0bb07c581.png)
システムコンポーネント(例えば、WAL、binlog、データノード、インデックスノード、クエリノード)をよりよく分離し、それぞれが独立して拡張および進化できるようにするために、Manuは「データとしてのログ」パラダイムに従い、分離されたシステムコンポーネントを接続するバックボーンとしてログシステムを使用します。**Manuでは、ログは異なるシステムコンポーネントによって永続的にサブスクライブすることができるため、これらのコンポーネントはログのサブスクライバと呼ばれる。
Manuのログは、ライトアヘッドログ(WAL)とビンログに分けられる。WALはシステムログの増分部分であり、binlogは基本部分である。WALはシステムログの増分部分であり、binlogは基本部分である。これらは遅延、容量、コストにおいて互いに補完しあう。
上の図に示すように、ロガーはログシステムの入口であり、データをWALに公開する。データノードはWALを購読し、行ベースのWALを列ベースのビンログに変換します。インデックスノードやクエリーノードなどの読み取り専用コンポーネントはすべて、ログサービスの独立したサブスクライバであり、自分自身を最新の状態に保ちます。
**ログシステムは、コンポーネント間のメッセージの受け渡しも行います。例えば、データノードはどのセグメントがオブジェクトストレージに書き込まれたかを他のコンポーネントに通知することができ、インデックスノードは新しいインデックスが構築されるとすぐにすべてのクエリコーディネータに通知することができます。さらに、異なるタイプのメッセージは、異なるチャネルに整理されます。各コンポーネントは、すべてのブロードキャストログをリッスンする代わりに、対応するチャンネルをサブスクライブするだけでよい。
データ処理ワークフロー
このセクションでは、Manu内部のデータ処理ワークフローを詳しく説明し、データ挿入、インデックス構築、クエリ実行のプロセスを紹介する。
データ挿入
データ挿入ワークフロー](https://assets.zilliz.com/data_insertion_workflow_f06d619f47.png)
上の図は、Manuにおけるデータ挿入のワークフローと、関連するコンポーネントを示しています。
プロキシによって処理された後、データ挿入リクエストはハッシュアルゴリズムに基づいていくつかのバケットに分散される。通常、Manu システムには複数のロガーがあり、一貫したハッシュに基づいて各ハッシュバケット内のエンティティを処理します。各ハッシュバケット内のエンティティは、このバケットにのみマップされるライトアヘッド ログ(WAL)チャネルに書き込まれます。ロガーがデータ挿入要求を受け取ると、この要求にグローバルに一意なログシーケンス番号(LSN)を割り当て、対応するWALチャンネルに書き込む。LSNは、中央のタイムサービスオラクル(TSO)によって生成されます。各ロガーはTSOからLSNを受け取り、定期的にローカルにLSNを保存する必要があります。
ほとんどの場合、WALはKafkaやPulsarなどのクラウドベースのメッセージキューを介して実装することができます。データノードはWALをサブスクライブし、行ベースのWALを列ベースのbinlogに変換する。**binlogの列ベースの性質は、データの圧縮とアクセスを容易にする。この効率の一例がインデックスノードです。インデックスノードは、インデックスを構築するために必要なベクター列だけをビンログから読み込むので、読み取りの増幅から解放されます。
インデックス構築
**バッチインデックス作成は、ユーザがコレクション全体のインデックスを作成するときに発生します(例えば、すべてのベクターが新しい埋め込みモデルで更新されるとき)。この場合、インデックス・コーディネータはデータ・コーディネータからコレクション内のすべてのセグメントのパスを取得し、各セグメントに対してインデックスを構築するようにインデックス・ノードに指示します。ストリームインデックスの作成は、ユーザーが継続的に新しいエンティティを挿入するときに行われ、インデックスは検索サービスを中断することなく、その場で非同期に作成される。
データノードが新しいセグメントをbinlogに書き込むと、データコーディネータはインデックスコーディネータに通知して、新しいセグメントにインデックスを構築するインデックスノードのタスクを作成させます。バッチとストリームの両方のインデックス作成シナリオで、セグメントに対して必要なインデックスが作成されると、インデックスノードはそれをオブジェクトストレージに永続化し、クエリコーディネータに通知して、クエリノードがクエリを処理するためにインデックスをロードできるように、ストレージパスをインデックスコーディネータに送信します。
クエリの実行
**Manuはコレクションをセグメントに分割し、クエリ要求を並列に実行するためにクエリノードにセグメントを分散します。プロキシは、クエリコーディネータに問い合わせることで、クエリノード上のセグメントの分布のコピーをキャッシュし、検索されたコレクションのセグメントを保持するクエリノードに検索要求をディスパッチします。クエリノードはローカルセグメントに対してベクトルクエリを実行し、結果をマージしてプロキシに返す。プロキシはさらに、各クエリノードによる結果を集約し、最終結果をクライアントに返す。
**クエリノードは、WAL、インデックスファイル、およびビンログの3つのソースからデータを取得します。過去のデータについては、クエリノードはオブジェクトストレージから対応するビンログまたはインデックスファイルを読み取ります。一方、増分データの場合、クエリノードはストリーミング方式でWALから直接読み込みます。インクリメンタルデータをビンログから取得すると、データの可視性に待ち時間が生じます。言い換えると、新しく挿入されたデータは、長い時間が経過してからしかクエリに利用できなくなり、シナリオによっては高い一貫性のニーズを満たすことができません。
前述したように、Manuは、ユーザが一貫性レベルをより柔軟に調整できるように、デルタ一貫性モデルを採用しています。デルタ一貫性は、データ更新要求がManuによって受信された後、デルタ時間単位まで更新データ(挿入および削除されたデータを含む)を照会および検索できることを保証します。
Manuは、すべてのデータ挿入およびクエリ要求にタイムスタンプを持つLSNを追加することで、デルタ一貫性を実現する。クエリ要求を実行するとき、クエリノードは要求のタイムスタンプ(Lr)とクエリノードによって処理された最新のデータ更新要求のタイムスタンプ(Ls)をチェックする。LrとLsの間隔がdeltaより小さい場合のみ、クエリーリクエストは実行される。そうでない場合、WALに記録されたデータ更新が処理されるまで、問い合わせ要求は実行されるのを待つ。しかし、長期間データの更新がない場合、Lsと現在のシステム時刻の時間間隔が非常に小さくなり、クエリがブロックされてしまう。このような問題を防ぐため、マニュは定期的にWALに制御情報を挿入し、クエリ・ノードにタイムスタンプの更新を強制する。
性能評価
本稿では、Manuを実際のアプリケーションに統合し、システム全体の性能評価も行った。以下は評価結果の一部である。
Manuと他のベクトル検索システムのクエリ性能](https://assets.zilliz.com/evaluation_result_1_f0eaa48459.png)
上図は、Manuと他の4つの匿名オープンソースベクトル検索システムとのクエリ性能の比較である。**SIFTおよびDEEPデータセットに対するクエリを実行した場合、Manuが他のベクトル検索システムを明らかに凌駕していることがわかる。
ノード数の違いによるManuのクエリ性能](https://assets.zilliz.com/image_1_948add7366.png)
上の図は、クエリノード数を変化させた場合のManuのクエリ性能を示している。異なる類似度メトリクスの異なるデータセットに対してクエリを実行した場合、Manuのクエリ性能はクエリノード数に対してほぼ直線的な関係を示すことがわかる**。
異なる一貫性レベルにおけるManuのクエリ性能](https://assets.zilliz.com/evaluation_result_3_17cd3b40ca.png)
上の図は、異なる一貫性レベルにおけるManuのクエリー性能を示しています。水平座標はデルタ一貫性におけるデルタの値を表す。各図は、クエリノードに時間の同期を強制するWALに送信される制御情報の頻度を反映しています。図から、デルタの値が大きくなるにつれてManuのクエリレイテンシが劇的に減少することがわかります。したがって、Manuのユーザーはパフォーマンスと一貫性の必要性に応じて適切なデルタ値を選択する必要があります。
結論
本稿では、ベクトルデータベースに対する実際の要件に基づき、Manuの設計とその主要機能のワークフローを紹介した。つまり、Manuの主な機能は以下の2つである:
Manuはシステムコンポーネントを接続するためにログバックボーンを使用し、各コンポーネントの独立したスケーリングと進化を可能にし、リソースの割り当てと障害の分離を容易にする。
ログシステムとLSNにより、Manuはデルタ一貫性モデルを採用し、一貫性、コスト、パフォーマンス間の柔軟なトレードオフを可能にする。
要約すると、我々の** VLDB 論文の主な貢献は、ベクトルデータベースに対する実世界の需要の紹介と、クラウドネイティブベクトルデータベース**の基本アーキテクチャの設計にある。現時点では、このアーキテクチャはまだ完璧には程遠く、私たちの今後の方向性には以下のようなものがあります:
マルチモーダルコンテンツから抽出されたベクトルをどのように取得するか;
データ検索をより効率的にするために、ローカルディスク、クラウドドライブ、その他のストレージサービスを含むクラウドストレージサービスをよりうまく活用する方法;
FPGA、GPU、RDMA、NVM、RDMAのような新しいコンピューティング、ストレージ、通信ハードウェアの助けを借りて、インデックス作成と検索のパフォーマンスを最大化する方法。
巻末資料
1年前、私は西安で開催されたACM SIGMOD 2021に、ZillizのCEOであるCharles Xie氏と共に参加した。この論文を書こうと思い立ったのは、Milvus 2.0のGAリリース](https://milvus.io/blog/2022-1-25-annoucing-general-availability-of-milvus-2-0.md)(Manu)のために上海に戻る途中のことだった。チャールズも私も、クラウドネイティブデータベースが学界で新たなホットトピックになりつつあると感じていた。Manuがまさにクラウドネイティブで、巨大ベクトル用に特化したデータベースシステムであることは、まさに偶然の一致でした。その結果、私たちはManuとクラウドネイティブ・データベース管理システムについてこの論文を書くことになった。
私たちの論文が何らかの光を放ち、より多くの学者や業界の同僚が私たちと一緒にクラウドネイティブなベクトルデータベース管理システムの探求と研究に参加してくれることを願っています。
また、ボー・タン助教授、シャオ・イェン助教授、ロン・シアン助教授の貢献にも感謝の意を表したい。本稿は、Zillizチームと南方科技大学のデータベースグループが共同で執筆した。
読み続けて

How to Choose the Best Embedding Model for RAG in 2026: 10 Models Benchmarked
We benchmarked 10 embedding models on cross-modal, cross-lingual, long-document, and dimension compression tasks. See which one fits your RAG pipeline.

Zilliz Cloud Audit Logs Goes GA: Security, Compliance, and Transparency at Scale
Zilliz Cloud Audit Logs are now GA, giving enterprises real-time visibility, compliance-ready trails, and stronger security across AWS, GCP, and Azure.

Building RAG Pipelines for Real-Time Data with Cloudera and Milvus
explore how Cloudera can be integrated with Milvus to effectively implement some of the key functionalities of RAG pipelines.



