しばやん雑記

Azure とメイドさんが大好きなプログラマーのブログ

各言語向けの Azure Cosmos DB SDK がサポートしている機能まとめ(随時更新)

Azure Cosmos DB は複数の API に対応したサービスとなっているので、利用している言語向けに Cosmos DB ネイティブの Core (SQL) API の SDK が提供されていなくても、代わりに Mongo や Cassandra の SDK を使って Cosmos DB を使ったサービスを開発することが出来ます。

Cosmos DB が提供する API については以下のドキュメントを参照してください。Mongo / Cassandra / Table API は独立していますが、実は Core API と Gremlin は相互運用が可能になっています。*1

Mongo や Cassandra を使って開発は出来ますが、Cosmos DB のフル機能を活用するには Core API が必要となるので、現在は公式で C# / Java / Node.js / Python / Go 向けの SDK が提供されています。

それぞれの言語向け SDK で同じ機能がサポートされていれば良いのですが、基本的に全ての機能が先行して実装される C# と Java SDK を除いて、それ以外の言語向けでは使える機能にばらつきがあります。ハッカソンやワークショップの際に C# 使いとしては混乱する原因になりがちなので、個人的によく使う機能を中心にサポート状況を確認しました。

長くなったので久し振りに目次記法を使いましたが、こう見ると Cosmos DB の機能はかなり多いと再認識しました。ちなみにストアドやトリガーは自分が全く使わないので入れていません。

もちろん SDK のアップデートがあれば更新していきたいと思います。言語はこれ以上は増えない気がするので、基本はサポートしている機能をメンテする形になると思います。

各言語向け Cosmos DB SDK の概要

C# (Microsoft.Azure.Cosmos)

Cosmos DB SDK の C# 版のみ、独立したリポジトリで開発が行われています。他の言語向けは Azure SDK のリポジトリに入っていますが、C# に関してはこちらが最新です。

現在の推奨される最小バージョンは 3.25.0 になるため、これより古いバージョンを利用している場合には早目にアップデートしましょう。v2 を使っている場合も早めに v3 へアップグレードを行いましょう。

Java (com.azure::azure-cosmos)

C# と同じレベルで開発が進んでる Cosmos DB SDK の Java 版です。こちらは Azure SDK のリポジトリに含まれているので、サンプルコードなどはこちらを参照してください。

Java SDK もいくつかバージョンが存在していますが、現状は v4 のみ更新されているので古いバージョンを使っている場合はアップグレードしましょう。

Node.js (@azure/cosmos)

最近の Cosmos DB SDK のベースとなる実装である Node.js 版ですが、新機能の追加に関しては C# と Java SDK の次ぐらいの速度で、若干利用できない機能が存在しています。

https://www.npmjs.com/package/@azure/cosmos

他の言語の SDK とは異なり、JavaScript ベースなのでブラウザでも一部の機能は利用可能です。現実的にはブラウザから使いたいユースケースはほぼ存在しないと思いますが。

Python (azure-cosmos)

Python SDK のデザインは他の言語の Cosmos DB SDK と最近の Azure SDK を混ぜたようなものになっています。既に Python 2 系のサポートは終わっているので気を付けてください。

ちなみに 2022/12 からは Python 3.6 のサポートも削除されるので、3.7 以上が必須となります。

Go (azcosmos)

最近になって開発が活発化してきた Cosmos DB SDK の Go 版ですが、まだプレビューとなっているので基本的な機能以外はまだまだ実装が足りていない状態です。

最近まで接続文字列を使って初期化出来なかったぐらい機能不足でしたが、最近のアップデートで対応しているので小まめにバージョンは確認した方が良いです。欲しい機能は Issue で要望しましょう。

特筆すべき Cosmos DB SDK の機能

