【WebSphere Liberty Hints & Tips】 クラスター環境を構成する方法


はじめに

Webサーバー(ここではApacheベースのIBM HTTP Server)と複数のLibertyでクラスター構成を取る方法がマニュアルなどに記載されつつも、少し手こずってしまったので備忘録のためStep-By-Stepでまとめておきます。公開されている最新情報をもとに検証しているつもりですが、誤植・より良い方法などございましたらご指摘ください。

前提環境

  • RHEL 7.3
  • WebSphere Liberty 17.0.0.2(以下Liberty)
  • IBM HTTP Server 9.0.0.2 (以下IHS)
  • WebSphere Plugins 9.0.0.2(以下Plugin)
  • IBM JDK 8

構成

  • クライアント => IHS(Plugin) => Liberty x2
    • IHSがバックエンドの2台のLibertyにラウンドロビンで割り振る
      • ラウンドロビンでリクエストを割り振るだけのシンプル・クラスターです。
      • バックエンドにDBを構成すればセッション・フェールオーバーもできますが、今回は対象外です。

方法

1. 各Libertyのserver.xmlを以下のように編集

server.xml
  <!-- Simple application server, supporting servlets and jsps -->
  <featureManager>
    <feature>jsp-2.2</feature>
    <feature>serverlet-3.1</feature>
    <feature>localConnector-1.0</feature>
  </featureManager>

  <config updateTrigger="mbean"/>
  <applicationMonitor updateTrigger="mbean" dropinsEnabled="true"/>
  <applicationManager autoExpand="true"/>

  <httpEndpoint id="defaultHttpEndpoint"
                host="*"
                httpPort="9080"
                httpsPort="9443">
      <tcpOptions soReuseAddr="true"/>
  </httpEndpoint>
</server>

2. テスト・アプリをdropinsディレクトリに配置
以下は例です。ここでは稼働サーバー情報を表示するテスト・アプリを入れています。

3. 各Libertyでプラグイン構成ファイルが自動生成されているのを確認
以下のディレクトリを確認し、各Libertyのplugin-cfg.xmlをリネームしておく

4. どちらかのプラグイン構成ファイルを、もう1台のLibertyにコピー
5. 以下のコマンドで2つのファイルをマージして過不足部分などあれば修正

pluginUtility.command
./pluginUtility merge --sourcePath=/2つのファイルがあるパス --targetPath=/任意の出力先パス

以下は例です:

マージしたplugin-cfg.xmlの例
    <?xml version="1.0" encoding="UTF-8"?><!-- This config file was generated by plugin's merge tool v1.0.0.2 on 2017.07.05 at 06:28:40 UTC --><Config ASDisableNagle="false" AcceptAllContent="false" AppServerPortPreference="HostHeader" ChunkedResponse="false" FIPSEnable="false" IISDisableNagle="false" IISPluginPriority="High" IgnoreDNSFailures="false" RefreshInterval="60" ResponseChunkSize="64" SSLConsolidate="false" TrustedProxyEnable="false" VHostMatchingCompat="false">
   <Log LogLevel="Error" Name="/opt/IBM/WebSphere/Plugins/logs/http_plugin.log"/>
   <Property Name="ESIEnable" Value="true"/>
   <Property Name="ESIMaxCacheSize" Value="1024"/>
   <Property Name="ESIInvalidationMonitor" Value="false"/>
   <Property Name="ESIEnableToPassCookies" Value="false"/>
   <Property Name="PluginInstallRoot" Value="/opt/IBM/WebSphere/Plugins"/>
<!-- Server Clusters -->
<ServerCluster CloneSeparatorChange="false" GetDWLMTable="false" IgnoreAffinityRequests="true" LoadBalance="Round Robin" Name="SimpleCluster" PostBufferSize="0" PostSizeLimit="-1" RemoveSpecialHeaders="true" RetryInterval="60" ServerIOTimeoutRetry="-1">
        <Server CloneID="xxxxxxxxxxxxxxxxxxxxxxx" ConnectTimeout="5" ExtendedHandshake="false" LoadBalanceWeight="20" MaxConnections="-1" Name="server1" ServerIOTimeout="900" WaitForContinue="false">
         <Transport Hostname="sample1.com" Port="9080" Protocol="http"/>
         <!--Transport Hostname="sample1.com" Port="9443" Protocol="https">
            <Property Name="keyring" Value="/opt/IBM/WebSphere/Plugins/config/webserver1/plugin-key.kdb"/>
            <Property Name="stashfile" Value="/opt/IBM/WebSphere/Plugins/config/webserver1/plugin-key.sth"/>
         </Transport-->
      </Server>
        <Server CloneID="yyyyyyyyyyyyyyyyyyyyyyy" ConnectTimeout="5" ExtendedHandshake="false" LoadBalanceWeight="20" MaxConnections="-1" Name="server1" ServerIOTimeout="900" WaitForContinue="false">
         <Transport Hostname="sample2.com" Port="9080" Protocol="http"/>
         <!--Transport Hostname="sample2.com" Port="9443" Protocol="https">
            <Property Name="keyring" Value="/opt/IBM/WebSphere/Plugins/config/webserver1/plugin-key.kdb"/>
            <Property Name="stashfile" Value="/opt/IBM/WebSphere/Plugins/config/webserver1/plugin-key.sth"/>
         </Transport-->
      </Server>
    </ServerCluster>
    <!-- Virtual Host Groups -->
    <VirtualHostGroup Name="/cell/sharedCell_2/vHostGroup/shared_host_0">
        <!--VirtualHost Name="*:443"/-->
        <VirtualHost Name="*:80"/>
    </VirtualHostGroup>
    <!-- URI Groups -->
    <UriGroup Name="/cell/sharedCell_2/application/default_host_server1_default_node_Cluster_URIs">
        <Uri AffinityCookie="JSESSIONID" AffinityURLIdentifier="jsessionid" Name="/*"/>
    </UriGroup>
    <!-- Routes -->
    <Route ServerCluster="SimpleCluster" UriGroup="/cell/sharedCell_2/application/default_host_server1_default_node_Cluster_URIs" VirtualHostGroup="/cell/sharedCell_2/vHostGroup/shared_host_0"/>
</Config>

6. 上記でマージしたプラグイン構成ファイルをIHSの任意のディレクトリにコピー

IHS.directory
/opt/IBM/WebSphere/HTTPServer/conf/plugin-cfg.xml

7. IHSのconfディレクトリにあるhttpd.confに下記を追記してIHSを再起動する

httpd.conf
LoadModule was_ap22_module "/opt/IBM/WebSphere/Plugins/bin/64bits/mod_was_ap22_http.so"
WebSpherePluginConfig "/opt/IBM/WebSphere/HTTPServer/conf/plugin-cfg.xml"
apache.command
./apachectl stop
./apachectl sart

8. 疎通確認
http://<IHSホスト名>/snoop でテスト・アプリへアクセスし、リロードをすると実行されているサーバーIPが変わり、ラウンドロビンで割り振られていることがわかる

まとめ

以上でIBM HTTP Serverと複数のLibertyによるクラスター構成方法を記しました。

7/12 追記

マニュアルによると、以下のような記述があります。
セッション・アフィニティが必要ならClone IDはデフォルトで自動生成されるものではなく、bootstrap.propertiesファイルで明記して、server.xml内で{cloneId}指定するのが良さそうです。詳細はマニュアルに書かれているので、ここでは省略します。そのうちこの方法で試すかもしれません。

Best Practice
If session affinity is important to your application, explicitly define a unique clone ID for each server. In that way, you do not have to depend on the default clone ID generated by the server, and you can be certain that the value of the clone ID never changes.

参考