スケーラブルな類似検索のためのベクターデータベースの構築
カバー画像
この記事はXiaofan Luanによって書かれ、Angela NiとClaire Yuによって翻訳されました。
統計によると、世界のデータの約80%〜90%は非構造化データである。インターネットの急成長に後押しされ、今後数年間は非構造化データの爆発的増加が予想される。その結果、企業はこのようなデータをよりよく扱い、理解するための強力なデータベースを緊急に必要としている。しかし、データベースの開発は「言うは易く行うは難し」である。この記事では、スケーラブルな類似検索のためのオープンソースでクラウドネイティブなベクトルデータベースであるMilvusを構築するための思考プロセスと設計原則を共有することを目的としている。また、Milvusのアーキテクチャについても詳しく説明する。
ジャンプする
非構造化データには完全な基本ソフトウェアスタックが必要
インターネットの成長と進化に伴い、電子メール、論文、IoTセンサーデータ、フェイスブックの写真、タンパク質の構造など、非構造化データがますます一般的になってきた。コンピュータが非構造化データを理解し処理するために、これらは埋め込み技術を使ってベクトルに変換される。
milvusはこれらのベクトルを保存し、インデックス化し、類似距離を計算することで2つのベクトル間の相関を分析する。2つの埋め込みベクトルが非常に類似している場合、元のデータソースも類似していることを意味する。
非構造化データ処理のワークフロー。
ベクトルとスカラー
スカラーは、1つの測定値(大きさ)のみで記述される量である。スカラーは数値で表すことができる。例えば、車が時速80kmで走っているとする。ここで、速度(80km/h)はスカラーである。一方、ベクトルは、大きさと方向という少なくとも2つの測定値で記述される量である。車が時速80kmで西に向かって走っている場合、ここで速度(時速80km西)はベクトルである。下の画像は、一般的なスカラーとベクトルの例である。
スカラーとベクトル
ほとんどの重要なデータには複数の属性があるため、ベクトルに変換することでこれらのデータをよりよく理解することができる。ベクトル・データを操作する一般的な方法の1つは、ユークリッド距離、内積、谷本距離、ハミング距離などの指標を使ってベクトル間の距離を計算することです。距離が近いほど、ベクトルは類似していることになる。膨大なベクトルデータセットを効率的にクエリするには、ベクトルデータにインデックスを作成して整理する。データセットにインデックスを付けると、入力クエリに類似したベクトルを含む可能性の高いクラスタ、つまりデータの部分集合にクエリをルーティングすることができる。
インデックスの詳細については、「ベクトル・インデックス」を参照してください。
ベクトル検索エンジンからベクトルデータベースへ
Milvus2.0は当初から検索エンジンとしてだけでなく、強力なベクトルデータベースとしても機能するように設計されています。
InnoDBと MySQL、あるいはLuceneと Elasticsearchを類推することで、この違いを理解することができます。
MySQLやElasticsearchのように、MilvusもFaiss、HNSW、Annoyといったオープンソースのライブラリの上に構築されており、これらのライブラリは検索機能の提供や検索パフォーマンスの確保に重点を置いている。しかし、MilvusをFaissの単なるレイヤーに貶めるのは不当であろう。Milvusはベクトルを保存し、検索し、分析し、他のデータベースと同様にCRUD操作のための標準的なインターフェースも提供している。さらに、Milvusは以下のような機能も備えている:
- シャーディングとパーティショニング
- レプリケーション
- ディザスタリカバリ
- ロードバランス
- クエリパーサまたはオプティマイザ
ベクター・データベース
ベクター・データベースとは何かについてのより包括的な理解については、こちらのブログを参照されたい。
クラウド・ネイティブな最初のアプローチ
Could-nativeアプローチ
シェアード・ナッシングからシェアード・ストレージ、そしてシェアード・シングへ
従来のデータベースは、分散システムのノードが独立しているがネットワークで接続されている「シェアード・ナッシング」アーキテクチャを採用していた。ノード間でメモリやストレージは共有されない。しかし、Snowflakeは、コンピュート(クエリ処理)とストレージ(データベースストレージ)を分離した「共有ストレージ」アーキテクチャを導入し、業界に革命をもたらした。共有ストレージアーキテクチャにより、データベースはより高い可用性、スケーラビリティ、データの重複の削減を実現することができる。Snowflakeに触発され、多くの企業がデータの永続化のためにクラウドベースのインフラを活用する一方で、キャッシュのためにローカルストレージを使用し始めた。このタイプのデータベースアーキテクチャーは "シェアード・サムシング "と呼ばれ、今日ほとんどのアプリケーションで主流となっている。
Milvusは、"shared something "アーキテクチャとは別に、Kubernetesを使って実行エンジンを管理し、マイクロサービスで読み取り、書き込み、その他のサービスを分離することで、各コンポーネントの柔軟なスケーリングをサポートしている。
サービスとしてのデータベース(DBaaS)
データベース・アズ・ア・サービスは、多くのユーザーが通常のデータベース機能に関心を持つだけでなく、より多様なサービスに憧れていることから、ホットなトレンドとなっている。これは、従来のCRUD操作とは別に、データベース管理、データ転送、チャージ、可視化など、データベースが提供できるサービスの種類を充実させなければならないことを意味します。
より広範なオープンソースのエコシステムとの相乗効果
データベース開発におけるもうひとつのトレンドは、データベースと他のクラウドネイティブなインフラとのシナジーを活用することだ。Milvusの場合、いくつかのオープンソースシステムに依存している。例えば、Milvusはメタデータの保存にetcdを使用している。また、マイクロサービス・アーキテクチャで使用される非同期サービス間通信の一種であるメッセージキューも採用しており、インクリメンタルなデータのエクスポートに役立っている。
将来的には、Sparkや TensorflowのようなAIインフラストラクチャの上にMilvusを構築し、Milvusをストリーミングエンジンと統合することで、Milvusユーザーの様々なニーズを満たすために、ストリーム処理とバッチ処理を統合的にサポートできるようにしたいと考えています。
Milvus2.0の設計方針
Milvus 2.0は、次世代のクラウドネイティブベクターデータベースとして、以下の3つの原則に基づいて構築されています。
データとしてのログ
データベースのログは、データに加えられたすべての変更を連続的に記録します。下図のように、左から「古いデータ」、「新しいデータ」となる。そして、ログは時間順に並んでいる。Milvusにはグローバルタイマーという仕組みがあり、グローバルに一意なタイムスタンプが自動的に付与されます。
ログ
Milvus2.0では、ログブローカーがシステムのバックボーンとして機能します。すべてのデータの挿入および更新操作はログブローカーを経由しなければならず、ワーカーノードはログを購読および消費することでCRUD操作を実行します。
テーブルとログの二重性
テーブルもログもデータであり、2つの異なる形態に過ぎない。テーブルは境界のあるデータであり、ログは境界のないデータである。ログはテーブルに変換できる。Milvusの場合、TimeTickの処理ウィンドウを使ってログを集約する。ログのシーケンスに基づいて、複数のログはログスナップショットと呼ばれる1つの小さなファイルに集約される。そして、これらのログスナップショットは、ロードバランスのために個別に使用することができるセグメントを形成するために結合される。
ログの永続性
ログの永続性は、多くのデータベースが直面する厄介な問題の一つです。分散システムにおけるログの保存は、通常レプリケーションアルゴリズムに依存する。
Aurora、HBase、Cockroach DB、TiDBなどのデータベースとは異なり、milvusは画期的なアプローチをとり、ログの保存と永続化のためにパブリッシュサブスクライブ(pub/sub)システムを導入している。pub/subシステムは、Kafkaや Pulsarのメッセージキューに似ている。システム内のすべてのノードがログを消費できる。Milvusでは、この種のシステムはログブローカーと呼ばれる。ログブローカーのおかげで、ログはサーバーから切り離され、Milvus自体がステートレスであることを保証し、システム障害から迅速に回復するためのより良い位置を確保します。
ログブローカー
スケーラブルな類似検索のためのベクトルデータベースの構築
Milvusは、Faiss、ANNOY、HNSWなどの一般的なベクトル検索ライブラリの上に構築されており、数百万、数十億、数兆のベクトルを含む高密度ベクトルデータセットの類似性検索用に設計されています。
スタンドアロンとクラスタ
Milvusには、スタンドアロンとクラスタの2つの導入方法がある。Milvusスタンドアロンでは、すべてのノードが一緒に配置されているため、Milvusを1つのプロセスとして見ることができる。現在、Milvusスタンドアロンでは、データの永続化とメタデータの保存をMinIOとetcdに依存しています。将来のリリースでは、Milvusシステムのシンプルさを確保するために、これら2つのサードパーティ依存を排除したいと考えています。Milvusクラスタには8つのマイクロサービスコンポーネントと3つのサードパーティ依存関係があります:MinIO、etcd、Pulsarです。Pulsarはログ・ブローカーとして機能し、ログ・パブ/サブ・サービスを提供する。
スタンドアロンとクラスタ
Milvusアーキテクチャの骨組み
Milvusは、データ・フローと制御フローを分離し、スケーラビリティとディザスタ・リカバリの点で独立した4つのレイヤに分かれている。
Milvusアーキテクチャ
アクセス層
アクセスレイヤーはシステムの顔として、クライアント接続のエンドポイントを外部に公開します。クライアント接続の処理、静的検証、ユーザーリクエストの基本的な動的チェック、リクエストの転送、結果の収集とクライアントへの返送を担当する。プロキシ自体はステートレスで、ロードバランシングコンポーネント(Nginx、Kubernetess Ingress、NodePort、LVS)を通じて、統一されたアクセスアドレスとサービスを外部に提供する。Milvusは超並列処理(MPP)アーキテクチャを採用しており、プロキシはワーカーノードから収集した結果をグローバルアグリゲーションと後処理の後に返す。
コーディネータサービス
コーディネータサービスはシステムの頭脳であり、クラスタトポロジーのノード管理、負荷分散、タイムスタンプ生成、データ宣言、データ管理を担当する。各コーディネータサービスの機能の詳細については、Milvus技術ドキュメントをご参照ください。
ワーカーノード
ワーカーノード(実行ノード)はシステムの手足となり、コーディネータサービスが発行する命令やプロキシが起動するデータ操作言語(DML)コマンドを実行します。MilvusのワーカーノードはHadoopのデータノードやHBaseのリージョンサーバに似ています。ワーカーノードの各タイプはコーディネートサービスに対応しています。各ワーカノードの機能の詳細については、Milvus技術ドキュメントを参照してください。
ストレージ
ストレージはMilvusの要であり、データの永続化を担う。ストレージレイヤーは3つのパートに分かれています:
- メタストアメタストア: コレクションスキーマ、ノードステータス、メッセージ消費チェックポイントなどのメタデータのスナップショットを保存する。Milvusはこれらの機能をetcdに依存しており、Etcdはサービス登録とヘルスチェックの責任も負う。
- ログブローカー:プレイバックをサポートし、ストリーミングデータの永続化、信頼性の高い非同期クエリの実行、イベント通知、クエリ結果の返送を担当するパブ/サブシステム。ノードがダウンタイム復旧を行う際、ログ・ブローカはログ・ブローカ再生を通じて増分データの整合性を保証します。MilvusクラスタはPulsarをログ・ブローカーとして使い、スタンドアロン・モードはRocksDBを使う。KafkaやPravegaなどのストリーミング・ストレージ・サービスもログ・ブローカーとして使用することができる。
- オブジェクト・ストレージ:ログのスナップショットファイル、スカラー/ベクトルインデックスファイル、中間クエリ処理結果を格納する。Milvusは、AWS S3や Azure Blobのほか、軽量でオープンソースのオブジェクトストレージサービスであるMinIOをサポートしている。オブジェクトストレージサービスはアクセスレイテンシーが高く、クエリごとの課金が発生するため、Milvusは近日中にメモリ/SSDベースのキャッシュプールとホット/コールドデータ分離をサポートし、パフォーマンス向上とコスト削減を実現する予定です。
データモデル
データモデルはデータベース内のデータを整理するものです。Milvusでは、すべてのデータはコレクション、シャード、パーティション、セグメント、エンティティごとに整理されます。
データモデル 1
コレクション
Milvusのコレクションはリレーショナルストレージのテーブルに例えることができます。コレクションはMilvusにおける最大のデータ単位である。
シャード
データを書き込む際にクラスタの並列計算能力を最大限に活用するために、Milvusのコレクションはデータの書き込み操作を異なるノードに分散させる必要があります。デフォルトでは、1つのコレクションには2つのシャードが含まれます。データセットのボリュームによっては、コレクション内にもっと多くのシャードを持つことができます。Milvusはシャーディングにマスターキーハッシュ法を使用します。
パーティション
シャードには複数のパーティションもあります。Milvusにおけるパーティションとは、コレクション内で同じラベルが付けられたデータの集合を指します。一般的なパーティショニング方法には、日付、性別、ユーザー年齢などによるパーティショニングがあります。パーティションを作成することで、膨大なデータをパーティションタグでフィルタリングできるため、クエリプロセスにメリットがある。
比較すると、シャーディングはデータを書き込む際のスケーリング機能を重視し、パーティショニングはデータを読み込む際のシステムパフォーマンスを強化する。
データモデル2
セグメント
各パーティション内には、複数の小さなセグメントが存在する。セグメントはmilvusのシステムスケジューリングの最小単位である。セグメントには、成長するセグメントと密封されたセグメントの2種類がある。グローイングセグメントはクエリノードによって登録される。Milvusのユーザーは成長するセグメントにデータを書き込み続けます。成長セグメントのサイズが上限 (デフォルトでは 512 MB) に達すると、システムはこの成長セグメントへの余分なデータの書き込みを禁止し、このセグメントを封印します。インデックスは封印されたセグメント上に構築される。
データにリアルタイムでアクセスするために、システムは成長中のセグメントと封印されたセグメントの両方のデータを読み込む。
エンティティ
各セグメントには大量のエンティティが含まれる。Milvusにおけるエンティティは、従来のデータベースにおける行に相当する。各エンティティは一意な主キーフィールドを持ち、これは自動生成することもできる。エンティティにはタイムスタンプ(ts)とMilvusの中核であるベクトルフィールドも含まれなければならない。
ディープダイブシリーズについて
Milvus 2.0の一般提供の正式発表に伴い、Milvusのアーキテクチャとソースコードの詳細な解釈を提供するために、このMilvus Deep Diveブログシリーズを企画しました。このブログシリーズで扱うトピックは以下の通りです:
Try Managed Milvus for Free
Zilliz Cloud is hassle-free, powered by Milvus and 10x faster.
Get StartedLike the article? Spread the word