GraphQL Application Server

Commerce GraphQL Application Serverを使用すると、Adobe CommerceはCommerce GraphQL API リクエスト間のステートを維持できます。 Swoole拡張機能で構築されているGraphQL Application Serverは、リクエスト処理を処理するワーカースレッドを持つプロセスとして動作します。 GraphQL API リクエスト間でブートストラップされたアプリケーションのステートを保持することで、GraphQL Application Serverはリクエスト処理と全体的な製品パフォーマンスを向上させます。 API リクエストが大幅に効率化されます。

GraphQL Application Serverは、Adobe Commerceでのみ使用できます。 Magento Open Sourceでは使用できません。 Cloud Pro プロジェクトの場合、GraphQL Application Serverを有効にするには、Adobe Commerce サポート ​ チケットを送信する必要があります。

NOTE
GraphQL Application Serverは現在Amazon Simple Storage Service (AWS S3)と互換性がありません。 ​ リモートストレージ ​でAWS S3を現在使用しているクラウドインフラストラクチャ上のAdobe Commerceのお客様は、GraphQL Application Serverを使用できません。

デザイン

GraphQL Application Serverは、Commerce GraphQL API リクエスト間のステートを維持し、ブートストラップを不要にします。 プロセス全体でアプリケーションの状態を共有することで、GraphQLリクエストの効率が大幅に向上し、応答時間が最大30%短縮されました。

共有なしPHP実行モデルは、各リクエストにフレームワークのブートストラップが必要なため、レイテンシの観点から課題を提供します。 このブートストラッププロセスには、設定の読み取り、ブートストラッププロセスの設定、サービスクラスオブジェクトの作成など、時間のかかるタスクが含まれます。

リクエスト処理ロジックをアプリケーションレベルのイベントループに移行すると、エンタープライズレベルでリクエスト処理を合理化するという課題に対処するようです。 このアプローチにより、リクエスト実行ライフサイクル中にブートストラップを実行する必要がなくなります。

利点

GraphQL Application Serverを使用すると、Adobe Commerceは連続したCommerce GraphQL API リクエスト間のステートを維持できます。 リクエスト間でアプリケーションの状態を共有することで、処理のオーバーヘッドを最小限に抑え、リクエスト処理を最適化することで、API リクエストの効率を高めます。 その結果、GraphQLのリクエストへの対応時間を最大30%短縮できます。

必要システム構成

GraphQL Application Serverを実行するには、次の操作が必要です。

  • Commerce バージョン 2.4.7以降
  • PHP 8.2以降
  • 予想される負荷に基づく適切なRAMとCPU
  • Swoole PHP拡張機能v5+(以下のプロジェクト固有の要件を参照)

クラウドプロジェクト

Adobe Commerce オンクラウドインフラストラクチャプロジェクトには、デフォルトでSwoole拡張機能が含まれています。 .magento.app.yaml ファイルのruntime プロパティで有効にすることができます。 例:

runtime:
    extensions:
        - swoole

オンプレミスプロジェクト

オンプレミス プロジェクトのSwoole PHP拡張機能を手動で​ インストールして設定する必要があります。

クラウドインフラストラクチャの有効化とデプロイ

ApplicationServer モジュール (Magento/ApplicationServer/)は、GraphQL Application Serverを有効にします。

Pro プロジェクトを有効にする

NOTE
Application Serverは、Cloud Pro インスタンスのオプトイン機能です。 これを有効にするには、サポートリクエストを送信します。

