バックグラウンド
EchoNestにはレート制限されたAPIがあります。特定のアプリケーション(APIキーを使用するリクエストで識別される)は、1分間に最大120回のREST呼び出しを行うことができます。サービス応答には、直前に行われたコールの総数の見積もりが含まれます。APIを繰り返し乱用すると(制限を超えて)、APIキーが取り消される可能性があります。
単一のマシン(クライアントにサービスを提供するWebサーバー)から使用する場合、アクセスの制御は簡単です。サーバーは要求の履歴を完全に認識しており、サーバー自体を正しく調整できます。
しかし、私は分散した独立したクライアントが並行して要求を行うプログラムに取り組んでいます。
このような場合、最適なソリューションが何であるかははるかに明確ではありません。そして、一般に、問題は決定不可能であるように見えます。120を超えるクライアントが、すべて以前の履歴がなく、同時に最初の要求を行うと、レートを超えます。
しかし、これは個人的なプロジェクトであり、クライアントの使用は散発的(バースト的)であると予想され、私のプロジェクトはこれまで大成功を収めたことがないため、大きな問題になることはないと予想されます。より可能性の高い問題は、少数のクライアントができるだけ早く多くのリクエストを行いたい場合があることです(たとえば、クライアントは、例外的に、初めて起動するときに数千のリクエストを行う必要がある場合があります-可能です2つのクライアントはほぼ同時に起動するため、利用可能な帯域幅を共有するには協力する必要があります)。
上記のすべてを考えると、クライアントが適切にレート制限するための適切なアルゴリズムは何ですか?APIはすべてのクライアントについて、直前のリクエストの総数を返すため、 限定的な連携が可能であることに注意してください。
現在のソリューション
私の現在の解決策(質問が書かれたとき-より良いアプローチが答えとして与えられています)は非常に単純です。各クライアントには、最後の呼び出しが行われた時間と、その呼び出しでAPIによって報告された、最後の1分間に行われた呼び出しの数の記録があります。
呼び出し数が60(制限の半分)未満の場合、クライアントはスロットルしません。これにより、少数のリクエストの高速バーストが可能になります。
それ以外の場合(つまり、以前のリクエストがさらにある場合)、クライアントは(つまり)で作業する必要がある制限レートを計算しperiod = 60 / (120 - number of previous requests)
、前の呼び出しと現在の時間とのギャップがその期間(秒単位、60秒単位)を超えるまで待機します。 1分;1分あたり最大120リクエスト)。これにより、レートが効果的に抑制され、単独で動作している場合でも制限を超えないようになります。
しかし、上記には問題があります。注意深く検討すると、多数のリクエストに対して、単一のクライアントが振動し、最大スループットに達しないことがわかります(これは、「最初のバースト」が突然「ウィンドウの外に落ちる」ためであり、一部はアルゴリズムはその履歴を十分に活用していません)。そして、複数のクライアントがある程度協力するでしょうが、それが最適であるとは思えません。
より良いソリューション
クライアントの完全なローカル履歴を使用し、たとえば隠れマルコフモデルを使用して他のクライアントをモデル化するより良いソリューションを想像できます。したがって、各クライアントはAPIレポートを使用して、他の(不明な)クライアントをモデル化し、それに応じてレートを調整します。
また、単一のクライアントのアルゴリズムが、小さなバーストの無制限の動作から、振動を導入することなく多くの要求の最適で制限された動作に段階的に移行することも想像できます。
そのようなアプローチは存在しますか?誰かが実装やリファレンスを提供できますか?誰もがより良いヒューリスティックを考えることができますか?
これはどこかで既知の問題だと思います。どの分野で?待ち行列理論?
また、最適な解決策はなく、実際にうまく機能する伝承/伝統/受け入れられたヒューリスティックがあるかもしれないと推測します(前述のコメントを参照)。私は何を知りたいです...現在、私は既知のネットワークプロトコルで同様の問題を特定するのに苦労しています(もしそうなら、Perlmanはいくつかの美しい解決策を持っていると思います)。
また、コラボレーションを支援するために中央サーバーを必要とするソリューションにも興味があります(プログラムが普及した場合の将来の参照用に)。
免責事項
この質問は、EchoNestを批判することを意図したものではありません。彼らのサービスと使用条件は素晴らしいです。しかし、これをどのように使用するのが最善かを考えれば考えるほど、より複雑で興味深いものになります...
また、各クライアントには、呼び出しの繰り返しを回避するために使用されるローカルキャッシュがあります。