今回の記事は、ShopifyDevs YouTubeチャンネルで公開した動画の補足記事になります。3回シリーズの1回目となるこの動画で、Shopify PlusのソリューションエンジニアであるZameer Masjedeeが、開発ストアのプライベートアプリをライブデモとして使用しながら、レート制限についてのベストプラクティスを解説します。Zameerはまず、レート制限の定義とそれがなぜ重要なのかを説明します。それから、Shopifyで使用されている「リーキーバケット」アルゴリズムに触れ、マーチャントとパートナーが得られるメリットについても話します。
はじめに:必要なツール
ツールの準備に関していうと、まず開発ストア(英語)が必要です。開発ストアはShopifyパートナーアカウントで無料で作れます。また開発ストアで使用するプライベートアプリも必要になります。これらについてはあとで設定しながら解説します。それとお気に入りのコードエディターをご用意ください。わたしはVS Codeを使用しますが、なんでも構いません。
動画とまったく同じように作業するなら,RubyとフレームワークのSinatraを使用することになります。とはいえ、お好みのプログラミング言語を自由にご使用ください。
このシリーズの最後には、実際にend-to-endのプライベートアプリをShopify上に作成して、APIコールとレート制限の対処法を試します。
このようなコンテンツに興味がありましたら、YouTubeのチャンネル登録を忘れずにお願いします。通知をオンにしていただければ、新しい動画がアップされたときに通知されます。
それでは、始めましょう!
こちらも参考にしてください:Shopifyアプリの開発方法
APIレート制限の概略
さて、そもそもAPIレート制限とは何でしょうか?
ドキュメントをチェックしてみましょう。
APIレート制限は、Shopifyがプラットフォームの安定性を確保するために使用している基礎的な方法です。わたしたちは、ウェブ標準であるRESTと新しくイノベーティブなGraphQLの両方で使える超フレキシブルなAPIを提供しています。もしレート制限がなかったら、事実上だれもがいつでも好きなだけAPIコールをおこなえます。
APIレート制限は、Shopifyがプラットフォームの安定性を確保するために使用している基礎的な方法です
価値的にはとても良いことのように思えます。なぜShopifyのデータ管理の面で、わざわざ制限をかける必要があるのでしょうか?
この思考プロセスの問題は、大規模な処理に対応できないことです。開発者がいつでもShopify APIにアクセスできて無制限のAPIリクエストを実行できるとなると、Shopifyサーバーに膨大な負荷が生じます。結果的に、ダウンタイムを引き起こしかねません。
ダウンタイムはサーバー全体に影響するため、マーチャントはストアにアクセスできず、あなたのアプリも機能しません。APIレート制限は、それぞれのアプリがプラットフォーム上でおこなうリクエストの数を管理する方法なのです。これがあることによって、APIコールを効率的におこなうことができ、APIコールに対するレスポンスを確実に得られることになります。
プラットフォーム全体におけるリクエストを安定したレベルに維持することで、サーバーの常時稼働と高速なレスポンスタイムが実現しています。
世界中の起業家に向けてビルドしよう
ブログにアップされる前にこのシリーズの動画をチェックしませんか? ShopifyDevs YouTubeチャンネルを登録して、開発のインスピレーションや役に立つヒント、実用的な重要ポイントを得てください。
購読する
さまざまなタイプのレート制限
それでは、具体的に見ていきましょう。まず何より重要なのは、APIレート制限にはさまざまな種類があるという点を理解しておくことです。
もっとも一般的なレート制限は、リクエストベースのものです。これはREST Admin API(英語)で使用されます。リクエストベースの制限では、レート制限は発生している個々のリクエスト数に関連します。
(画像)
APIごとのレート制限の比較
上記の比較表で確認できるように、スタンダードなShopifyプランの標準制限があり、一方でShopify Plusマーチャントの場合は数字が実質2倍になります。
今後ほとんどのケースにおいて、標準制限をベースに説明します。
REST admin API:リクエストベースのレート制限システム
ShopifyのREST admin APIを使用した場合、1秒で2つのリクエストが可能です。この制限は追跡が楽なので、全体でどれだけのリクエストを1分間で、1時間で、または1日で可能なのか把握しやすいといえます。
このアプローチによると、どんなリクエストをしているかは問題になりません。前回リクエストと同じ内容であれ、何かの更新または削除であれ、単なるデータ取得であれ、何をしても1秒で2つのリクエストです。
GraphQL admin API:ポイントベースのレート制限システム
GraphQLは、計算されたクエリコストと呼ばれているものを使用して、リクエストをネクストレベルに引き上げます。このアプローチでは、クエリとミューテーションによってデータの読み込みや更新が可能ですが、一番の違いとして、それぞれのリクエストの複雑な関連性が考慮される点が挙げられます。たとえばデータ更新であれば、データ取得と比べてリソースを多く消費します。
GraphQLのリクエストの場合、レート制限はポイントシステムになります。スタンダードプランでは、毎秒50ポイントが割り当てられます。ポイントの仕組みはとてもシンプルです。データの更新、作成、削除を要求するミューテーションは10ポイントのリクエストコストがかかります。一方でオブジェクトの取得は、1ポイントのみです。
GraphQLはここで興味深くなります。今回の動画ではあまり詳しく扱いませんが、GraphQL内でデータをネスト化できるのです。
1つの注文とさらにその注文におけるすべてのラインアイテムを要求するとしましょう。これは1ポイントでは済みません。10のラインアイテムがあるなら、それぞれ1ポイント、さらに注文自体も1ポイントなので、このリクエストは11ポイントのコストになります。
ざっくりとこのような仕組みであり、GraphQL APIの計算はかなり簡単です。
ほとんどのケースにおいて、GraphQLのほうが効率的です。何を使うべきか決めかねているなら、この理由だけでもGraphQLの使用をおすすめします(このシリーズでさらに別のいくつかの理由についても言及します)。
Shopifyマーチャント向けのアプリを構築する
Shopifyアプリストア向けのアプリ開発、カスタムアプリの開発サービス、ユーザーベースの成長促進、あなたが望むことがなんであれ、Shopifyパートナープログラムがその成功をサポートします。無料で登録して、教育リソース、開発者プレビュー環境、継続的な収益シェアプログラムを利用しましょう。
購読する
Storefront API:時間ベースのレート制限システム
最後のAPIレート制限メソッドは、Storefront API(英語)で使用される時間ベースの制限です。このアプローチはリクエスト数に基づくものではなく、リクエストとリクエストの間の時間に関わってきます。
これはヘッドレスの実装で使われるため、今回の記事では時間を割きませんが、違いを理解しておくことは大切かと思います。
リーキーバケットアルゴリズム
Shopifyのレート制限を理解するうえで次に重要になるピースが、リーキーバケットアルゴリズムです。
リーキーバケットについて考える場合、事前に決められた数のビー玉が入ったバケツを想像するのが一番良いでしょう。1秒に1個のビー玉がこぼれ落ちます。これはつまり、同じ割合で新しいビー玉を追加できるということです。バケツが一杯になったら、もうビー玉は追加できません。バケツの中にどれだけのビー玉を保持できるかは、いくつかの要因によって決まります。
スタンダードプランのREST Admin APIとShopify Plusのバケットサイズ
REST Admin APIを使用するスタンダードプランでは、ストアごと、アプリごとに40個のリクエストが可能なバケットサイズです。
ここでは以下のことが明示されています。もしあなたが公開アプリをもっていて、それが2つのストアにインストールされている場合、この2つのインストールに関連性や依存性はありません。それぞれが独立したレート制限をもっています。REST Admin APIの場合は、リクエスト数40のバケットサイズが割り当てられているので、あなたはプライベートアプリか公開アプリで40のリクエストをおこなう余裕があります。
もしあなたが公開アプリをもっていて、それが2つのストアにインストールされている場合、この2つのインストールに関連性や依存性はありません。それぞれが独立したレート制限をもっています
新しい商品を作成するとしましょう。前述したように、RESTの場合はすべて直接的です。それぞれのリクエストがレート制限において1とカウントされます。
そこで商品を作成し、ビー玉をバケツに入れます。2度目に何らかの作業、たとえばデータの更新や削除などをしようとするとき、また別のビー玉をバケツに入れることになります。
時間が経つにつれ、バケツは徐々に一杯になることがわかると思います。ビー玉を入れる余裕があるときしか、リクエストはできません。バケツが一杯のときにビー玉を入れようとすると、Shopifyは429エラーを返します。「リクエストが多すぎます」「レート制限に達しました」「リクエストを処理できません」というエラーです。少し待たなければいけません。
ここでリーキーモデルの登場となります。
40リクエストの入ったバケツがあっても、同時に、以前のリクエストが継続的に排出されていきます。
どういうことでしょうか?
1秒間に2個というリークレートによって、毎秒バケツの中に2つのビー玉あるいは2つのリクエストを入れるスペースができるのです。バケツには何かが入っていると仮定します。完全に空の状態、つまり直近1時間でリクエストが一切おこなわれていない場合などは、バケットサイズは40のままです。それ以上スペースが増えることはありません。
そこに何もなければ、リークさせることはできません。
たとえば1秒間で10のリクエストを実行すると、バケツの中の40分の10を埋めることになります。その1秒後に、そのうちの2がなくなります。ビー玉は8個になり、32個分の余裕ができます。つまり32のリクエストが可能になるのです。
なぜリーキーバケットアルゴリズムなのか?
このようにわかりやすいアプローチを実装した理由は、1秒間に2つのコールという標準のレート制限だけでは、大量のリクエストを扱う柔軟性が得られないからです。
あなたのアプリが次のように動いていると仮定してください。注文が入り、その注文に含まれる商品を毎回更新し、タグに保存されている値を加算します(おそらく全体でいくつの商品が売れたかを追跡するために)。
となると、各注文ごとにX個の関連商品の更新がおこなわれます。
注文が入るたびに、必要なリクエストが増えることは、すぐにわかりますね。
リーキーバケット方式なら、バケットサイズが40なので、20個のラインアイテムを含む注文が入ってくると、それぞれの商品に対する20の異なるリクエストが一度に可能です。
集中的な一連のリクエストを同時に処理できる能力が、アプリに柔軟性をもたらします
リークレートが毎秒2コールだとしても、20個のビー玉を入れてから1秒後には2個が放出されるので、18個だけが残り、バケツの中には余裕があります。集中的な一連のリクエストを同時に処理できる能力があなたのアプリにもたらす柔軟性について、少しずつわかってくると思います。
この方式を実装した理由がそこにあります。
GraphQLの場合も、ほとんど同じです。異なるサイズのバケットが与えられ、バケットサイズはさまざまです。
このケースでは、バケットに1,000コストポイントが与えられています。リークレートは毎秒50です。ミューテーションとオブジェクトは、やはりコスト面で異なります。
ミューテーションとクエリのコストについて、こちらのドキュメント(英語)にもっと多くの定義が載っています。
この情報は、GraphQLを使って一定時間内にどれだけのリクエストが可能なのかを理解するのに役立ちます。
レート制限についての概要の説明は以上です。わたしたちが使用しているさまざまな方法とリクエストのタイプを確認し、プラットフォームの安定性のためにリーキーバケットアルゴリズムが存在する理由を見てきました。
リーキーバケットアルゴリズム:考慮すべきデータ
最後にご紹介するのは、おもしろいデータです。わたしはデータが大好きなので。これはわたしたちのAPIのボリュームです。過去30日くらいのデータセットから任意に取り出した1日のデータになります。
1日のうちで、もっともポピュラーなRESTエンドポイント4つにおいて、どれだけのAPIリクエストのボリュームがあるかおわかりでしょうか。
Productsは1日で2億2,200万のAPIコールがあります。InventoryLevelsでは1億5,800万、Ordersは1億3,700万、メタフィールドは1億600万です。
Shopifyサーバーには凄まじい量のトラフィックが生じています。わたしたちがレート制限を実装しているのは、そうする責任があるからですし、またマーチャントとパートナーに対して最高レベルの安定性と稼働時間を提供しているということでもあります。
こうしたレート制限の中で、責任をもってアプリを作成されている開発者のみなさんに感謝します。このシリーズの次の記事では、レート制限のベストプラクティスをもう少し扱いたいと思います。
ShopifyDevs YouTubeチャンネルの次回の動画をお楽しみに。レート制限を重視したコードを実際に書く方法を見ていきます。
原文:Zameer Masjedee 翻訳:深津望