CData Software Blog

クラウド連携のCData Software の技術ブログです。

Dynamics 365・Dataverse(CDS) の API制限を確認してみる:CData Dynamics 365 / Dataverse Driver

f:id:sugimomoto:20210308222924p:plain

こんにちは。CData Software Japan リードエンジニアの杉本です。

今回は Dynamics 365・Dataverse(CDS)のWeb APIを扱うにあたって重要な API 制限について確認したいと思います。

ちなみに、Dynamics 365 ・Dataverse(CDS)では Web API(OData)とSOAPの2種類のAPIがありますが、今回の記事では前者のWeb API(OData)を対象としています。

docs.microsoft.com

Dynamics 365 FO や BCのAPIとは異なるので注意してください。

Dynamics 365・DataverseのAPI制限について

まず、基本的なAPI制限を確認しておきましょう。

Dynamics 365・DataverseのAPI制限は24時間制のAPI制限となっており、APIアクセスを行っているユーザーに紐付いたライセンスの種類によって、24時間以内のリクエスト数が変わります。

それぞれのライセンスごとのAPI要求数は以下の通り。

docs.microsoft.com

f:id:sugimomoto:20210308222141p:plain

※ 2021/03/08 時点の情報です

ライセンスを複数持っている場合は合算され、

例えば、Dynamics 365 プロフェッショナル(10,000)とPower Apps ユーザーごとのプラン(5,000)であれば、24時間以内のAPIリクエスト数は 15,000になるようです。

なお、ライセンスが紐付かないユーザーによるアクセス、例えばClientCredentialsを用いたアプリケーションユーザーによるアクセスの場合は、Office365(Microsoft 365)テナントごとに保持しているライセンスによって決定されます。

docs.microsoft.com

f:id:sugimomoto:20210308222149p:plain

ただ、こちらの上限は最上位のプランに左右されるようなので、Dynamics 365 Enterpriseを持っていれば、ほかのどのライセンスがあっても、最大24時間で100,000リクエストまでのようです。

API リクエストあたりのデータ処理量

併せて気になるのは、1回のAPIリクエストでどのくらいのデータを処理できるのか? ではないでしょうか。

まず、データの取得に関しては、特に明示的な指定が無い限り1APIリクエストで「5000」レコード取得することができます。

docs.microsoft.com

より小さなページサイズを指定しない限り、リクエストごとに最大5000個のエンティティが返されます。

データの書き込み、更新などの処理では、バッチリクエストを利用することができるので、このバッチリクエストの制限が1回でのリクエスト上限となります。

このバッチリクエストでは、最大「1000レコード」を同時に処理できるようでした。

docs.microsoft.com

バッチリクエストには、最大1000の個別のリクエストを含めることができ、他のバッチリクエストを含めることはできません。

つまり、10,000 APIリクエスト保持している状態であれば、理論上は「5千万レコードの取得」もしくは「1千万レコードの書き込み」が可能になります。とはいっても、単純な取得や書き込みをひたすら実施することは無いと思うので、あくまで目安として考えておきましょう。

API リクエスト状況の確認方法

現在のAPI Call数は Power Platform Admin centerの「Analytics」→「Dataverse」にある「API calls statistics」から確認できます。

ただ、ユーザーごとにAPI Limitが紐付いているはずなのに、ここではテナントごとのトータルリクエスト数しか見れません・・・。

f:id:sugimomoto:20210308222226p:plain

でも、上記以外にもAPIリクエストの消費状況を確認する方法があります。それは実際にAPIリクエストを行った際のレスポンスに含まれるヘッダー情報です。

docs.microsoft.com

ヘッダー名 値の説明
x-ms-ratelimit-burst-remaining-xrm-requests この接続の残りの要求の数
x-ms-ratelimit-time-remaining-xrm-requests 同じユーザー アカウントを使用するすべての接続の残りの合計期間

実際のHTTPレスポンスをキャプチャしたところ、以下のように値が含まれていました。

f:id:sugimomoto:20210308222250p:plain

この画像では「x-ms-ratelimit-burst-remaining-xrm-requests: 5413」となっており、APIリクエストを実行するごとに、値が減っていきました。

これを消費しつくすと、API 制限に抵触するようですね。

