Azure App ServiceにおけるJSS SSRプロキシのパフォーマンスの問題


解説

ヘッドレス モードで運用している場合、JSSアプリケーションはHTTPリクエストを受信し、それをSitecore XPサーバーへのレイアウト サービス リクエストに書き換えてプロキシされます。Azure上で運用する場合、プロキシからSitecore XP Serverへの各アウトバウンド接続はSNATポートを使用し、接続の再利用が有効にされていない場合、SNATポート枯渇のリスクが高くなります。この場合、アプリケーションに以下のような症状が発生することがあります:

これは、JSS 11.0.0〜14.0.2バージョンに適用されます。

解決策

この問題を解決するには、connection keep-aliveを実装する必要があります:

  1. 以下のコンテンツでhttpAgents.js をアプリケーションに追加します:
    const http = require("http");
    const https = require("https");
    const keepAliveConfig = {
                maxSockets: 200,
                maxFreeSockets: 20,
                timeout: 240 * 1000,
                freeSocketTimeout: 240 * 1000,
    };
    
    const httpAgent = new keepAlive(keepAliveConfig);
    const httpsAgent = new keepAlive.HttpsAgent(keepAliveConfig);
    
    
    module.exports = {
      setUpDefaultAgents: (serverBundle) => {
        http.globalAgent = httpAgent;
                            https.globalAgent = httpsAgent;
                            if (serverBundle.setUpDefaultAgents) {
                                       serverBundle.setUpDefaultAgents(httpAgent, httpsAgent);
                            }
                },
                /**
                 * 接続プールを有効にします。「connection:keep-alive」ヘッダーを追加します。
                 * @param {string} url api host
                */
      getAgent: (url) => {
                            if (!url) {
                                        throw new Error("[KEEP-ALIVE-CONFIG] SITECORE_API_HOST value is required, but was undefined")
                            }
                            if (!url.indexOf("http://")) return httpAgent;
                            if (!url.indexOf("https://")) return httpsAgent;
                            throw new Error(
                                        "[KEEP-ALIVE-CONFIG] Unexpected SITECORE_API_HOST value, expected http:// or https://, but was " +
                                                   url
                            );
      },
    };
    …
  2. プロキシ アプリケーションのconfig.jsを変更します:
    …
    const NodeCache = require('node-cache');
    const httpAgents = require("./httpAgents");
    …
    const serverBundle = require(bundlePath);
    httpAgents.setUpDefaultAgents(serverBundle);
    …
    proxyOptions: {
        // 接続プールを有効にします
        agent: httpAgents.getAgent(apiHost),
        // これをfalseに設定すると、SSLSitecoreインスタンスにプロキシするときにSSL証明書の検証が無効になります。
        // これは重大なセキュリティ問題であるため、ローカル開発以外では決してこれをfalseに設定しないでください。CAが発行した実際の証明書を使用してください。
                            secure: true,
                            headers: {
                                        "accept-encoding": "gzip, deflate"
                            },
                            xfwd: true
                },
    …
    return fetch(
          `${config.apiHost}/sitecore/api/jss/dictionary/${appName}/${language}?sc_apikey=${
            config.apiKey
          }`,
          {
            headers: {
              connection: "keep-alive",
            },
          }
        )
    
  3. アプリケーションのserver.jsを変更します:
    …
    import Helmet from 'react-helmet';
    import axios from "axios";
    import http from "http";
    import https from "https";
    …
    // keep-alive用にHttp/Httpsエージェントを設定します。ヘッドレス プロキシで使用
    export const setUpDefaultAgents = (httpAgent, httpsAgent) => {
      axios.defaults.httpAgent = httpAgent;
      axios.defaults.httpsAgent = httpsAgent;
      http.globalAgent = httpAgent;
      https.globalAgent = httpsAgent;
    }; 
  4. GraphQLClientFactory.jsを変更します:
    const link = createPersistedQueryLink().concat(
        new BatchHttpLink({
          uri: endpoint,
          credentials: 'include',
          headers: {
            connection: "keep-alive"
          }
        })
    


現在、「proxyOptions.onProxyReq」の使用には制限があることに注意してください。「onProxyReq」を「keep-alive」と一緒に使うと、サーバがクラッシュする可能性があります。カスタム ミドルウェアを追加することで、プロキシする前のリクエストを変更して、プロキシしたい値を含むようにすることができます:

server.use((req, res, next) => {
  // ここに動的ヘッダーを設定します
  next();
});


詳細については、以下のリンク先を参照してください: