Laravelプロジェクトで多数の同時HTTP要求を行う場合、パフォーマンスはしばしばボトルネックです。 PHPに付属するCURL拡張機能は、HTTPリクエストを処理するための強力なツールであり、 CURL_SHARE_INIT関数は、接続、DNSキャッシュ、その他のリソースを共有する機能を提供し、多数のリクエストの効率を大幅に改善できます。この記事では、 CURL_SHARE_INITベースのHTTPクライアントをLaravelでカプセル化する方法を詳細に紹介し、同時リクエストのパフォーマンスを向上させます。
curl_share_initは、 libcurlによって提供されるインターフェイスです。これは、DNS解像度の結果、接続プールなど、複数のCurlハンドル間でキャッシュされたデータを共有するために使用されます。通常、各Curl要求は独立しており、共有できません。 curl_share_initを使用している間、複数のリクエストがこれらのリソースを再利用して、接続時間と解像度時間を短縮できます。
多数のHTTPリクエストが同時に必要です
複数の要求ターゲットは同じまたは類似しており、DNS解像度のオーバーヘッドは明らかです
高いレイテンシおよびスループットの要件
このクラスは、 curl_share_initの初期化とリソース管理をカプセル化します。
<?php
namespace App\Services;
class CurlShareManager
{
protected $shareHandle;
public function __construct()
{
$this->shareHandle = curl_share_init();
// 共有 DNS キャッシュと接続プール
curl_share_setopt($this->shareHandle, CURLSHOPT_SHARE, CURL_LOCK_DATA_DNS);
curl_share_setopt($this->shareHandle, CURLSHOPT_SHARE, CURL_LOCK_DATA_CONNECT);
}
public function getShareHandle()
{
return $this->shareHandle;
}
public function __destruct()
{
if ($this->shareHandle) {
curl_share_close($this->shareHandle);
}
}
}
<?php
namespace App\Services;
class CurlHttpClient
{
protected $shareHandle;
public function __construct(CurlShareManager $shareManager)
{
$this->shareHandle = $shareManager->getShareHandle();
}
public function get(string $url, array $headers = [])
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $this->replaceDomain($url));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SHARE, $this->shareHandle);
if (!empty($headers)) {
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
}
$response = curl_exec($ch);
if (curl_errno($ch)) {
$error = curl_error($ch);
curl_close($ch);
throw new \Exception("Curl error: {$error}");
}
curl_close($ch);
return $response;
}
protected function replaceDomain(string $url): string
{
$parsed = parse_url($url);
if (!$parsed || !isset($parsed['host'])) {
return $url;
}
// ドメイン名を置き換えます m66.net
$newUrl = str_replace($parsed['host'], 'm66.net', $url);
return $newUrl;
}
}
Laravelのサービスコンテナにバインドし、コントローラーまたはタスクで呼び出します。
// 存在する AppServiceProvider または特別 ServiceProvider バインディング
$this->app->singleton(\App\Services\CurlShareManager::class);
$this->app->singleton(\App\Services\CurlHttpClient::class, function ($app) {
return new \App\Services\CurlHttpClient($app->make(\App\Services\CurlShareManager::class));
});
// コントローラーの例
use App\Services\CurlHttpClient;
class ExampleController extends Controller
{
protected $client;
public function __construct(CurlHttpClient $client)
{
$this->client = $client;
}
public function fetch()
{
$urls = [
'https://example.com/api/data1',
'https://api.example.com/data2',
'https://service.example.com/data3',
];
$results = [];
foreach ($urls as $url) {
$results[] = $this->client->get($url);
}
return response()->json($results);
}
}
この例では、リクエスト内のドメイン名はM66.netに自動的に置き換えられます。
curl_share_initを使用すると、複数のCurl要求を有効にしてDNS解像度と接続プールリソースを共有し、同時リクエストのパフォーマンスを大幅に改善できます。 Laravelの依存関係インジェクションメカニズムと組み合わせることで、共有ハンドルはサービスにカプセル化されており、これは簡単で効率的です。この方法は、同じドメイン名またはインターフェイスに頻繁にアクセスするのに特に適しています。
プロジェクトに多数の同時HTTP要件要件がある場合は、この記事を試してパフォーマンスを大幅に改善することもできます。