SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

DeveloperZine(デベロッパージン)- エンジニアの意思決定を支える技術情報メディア ProductZine

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

Microsoft AzureのNoSQLデータベース「Cosmos DB」を使ってみよう

Microsoft AzureのNoSQLデータベース「Cosmos DB」における運用時の考慮ポイントを知る

Microsoft AzureのNoSQLデータベース「Cosmos DB」を使ってみよう 第5回

可用性に関する検討事項

 PaaSであるCosmos DBではSLAによって可用性が担保されていますが、アプリケーション全体としての可用性を高めるためにも検討すべき項目があります。

リトライ処理を組み込む

 Cosmos DBのDocumentDB APIでは、コレクションに設定したRUを超える操作を行うと、スループットを平坦化するためにリクエストを処理せずにHTTPレスポンスコード429(RequestRateTooLarge)を返します。Cosmos DBのSDKを使用している場合は、HTTPレスポンスコード429でレスポンスを受けると暗黙的にリトライを実行してくれます。SDKによる暗黙的なリトライを数回行っても操作が終了しなかった場合は例外(DocumentClientException)を返します。そのためクライアント側では、例外とHTTPレスポンスコードをハンドリングし、失敗したリクエストをリトライするように実装することで、一時的な高負荷によるドキュメント操作の失敗を軽減することができます。

 以下のコードは、SDKによる暗黙的なリトライでも操作が終了しなかった場合に、さらにリトライを実行するクライアントコードのサンプルです。

リスト1 リトライ処理を組み込んだDocumentDB API呼び出しメソッド
protected static async Task<T> ExecuteWithRetries<T>(Func<Task<T>> function)
{
    var sleepTime = TimeSpan.Zero;

    while (true)
    {
        try
        {
            // Cosmos DBに対する操作を実行する(DocumentDB APIの呼び出し)
            return await function();
        }
        catch (DocumentClientException e)
        {
            // HTTPレスポンススコードが429であればリトライする
            if ((int) e.StatusCode == 429)
            {
                // DocumentClientExceptionに含まれるリトライまでの待機時間を取得する
                sleepTime = e.RetryAfter;
            }
            else
            {
                // HTTPレスポンスコードが429以外であればスローする
                throw;
            }
        }
        catch (AggregateException e)
        {
            // AggregateExceptionの内部例外にDocumentClientExceptionが含まれているか調べる
            if (e.InnerException is DocumentClientException)
            {
                var de = (DocumentClientException) e.InnerException;

                if ((int) de.StatusCode == 429)
                {
                    // DocumentClientExceptionに含まれるリトライまでの待機時間を取得する
                    sleepTime = e.RetryAfter;
                }
                else
                {
                    // HTTPレスポンスコードが429以外であればスローする
                    throw de;
                }
            }
            else
            {
                // DocumentClientException以外の例外の場合はスローする
                throw e;
            }
        }

        // スリープ後にリトライする
        await Task.Delay(sleepTime);
    }
}

 このメソッドでは、引数で受け取った何らかのDocumentDB APIの処理を実行し、例外とHTTPレスポンスコードの種類によってリトライの要否を決定しています。リトライが必要な場合は、リトライまでの待機時間が例外のプロパティ(RetryAfter)に含まれているのでそれを使って待機し、もう一度処理を実行するようにしています。

 以下のコードは、リスト1のメソッドでラップしたアップサート処理の例です。

リスト2 リトライ処理を追加したアップサートの例(UpsertDocumentAsyncメソッド)
public static async Task UpsertDocumentAsync(T document)
{
    try
    {
        // ドキュメントのアップサート処理をリトライ可能にする
        await ExecuteWithRetries(() => client.UpsertDocumentAsync(
            UriFactory.CreateDocumentCollectionUri(DatabaseId, CollectionId), document));
    }
    catch (Exception)
    {
        throw;
    }
}

スケールアップ/ダウン

 Cosmos DBはRUをダウンタイムなしでスケールアップ/ダウンすることができます。スケールは、Azureポータル画面かSDKを使用して設定します。Azureポータル画面でのスケールは、手動での即時スケールのみに対応しており、スケジュールやしきい値をトリガーとした、細やかなスケールの設定はできません。

 現時点ではCosmos DBにオートスケールの機能がありませんが、他のAzureサービスと組み合わせてスケジュールやしきい値ベースのオートスケールを実現できます。

 スケジュールベースの場合は、Azure WebJobsやAzure Functionsなどのスケジューラー機能を持ったサービスを使います。Azure WebJobsやAzure Functionsをタイマー起動で実行するように指定し、その中でCosmos DBのSDKのスループット変更APIを呼び出します。

 しきい値ベースの場合は、Cosmos DBの「アラートルール」とSDKのスループット変更APIを組み合わせます。「アラートルール」は時間あたりのリクエスト数やRU消費量をしきい値に、アラートを発報させることができます。アラートの通知先としてWebhookが指定可能なため、スケールアップ/ダウンを行うAPIを用意し、そこへWebhookを設定することでスケールアップ/ダウンをコントロールします。

 以下のコードは、引数で指定したRU/sにスループットを変更するコードの例です。