Direct Mode (C# / Java)

Cosmos DB には Gateway Mode と Direct Mode という 2 種類の接続方式が用意されていて、名前からも想像が付くと思いますが Direct Mode の方がパフォーマンスが良いです。

仕組みと違いについては以下のドキュメントを参照してください。要約するとバックエンドの物理パーティションに直接リクエストを投げるので Direct Mode です。

Gateway Mode は通常の HTTP が使われるので実装が比較的容易という事情もあるので、新しい言語向け SDK では Gateway Mode のみサポートされることが多いです。

C# と Java SDK ではデフォルトが Direct Mode となっているのでパフォーマンス上は有利ですが、後述する Integrated Cache の利用時には気を付ける必要があります。

Multi-region Writes (C# / Java / Node.js / Python)

Cosmos DB は複数リージョンにレプリカを作成して、一番近いリージョンに対してデータの読み書きが行えるようになっていますが、Go SDK では Multi-region に対応していないようです。

https://docs.microsoft.com/en-us/azure/cosmos-db/sql/how-to-multi-master

SDK の実装レベルで確認しましたが、現状は優先するリージョンの設定も出来ないためシングルリージョンで利用する前提になっているようです。重要な機能なので今後対応されると思います。

Async (C# / Java / Node.js / Python)

当然ながら Cosmos DB は細かく、そして多くのネットワーク I/O が発生するので非同期で処理を書くことが重要になります。Go 以外の SDK では Task / Reactive / Promise ベースの非同期に対応しているので、適切に利用することでパフォーマンスを向上させることが出来ます。

最近にはプレビューとして公開されていた Python SDK の Async 対応が GA もしています。

Go に関しては非同期の実装がそもそも他の言語とは異なっているので、SDK レベルでの対応が必要ない気配があります。Go に詳しくはないので少し怪しいです。

Bulk (C# / Java / Node.js)

以前は Bulk Executor という別ライブラリが公開されていて、それを利用することで Cosmos DB への大量データのインポートを行っていましたが、Bulk Executor 自体が廃止されて Cosmos DB SDK 自体に組み込まれたので、使い勝手が改善しています。

特に C# SDK の Bulk サポートは Task ベースの非同期が上手く利用されているので、クライアント初期化時に Bulk を有効化しておくだけという簡単さが売りです。

Bulk Executor の時代は C# と Java SDK のみサポートされていましたが、最近では Node.js でも一部が実装されているようです。しかし C# のように Task と通常の API を組み合わせたシンプルな API にはなっていないので、実際には Partial Update っぽい使い勝手です。

後述する Transactional Batch と実体はほぼ同じなので、もうちょっと頑張って欲しさがあります。

Transactional Batch (C# / Java / Node.js / Go)

Cosmos DB には RDB のようなトランザクションは機能として存在していないですが、1 リクエストに複数の処理を含めることで 1 トランザクションとして扱うことが出来る機能があります。1 リクエストに含まれている処理が 1 つでも失敗すれば、他の処理も反映されないという分かりやすい実装です。

https://docs.microsoft.com/en-us/azure/cosmos-db/sql/transactional-batch

Transactional Batch は Python SDK 以外では利用できるようになっています。珍しく Go SDK は早目に実装されているので、要望が多かったのかもしれません。

Node.js の API 実装は Bulk とほぼ同じで、リクエスト内の処理が 1 つでも失敗した時に全体をロールバックするかどうかの差ぐらいのようです。使い勝手はあまり良くありません。

Partial Update (C# / Java / Node.js)

Cosmos DB ではプロパティを変更する処理は、一度その項目を全て読み取ってから Replace を実行して実現されますが、元の値を必要としないケースでは項目をわざわざ読み取る必要が無いので無駄となります。

Partial Update では JSON Patch に似た記法で項目のプロパティを、項目を読み取らずに変更が可能となります。読み書きが Cosmos DB 側で完結するので衝突も自動的に解決してくれます。

現状では Python と Go 以外の SDK で利用可能になっています。API 的には Transactional Batch に近いので Python よりは Go でのサポートの方が早くなりそうな予感です。

Hierarchical Partition Keys (C# / Java / Node.js)

利用する上で最重要となるパーティションキーですが、これまで複数の値を基にしたパーティションキーを利用する際には合成した値を使う必要がありました。階層パーティションキーあるいはサブパーティションキーを使うと、重複したデータを持たせることなく合成した値でパーティションキーを定義できます。

現在プレビュー中なので対応したコンテナーの作成自体も C# か Java SDK を使う必要があります。クエリに関しては Node.js SDK 側に対応しているような記載があるのですが未確認です。

機能的にはそこまで複雑なものではないので、GA する頃には残りの SDK での対応も期待できます。

ReadMany (C# / Java)

SDK レベルでパーティションキーが割り当てられている物理パーティションを認識することで、複数項目の読み取りを効率的に行う ReadMany ですが C# と Java SDK での対応に留まっています。

仕組みとしては Change Feed に近いので、Change Feed に対応している SDK では実装が期待できます。Node.js と Python には実装される可能性が高いと考えています。

Change Feed

Cosmos DB 最大の特徴である Change Feed も SDK によって実装にばらつきがありますが、現実的には Azure Functions の CosmosDBTrigger を使えば解決出来るので、あまり問題になりません。

https://docs.microsoft.com/en-us/azure/cosmos-db/sql/change-feed-functions

とは言え CosmosDBTrigger が適していないユースケースも世の中には存在するので、SDK レベルでの対応状況を理解しておくのはここぞという時に効いてきます。

Change Feed 自体の API は 1 つしか存在しませんが、SDK レベルで高レベル API と低レベル API が用意されています。前者は Change Feed Processor と、後者は Pull Model と呼ばれることが多いです。

Change Feed Processor (C# / Java)

高レベルな Change Feed 実装となる Change Feed Processor は Lease コンテナーの管理まで行ってくれるので、利用者は Change Feed が発火した時のイベントだけ実装すれば良いという手軽さがあります。

https://docs.microsoft.com/en-us/azure/cosmos-db/sql/change-feed-processor

非常にシンプルで使いやすい API となっているので、Azure Container Apps のように Azure Functions の CosmosDBTrigger がそのままでは使えない環境での利用に適しています。

Pull Model (C# / Java / Node.js / Python)

低レベルな Change Feed 実装となる Pull Model は、名前の通り API を利用者側で呼び出して Change Feed を読み取るといった処理が必要となりますが、任意のタイミングで自由に読み取れるのが特徴です。

大半の SDK で実装されているのは Pull Model となるので、Change Feed Processor と混同しないように注意が必要です。Continuous Token の管理も自前で必要となるので手間が多いです。

https://docs.microsoft.com/en-us/azure/cosmos-db/sql/change-feed-pull-model

イベントドリブンではなく Batch での Change Feed 読み取りが可能となるので、まとまったデータをアーカイブする際には Pull Model が適切な選択肢となります。

Integrated Cache (C# / Java / Node.js / Python)

Cosmos DB の Gateway に相当する部分に専用のキャッシュ用インスタンスを置くことで、透過的に非常に高速なインメモリキャッシュを追加できます。

基本は接続文字列を変更するだけなので SDK の実装に依存しませんが、キャッシュの保有時間を設定する機能は Go SDK のみ未対応となります。Gateway Mode での接続が必須になるので、C# と Java SDK では明示的に Gateway を指定する必要があります。

Azure RBAC (C# / Java / Node.js / Python / Go)

長い間 Azure は全体的に API キーを使った認証が使われていましたが、最近では多くのサービスが Azure AD ベースの RBAC がサポートされています。Cosmos DB でも RBAC がサポートされているので、Service Principal や Managed Identity を使ったアクセスが可能です。

ローカル開発環境でも Visual Studio の Azure サービス認証や Azure CLI を使うことで、Azure AD を使った Cosmos DB へのアクセスが本番向けと同一コードで可能になります。

開発者の Azure アカウントにリソース単位で権限を与えておけば、Azure へのログインは MFA などで保護できるので API キーを共有する必要が無く安全に利用できます。

Always Encrypted (C# / Java)

Cosmos DB に限らず Azure に保存されているデータは全て Microsoft が管理しているキー、あるいは Key Vault に保存されているキーを使って暗号化されていますが、クライアントサイドで暗号化して保存する機能が Always Encrypted となります。

プロパティレベルで暗号化するか設定出来るので、機密データの種類に合わせて選択可能です。

C# と Java SDK のみで対応していますが、両方とも追加のパッケージが必要になります。さらに Azure Portal で Always Encrypted に対応したコンテナーは作成できないので、全てを SDK で行う必要があります。

クライアントサイドでの暗号化が必要になるユースケースはあまり多くないですが、C# と Java SDK が現状必須なので設計時から考慮する必要があります。