PHPのcurl_multi_*関数は通常、特に高い並行シナリオで複数の同時のHTTP要求を実行するために使用されます。 curl_multi_closeは、curl_multi_init()によって初期化されたすべての複数のCurlハンドルを閉じるために使用される関数です。多くのシナリオで非常に効果的ですが、同時性環境の高いパフォーマンスボトルネックになりますか?この記事では、 curl_multi_closeの作業原則を詳細に分析し、それがもたらす可能性のあるパフォーマンスの問題について議論し、関連する最適化の提案を提供します。
curl_multi_*一連の関数は、PHPが複数のHTTP要求を同時に処理できるようにするメカニズムを提供します。使用する一般的な手順は次のとおりです。
curl_multi_init() :複数のカールハンドルを初期化します。
curl_multi_add_handle() :複数のカールハンドルを複数のカールハンドルに追加します。
curl_multi_exec() :すべてのcurlリクエストを実行します。
curl_multi_getContent() :リクエストの応答コンテンツを取得します。
curl_multi_close() :複数のハンドルに追加されたすべてのカールハンドルを閉じます。
curl_multi_closeの機能は、すべてのCurlハンドルを閉じて、対応するリソースをリリースすることです。この関数は、すべての要求が完了し、関連するデータが取得された後に呼び出される必要があります。
ただし、特に数十万のリクエストを処理する場合、高い並行性環境では、 curl_multi_closeの実行はパフォーマンスボトルネックになる可能性があります。なぜ?もっと深く見てみましょう。
高い並行性環境では、 curl_multi_closeはすべてのCurlハンドルを1つずつ閉じる必要があります。これには、多数のメモリリリース操作が含まれる場合があります。各リクエストについて、Curlは一定のメモリを割り当てて接続情報を保存し、データを要求し、応答データを要求します。リクエストの数が非常に大きい場合、 curl_multi_closeはこれらのメモリリソースを1つずつリリースする必要があります。
Curlはオペレーティングシステムのネットワーク接続プールを使用するため、各Curl要求は実際にシステムの基礎となるネットワーク接続を介して実装されます。多数のリクエストが完了すると、 curl_multi_closeへの呼び出しにより、多数のネットワーク接続が閉じられます。これには、完了するまでに時間がかかります。要求ボリュームが非常に大きい場合、接続を閉じるプロセスが遅延を引き起こし、システムの応答時間に影響を与える可能性があります。
PHP自体はシングルスレッドですが、Curlは複数の同時リクエストを実行する際に、管理システムのスレッドに依存します。高い並行性シナリオでは、 curl_multi_exec()は複数のスレッドを起動して要求を処理しますが、 curl_multi_closeはすべてのハンドルを閉じる前にすべてのスレッドが終了するのを待つ必要があります。一部のリクエストが長時間応答すると、 curl_multi_closeがブロックされ、パフォーマンスの劣化が生じます。
curl_multi_closeがパフォーマンスのボトルネックになるのを避けるために、次の最適化測定値をとることができます。
あまりにも多くの同時リクエストを一度に開始しないようにし、リクエストプールに似たメカニズムを使用してバッチでリクエストを実行します。たとえば、PHPのcurl_multi_select関数を使用して、要求された同時数の最大数を制御できます。
$multiHandle = curl_multi_init();
$handles = [];
for ($i = 0; $i < 1000; $i++) {
$url = "https://gitbox.net/api/v1/data/{$i}";
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_multi_add_handle($multiHandle, $ch);
$handles[] = $ch;
}
$active = null;
do {
$mrc = curl_multi_exec($multiHandle, $active);
if ($active) {
curl_multi_select($multiHandle);
}
} while ($active && $mrc == CURLM_OK);
// すべてのハンドルを閉じます
foreach ($handles as $ch) {
curl_multi_remove_handle($multiHandle, $ch);
curl_close($ch);
}
curl_multi_close($multiHandle);
リクエストブロッキングが長すぎないようにするために、各リクエストに適切なタイムアウトを設定して、リクエストがゆっくりと応答した場合、時間内に閉じて他のリクエストを処理し続けることができます。適切なタイムアウト設定は、システムリソースの無駄を減らすことができます。
curl_setopt($ch, CURLOPT_TIMEOUT, 10); // リクエストタイムアウト時間をに設定します102番
同じドメイン名の多数の繰り返しリクエスト、永続的な接続と接続のプーリング手法を考慮することができるシナリオの場合。 Curlは、接続の多重化を防ぐためにcurlopt_forbid_reuseオプションを提供し、それにより複数の接続のオーバーヘッドが減少します。
curl_setopt($ch, CURLOPT_FORBID_REUSE, true); // 接続の再利用を無効にします
サーバーが多数の同時接続を処理できることを確認し、PHPの最大実行時間を増やし、オペレーティングシステムのファイルハンドル制限などを調整することにより、パフォーマンスを最適化できることを確認します。
高い並行性環境では、 CURL_MULTI_CLOSEは実際にパフォーマンスボトルネックになる可能性があります。特にリクエストの数が非常に多い場合、リソースのリリースと接続のシャットダウンのプロセスは、遅延とパフォーマンスの低下をもたらす可能性があります。ただし、並行性の数を合理的に制御することで、リクエストのタイムアウトを最適化する、接続プールなどを使用することにより、システムのパフォーマンスを大幅に改善し、 curl_multi_closeをボトルネックとして回避できます。