Pro プロジェクトでApplication Server機能を有効にした後、GraphQL Application Serverをデプロイする前に次の手順を実行します。

  1. 2.4.7-appserver ブランチ ​のクラウドテンプレートを使用して、Adobe Commerceをクラウドインフラストラクチャにデプロイします。

  2. すべてのCommerce カスタマイズと拡張機能がGraphQL Application Serverと互換性があることを確認してください。

  3. Commerce Cloud プロジェクトを複製します。

  4. 必要に応じて、「application-server/nginx.conf.sample」ファイルの設定を調整します。

  5. project_root/.magento.app.yaml ファイル内のアクティブな「web」セクションを完全にコメントします。

  6. GraphQL Application Server start コマンドを含むproject_root/.magento.app.yaml ファイルで、次の「web」セクション設定のコメントを解除します。

    code language-yaml
    web:
        upstream:
            socket_family: tcp
            protocol: http
        commands:
            start: ./application-server/start.sh > var/log/application-server-status.log 2>&1
    
  7. 次のコマンドを実行して、/application-server/start.shが実行可能であることを確認します。

    code language-shell
    chmod +x application-server/start.sh
    
  8. 次のコマンドを使用して、更新されたファイルをGit インデックスに追加します。

    code language-shell
    git add -f .magento.app.yaml application-server/*
    
  9. 次のコマンドで変更をコミットします。

    code language-shell
    git commit -m "AppServer Enabled"
    

Pro プロジェクトのデプロイ

イネーブルメント手順が完了したら、Git リポジトリに変更をプッシュして、GraphQL Application Serverをデプロイします。

git push

スタータープロジェクトの有効化

スタータープロジェクトにGraphQL Application Serverをデプロイする前に、次の手順を実行します。

  1. 2.4.7-appserver ブランチ ​のクラウドテンプレートを使用して、Adobe Commerceをクラウドインフラストラクチャにデプロイします。

  2. Commerceのすべてのカスタマイズと拡張機能がGraphQL Application Serverと互換性があることを確認します。

  3. インスタンスにCRYPT_KEY環境変数が設定されていることを確認します。 この変数のステータスは、Cloud Consoleで確認できます。

  4. Commerce Cloud プロジェクトを複製します。

  5. application-server/.magento/.magento.app.yaml.sampleの名前をapplication-server/.magento/.magento.app.yamlに変更し、必要に応じて.magento.app.yamlの設定を調整します。

  6. /graphql トラフィックをGraphQL Application Serverにリダイレクトするには、project_root/.magento/routes.yaml ファイルで次のルートの設定のコメントを解除します。

    code language-yaml
    "http://{all}/graphql":
        type: upstream
        upstream: "application-server:http"
    
  7. .magento/services.yaml ファイルのfiles セクションのコメントを解除します。

    code language-yaml
    files:
        type: network-storage:2.0
        disk: 5120
    
  8. .magento.app.yaml ファイルのマウント設定のTEMPORARY SHARED MOUNTS部分のコメントを解除します。

    code language-yaml
    "var_shared":
        source: "service"
        service: "files"
        source_path: "var"
    "app/etc_shared":
        source: "service"
        service: "files"
        source_path: "etc"
    "pub/media_shared":
        source: "service"
        service: "files"
        source_path: "media"
    "pub/static_shared":
        source: "service"
        service: "files"
        source_path: "static"
    
  9. 更新されたファイルをGit インデックスに追加します。

    code language-shell
    git add -f .magento.app.yaml .magento/routes.yaml .magento/services.yaml application-server/.magento/*
    
  10. 変更を確定し、デプロイメントのトリガーにプッシュします。

    code language-shell
    git commit -m "Enabling AppServer: initial changes"
    git push
    
  11. SSHを使用してリモートクラウド環境にログインします(application-server アプリの​not)。

    code language-shell
    magento-cloud ssh -p <project-ID> -e <environment-ID>
    
  12. ローカルマウントから共有マウントにデータを同期します。

    code language-shell
    rsync -avz var/* var_shared/
    rsync -avz app/etc/* app/etc_shared/
    rsync -avz pub/media/* pub/media_shared/
    rsync -avz pub/static/* pub/static_shared/
    
  13. DEFAULT MOUNTSとマウント設定のTEMPORARY SHARED MOUNTS部分を.magento.app.yaml ファイルにコメントアウトします。

    code language-yaml
    #"var": "shared:files/var"
    #"app/etc": "shared:files/etc"
    #"pub/media": "shared:files/media"
    #"pub/static": "shared:files/static"
    
    #"var_shared":
    #    source: "service"
    #    service: "files"
    #    source_path: "var"
    #"app/etc_shared":
    #    source: "service"
    #    service: "files"
    #    source_path: "etc"
    #"pub/media_shared":
    #    source: "service"
    #    service: "files"
    #    source_path: "media"
    #"pub/static_shared":
    #    source: "service"
    #    service: "files"
    #    source_path: "static"
    
  14. .magento.app.yaml ファイルのマウント設定のOLD LOCAL MOUNTSSHARED MOUNTS部分のコメントを解除します。

    code language-yaml
    "var_old": "shared:files/var"
    "app/etc_old": "shared:files/etc"
    "pub/media_old": "shared:files/media"
    "pub/static_old": "shared:files/static"
    
    "var":
        source: "service"
        service: "files"
        source_path: "var"
    "app/etc":
        source: "service"
        service: "files"
        source_path: "etc"
    "pub/media":
        source: "service"
        service: "files"
        source_path: "media"
    "pub/static":
        source: "service"
        service: "files"
        source_path: "static"
    
  15. 更新されたファイルをGit インデックスに追加し、変更をコミットして、デプロイメントをトリガーにプッシュします。

    code language-shell
    git add -f .magento.app.yaml
    git commit -m "Enabling AppServer: switch mounts"
    git push
    
  16. *_old ディレクトリのファイルが実際のディレクトリに存在することを確認します。

  17. 古いローカルマウントのクリーンアップ:

    code language-shell
    rm -rf var_old/*
    rm -rf app/etc_old/*
    rm -rf pub/media_old/*
    rm -rf pub/static_old/*
    
  18. マウント設定のOLD LOCAL MOUNTS部分を.magento.app.yaml ファイルにコメントします。

    code language-yaml
    #"var_old": "shared:files/var"
    #"app/etc_old": "shared:files/etc"
    #"pub/media_old": "shared:files/media"
    #"pub/static_old": "shared:files/static"
    
  19. 更新されたファイルをGit インデックスに追加し、変更をコミットして、デプロイメントをトリガーにプッシュします。

    code language-shell
    git add -f .magento.app.yaml
    git commit -m "Enabling AppServer: finish"
    git push
    
NOTE
ルート .magento.app.yaml ファイルのすべてのカスタム設定がapplication-server/.magento/.magento.app.yaml ファイルに適切に移行されていることを確認します。 application-server/.magento/.magento.app.yaml ファイルをプロジェクトに追加した後、ルート .magento.app.yaml ファイルに加えてファイルを管理する必要があります。 例えば、RabbitMQ サービス ​またはweb プロパティを管理する必要がある場合は、application-server/.magento/.magento.app.yamlにも同じ設定を追加する必要があります。

クラウドプロジェクトでのイネーブルメントの確認

  1. インスタンスに対してGraphQL クエリまたはミューテーションを実行し、graphql エンドポイントにアクセスできることを確認します。 例:

    code language-graphql
    mutation {
     createEmptyCart
    }
    

    期待される応答は、次の例のようになります。

    code language-json
    {
     "data": {
         "createEmptyCart": "HLATPzcLw5ylDf76IC92nxdO2hXSXOrv"
         }
     }
    
  2. クラウドインスタンスにアクセスするには、SSHを使用します。 project_root/var/log/application-server.logには、GraphQL リクエストごとに新しいログレコードを含める必要があります。

  3. また、次のコマンドを実行して、GraphQL Application Serverが実行されているかどうかを確認することもできます。

    code language-shell
    ps aux|grep php
    

    複数のスレッドを持つbin/magento server:run プロセスが表示されます。

これらの検証手順が正常に実行された場合、GraphQL Application Serverは実行中で、/graphql件のリクエストを処理しています。

オンプレミスプロジェクトの有効化

ApplicationServer モジュール (Magento/ApplicationServer/)は、GraphQL API用のGraphQL Application Serverを有効にします。

GraphQL Application Serverをローカルで実行するには、Swoole拡張機能のインストールと、デプロイメントのNginx設定ファイルのマイナーな変更が必要です。

前提条件

ApplicationServer モジュールを有効にする前に、次の手順を実行します。

  • Nginxの設定
  • Swoole v5+拡張機能のインストールと設定

Nginxの設定

Commerceのデプロイメントによって、Nginxの設定方法が決まります。 一般に、Nginx設定ファイルはデフォルトでnginx.confという名前で、次のいずれかのディレクトリ(/usr/local/nginx/conf/etc/nginx、または/usr/local/etc/nginx)に配置されます。 Nginxの設定について詳しくは、初心者向けガイド ​​を参照してください。

Nginx設定の例:

location /graphql {
    proxy_set_header Host $http_host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

    proxy_pass http://127.0.0.1:9501/graphql;
}

Swooleのインストールと設定

GraphQL Application Serverをローカルで実行するには、Swoole拡張機能(v5.0以降)をインストールします。 この拡張機能をインストールするには、複数の方法があります。

次の手順では、OSX ベースのシステムにPHP 8.2用のSwoole拡張機能をインストールする方法について説明します。 Swoole拡張機能をインストールするいくつかの方法の1つです。

pecl install swoole

インストール中に、Adobe Commerceに、opensslmysqlndsocketshttp2、およびpostgresのサポートを有効にするためのプロンプトが表示されます。 postgresを除くすべてのオプションに対してyesと入力します。

Swoole インストールの確認

拡張機能が正常に有効になっていることを確認します。

php -m | grep swoole

Swoole インストールの一般的なエラー

Swooleのインストール中に発生するエラーは、通常、pecl インストール フェーズで発生します。 一般的なエラーには、openssl.hpcre2.h個のファイルがありません。 これらのエラーを解決するには、これらの2つのパッケージがローカルシステムにインストールされていることを確認します。

  • 次を実行して、opensslの場所を確認します:
openssl version -d

このコマンドは、opensslがインストールされているパスを示します。

  • 次を実行して、pcre2の場所を確認します:
pcre2-config --prefix

コマンド出力でファイルが見つからないことが示された場合は、Homebrewを使用して見つからないパッケージをインストールします。

brew install openssl
brew install pcre2

opensslの問題を解決する

opensslに関連する問題を解決するには、次を実行します。

export LDFLAGS="-L/opt/homebrew/etc/openssl@3/lib" export CPPFLAGS="-I/opt/homebrew/etc/openssl@3/include"

ローカル dev環境のパスを使用していることを確認してください。

openssl関連の問題の解決を確認する

次のコマンドを再度実行して、openssl関連の問題が解決されたかどうかを確認できます。

pecl install swoole

pcre2.hの問題を解決する

pcre2.hに関する問題を解決するには、インストールされているPHP拡張ディレクトリにpcre2.h パスをシンボリックリンクします。 インストールされている特定のバージョンのPHPとpcr2.hによって、使用するコマンドの特定のバージョンが決まります。

GraphQL Application Serverの実行

GraphQL Application Serverを起動します。

bin/magento server:run

このコマンドは、9501でHTTP ポートを開始します。 GraphQL Application Serverが起動すると、ポート 9501はすべてのGraphQL クエリのHTTP プロキシサーバーになります。

GraphQL Application Serverがデプロイメントで実行されていることを確認するには、次の手順を実行します。

ps aux | grep php

GraphQL Application Serverが実行中であることを確認する追加の方法は次のとおりです。

  • 処理済みのGraphQL リクエストに関連するエントリについては、/var/log/application-server.log ファイルを確認してください。
  • GraphQL Application Serverが実行するHTTP ポートへの接続を試みます。 例:curl -g 'http://localhost:9501/graph

GraphQL リクエストが処理中であることを確認します

GraphQL Application Serverは、処理する各リクエストに、値graphql_serverX-Backend応答ヘッダーを追加します。 GraphQL Application Serverがリクエストを処理したかどうかを確認するには、この応答ヘッダーを確認します。

拡張機能とカスタマイズの互換性を確認

拡張機能の開発者と販売者は、最初に、拡張機能とカスタマイズ コードが​ テクニカル ガイドライン ​ ​に記載されているガイドラインに準拠していることを確認する必要があります。

コードの評価時に、次のガイドラインを検討します。

  • サービス クラス (つまり、EventManagerなど、動作を提供するがデータを提供しないクラス)には、可変ステートを設定しないでください。
  • 一時的な結合を避ける。

GraphQL Application Serverを無効にする

GraphQL Application Serverを無効にする手順は、サーバーがオンプレミスまたはクラウドのデプロイメントで実行されているかどうかによって異なります。

GraphQL Application Server (cloud)を無効にする

  1. デプロイメントの準備中にAppServer Enabled コミットに含まれていた新しいファイルやその他のコード変更を削除します。

  2. 次のコマンドを使用して変更をコミットします。

    code language-shell
    git commit -m "AppServer Disabled"
    
  3. 次のコマンドを使用して、これらの変更をデプロイします。

    code language-shell
    git push
    

GraphQL Application Serverを無効にする(オンプレミス)

  1. GraphQL Application Serverを有効にする際に追加したnginx.conf ファイルの/graphql セクションをコメントアウトします。
  2. nginxを再起動します。

GraphQL Application Serverを無効にするこの方法は、パフォーマンスを迅速にテストまたは比較するのに便利です。

GraphQL Application Serverが無効になっていることを確認します

php-fpmがGraphQL Application ServerではなくGraphQL リクエストを処理していることを確認するには、次のコマンドを入力します:ps aux | grep php

GraphQL Application Serverを無効にした後:

  • bin/magento server:runは非アクティブです。
  • var/log/application-server.logには、GraphQL リクエストの後にエントリが含まれていません。

GraphQL Application Serverの統合テストと機能テスト

拡張機能の開発者は、2つの統合テストを実行して、GraphQL Application Serverとの拡張機能の互換性を検証できます:GraphQlStateTestResetAfterRequestTest

GraphQlStateTest

GraphQlStateTestは、複数の要求に再利用できない共有オブジェクトの状態を検出します。

このテストは、ObjectManagerが生成するサービス オブジェクトの状態の変更を検出するように設計されています。 テストでは、同じGraphQL クエリを2回実行し、2回目のクエリの前後でサービスオブジェクトの状態を比較します。

GraphQlStateTestのエラーと潜在的な修正

  • リストを追加、スキップ、またはフィルターできません。 このエラーが発生した場合は、可変ステートのサービスクラスにファクトリを使用するようにクラスをリファクタリングしてみてください。

  • クラスに可変ステートが表示されます。 クラス自体が可変ステートを示す場合は、このステートを回避するためにコードを書き換えてみてください。 パフォーマンス上の理由から可変ステートが必要な場合は、ResetAfterRequestInterfaceを実装し、_resetState()を使用して、オブジェクトを最初に構築されたステートにリセットします。

  • 初期化メッセージ​の前に、入力されたプロパティ $xにアクセスすることはできません。 このタイプのメッセージでエラーが発生した場合は、指定したプロパティがコンストラクターによって初期化されていないことが示されます。 これは、オブジェクトが最初に構築された後に使用できないため、時間的な結合の一形態です。 プロパティからデータを取得するCollectorがPHP リフレクション機能を使用しているため、プロパティがプライベートである場合でも、この結合が発生します。 この場合は、時間的な結合を避け、可変状態を避けるために、クラスをリファクタリングしてみてください。 リファクタリングで失敗が解決しない場合は、プロパティタイプをnull可能なタイプに変更して、nullに初期化できます。 プロパティが配列の場合は、プロパティを空の配列として初期化してみてください。

vendor/bin/phpunit -c $(pwd)/dev/tests/integration/phpunit.xml dev/tests/integration/testsuite/Magento/GraphQl/App/GraphQlStateTest.phpを実行してGraphQlStateTestを実行します。

ResetAfterRequestTest

ResetAfterRequestTestは、ResetAfterRequestInterfaceを実装するすべてのクラスを検索し、_resetState() メソッドが、ObjectManagerによって構築された後に保持した状態と同じ状態にオブジェクトの状態を返すことを確認します。  このテストでは、ObjectManagerを含むサービスオブジェクトを作成し、そのオブジェクトを複製して_resetState()を呼び出し、両方のオブジェクトを比較します。 このテストでは、オブジェクトのインスタンス化と_resetState()の間のメソッドは呼び出されないので、変更可能な状態のリセットは確認されません。 _resetState()のバグまたはタイプミスが元の状態とは異なる状態に設定される可能性がある問題が見つかります。

ResetAfterRequestTestのエラーと潜在的な修正

  • クラスに一貫しないプロパティ値​があります。 このテストが失敗した場合は、クラスが変更されたかどうかを確認し、_resetState() メソッドが呼び出された後のオブジェクトのプロパティ値と、コンストラクション後のオブジェクトのプロパティ値が異なることを確認します。 作業中のクラスに_resetState() メソッド自体が含まれていない場合は、それを実装するスーパークラスのクラス階層を確認してください。

  • 初期化メッセージ​の前に、入力されたプロパティ $xにアクセスすることはできません。 この問題はGraphQlStateTestでも発生します。

    実行してResetAfterRequestTestを実行:vendor/bin/phpunit -c $(pwd)/dev/tests/integration/phpunit.xml dev/tests/integration/testsuite/Magento/Framework/ObjectManager/ResetAfterRequestTest.php

機能テスト

GraphQL Application Serverのデプロイ時に、拡張機能の開発者はWebAPI機能テストと、GraphQLのカスタム機能テストの自動または手動テストを実行する必要があります。 これらの機能テストは、開発者が潜在的なエラーや互換性の問題を特定するのに役立ちます。

状態モニターモード

機能テスト (または手動テスト)の実行中に、GraphQL Application Serverは--state-monitor modeを有効にして実行し、ステートが意図せず再利用されているクラスを見つけるのに役立てることができます。 --state-monitor パラメーターを追加する場合を除き、通常どおりアプリケーションサーバーを起動します。

bin/magento server:run --state-monitor

各リクエストが処理されると、新しいファイルがtmp ディレクトリに追加されます(例:var/tmp/StateMonitor-thread-output-50-6nmxiK)。 テストが完了すると、これらのファイルをbin/magento server:state-monitor:aggregate-output コマンドと結合して、XMLJSONの2つの結合ファイルを作成できます。

例:

/var/workspace/var/tmp/StateMonitor-json-2024-04-10T18:50:39Z-hW0ucN.json
/var/workspace/var/tmp/StateMonitor-junit-2024-04-10T18:50:39Z-oreUco.xml

これらのファイルは、GraphQlStateTestのようにサービスオブジェクトの変更されたプロパティを示すXMLまたはJSONを表示するために使用する任意のツールで検査できます。 --state-monitor モードでは、GraphQlStateTestと同じスキップリストとフィルターリストが使用されます。

NOTE
実稼動環境では--state-monitor モードを使用しないでください。 開発とテスト専用に設計されています。 多くの出力ファイルを作成し、通常よりも動作が遅くなります。
NOTE
--state-monitorは、PHP ガベージコレクターのバグにより、PHP バージョン 8.3.08.3.4と互換性がありません。 PHP 8.3を使用している場合、この機能を使用するには8.3.5以降にアップグレードする必要があります。

クライアント IP検出のための代替ヘッダーの設定

デフォルトでは、GraphQL Application Serverはapp/etc/di.xml ファイルで定義されたx-forwarded-for ヘッダーの標準設定をサポートしており、一般的なプロキシ環境およびCDN環境でクライアント IP アドレスを正確に取得できます。

追加ヘッダーまたはカスタムヘッダー(x-client-ipfastly-client-ipx-real-ipなど)をサポートする必要がある場合は、app/etc/di.xml ファイルのalternativeHeaders引数を拡張または上書きできます。 これは、環境でx-forwarded-for以外のヘッダーを使用してクライアント IP アドレスを渡す場合にのみ必要です。

例えば、他のヘッダーのサポートを追加するには、次のようにapp/etc/di.xmlを更新します。

<type name="Magento\Framework\HTTP\PhpEnvironment\RemoteAddress">
    <arguments>
        <argument name="alternativeHeaders" xsi:type="array">
            <item name="x-client-ip" xsi:type="string">HTTP_X_CLIENT_IP</item>
            <item name="fastly-client-ip" xsi:type="string">HTTP_FASTLY_CLIENT_IP</item>
            <item name="x-real-ip" xsi:type="string">HTTP_X_REAL_IP</item>
            <item name="x-forwarded-for" xsi:type="string">HTTP_X_FORWARDED_FOR</item>
        </argument>
    </arguments>
</type>

必要に応じてヘッダーを追加、削除、または並べ替えることで、設定の正しいソースからクライアント IPを取得できます。

NOTE
Fastly CDN モジュールでAdobe Commerce Cloudを使用している場合、この設定は自動的に処理され、手動での変更は必要ありません。 手動による設定は、カスタム CDN、プロキシ、または非標準ヘッダーの設定に対してのみ必要です。
recommendation-more-help
commerce-operations-help-performance