SQL

Azure Cosmos DBのSQLサブクエリの書き方を見てみましょう。
例えば、次のようなクエリを表現したい場合はどうすればいいでしょうか。

SELECT Count(1) AS Count
FROM c
JOIN t IN c.tags
JOIN n IN c.nutrients
JOIN s IN c.servings
WHERE
t.name = ‘infant formula’
AND (n.nutritionValue > 0 AND n.nutritionValue < 10)
AND s.amount > 1

このクエリでは、インデックスは、タグの名前に「infant formula」を持つDocumentと一致します。
nutritionValue が0から10で、amaoutが1より大きいものです。

ここでのJOIN式は、フィルターを適用する前に、マッチしたtag、nutrients、servings配列を外積します。
Where句は、「c,t,n,s」タプルにフィルターを適用します。

マッチするDocumentが、tag、nutrients、servingsにそれぞれ10個あるとすると、10×10×10の1000個に拡張し、それに対してフィルターを書けます。

結合する前にフィルターをかけて効率化するにはサブクエリを利用します。

SELECT Count(1) AS Count
FROM c
JOIN (SELECT VALUE t FROM t IN c.tags WHERE t.name = ‘infant formula’)
JOIN (SELECT VALUE n FROM n IN c.nutrients WHERE n.nutritionValue > 0 AND n.nutritionValue < 10)
JOIN (SELECT VALUE s FROM s IN c.servings WHERE s.amount > 1)

タグが1つ、nutritionValue とservings が5つフィルターされたとすると、JSON式は25項目を展開します。

利用事例

元記事:How Skype modernized its backend infrastructure using Azure Cosmos DB

Skypeは従来、SQL Serverをデータソースに使用して運営されてきました。
3か所のデータセンターにSQL Serverを分散して配置し、アプリケーション側のロジックで3か所にユーザーデータをパーティショニングしていました。
マイクロソフトに買収された後、SkypeはデータベースチームをMicrosoftに移し、データベースの管理を委譲しました。
そうして運用してきましたが、40憶ユーザーを支えるには、システム的な限界が来ていました。
デッドロックの発生や、スキーマー変更の難しさ、レコード量の多さによる性能劣化、独自パーティショニング技術の維持など技術負債がありました。

開発概要

Skypeは新しいアーキテクチャによるシステムに切り替えるため、2017年5月から開発を開始し、2017年10月までに開発を完了しました。
チームは、8人の開発者、1人のプログラムマネージャー、1人のマネージャーで構成していました。

移行後は、Cosmos DBには140TBのデータが含まれ、毎秒最大15000回の読み取りと6000回の書き込みを処理しています。
利用状況を監視して、RU使用量を必要に応じてスケールアップさせて割当量を自動で増やしています。

初期設計

チームは、Azure Cosmos DBの利用経験はなかったのですが、開発スピードを上げるのは容易でした。
物理的なインフラストラクチャを気にしなくていい、SQL構文とChange Feedの両方が組み込まれたスキーマーフリーのドキュメントデータベースを提供している、SLAが提供されているなどから迅速に開発できました。

  • 地理的冗長性:北米、ヨーロッパ、アジア太平洋の3リージョンに1つずつ配置することで、1秒未満でレスポンスを返すというSkypeのSLAを満たしました。
  • 一貫性レベル:Cosmos DBが提供する5つの一貫性レベルからSession一貫性(読み込みは先祖返りしない、書き込み順序は保証される、書き込み処理したプロセスは書き込み後のデータが読める)を選択しました。
  • パーティショニング:パーティションキーとしてUserIDを選択。各ユーザーのすべてのデータが同じ物理パーティションに存在するようになりました。

Change Feedに基づくイベント駆動型アーキテクチャ

Azure Cosmos DB のChange Feedに基づくマイクロサービスのイベント駆動型アーキテクチャを実装しました。
通常、イベント駆動型アーキテクチャでは、Kafka、Event Hubなどのイベントソースを利用しますが、Cosmos DBはChange Feedを組み込みで提供しているためアーキテクチャをシンプルにできます。

監査履歴のために、状態取得によるイベントソーシングパターンを実装しました。
ドメインで現在の状態のデータを保存する代わりに、このデザインパターンでは、データに対するすべての操作を変更された状態とともに保存していきます。
トランザクションデータの一貫性を提供し、保管対応ができる完全な監査証跡と履歴を維持します。

性能最適化のために読み込みと書き込みのパスとデータモデルの分離

コマンドとクエリの責任分離パターン(CQRS)を使用しました。
書き込みと読み込みのパスとインターフェイスとデータモデルを分離しました。
イベントの保存がWriteモデルで、何が発生して変わったのか、何を意図するのか、だれが実行したのかを提供する情報源です。
これらすべては各変更毎に一つのJSONドキュメントに保存されます。
読み取りモデルは、マテリアライズビューで小さなJSONドキュメントで参照に最適化されています。

詳細は、イベントソーシングとCQRSを参照してください。

独自のChange Feed処理

Azure Functionを使用してChange Feedをの処理を扱う代わりに、開発チームは、Azure Cosmos DB change feed processor Libraryを使用して、独自にChange Feedを処理する実装を開発することを選択しました。
Azure Cosmos DB change feed processor Libraryは、Azure Functionの内部的に使用されるコードと同じです。
これを使用することで開発者は、Change Feed処理を細かく制御できます。
キューに対する再試行の実装、配信不能イベントのサポート、詳細な監視などが可能になります。
このアプリは、仮想マシンPaaS v1モデルで動作しています。

学んだ教訓

  • 性能向上のためにダイレクトモードを使用する
    クライアントがAzure Cosomos DBに接続する方法はデフォルトのゲートウェイ接続モードからダイレクトモードに切り替えました。
    クライアント側の待ち時間の短縮につながります。
  • ストアドプロシージャーの作成と処理方法を学ぶ
    トランザクションはストアドプロシージャーのみで対応しています。JavaScriptはデータベースと同じメモリスペースでホストされます。
  • クエリの設計に注意を払う
    クエリのはRUの消費という点で大きな影響を与えます。
    可能な限り読み取りポイントドキュメントを使用したり、API毎にクエリを最適化しました。
  • Azure Cosmos DB SDK 2.xを使用して接続を最適化する
    クライアントSDKがパーティションをホストしている物理ノードとの接続を確立する必要があります。
    Cosmos SDK 2.xで接続の多重化がサポートされ、SNATポートの枯渇問題の軽減に役立ちました。

利用事例

元記事:Connecting Global Azure Bootcampers with a cosmic chat app

2019年4月27日に世界同時に実施するGlobal Azure Bootcampが開催されました。
マイクロソフトは、そのイベント中に世界中のユーザーがコミュニケーションをとるための、世界規模のチャットサービスを新たに作成し提供しました。
そのチャットサービスを提供するのに使用されたのが、Azure Cosmos DBです。
この記事では、どのような構成で実現したのかを紹介します。

世界中の利用者が快適に利用できるようにするために、メッセージの取り込みと配信が素早く実施できるサービスを開発しました。

世界中にCosmos DBをレプリケーションさせ、ユーザーは、Azure Traffic Managerによって、一番近いエンドポイントにアクセスできるようにしました。

Azure Cosmos DB領域を表示する地図

メッセージの取り込み時間を最小にするために、Cosmos DBをマルチマスターモードで構成しました。
メッセージの配信の根幹部分には、Azure Cosmos DBのChnage Feedを使用しました。

チャットアプリがリアルタイムに新しいメッセージを表示できるようにするために、ポーリングではなくプッシュするようにしました。
Cosmos DBのChange Feedを受信して、Azure SignalRサービスが各クライアントにメッセージを配信するようにしました。

配信の地理的遅さを最小限にするために、各リージョンのローカルのChangeFeedを使用してメッセージを配信しました。

チャットボットの作成に使用されたAzureサービスとそれらがどのように対話するかを示す図

世界中に配信する部分は、Azure Cosmos DBが担ってくれるため、開発者は気にする必要がありません。
それでも次のことが実現できます。
・最も近いリージョンにメッセージを書き込みます。
・度のリージョンから書き込まれたメッセージであっても、ChangeFeedを通じてメッセージを受信できます。

これらを実現するのに必要だった開発日数は1日でした。

さらに、メッセージは誰でも書き込みができたので、Azure Globa Bootcampの雰囲気がネガティブなものにならないように、不適切なメッセージは取り除きました。
自動的に不適切なメッセージを取り除くために、Cognitive ServiceのContent Moderator APIによるコンテンツ検証を実施し、メッセージをチェックしました。
潜在的な冒涜や個人情報などをブロックし、前向きで安全な体験を提供しました。

利用事例

元記事:Quest powers Spotlight Cloud with Azure

Quest の Spotlight は、昔からSQL Serverの性能モニタリングとチューニングをする際に使用するととても便利なツールとして知られてきました。その製品をSpotlight Cloudとして、Azure SQL Databaseの性能モニタリングに特化したものに進化して提供されています。

Spotlight Cloudは、Azure Cosmos DBとAzure Functionsを利用して開発しています。
Spotlight Cloudとして必須要件は以下のようなものでした。

  • 収集した多くの様々な形式のデータをAzureベースのストレージに送信して保存できる。
    データは、SQL Server DMVやOSのパフォーマンスカウンター、SQLプラン、その他の便利な情報などが含まれます。
    収取するデータは、データによって、データフォーマットとサイズ(100バイト~数メガバイト)が多岐にわたります。
  • Spotlight Cloudを使用する顧客が増えるのに合わせて、拡張し続けられて、秒間1200操作を受け付けます。
  • SQL Serverの性能問題を素早く分析し診断するために、データの紹介と結果の取得を返します。

解決策

Diagram displaying data flow in Spotlight Cloud

この図は、Spotlight Cloudのコア部分のデータフローです。図示していませんが、Event Hub、Application Insights、Key Vault、DNSなども利用しています。
Spotlight Cloudのコア部分は、Azure FunctionsとCosomos DBで構築しました。
この技術選択は、高い拡張性と性能を提供してくれます。

