LiferayのHA構成についてメモ

しばらく書き溜めていた、ここ最近のプロジェクトでハマったことをメモしていこうと思います。まずはLiferayのHA構成についてから。

LiferayのHA構成はどうやるの?

Liferayをアクティブ-アクティブのHA構成にする場合、いくつか方法があります。Liferay本系のWikiを見るといくつか参考となる情報があります。

読んでみると、色々やり方はありそうです。例えばHigh Availability Guide - Wiki - Liferay.comの中では、データベースのクラスタ化にはSequoiaというOSSを使って対応するような方式になっています。Sequoiaって正直聞いたことないのでこれをいきなり使うのは怖い。本当に実績があるのか、十分なパフォーマンスが出るのか大変気になるところ。また、JBoss-Tomcat-Liferay portal Clustering - what and how - Wiki - Liferay.comを見るとセッションレプリケーションを行う設定が書かれていますが、High Availability Guide - Wiki - Liferay.comだとおすすめしないとも書かれている。結局、上記Wikiを見てもどのような構成にすれば良く分からん状態になるかと。

HA構成のポイント

個人的にはLiferayのHA構成を構築するにあたり以下がポイントになるかと考えています。

今回私が関わったところでは以下のような感じ。

  • LiferayへのHTTP(s)の振分:ロードバランサをフロントに置いてお任せ。
  • セッションレプリケーション:しない。障害時に再ログイン許容可能なシステムなので、性能とかトラブルらないようにとレプリケーションは使用せず。なのでロードバランサの振分はスティッキーセッションです。
  • Hibernateキャッシュのレプリケーション:しない。スティッキーセッションなのでクラスタ間での共有は特に不要、かつ無用なトラブルを避けるため。
  • Luceneインデックスの共有:データベースでの共有。
  • JackRabbit管理データの共有:データベースでの共有。
  • データベースのクラスタ方式:MySQL+Heartbeat+共有ディスク。

上記は結構無難な構成だと思います。特にセッションレプリケーションとかHibernateセッションのレプリケーションをばっさり落としている当たり。データベースのクラスタ方式はLiferay云々の話ではないので、一般的に実績のある方式を取ればよいでしょう。今回は共有ディスクを使いましたが、お金が無ければMySQL+Heartbeat+DRBDとか。

しかし落とし穴が...

ただ、先ほどの構成では大きな落とし穴がありました。問題はLuceneインデックスの共有方式をデータベースとしているところでした。

Liferayでは各種情報(ユーザ情報、Wikiコンテンツのデータなどなど)をLuceneのインデックスとして保存し、検索に使用しています。なので、HA構成だと複数ノードからLuceneのインデックスを共有する必要があります。

Lucene単体ではファイルシステムを使ったインデックス方式しか持っていません。そこでLiferayでは、CompassというOSSLuceneラッパーを利用しています。CompassLuceneのインタフェースを拡張し、インデックスファイルをデータベースに保存できるような機能をもっています。Liferayの設定ファイル(portal-ext.propertiesなど)で下記のようにfileからjdbcに変更すればこの機能は働きます。

#lucene.store.type=file
lucene.store.type=jdbc
lucene.store.jdbc.auto.clean.up=true

ただ、この機能を検証してみて分かりましたが大きな欠点があります。

  • パフォーマンスが悪い
    • ファイルをデータベースにすることでかなりパフォーマンスが落ちます。環境によるかと思いますが、大量にインデックスデータがあると数十倍は遅くなります。
  • そもそも不安定
    • Compassの問題というよりLiferayのLuceneを使っているところが怪しいです。きちんと排他制御できていないようで、HA構成で同時にインデックス更新を行うとあっさりインデックス更新でコケてくれます(>_<) いずれLiferayのJIRAに登録しようと思いますがこれではとても使い物になりません。

Liferayのフォーラムでも、「using JDBC is both too slow and still unreliable」と書かれています。また、このフォーラムではCluster linkというLiferay6からある機能を参照してねと返信が書かれていました。

Cluster linkは、Luceneのインデックスはファイルに保存するのですが、クラスタ間ではJGroupsを使って更新情報を受け取り、ファイルに反映させる機能のようです。Liferay6からLPS-445で追加された模様。ただ、1台Liferayがダウンしてしまうと、その間にもう1台で更新されたインデックス情報を反映させる方法が現状無いように見えます。なので、Cluster linkで全て解決というわけでもなさそう。

じゃあLuceneのインデックスの共有はどうするの?

データベースの共有も駄目、Cluster linkも完璧ではないとすると、Luceneインデックスの共有はどう実現すれば良いのか。

正直ここは答えが出ていません。今回はマシンが用意できず試せませんでしたが、NFSLuceneインデックスファイルを共有する方式もあるようです。ただ、こことか見るとこれも不安になってきます。

また、IndexWriter、IndexReaderというLiferayのインデックス処理クラスをごそっと入れ替えてSolr連携させるという方法もあるようです。Solr連携ができるのであれば、そちらでインデックスのレプリケーションを行うことが可能です。信頼性としてはそちらの方が高そうな感じです。

あたりに情報があるので、是非誰か検証して欲しいところ。

ちなみに実際のプロジェクトでは、Luceneでインデックスは大量に作成しないという制限付きの物でしたので、データベース方式のままにしています。インデックス更新がほとんどないのであれば、割り切ってデータベース方式でもよいかも。ただ、ポータルの使い方をかなり制限するので通常は難しいとは思いますが。。。

まとめ

  • LiferayのHA構成を決める上で、いくつか方式を選択すべきポイントがあります。ここは検証にかけられるお金や納期、リスクなどを考慮した上で選択する必要があります。
  • Luceneインデックスのクラスタ間共有でベストな方法は現状なさそう。Liferay6ならCluster linkで共有し、障害時にはインデックス再作成を行うような運用を別途考える必要がありそうです。Liferay5なら選択肢がデータベースとNFSくらいしかなくかなり厳しいのが現状です。