リスト3 Cosmos DBのスケールアップ/ダウンをDocumentDB APIから行う例
public static async Task ReplaseRequestUnitsAsync(int desiredRequestUnits)
{
    // (1)コレクションのインスタンスを取得する
    var collection = client.ReadDocumentCollectionAsync(
        UriFactory.CreateDocumentCollectionUri(DatabaseId, CollectionId)).Result.Resource;

    // (2)コレクションの現在のRU/s情報を保持するインスタンスを取得する
    var offer = client.CreateOfferQuery()
        .Where(r => r.ResourceLink == collection.SelfLink)
        .AsEnumerable()
        .SingleOrDefault();

    // (3)新しいRU/sの値でインスタンスを置き換える
    offer = new OfferV2(offer, desiredRequestUnits);

    // (4)DocumentDB APIのスループット変更APIを呼び出す
    await client.ReplaceOfferAsync(offer);
}

 (2)でデータベースアカウントの中からスループットを変更したいコレクションを検索するために、(1)であらかじめコレクションのインスタンスを取得しています。(2)ではコレクションに割り当てられている現在のRU/sを保持するOfferインスタンスを取得し、(3)で新しいRU/sに置き換えます。最後に(4)でDocumentDB APIのメソッドを呼び出すことで、コレクションのスループット変更がCosmos DBに反映されます。

ストレージの拡張

 Cosmos DBのストレージには固定と無制限のプランがあります。固定の場合は最大10GBまでのストレージ上限があり、それ以上の容量に拡張することができません。固定プランを利用する場合は、事前にアプリケーションのデータサイズの見積もりをして10GBを上回ることがないかをよく確認することをお薦めします。

 また、無制限プランで10TB以上の容量を必要とする場合は、Azureサポートに容量引き上げリクエストを送る必要があります。

 現在コレクションがどの程度ストレージを使用しているかは、Azureポータル上でCosmos DBの概要メニューから簡単に確認することができます。

図4 Cosmos DBのストレージ使用量の例
図4 Cosmos DBのストレージ使用量の例

 より詳しい、コレクションのストレージ使用量の情報は「メトリック」画面の「ストレージ」タブから確認できます。

 ドキュメントとインデックス別のストレージ使用量や各パーティション別のストレージ使用量・ドキュメント数をこの画面で見ることができます。

図5 メトリック画面のストレージタブでストレージ使用量を確認する例
図5 メトリック画面のストレージタブでストレージ使用量を確認する例

バックアップ

 Cosmos DBは、以下の要件で全てのデータをバックアップします。

  • 全てのデータを4時間ごとに自動的に取得
  • 最新のスナップショットは90日間保持される
  • 8時間以内であればAzureサポートへの問い合わせでデータの復元が可能
  • バックアップはAzureの別ストレージサービス(Azure Blob Storage)に自動で保存され、その中でもレプリケートされる
  • RUの消費やパフォーマンスに影響を与えない

 さらに対象外性を高めるために、データを地理的に離れた別リージョンにレプリケートすることもできます。詳細はCosmos DBのグローバル分散に関するドキュメントをご確認してください。

次のページ
セキュリティに関する検討事項

この記事は参考になりましたか?

Microsoft AzureのNoSQLデータベース「Cosmos DB」を使ってみよう連載記事一覧

もっと読む

この記事の著者

WINGSプロジェクト 秋葉 龍一(アキバ リュウイチ)

WINGSプロジェクトについて>有限会社 WINGSプロジェクトが運営する、テクニカル執筆コミュニティ(代表 山田祥寛)。主にWeb開発分野の書籍/記事執筆、翻訳、講演等を幅広く手がける。 2026年時点での登録メンバは約50名で、現在も執筆メンバを募集中。興味のある方は、どしどし応募頂きたい。著書記事多数。 RSS X: @WingsPro_info(公式)、@WingsPro_info/wings(メンバーリスト) Facebook

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

山田 祥寛(ヤマダ ヨシヒロ)

静岡県榛原町生まれ。一橋大学経済学部卒業後、NECにてシステム企画業務に携わるが、2003年4月に念願かなってフリーライターに転身。Microsoft MVP for Visual Studio and Development Technologies。執筆コミュニティ「WINGSプロジェクト」代表。主な著書に「独習シリーズ(Java・C#・Python・PHP・Ruby・JSP&サーブレットなど)」「速習シリーズ(ASP.NET Core・Vue.js・React・TypeScript・ECMAScript、Laravelなど)」「改訂3版JavaScript本格入門」「これからはじめるLaravel実践入門」「はじめてのAndroidアプリ開発 Kotlin編 」他、著書多数

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

CodeZine(コードジン)
https://codezine.jp/article/detail/10469 2017/10/26 14:00

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー