3

ドメイン名や検索キーワードに関連するSEOデータにアクセスできるSEMrushAPIを使用する予定です。利用規約では、サーバーの強制終了を回避するために使用を制限しています。

1秒あたり10を超えるリクエストを実行することはできません。また、2つを超える同時リクエストを実行することもできません。

ドメイン名に基づいてデータを集約するシンプルなツールをPHPで構築し、その要件を満たす方法の基本を探しています。数百/数千の潜在的な同時ユーザーを計画しています。

誰かがPHPでこれを可能にする疑似コードを提供できるかもしれません-それとも、実際のAPIリクエスト関数を各コマンドの間に1秒間スリープさせるのと同じくらい簡単ですか?私はAPIと大量の同時ユーザーの経験があまりないので、助けていただければ幸いです。

4

2 に答える 2

2

PHPは、並行プログラミングに使用するのに最適な言語ではありません。ただし、目標の達成に役立つPHPと一緒に使用できるサードパーティのソリューションがいくつかあります。

必要なのは、実際の要求を処理できるジョブマネージャーまたはキューシステムです。これはバックエンドツールであるため(少なくとも私があなたの質問から集めたものです)、PHPがジョブ自体の実際の制御を処理する必要はありませんが、これらの個々のジョブを制御するプロセススケジュールを設定して、それらをあなたに渡します。これらの制限を効果的に課すことができるように、PHPスクリプト。

私の最初の提案は、 gearmanのようなものを試すことです。これは、優れたジョブマネージャーであり、ライブラリとのインターフェイスを支援するPHPの拡張機能を備えています。

もう1つの提案は、amqpzmqなどのキューシステムを調べることです。これらの一部には、PHPにも拡張機能があります

だからここにあなたのためのシナリオ例があります...

これらのリクエストを受け入れてジョブマネージャーに渡すか、ソケットを介してキューに入れるPHPスクリプトがあります。ジョブマネージャーまたはキューは、要求を保存し、これらの制限を課すために一元化および制御できる方法で、個々のワーカーに配布します。私があなたに与えたリンクから、あなたがそこにたどり着くのを助けることができるいくつかの例があります。ただし、これらのツールを使用せずに純粋にPHPで実行すると、非常に注意が必要であり、慎重に作成して検討しないと、非常にエッジケースのバグのある動作になってしまう可能性があります。

于 2012-12-10T23:56:33.280 に答える
1

一部のAPIは、応答ヘッダーでレート制限情報を返します。チェックアウト: HTTP APIレート制限HTTP応答ヘッダーの例 この情報は、PHPを使用して次のリクエストを続行する前に、数ナノ秒待つのに役立ちます。time_nanosleep()

一部のPHPライブラリは、レート制限の方法についてかなり詳細に説明しています。バケットトークンアルゴリズムは、Web全体でかなり一般的です: https ://github.com/bandwidth-throttle/token-bucket

X-RateLimit-Remainingリターンヘッダーに何かが含まれていないURLリクエストを制限することになると、これは少しやり過ぎだと思います。一般に、APIリクエストはかなり遅いです。そこで、以下のPHPスクリプトを作成しました。

このPHPスクリプトは、に基づいて数ミリ秒待機します$throttlerID。高いrequestsInSecondsほど待機時間が短くなります...$throttlerID同時リクエストで同じものが使用されている場合、各リクエストはファイルロック(FLOCK())を使用して他のリクエストを待機します。

    function Throttler($requestsInSeconds, $throttlerID) {

        // Use FLOCK() to create a system global lock (it's crash-safe:))
        $fp = fopen(sys_get_temp_dir()."/$throttlerID", "w+");

        // exclusive lock will blocking wait until obtained
        if (flock($fp, LOCK_EX)) { 

             // Sleep for a while (requestsInSeconds should be 1 or higher)
             $time_to_sleep = 999999999 / $requestsInSeconds; 
             time_nanosleep(0, $time_to_sleep);
    
             flock($fp, LOCK_UN); // unlock
         }

        fclose($fp);

    }

Throttler()各呼び出しの直前に呼び出しを置きCURLます。それでおしまい!

于 2021-05-11T19:39:12.270 に答える