API 制限に抵触したらどうなるの?

そこで皆さん気になるのは、「x-ms-ratelimit-burst-remaining-xrm-requests」が無くなったら、つまりAPI制限に抵触したらどうなるの? ということだと思います。

というわけで、試しに CData Dynamics 365 for Sales Driver を使って、2万回 APIリクエストを投げてみました。

www.cdata.com

using System;
using System.Collections.Generic;
using System.Data;
using System.Data.CData.D365Sales;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Dynamics365APILimitTest
{
    class Program
    {
        static void Main(string[] args)
        {
            string connectionString = "InitiateOAuth=GETANDREFRESH;OrganizationUrl=https://XXXXX.crm7.dynamics.com/;";

            using (D365SalesConnection connection = new D365SalesConnection(connectionString))
            {
                for (int i = 0; i < 20000; i++)
                {
                    D365SalesDataAdapter dataAdapter = new D365SalesDataAdapter(
                    "SELECT accountid, Name FROM Accounts", connection);

                    DataTable table = new DataTable();
                    dataAdapter.Fill(table);

                    Console.WriteLine($"Count: {i}; {table.Rows[1]["accountid"]}");
                }
            }
        }
    }
}

すると結果は、、、

全然エラーにならない!!!

いやいや、どう考えてもおかしいでしょ? と思って、「x-ms-ratelimit-burst-remaining-xrm-requests」を確認してみたら、、、、4959?

f:id:sugimomoto:20210308225640p:plain

そんなに減ってない!?

開始時点で「x-ms-ratelimit-burst-remaining-xrm-requests」は5999(おそらく私の環境では6000がデフォルト値だったと思われる)だったんですね。

f:id:sugimomoto:20210308222335p:plain

というわけで、改めてドキュメントを色々と見てみたところ、以下のような文章を発見しました。

docs.microsoft.com

アプリケーション ユーザーが基本要求容量を超えると、統合が機能しなくなりますか?

現在、発生する可能性のある合理的な超過分については、統合を停止していません。 管理者は Power Platform 管理センターで使用状況を確認することができます (Dataverse では、一般的なレポート機能は 2020 年のリリース サイクル 2 に含まれています)。 ただし、現時点でユーザーやフローが一貫して長期間制限を超ている場合は、そのユーザーを無効にするか、フローをオフにすることができます。

移行期間が終了すると、テナントが Power Platform のリクエスト限度を超えた場合には、一部の操作がさらにブロックされます。 これらのブロック作業は、主に管理、カスタマイズ領域での作業となりますが、これらの作業に限定されるものではありません (また、超過シナリオによっては他の領域にも拡大する可能性があります)。

ここには「現在、発生する可能性のある合理的な超過分については、統合を停止していません。」と書かれています。つまり、現状は合理的な範囲(?)であれば、API Limitを超過しても、特にエラーにはならないようでした。

並列処理を実施して、無理やり引き起こそうかなとも思ったんですが、あんまりやりすぎるのも忍びないので、今回の検証はここまでにしました。

CData Dynamics 365 / Dataverse Driver はどのように APIリクエストを行っているのか?

続いて CData Dynamics 365 / Dataverse Driver についても解説していきましょう。

まず、誤解の無いように予めお伝えしておきたいのですが CData DriverはDynamics 365 / Dataverse のRDBSQL server)に接続しているわけではありません

何かMicrosoft 側と裏口工作とかを行って、秘密裏にデータを取得しているとか、そういうわけではなく、Dynamics 365 / Dataverse のAPIを活用して、CData Driverのエクスペリエンスを実現しています。前述のAPI制限の検証例からもわかるかと思います。

現在、Dynamics 365 ・Dataverseでは、SQL ServerTDSプロトコル)のエンドポイントを使うことができますが、これともまた違ったアプローチになっています。

docs.microsoft.com

そのため、CData Dynamics 365 / Dataverse Driverを使うと、上記で紹介した API リクエスト数を消費してデータの疎通を行います。

それらを踏まえた上で実際にCData Driverがとのように、Dynamics 365 / Dataverse API に対してリクエストを行い、API 制限を消費しているのか? を解説していきます。

www.cdata.com

f:id:sugimomoto:20210308222433p:plain

www.cdata.com

f:id:sugimomoto:20210308222440p:plain

CData Driverのリクエストの内容はログからも確認できますが、今回はHTTPキャプチャ・プロキシツールのFiddlerを利用して、見てみました。

www.cdatablog.jp

それでは例をあげて、リクエストを見てみましょう。

例えば、CData Driverに対して「SELECT accountid, Name FROM Accounts」を発行した場合です。

これで取引先企業のデータを取得できるのですが、Fiddlerを確認してみると、以下のように3つのリクエストが飛んでいることがわかります。

f:id:sugimomoto:20210308222525p:plain

「sugimomoto45.crm7.dynamics.com」のHostに対してのリクエストが今回のAPIリクエスト制限を消費するものです。Host名は皆さんの環境に併せて置き換わります。

おそらくこの記事をご覧になられている方は「1APIリクエストで済むのではないか」 とイメージされているのではないかと思いますが、実はそうではありません。

このリクエストを一つづつ紐解いてみましょう。

まず、以下の「GET https://sugimomoto45.crm7.dynamics.com/api/data/v9.0/ 」というリクエストです。これは、Dynamics 365 の環境の疎通・存在確認を行っています。

f:id:sugimomoto:20210308222538p:plain

次に「GET https://sugimomoto45.crm7.dynamics.com/api/data/v9.0/$metadata 」というリクエストです。

これは、Dynamics 365 のMetadataの取得を行っています。CData Driverはその特性上、Dynamics 365 ・Dataverseでどのようなエンティティ・項目を保持しているかを事前に確認する必要があります。そのため、このようなリクエストを最初に行い、データ定義を取得しています。

f:id:sugimomoto:20210308222544p:plain

最後に「GET https://sugimomoto45.crm7.dynamics.com/api/data/v9.0/accounts?$select=accountid%2cname 」というリクエストです。これで実際に取引先企業のデータを取得しています。レスポンスのJSONが確認できますね。

f:id:sugimomoto:20210308222551p:plain

いかがでしょうか。このように、CData Driverでは、1SQL=1APIリクエストという図式で成り立っているわけではありません。

なお、ここで取得していたテーブル構造やカラム構造は内部的にキャッシュされるため、SELECTクエリ発行の度に取得し直すわけではありません。

また、もし1回のAPIリクエストで取得しきれないデータがある場合は、自動的にページネーションなどの処理を行って、複数回APIリクエストを実施し、データを取得するケースもあります。

「CData DriverはどのくらいAPIリクエストを消費するのか?」という質問は良く頂くのですが、上記のように様々な係数およびユースケースがあるため、一概に答えることができないものとなっています。

API Limitに抵触しないようにするにはどうしたらいいの?

最後に、これもまたよく頂く質問「API Limitに抵触しないようにするにはどうしたらいいの?」についても、回答したいと思います。

単刀直入に言ってしまえば、抵触しないようにするためのアプローチとして、単純な解決策はありません。

そのため、現在想定しているユースケースでどのくらいAPI Limitを消費するのか? を最初に見極める必要があります。

まずは自身のユースケースに合わせたAPIリクエストを実行してみて、管理画面にてどのくらいAPIリクエストを消費しているのか、是非確認してみてください。

f:id:sugimomoto:20210308222624p:plain

その上で、例えばデータの書き込みが多数の割合を締めているような場合であれば、Bulk Insertなどの一括処理を行うことが可能です。

cdn.cdata.com

また、同じテーブルに何度もアクセスしてデータを取得し集計などを実施している、といったユースケースであれば、CData Driverのキャッシュ機能を利用したり

cdn.cdata.com

CDataSyncという製品を利用して、RDBやDWHに一度データをロードしてしまう、といったアプローチも有効です。

www.cdata.com

このように単純にこれを実施すれば良い、という対策はありませんが、CData Driverが標準で備えている機能を活用することで、各ユースケースごとにフィットしたクエリ方法を探ることが可能です。

もし、こういったユースケースで、APIリクエスト数を緩和したい、何か良い方法はないか? といった悩み事があれば、お気軽にテクニカルサポートまで連絡ください。

CData Software Japan - サポートフォーム