Cosmos DBで読み取りリージョンへ明示的にルーティングする

Cosmos DBのセッションでよくみかける「世界地図をポチポチしてDBをグローバルに分散させるデモ」、いとも簡単にデータを世界に分散させられるように見えますよね。
はい、確かに”DB”はポチポチするだけで分散します。でも、アプリのトラフィックはポチポチしただけでは分散しないんです。

私はこのテーマで1ヶ月くらい検証したり、ドキュメントを漁ったり、いろんな人を捕まえたりしてモヤモヤしてましたが、ようやくとある筋から確証情報を得たので、記事にすることにしました。

目指すべき構成

Cosmos DBを複数のリージョンに分散させつつ、(AppService等の)クライアントから読み取りのトラフィックを分散させるには、一般的に以下のような構成にすると思います。

目指すべき構成

ポイントは、読み取りリージョンとなっているCosmos DBと同一のリージョンに、AppServiceをそれぞれ配置している点です。図でいうところの「読み取り-2」の矢印の流れを実現することが重要になります。

明示的な読み取りリージョンの指定が必要

このトラフィック構成は、Cosmos DBの地図をポチポチしただけでは実現できません(DBが各地域にレプリケーションされるだけです)。
しかもCosmos DB関連の各種情報によっては、近くの読み取りリージョンに自動的にルーティングしてくれるかのように読み取れる表現があったりなかったりしますが、そんなことはできないので忘れましょう。

では、ここからはDocmentDB API の.NET SDKを例に実現方法を説明します。
結論からいうと、読み取りリージョンの設定は、SDKのPreferredLocationsプロパティで明示的にリージョン名を指定します。具体的には以下のようなコードになります。

この例は、EastUS2にあるAppServiceからEastUS2のCosmos DB読み取りリージョンにトラフィックを向けています。これと同じ設定を各リージョンに配置したAppService毎に実装しておけば、各地域に分散配置したアプリが、近くの読み取りリージョンのCosmos DBにアクセスできるという構成ができます。

PreferredLocationsを動的に設定する

上記の例だと、例えばEastUSをWestUSに変更した時にコードを書きかえなくてはならないので、リージョン名はAppSetting等から与えるようにするのが良いかと思います。

また、その他のリージョンも増えたり減ったりする可能性があるので、以下のようなコードで、現在のDBアカウントで有効になっているリージョンのリストを取得してPreferredLocationsに動的に加える処理をいれておくのも有効だと思います。

DR目的だけなら、Cosmos DBをレプリケーションさせておくだけでも良いですが、Cosmos DBは2つ目以降のレプリカがせっかくアクティブな読み取りリージョンになってくれるので、読み取りトラフィックを分散した構成にしてレプリカDBのリソースを有効活用したいところです。

また、東日本と西日本のような同一国内での分散でも十分意味があると思いますので、プラネットスケールで分散させる必要がないドメスティックなシステムでも十分活用できる戦略ではないでしょうか。