Fine Tuning Payara Server in Production (Japanese)

Photo of Fabio Turizo by Fabio Turizo

Webアプリケーションを開発する際における最大の挑戦の一つは、商用環境へのリリース時にアプリケーションをどのように調整すべきかを理解することです。これはJavaのエンタープライズ・アプリケーションをPayara Serverへデプロイする場合でも例外ではありません。

 

For this blog in English, click here.

 

Payara Serverを実行するのは簡単です。ニーズに合った最新のディストリビューション(full, web, micro等)をダウンロードして、/bin フォルダーに移動し、デフォルトのドメインを開始するだけです。しかし、Payara Serverは開発用途向けに調整されていることに注意してください(これはGlassFishと同様です)。Webアプリケーションの開発時には、機能を素早く実装し、アプリケーションのデプロイ・テスト・アンデプロイ(または再デプロイ)を高速に実行し、そしてすぐに次の機能セットに取り掛かれる方が良いのです。

 

しかし、商用環境においては、システムに要求されている品質項目(パフォーマンス、可用性、信頼性、他)を満たすように適切な構成を行うことが必須です。このブログ記事の目的は、Payara Serverを使用する商用環境を準備する際に適用可能な最適化のセットについて説明し、同時にこれらの最適化に関連する重要な部分を微調整する方法を示すことです。

 

 

payaradomain テンプレート

通常、アプリケーション・サーバーを調整する際には、サーバー構成に対して行われるお決まりのパラメーター化として以下の事柄を扱います。

  • Java仮想マシン(JVM)の初期化オプション
  • 全般的なシステム・プロパティ―
  • ネットワークおよびHTTPリスナー
  • クラスロードおよびファイル処理
  • JDBC設定

Payara Server 4.1.1.152.1以降では、payaradomainと呼ばれる新しいドメイン・テンプレートが標準で含まれています。このドメインは先に挙げた事柄を扱ういくつかの共通的な設定が構成済みであり、ほとんどすべてのシナリオにおいてパフォーマンスを容易に向上させることができます。

このテンプレートを使用する方法はとても簡単です。デフォルト・ドメインまたはカスタム・ドメインを実行する代わりに、このドメインを実行してアプリケーションをデプロイすれば良いのです。

 

./asadmin start-domain payaradomain

 

では、このテンプレートにはどのような最適化が含まれているのでしょうか。以下のセクションでは、商用環境に適用すべきであろう各構成の設定値を詳しく説明しつつ、それを示します。

これらの最適化を分かりやすく示すために、domain/config/domain.xmlファイル内の該当する要素を、必要に応じて変えながら使用します。これは、この記事全体で一貫して用います。また、関連する構成についてもserver-config構成グループと同様とみなします。

 

JVMオプション

デフォルトのJVMオプションは、商用環境上で動作し続けるJavaアプリケーションには適していません。そのため、以下のような変更が常に推奨されています。

 

 「サーバー」モードに設定する(payaradomainに含まれる):

 <jvm-options>-client</jvm-options> à <jvm-options>-server</jvm-options>

 

server オプションではJVMをサーバー・モードで実行します。このモードでは、長時間の処理実行時において処理速度が最高となるように調整されます。

 

ヒープ・サイズを調整する(payaradomainに含まれる):

<jvm-options>-Xmx2048m</jvm-options>

<jvm-options>-Xms2048m</jvm-options>

 

ヒープ領域に確保されるメモリの量を増加させるため、XmxおよびXms オプションを調整します。また、双方に同じ値を設定することで、サーバーは起動時からすべてのメモリを使用するようになり、実行中のメモリ再割り当て実行が抑制されます。

 

なお、これは個人的な意見ですが、確保するメモリの量は2ギガバイトから16ギガバイトの間にすると良いでしょう。これ以上のメモリ量ではガベージ・コレクターによって管理されるオブジェクトの数が把握できなくなり、JVMのパフォーマンスに影響を及ぼしかねないためです。もし、アプリケーションが大量のヒープ領域を必要とするのであれば、クラスタ構成を行ってワークロードを全体的に低下させることを検討してください。

 

payaradomainテンプレートでは、ヒープ領域は1Gに設定しています。より適切な値に調整するよう忘れないでください。

 

PermGen の最大サイズを増加させる(payaradomainに含まれる):

<jvm-options>-XX:MaxPermSize=512m</jvm-options>

 

使用される依存関係数・クラス数によってPermGen領域に割り当てるメモリの最大サイズを増加させます。PermGen領域にはアプリケーションによってロードされたクラスのメタデータが格納されるため、この数を考慮して適切な値を構成する必要があることに留意してください。payaradomainテンプレートでは、デフォルトでこの値は512メガバイトに設定されています。

また、このオプションはバージョン8よりも前のJDKでのみ使用可能であることに注意してください。JDK 8ではPermGen領域は削除され、Metaspace領域へと置き換えられています。

 

Secure Client-Initiated Renegotiationを無効化する (payaradomainに含まれる):

<jvm-options>-Djdk.tls.rejectClientInitiatedRenegotiation=true</jvm-options>

 

これはTLSプロトコルのSecure Client-Initiated Renegotiation機能の脆弱性によりサーバー上で発生するDDoS攻撃を防ぐために必要です。このオプションはJDK 8でのみ有効です。

 

クラス・ローディング分離を有効化する

<jvm-options>-Dfish.payara.classloading.delegate=false</jvm-options>

 

サードパーティーのライブラリを使用する場合で、Payara Serverのモジュールとして既に含まれている以前のバージョンとコンフリクトする可能性がある場合には、クラス・ローディング分離の有効化を検討してください。この設定は、domain/libフォルダー以下に配置されているすべてのライブラリと同様に、アプリケーション内部に含まれているライブラリにも適用されます。もし、アプリケーションで広く普及しているサードパーティー・ライブラリ(Apache Commons、Google Guava、Spring Framework、等)を多用している場合には、この機能の有効化は良いアイデアです。

 

ガベージ・コレクションを調整する

ガベージ・コレクションは、既に不要であると認識されたすべてのオブジェクトを用いて、JVM上に割り当てられた“未使用”のヒープ領域を再利用します。ガベージ・コレクションのオブジェクトを配置および削除する処理により、アプリケーションのパフォーマンスがスローダウンする可能性があります。高負荷時にサーバーのパフォーマンスを最大限に生かすためには、効果的なガベージ・コレクションの構成が不可欠です。

 

ガベージ・コレクターの調整は、それだけで書籍が書けてしまうほどの大きなトピックですので、この記事では詳細を割愛します。以下のメトリクスをもとにサーバーのJDKが使用するGCアルゴリズムを賢く選択することをお勧めします。

  • CPU使用率(パーセント)
  • CPU停止頻度
  • CPU停止時間の長短比較

また、以下のプロパティを用いてSystem.gcメソッドによるガベージ・コレクションを明示的に禁止する方法もお勧めします。

 

<jvm-options>-XX:+DisableExplicitGC</jvm-options>

 

稀なケースですが、開発者がJDKのこの機能を使用している場合があります。しかし、このメソッドを無効化することにより、望まないガベージ・コレクションの繰り返しに起因するCPU使用率の上昇を抑制することができます。

 

開発向け機能を無効化する

商用環境では、自動デプロイ動的再読み込みの双方を常に無効化してください。これらの機能はアプリケーションの開発をスピードアップさせるものですが、日常の運用では全く必要ありません。そして、これらによりパフォーマンスに悪影響を及ぼす可能性があります(例えば、アプリケーションの状態やディレクトリ上のファイルの変更を監視するために余計なサーバーのリソースを消費します)。

 

これらの機能を無効化するには、domain.xmlファイルのdas-config要素を修正します。

 

<das-config dynamic-reload-enable=“false” autodeploy-enabled=”false”></das-config>

 

JspServletの動的リロードを無効化するのも良い方法で、これにより常時JSPファイルの変更をチェックすることがなくなります。すべての文字列値を静的な文字配列として管理するよう構成することで、サーバーのメモリ消費量を減らすことが可能です。

これらの変更を設定するには、domain/config/default-web.xmlファイル以下のサーブレット構成を編集する必要があります。

 

<servlet>
    <servlet-name>jsp</servlet-name>
    <servlet-class>org.apache.jasper.servlet.JspServlet</servlet-class>
    <init-param>
        <param-name>development</param-name>
        <param-value>false</param-value>
    </init-param>
    <init-param>
        <param-name>genStrAsCharArray</param-name>
        <param-value>true</param-value>
    </init-param>
     
</servlet>

 

EJBプールの設定

アプリケーションがビジネス・コンポーネント・モデルとしてEJBを使用している場合には、パフォーマンス向上と効果的なリソースへのアクセス実現のため、アプリケーション・サーバーのEJBコンテナのキャッシュ、プールおよびEJBコンポーネント・インスタンスの再利用に注意してください。もし、アプリケーションがステートレスEJBを使用しているのであれば、パフォーマンスを維持するためプール・サイズを調整する必要があります。

 

<ejb-container pool-resize-quantity="16" max-pool-size="120" steady-pool-size="10">

    <ejb-timer-service></ejb-timer-service>

</ejb-container>

 

EJBプールをリサイズする際にコンテナによって使用される、プールの最小サイズ(steady-pool-size)、最大サイズおよびリサイズ量にそれぞれ適切な値を設定します。これらはアプリケーションが管理する現在のクライアント数をもとに値を設定することをお勧めします。最大プール・サイズは予想されるシステムの最大負荷に耐えうる値を設定し、最小/初期プール・サイズは比較的低負荷な状態に合わせて設定します。システムの稼働中に頻繁な高負荷のピークが想定される場合にはリサイズ量を大きく取ります。

 

もしアプリケーションがリモートEJBインタフェースを使用している場合には、同様に適切なORB 設定を構成しなければなりません。ORB (CORBA Object Request Broker)はクライアント・アプリケーション(Java EEアプリケーション・クライアントまたはクラシックなスタンドアロン・アプリケーション)とのリモート通信にRMI/IIOPプロトコルを使用します。これらのリモート・クライアントからのリクエストに対応するため、サーバーのリモート呼び出し実行を扱うスレッドの可用性を設定するthread-poolが使用されます。

 

ORBサービスによって割り当てられるスレッド・プールの最大および最小サイズを調整します(payaradomainドメインではthread-pool-1と呼んでいます)。最大値を設定するにはパフォーマンスを向上させるため特に注意を払ってください。もしアプリケーションがリモート・クライアントから多くの呼び出しを受け付けるのであれば、サーバーのスローダウンを避けるため適切なスレッド数を呼び出し数に合わせる必要があります。

 

<thread-pool name="thread-pool-1" min-thread-pool-size="50"

      max-thread-pool-size="200"></thread-pool>

 

HTTPおよびネットワークの構成

Webアプリケーションを商用環境にリリースする際には、HTTPネットワーク・リスナーを適切に設定することが極めて重要になります。そのため、サーバーはクライアントのリクエストに対して可用性と信頼性を妥協せずに処理する必要があります。

デフォルトでは、いずれのドメインでも3つのネットワーク・リスナーが存在します。

  • admin-listener, 管理コンソールWebインタフェースに対するHTTP接続を扱う
  • http-listener-1, すべてのアプリケーションに対するHTTP接続を扱う
  • http-listener-2, すべてのアプリケーションに対する排他的なHTTPS接続を扱う

HTTPかHTTPSか?

商用環境でHTTPS接続のみを使用する計画であれば(これはクラウド環境で全般的に起こります)、http-listener-1は無効化しておくことをお勧めします。

 

<network-listeners>

     <network-listener protocol="http-listener-1" port="8080" name="http-listener-1"

      thread-pool="http-thread-pool" transport="tcp"

      enabled="false"></network-listener>

   …

</network-listeners>

 

いくつかのケースでは、セキュリティ基盤によってHTTPSアクセスが不要な場合があります(イントラネット環境、パブリックまたは暗号化不要なデータを扱うアプリケーション)。その場合には、同様にhttp-listener-2を無効化します。

 

すべてのHTTP通信をHTTPSにリダイレクトする必要がある場合には、ロード・バランサーをセットアップするか、Payara ServerのフロントエンドにシンプルなWebサーバーを構築してこのタスクを行うようにすることをお勧めします。

 

HTTPの設定

ネットワーク・リスナーに設定する、有効な接続当たりのリクエスト数の最大値は、Webアプリケーションが想定する同時ユーザー数に依存します。リクエスト数×接続数で表される値は、HTTPリクエストを処理するKeep-Aliveスレッド間で等しく分割されることに注意してください。

 

タイムアウトにはサーバーがHTTP接続を開いた状態で保持する最大の秒数を設定します。tこのタイムアウトの設定はトリッキーな最適化であり、クライアントがサーバーへの接続を開いたまま保持できるように、サーバーへの複数のリクエストは単一のネットワーク接続によって処理されます。サーバーは開いた接続数のみを制限可能であるため、システムが大量のリクエストを処理する場合には、可能な限り接続が開かれていることを確認する必要があります。

 

最後に、リスナーのファイル・キャッシュを有効にします。このキャッシュにはサーバーにホストされたHTML、CSS、画像、プレーン・テキスト・ファイルといった静的なファイルの情報を含みます。このキャッシュを有効化することで、サーバーがファイルシステムからファイルを探し出す回数が削減され、パフォーマンスの向上につながります。また、ファイルがキャッシュに保持されるmax age (単位: 秒)を最適な値に設定します。

 

これらのパラメーターはネットワーク・リスナーに関連するprotocol要素にて構成します。

 

<protocol name="http-listener-1">

   <http max-connections="500" timeout-seconds="60" default-virtual-server="server">

        <file-cache enabled="true" max-age-seconds="3600"></file-cache>

   </http>

   …

</protocol>

 

payaradomainテンプレートでは、コネクションの最大数はデフォルトで500に設定されており、これはクラウド環境向きの良い平均的な値です。

サーバーが動作するマシンが1つのネットワーク・インタフェース・カードのみ持つ場合、ネットワーク・リスナーのネットワーク・アドレスにはこのネットワーク・インタフェース固有のIPアドレスを設定します。こうすることで、サーバーがオペレーティング・システムにIPアドレスを問い合わせる必要がなくなるため、パフォーマンスを向上させることができます。

 

<network-listener protocol="http-listener-1" address="192.168.1.103" port="8080"                             name="http-listener-1" thread-pool="http-thread-pool" transport="tcp">

</network-listener>

 

サーバー・マシンが複数のネットワーク・インタフェース・カードを持っている場合、複数のネットワーク・リスナーを作成して、それぞれにネットワーク・インタフェースで使用可能なIPアドレスを割り当てると良いでしょう。ロード・バランサーまたはWebサーバーを用いて、クライアント・アプリケーションからのリクエストをこれらのネットワーク・リスナーに分散させるようにします。

 

アクセプタ・スレッドとリクエスト・スレッド

使用したいトランスポート・サービスのアクセプタ・スレッド数を構成します。アクセプタ・スレッドはソケット上で新しいリクエストを常に待ち受け、受信時にそれをリクエスト・スレッドに渡します。スレッド数の推奨値は、サーバー・マシンのCPU数と同じ値です。例えば、4個のクアッド・コアCPUを搭載しているサーバーの場合、アクセプタ・スレッドの合計値は16 (4x4)にすると良いでしょう。この設定はtcptransport要素で行います。

 

<transports>

    <transport name="tcp" acceptor-threads="16" byte-buffer-type="HEAP"></transport>

</transports>

 

一方、リクエスト・スレッドはHTTPリクエストを実行します。これらはORBリクエストと同様にthread-poolにより処理されます。http-listener-1およびhttp-listener-2のスレッド・プールはhttp-thread-poolと呼ばれます。このプールに割り当てる最小値と最大値は50から500の範囲で、アプリケーションで想定される負荷とユーザーに依存します。これらの値を調整するには、システムの負荷が高い時にどれくらいのスレッドがプールによって使用されているかを注意深くモニタリングして、徐々に値を増やしていくようにすると良いでしょう。

 

<thread-pool name="http-thread-pool" min-thread-pool-size="25"

             max-thread-pool-size="350"></thread-pool>

 

payaradomainテンプレートでは、Webの管理コンソールが使用するリクエスト・スレッドのスレッド・プールであるadmin-thread-poolは、1~15の範囲で構成されています。これはほとんどの商用環境で一貫している平均値です。

 

JDBCプールの構成

アプリケーションでデータベース接続を集中的に使用するのであれば、JDBC接続プールの設定を適切にチューニングすると良いでしょう。サーバーは接続のオープン・再利用・クローズをプールの構成をもとに行うため、これらの設定を調整することは高負荷時でも良いパフォーマンスを維持するために必須となります。

 

プール・サイズの最小値と最大値の割り当ては、アプリケーションでどれくらいの接続を行うかに依存します。受信するリクエスト数に比例した大きな数を設定するよう考慮します。また、最小値と最大値の差が非常に大きい場合には、サーバーによってより多くの接続が速く生成されるよう、変更量を大きく設定することを検討します。

 

さらに、可能であれば接続プールの最大待機時間をゼロ(0)に設定します。こうすることにより、すべての呼び出しスレッドは接続が使用可能になるまでブロックされます。この方法により、サーバーが各接続について経過待機時間を追跡する必要がなくなり、パフォーマンスの向上を図ることができます。ただし、これは諸刃の剣であり、アプリケーションがJDBC接続を独占する傾向にあると、待機し続ける接続リクエストが多数生成されることにより、プールがボトルネックになってくる可能性もあります。

 

<jdbc-connection-pool steady-pool-size="10" max-pool-size="64" pool-resize-quantity="12"
is-isolation-level-guaranteed="false" max-wait-time-in-millis="0" datasource-classname="org.apache.derby.jdbc.EmbeddedDataSource" name="DerbyPool" res-type="javax.sql.DataSource">
<property name="databaseName"
value="${com.sun.aas.instanceRoot}/lib/databases/embedded_default">
      </property>
      <property name="connectionAttributes" value=";create=true"></property>
</jdbc-connection-pool>

 

 

Hazelcast and JCache

Enabling Hazelcast is required when you want to enable the use of the JCache API in your applications or when taking advantage of the auto-clustering capabilities of the server instead of using the Shoal-based clustering.

Keep in mind that you should implement the following configuration changes when enabling Hazelcast for your server:

  • Change the name of your cluster group! The default group name is development, so assign a proper name for your cluster group. Since the default discovery of the cluster group is done using multicast, your server may accidentally join a default cluster on a test environment and cause unwanted behavior if left unconfigured.
  • Change the password the server should use to join the cluster group as well, to prevent unwanted members to join these clusters.
  • Consider configuring the server as a lite member of the cluster group when it’s applications are stateless in nature and do not store information locally. For more information about the benefits of lite members, check out this blog post.

 

<hazelcast-runtime-configuration cluster-group-name="production-cluster"

           cluster-group-password="securePassword"

    lite="true" enabled="true">

</hazelcast-runtime-configuration>

 

HazelcastおよびJCache

アプリケーションでJCache APIを使用する場合や、Shoalベースのクラスタリングに代えてサーバーの自動クラスタリングのアドバンテージを得たい場合には、Hazelcastが必要になります。

サーバーでHazelcastを有効化する際には、以下の点に注意してください。

  • クラスタ・グループ名を変更してください。デフォルトのグループ名はdevelopmentとなっているため、クラスタ・グループに適した名前を設定してください。デフォルトではクラスタ・グループの探索はマルチキャストを使用して行われるため、そのままではサーバーがテスト環境のデフォルト・クラスタに参加してしまい予期しない挙動を起こす原因となります。
  • 同様に、サーバーがクラスタ・グループに接続する際のパスワードも変更してください。これにより想定外のメンバーがクラスタに参加することを防ぐことができます。
  • もしアプリケーションがステートレスで情報をローカルに保持する必要がなければ、サーバーをlite memberとしてクラスタに参加させることを検討してください。lite memberのメリットについては、こちらのブログ記事を参照してください。

 

<hazelcast-runtime-configuration cluster-group-name="production-cluster"

           cluster-group-password="securePassword"

    lite="true" enabled="true">

</hazelcast-runtime-configuration>

 

商用環境でのDockerの利用

最近では多くの商用環境で Dockerコンテナが使用されています。環境全体をシンプルなファイルで容易に管理でき(Infrastructure as Code)、JVMが持つ素晴らしい相乗効果が期待できるためです。アプリケーションをカスタムDockerイメージを用いてデプロイし、それが公式のpayara/server-fullイメージをベースとしている場合には、asadminコマンドを用いてすべての推奨する最適化を適用しておきましょう。

 

イメージしやすいように、以下にいくつかの最適化を行ったサンプルのDockerfileを示します。

 

FROM payara/server-full

ENV AS_ADMIN $PAYARA_PATH/bin/asadmin 
ENV DOMAIN payaradomain

#In order to edit the default-web-xml file to disable development features, it's easier to have a copy of the file with theses optimization applied and then replace the file in the server
ADD custom-default-web-xml ~./default-web-xml

RUN $AS_ADMIN start-domain $DOMAIN && \
    $AS_ADMIN set configs.config.server-config.admin-service.das-config.dynamic-reload-enabled=false
                  configs.config.server-config.admin-service.das-config.autodeploy-enabled=false && \
    $AS_ADMIN create-jvm-options -client:
                             -Xmx1024m:-Xms512m && \
    $AS_ADMIN create-jvm-options -server: 
                                 -Xmx2048m:-Xms2048m:                                 
                                 -Dfish.payara.classloading.delegate=false && \
    $AS_ADMIN set-hazelcast-configuration --clusterName=my-production-cluster 
  --clusterPassword=***** --target=server-config && \
    $AS_ADMIN stop-domain $DOMAIN && \
    mv ~./default-web-xml $PAYARA_PATH/glassfish/domains/payaradomain/config/

ENTRYPOINT $AS_ADMIN start-domain $DOMAIN 

 

 

Docker環境変数を使用してプロビジョニング構成をパラメーター化することもできます。これは最適化されたドメインのコンテナ・テンプレートを作成して異なるアプリケーションで使いまわすのにとても便利です。独自に最適化したいけれども必要となる具体的なasadminコマンドがわからない―そのような時でも163リリースから含まれるasadmin recorder機能でカバーできますのでご心配なく。

 

まとめ

商用環境向けにPayara Serverを調整することは、パフォーマンス低下を防ぐために避けては通れない作業です。そのためには、異なるワークロードにおけるシステムの挙動について測っておく必要があります。サーバーをインストールしてデフォルト構成のままにしておいてはいけません。そのために、ソフトウェア・アーキテクチャで必要とされる最適化を慎重に計画して、適切なタイミングでそれを適用してください。

 

payaradomainテンプレートについても忘れないでください。このテンプレートには多くの推奨される最適化が含まれており、これを使用することで作業を簡略化できます。今後、Payara Serverの新機能やGlassFishのアップデートに合わせて、さらに最適化を含めることを計画しています。公式ドキュメントもチェックしてください。サーバーのアップグレード時には、これらの将来追加される最適化の恩恵を受けられることでしょう。

 

 

 

 Payara Server in Production See the Guides 

 

 

 

Comments