WordPressのパフォーマンス問題は、サーバー環境が原因とされることが多く、実際にその診断が正しいケースも少なくありません。一方で、サードパーティ依存の要素も同じような問題を引き起こしますが、こちらはサーバー側で直接コントロールできない領域です。

例えば、タイムアウトする決済ゲートウェイ、応答しない配送API、動作の遅い分析スクリプトなどは、発生してしまうと被害を最小限に抑える対応しかできないタイプの障害です。とはいえ、こうした状況でもサイトの機能を維持できるかどうかは、サーバーインフラの質に加えて、依存サービスに障害が起きた際にアプリケーションレベルでどのような対策を講じているかにかかっています。

サードパーティの依存関係がWordPressの障害を連鎖させる理由

現代のWordPressサイトは、単体で完結して動作することはほぼありません。WooCommerceの決済処理だけを見ても、以下のようにさまざまな外部サービスに依存しています。

  • 決済ゲートウェイが支払い処理を担当
  • 配送APIがリアルタイムの送料計算を担当
  • 税務サービスが税計算やコンプライアンス対応を担当

サイトによっては分析ツール、CRM連携スクリプト、ライブチャットウィジェットなど、多数の外部サービスを読み込んでいます。

問題は、これらサービスのどれか1つでも遅延したり応答しなくなったりすると、その影響が単一の機能だけでは済まないことです。WordPressは外部APIからのレスポンスを待ちながらページ生成を行うため、処理中のPHPスレッドがブロックされ、影響がサイト全体へ波及していきます。

たとえば、決済ゲートウェイの応答が30秒後にタイムアウトすると、その間ずっと1つのスレッドが占有され続け、そのスレッドは他のリクエストを処理することができません。さらに、複数のユーザーが同時にその遅い決済処理に到達すると、複数のスレッドが次々と塞がれ、サイト全体のページ表示速度が低下していきます。共用サーバー環境では、こうしたスレッドを複数サイトで共有しているため、影響はさらに深刻になりやすくなります。

可視性のギャップ:内部要因と外部要因のパフォーマンス問題

そのため、同時に発生するタイムアウトが少数でも、共有プールを簡単に使い切ってしまいます。そうなると外部 APIへのリクエストがタイムアウトし、空きスレッドを待っている他の訪問者にも、502や504などのタイムアウト関連エラーが表示されます。

504エラーの厄介な点は、原因に関係なく同じように見えてしまうことです。こうしたエラーが発生すると、多くの場合、まず CPU 使用率やメモリ消費、インフラ関連の指標を確認します。しかし実際には、根本原因が外部サービス側にあるケースも少なくありません。それでも症状だけを見ると、あたかもサーバー環境に問題があるように見えてしまいます。

サードパーティ障害の影響を最小限に抑えるKinstaのコンテナ化アーキテクチャ

Kinstaでは、すべてのWordPressサイトを独立した隔離コンテナ内で稼働します。これにより、サードパーティサービスで障害が発生した際の影響範囲を限定することができます。

各コンテナには、専用のPHPスレッドプールが割り当てられており、同じプラットフォーム上の他サイトと共有されることはありません。そのため、PHPスレッドが枯渇しても影響はそのコンテナ内にとどまり、他のサイトへ波及することはありません。また、外部APIへのリクエストによってPHPスレッドがすべて使用中になった場合でも、受信リクエストは即座にエラーになるのではなく、NginxとPHP-FPM内部で処理待ちの状態になります。

実際には、共用サーバー環境(いわゆるレンタルサーバー)であれば、全サイトに影響を及ぼしかねない決済ゲートウェイ障害でも、Kinstaでは影響がそのサイトのコンテナ内に限定されます。コンテナ内のスレッドプールには負荷がかかるものの、同一インフラ上の他サイトには一切影響しません。

リクエストタイムアウトの制限により、無期限のブロックを防ぐ

適切に制御されていない場合、PHPスレッドは障害が発生した外部APIへの接続を長時間保持し続ける可能性があります。これに対処するため、Kinstaではmax_execution_timeをデフォルトで300秒に設定し、PHPスクリプトが実行可能な最大時間を制限しています。

さらにブラウザとサーバー間の接続を打ち切り、訪問者に504エラーを返すためのHTTPタイムアウトも別途存在し、Kinstaでは180秒に設定されています。

これらの制限によって、最悪のケースでも訪問者側から見た待機時間には明確な上限が設けられています。ただし、これらの制限だけでは、応答しなくなった外部API呼び出しを確実に停止できるわけではありません。Linux環境では、PHPの実行タイマーはストリーム操作の待機時間をカウントしないためです。

たとえば、決済ゲートウェイの応答待ちでブロックされているスレッドは、PHP側から見ると実行時間がほとんど消費されていないように見えます。そのため、300秒の制限も見た目ほど強力な保護にはなりません。

だからこそ、http_request_timeoutを利用してプラグイン側で明示的にタイムアウトを設定することが、アプリケーションレベルで外部サービスのハングアップを確実に終了させる最も有効な方法になります。

リクエストがタイムアウトすると、占有されていたスレッドは解放され、コンテナは通常数分以内に復旧プロセスへ入ります。

Kinsta APMでサーバーとサードパーティのボトルネックを切り分ける

KinstaのAPMツールは、PHPプロセス、MySQLクエリ、外部HTTPリクエストに関するタイムスタンプ付きデータを収集します。これにより、問題の原因がサーバー環境にあるのか、それともサードパーティ依存サービスにあるのかを可視化し、両者のパフォーマンスギャップを把握できます。

KinstaのAPMツール
KinstaのAPMツール

MyKinstaの「APM」画面でAPMを有効化し、2時間〜24時間から監視期間を選択します。Kinsta APMは追加のサーバーリソースを使用するため、問題が発生している場合、あるいは再現できる状況でのみ有効化するのが適切です。

APMを実行すると、「トランザクション」「WordPress」「データベース」「外部」の4つのタブにわたり、多数のチャート、グラフ、分析データが表示されます。特に「外部」タブは、ボトルネックがどこで発生しているのかを特定するうえで重要な手がかりになります。

Kinsta APMの外部画面の使い方

外部」タブでは、サイトが実行しているすべての外部HTTPリクエストを確認できます。これには、決済処理、送料計算、CRM連携、分析ツールなどのために、プラグインやテーマが実行するAPI呼び出しも含まれます。

各エントリには、合計実行時間、最大実行時間、平均実行時間、そして1分あたりのリクエスト数が表示されるため、どの外部サービスがパフォーマンス低下の原因になっているのかを把握可能です。

Kinsta APMの「外部」タブには外部からのHTTPリクエストが表示される
Kinsta APMの「外部」タブには外部からのHTTPリクエストが表示される

たとえば、決済APIが一覧の上位に表示され、最大応答時間が数秒単位になっている場合、それがパフォーマンス問題の原因である可能性が高いことを示しています。

トランザクションのトレース

外部」タブでリクエストURLをクリックすると、トランザクションサンプルの一覧が表示されます。そこから特定のサンプルを選択すると、トランザクショントレースのタイムラインが開き、実行中に発生したすべてのプロセスの詳細な内訳を確認できます。

総トランザクション時間の5%以上を消費しているスパンはオレンジ色で表示され、25%以上を消費しているスパンは赤色で表示されます。

KinstaのAPMツールのトランザクショントレースタイムライン
KinstaのAPMツールのトランザクショントレースタイムライン

トレースを確認することで、どの依存サービスを優先的に最適化または置き換えるべきかを判断できます。たとえば、決済APIへの外部HTTPリクエストが、5.5秒のトランザクション時間のうち5秒を占めていた場合、サーバーインフラ自体は残りの処理をわずか0.5秒で完了していたことになります。

問題が疑われる際にKinsta APMを使用する場合は、次のような流れで調査を進めることができます。

  • APMを有効化し、問題が発生している時間帯をカバーする監視期間を選択する
  • 問題が現在発生していない場合は、再現を試みる(またはAPMがライブデータを取得するのを待つ)
  • データが蓄積されたら「外部」タブを開き、対象の外部リクエストをクリックしてトランザクショントレースを確認し、各スパンの実行時間を調べる

もし外部HTTPリクエストが、トランザクション時間の大部分を占める状態で一覧の上位に表示されていれば、問題の原因を特定するために必要な情報は揃っています。

サードパーティ依存関係を管理するための運用戦略

隔離コンテナ技術によって外部障害の影響範囲は限定できますが、同時に重要なのが、外部サービスをどのように読み込み・呼び出すかです。どれだけ優れたサーバー環境を利用していても、サードパーティ依存関係はアプリケーションレベルで積極的に管理する必要があります。

重要ではないスクリプトを非同期で読み込む

WordPressは、デフォルトではスクリプトを同期的に読み込みます。つまり、<head>内のスクリプトは、ダウンロードと実行が完了するまでブラウザによるページ描画をブロックします。分析スクリプト、ヒートマップツール、マーケティングオートメーション系のコードでは、サードパーティサーバーが遅いだけでページ全体の表示が止まってしまう可能性があります。

ここで重要なのは、外部サーバーが遅延した場合に、同期読み込みと非同期読み込みで挙動が大きく異なる点です。

  • 同期(ブロッキング)読み込み:スクリプトのダウンロードと実行が完了するまで、HTML解析が停止。外部サーバーが遅ければ、その間ページ表示も止まる。
  • 非同期読み込み:スクリプトをバックグラウンドで読み込みながら、ブラウザはHTML解析とコンテンツ描画を継続。たとえ外部サーバーが遅くても、ページ自体は表示される。

WordPressでは、wp_enqueue_script()を使ってasyncdeferの両方を標準サポートしています。どちらも、重要ではないスクリプトによるレンダリングブロックを防ぐための仕組みですが、動作には違いがあります。

  • defer:スクリプトを順番通りに実行するため、依存関係のあるスクリプトに適している
  • async:読み込み完了後すぐに実行され、実行順序は保証されない

そのため、asyncは他スクリプトとの依存関係がない単独のトラッキングスクリプトに適しています。

add_action( 'wp_enqueue_scripts', function() {
    // Analytics — deferred so it doesn't block the critical path.
    wp_enqueue_script(
        'google-analytics',
        'https://www.googletagmanager.com/gtag/js?id=G-XXXXXXXX',
        [],
        null,
        [ 'strategy' => 'defer', 'in_footer' => false ]
    );

    // Marketing script — async because execution order doesn't matter.
    wp_enqueue_script(
        'hotjar',
        'https://static.hotjar.com/c/hotjar-XXXXXX.js',
        [],
        null,
        [ 'strategy' => 'async', 'in_footer' => false ]
    );
} );

しかし、決済のような重要な機能に関わるスクリプトは、分析タグやマーケティングスクリプトよりも慎重に読み込む必要があります。決済関連の統合では、決済処理を壊さないために、スクリプトを同期的に実行したり、厳密な実行順序を維持したりする必要がある場合もあります。

つまり、ページ全体に影響を与えずに失敗できる非クリティカルなスクリプトにはasyncdeferを適用し、ユーザーが取引を完了するために不可欠なスクリプトには適用しない、という考え方が重要です。

外部API呼び出しにタイムアウトを設定

Kinstaのデフォルトのmax_execution_timeは、複雑な処理にも対応できる十分な長さがありますが、ユーザーを待たせるには長すぎます。そのため、外部APIを利用するプラグインは、サーバーレベルの制限に頼るのではなく、独自にタイムアウトを設定するべきです。

WordPressでは、プラグインやフィルターによる上書きがない限り、外部HTTPリクエストのデフォルトタイムアウトは5秒に設定されています。さらに、特定サービスごとに異なる制限を設定したい場合は、http_request_timeoutフィルターを利用できます。このフィルターはリクエスト実行前に呼び出され、現在のタイムアウト値と対象URLの両方を受け取るため、サービスごとに個別のタイムアウトを設定できます。

add_filter( 'http_request_timeout', function( $timeout, $url ) {
    if ( str_contains( $url, 'api.example.com' ) ) {
        return 10; // Don't wait longer than 10 seconds.
    }
    return $timeout;
}, 10, 2 );

このような上限を設けることで、障害が発生したサービスにPHPスレッドを長時間占有されるのではなく、ユーザーに素早くエラーを返せるようになります。プラグインレベルのタイムアウトをサーバー側の上限よりも十分に短く設定しておけば、1つの遅いAPIが不必要に長い時間スレッドを消費するのを防げます。

ただし、タイムアウト値を長くしても、応答の遅い API 自体が改善されるわけではありません。むしろ、サービスは稼働しているものの高負荷によって応答が遅れている場合に、早期失敗を回避できるだけです。一般的には、短いタイムアウトで素早く失敗させ、その後フォールバック処理へ引き継ぐアプローチが適切です。

フォールバック機構とグレースフルデグラデーション

フォールバックは、外部サービスに障害が発生した際に、エラーを表示する代わりにサイトの機能を維持するための仕組みです。このパターンでは、WordPressのtransientsを使って成功したAPIレスポンスをキャッシュし、ライブ呼び出しが失敗した場合にはキャッシュ済みのデータを返します。

例えば、以下のようになります。

function get_shipping_rates_with_fallback( $package ) {
    $cache_key  = 'live_shipping_rates_' . md5( serialize( $package ) );
    $backup_key = 'backup_shipping_rates_' . md5( serialize( $package ) );
    // Return fresh cached rates if they're available.
    $cached = get_transient( $cache_key );
    if ( $cached !== false ) {
        return $cached;
    }
    // Attempt the live API call with a short timeout.
    $response = wp_remote_post( 'https://api.example.com/rates', [
        'timeout' => 8,
        'body'    => [
            'destination' => $package['destination'],
            'weight'      => $package['contents_weight'],
        ],
    ] );
    // On success: cache the result and update the longer-lived backup.
    if ( ! is_wp_error( $response ) && wp_remote_retrieve_response_code( $response ) === 200 ) {
        $rates = json_decode( wp_remote_retrieve_body( $response ), true );
        set_transient( $cache_key, $rates, HOUR_IN_SECONDS );
        set_transient( $backup_key, $rates, DAY_IN_SECONDS );
        return $rates;
    }

    // On failure: serve stale backup rates rather than an error.
    $backup = get_transient( $backup_key );
    if ( $backup !== false ) {
        return $backup;
    }
    // No cached data at all: return a flat-rate fallback.
    return [
        [ 'id' => 'fallback_flat', 'label' => 'Standard Shipping', 'cost' => 9.99 ],
    ];
}

1時間のtransientsは、不要なAPI呼び出しを減らすための通常キャッシュとして機能します。一方、24時間のtransientsは、ライブAPIが正常なレスポンスを返した場合にのみ更新されるため、サイトは直近で成功したレスポンスへフォールバックできます。たとえばAPIが停止した場合でも、サイトはエラーを表示する代わりに、前日に取得した送料データを表示できます。

グレースフルデグラデーションは、外部サービスが利用できない状況でも、サイトの中核機能を維持するための仕組みです。特に、障害の影響をコンテナ単位に隔離できるホスティングインフラと組み合わせることで効果を発揮し、1つの依存サービスの問題によって全体のリソースが消費される事態を防げます。

サーバーは外部障害からサイトを守る最後の砦

サードパーティサービスの障害は、外部依存を持つWordPressサイトでは避けられません。そうした依存関係に対してサイトがどれだけ耐性を持てるかが重要であり、それはサーバー環境の設計に大きく左右されます。

隔離コンテナ技術、専用PHPスレッドプール、組み込みのタイムアウト制御、そしてアプリケーション監視機能を備えたKinstaのようなインフラを利用することで、依存サービス側の問題とサーバー側の問題を明確に切り分けられるようになります。

Kinstaのインフラにご興味がありましたら、WordPress専用マネージドクラウドサーバーのプラン詳細をご覧ください。現在の構成や要件に関するお悩みがありましたら、お気軽にご相談ください

Joel Olawanle Kinsta

Kinstaでテクニカルエディターとして働くフロントエンド開発者。オープンソースをこよなく愛する講師でもあり、JavaScriptとそのフレームワークを中心に200件以上の技術記事を執筆している。