拡張性

Ingestアプリは、秒間1000以上の顧客モニタリングデータを処理します。
これを実現するために、Azure Functionの従量課金プランで自動的に100VMまで自動スケールアップさせます。

Azure Cosmos DBはSLAで保障されたリクエスト単位/秒(RU/s)で計測されるデータベースとコンテナーのスループットが保証されます。
見積もりをするためにReadとWriteのスループットを計測して予測しました。

性能

Azure Cosmos DBは、60ミリ秒以下でQuestアプリケーションのReadとWrite処理をします。
これは素早くSQL Serverのデータを分析しリアルタイムに診断を提供するのに役立ちます。

高可用性

Azure Cosmos DBは、2リージョン以上使用している場合、99.999%の高い可用性SLAを提供します。
フェイルオーバーが必要になったとき、Azure Cosmos DBは自動的にフェイルオーバーし、継続性を提供します。

簡単な操作で世界分散ができ、自動的に非同期にリージョン間のデータ同期ができます。
スループットを最大限利用するため、Questでは、書き込み専用の1つのリージョンと読み取り専用の1つのリージョンを使用しています。
結果、ユーザーの読み取り性能時間は書き込み量に影響を受けなくなりました。

柔軟なスキーマー

スキーマーとサイズが自由なJSONデータを扱います。
SQL Server DMVやOS性能カウンターなど様々なデータ源から様々なデータを受け取れます。
これはスキーマー管理やスキーマー修正の必要性から解放されます。

開発生産性

Azure Functionは、開発プロセスをスムーズにしました。
Cosmos DBのクエリ言語も簡単に使うことができました。

Deployment Diagram of Spotlight Cloud’s Ingest and Egress app

データは、Traffic Managerによって、Ingest Appに提供されます。
Ingest AppはCosmos DBの書き込みリージョンに書き込みます。Traffic Manager経由で、Azure Cosmos DB Readリージョンからデータを読み込んだEngress Appからデータが提供されます。

Questの学び

Azure Cosmos DBを効率的に使う方法について、Questは深く学びました。

  • Azure Cosmos DBのプロビジョンニングスループットモデル(Ru/s)を理解する
    Questはそれぞれの操作でコストを計測しました。秒間何操作で、合計どれぐらいのAzure Cosmos DBのスループットが必要なのかを算出します。
    Azure Cosmos DBの費用は、ストレージとスループットに依存するので適切なRUSを選択する必要があります。
  • 適切なパーティション戦略を選ぶ
    パーティションキーを選択し、ストレージとリクエスト量が分散されるようにしました。
    これはとても重要です。Azure Cosmos DBはデータを水平分散し、プロビジョニングされた総RUをデータのパーティション間で均等に分散させます。
    開発段階で、いくつかのパーティションキーを試し、計測しました。
    もしアンバランスなパーティションキーを選択すると、余分にRU/sが必要になってしまいます。
    Questは、サーバーIDとデータ型を組み合わせた合成パーティションキーを選択しました。
    これにより高い基数が得られ、データの均等な分散を得ることができました。
    これは書き込みの多いワークロードには不可欠な対応です。
  • Questの多い書き込み量のため、インデックスのポリシーと書き込み時のRUコストを調整することは良い性能を得るのに重要です。
    インデックスポリシーを変更して、よく利用されるプロパティに明示的にインデックスを付け、残りを除外しました。
    よく利用されるプロパティをドキュメント本文に2,3個入れ、残りのデータを1つのプロパティに格納しました。
  • Questは書き込み量が多く、直近のデータがよく参照されるモデルです。
    データを複数のコンテナーに分割し、新しいコンテナーは高いRUで定期的に作成(毎週~数か月)し、書き込みを受け付けます。
    新しいコンテナーが容易で来たら、前のコンテナーはRUを縮小します。

CosmosDB

Azure Cosmos DB emulator は、開発目的でローカルで実行することができるエミュレーターです。
Azure Cosmos DB emulatorは、SQL、Casandra、MongoDB、Gremlin、TableのAPIに対応しています。

エミュレーターは、https://aka.ms/cosmosdb-emulator からダウンロードができます。
Dockerで起動も可能。

docker pull microsoft/azure-cosmosdb-emulator
md %LOCALAPPDATA%\CosmosDBEmulator\bind-mount docker run –name azure-cosmosdb-emulator –memory 2GB –mount “type=bind,source=%LOCALAPPDATA%\CosmosDBEmulator\bind-mount,destination=C:\CosmosDB.Emulator\bind-mount” –interactive –tty -p 8081:8081 -p 8900:8900 -p 8901:8901 -p 8902:8902 -p 10250:10250 -p 10251:10251 -p 10252:10252 -p 10253:10253 -p 10254:10254 -p 10255:10255 -p 10256:10256 -p 10350:10350 microsoft/azure-cosmosdb-emulator

エミュレーターを起動すると、Azure Cosmosデータエクスプローラーが表示され利用が可能になります。

image