第5回 Solr4でレプリケーションを構築する

2013-12-28

Solr4を動かしてみるシリーズの5回目です。

今回はSolr4でmaster-slaveの単純レプリケーションを構築したいと思います。

master_slave

レプリケーションの構成にはReplicationHandlerを使います。
coreのインスタンスディレクトリ下のconf内にあるsolrconfig.xmlを開くと、レプリケーション構成のテンプレートが記述してあり、この部分のコメントを外して必要な項目を設定すればレプリケーション完了なのです(`_´)ゞ

非常にかんたんです。

レプリケーションを構築するにあたっては何はともあれ、MasterSlaveの2サーバが必要です。
ここから先は、Master用のサーバとSlave用のサーバの2つがあると仮定して話をすすめます。

5.1. Masterの設定をおこなう

まずはMaster側の設定から行いましょう。
Masterサーバのsolrconfig.xmlを開きます。
こんなふうにReplicationの設定がコメントアウトされています。

  <!-- Solr Replication

       The SolrReplicationHandler supports replicating indexes from a
       "master" used for indexing and "slaves" used for queries.

       http://wiki.apache.org/solr/SolrReplication

       It is also necessary for SolrCloud to function (in Cloud mode, the
       replication handler is used to bulk transfer segments when nodes
       are added or need to recover).

       https://wiki.apache.org/solr/SolrCloud/
    -->
  <requestHandler name="/replication" class="solr.ReplicationHandler" >
    <!--
       To enable simple master/slave replication, uncomment one of the
       sections below, depending on whether this solr instance should be
       the "master" or a "slave".  If this instance is a "slave" you will
       also need to fill in the masterUrl to point to a real machine.
    -->
    <!--
       <lst name="master">
         <str name="replicateAfter">commit</str>
         <str name="replicateAfter">startup</str>
         <str name="confFiles">schema.xml,stopwords.txt</str>
       </lst>
    -->
    <!--
       <lst name="slave">
         <str name="masterUrl">http://your-master-hostname:8983/solr</str>
         <str name="pollInterval">00:00:60</str>
       </lst>
    -->
  </requestHandler>

これをこんなふうに変更します。

  <requestHandler name="/replication" class="solr.ReplicationHandler" >
    <!-- コメント外します。 -->
       <lst name="master">
         <str name="enable">true</str>
         <str name="replicateAfter">commit</str>
         <str name="replicateAfter">startup</str>
         <str name="confFiles">schema.xml,stopwords.txt,elevate.xml</str>
         <str name="commitReserveDuration">00:00:10</str>
       </lst>

    <!-- slaveの設定は削除しちゃいます。 -->

    <!-- バックアップファイルの数を指定しました。 -->
    <str name="maxNumberOfBackups">1</str>
  </requestHandler>

設定内容について、詳しくはhttp://wiki.apache.org/solr/SolrReplicationを見ろということですが、
ざっくり解説します。

# 項目 内容 備考
1 enable Masterとして有効かどうかを指定します。 true/false falseを指定すると、Masterサーバとしては動きません。
2 replicateAfter レプリケーションを行うトリガーとなるアクションを指定します。commitを指定するとコミット時にslaveにインデックスが同期されます。
startupのみを指定すると、起動時にしかレプリケーションを行わないので、実質レプリケーションとなりません^^;
commit commit: コミット時、startup: 起動時、optimize: 最適化時の1つ以上を指定します。
3 confFiles slaveに同期する設定ファイルを指定します。サーバの設定以外に、ユーザディクショナリ系のファイルも指定した方がよいでしょう。 schema.xml,stopwords.txt カンマ区切りで複数指定できます。slave用のsolrconfig.xmlを別名で保存しておき、slaveにはsolrconfig.xmlとして同期することもできます。

<str name=”confFiles”>
solrconfig_slave.xml:solrconfig.xml,x.xml</str>

4 commitReserveDuration 指定がない場合デフォルト値の10secが使われます。おおよそ5MBを転送できる時間。 00:00:10 コミット量が多かったり、ネットワーク速度が遅い場合に指定しろと・・・
5 backupAfter バックアップを行うトリガーとなるアクションを指定します。
レプリケーションの機能として必要なわけではありません。
commit commit: コミット時、startup: 起動時、optimize: 最適化時の1つ以上を指定します。
6 maxNumberOfBackups バックアップを作成する場合に、保持するバックアップファイルの数を指定します。 2 Solr3.6系ではバグがあったようです。https://issues.apache.org/jira/browse/SOLR-3361

solrconfig.xmlを編集したら、Solrを再起動してに設定を反映させましょう。

service solr restart

5.2. Slaveの設定をおこなう

つづいて**Slave**側の設定も行いましょう。
Slaveサーバのsolrconfig.xmlを開きます。

  <requestHandler name="/replication" class="solr.ReplicationHandler" >

    <!-- masterの設定は削除しちゃいます。 -->

      <lst name="slave">
         <str name="enable">true</str>
         <str name="masterUrl">http://master_host:port/solr/corename</str>
         <str name="pollInterval">00:00:20</str>
         <str name="compression">internal</str>
         <str name="httpConnTimeout">5000</str>
         <str name="httpReadTimeout">10000</str>
         <!--
         <str name="httpBasicAuthUser">username</str>
         <str name="httpBasicAuthPassword">password</str>
         -->
      </lst>

    <!-- バックアップファイルの数を指定しました。 -->
    <str name="maxNumberOfBackups">1</str>
  </requestHandler>

Masterの設定項目と全然ちがいます。
(あたりまえですが・・)

Slaveの設定項目もざっくり解説します。

# 項目 内容 備考
1 enable Slaveとして有効かどうかを指定します。 true/false falseを指定すると、Slaveサーバとしては動きません。
1 masterUrl MasterサーバのURLを指定します。 http://master.solr.local:8983/solr/core0 つまり、httpプロトコルで疎通するということです。
2 pollInterval masterにポーリングする間隔をHH:mm:ss形式で指定します。 00:00:20 pollIntervalを指定しなかった場合、自動でのポーリングは行いません。
管理ツールから同期させるとかHTTP APIを叩くとかでmasterとの同期を行う必要があります。
3 compression インデックスファイルの転送時に圧縮を行いたい場合に指定します。 internal ‘internal'(slave側で圧縮)と’external'(master側で圧縮)を指定できますが、’external’を指定した場合にはmasterサーバの方でaccept-encodingヘッダの設定が必要となります。
4 httpConnTimeout masterサーバからインデックスファイルを取得する際のコネクションタイムアウトを指定します。 5000 ミリ秒で指定します。デフォルト値は5,000msです。特に指定する必要はありません(と書いてありました)。
5 httpReadTimeout masterサーバからインデックスファイルを取得する際のリードタイムアウトを指定します。 10000 ミリ秒で指定します。デフォルト値は10,000msです。ここも特に指定する必要はありません(と書いてありました)。
6 httpBasicAuthUser masterサーバでBasic認証を行っている場合にBasic認証ユーザを指定します。 solr-repl
7 httpBasicAuthPassword masterサーバでBasic認証を行っている場合にBasic認証パスワードを指定します。 password

Slaveサーバも、solrconfig.xmlを編集したら、Solrを再起動してに設定を反映させましょう。

service solr restart

5.3. 管理ツールから確認する

レプリケーションの設定は以上で完了です。
管理ツールで見てみましょう。

Master

管理ツールでコアを選択します(私の設定ではcore0)。
コアを選択したら次にReplicationを選択します。
Masterに設定した内容を確認することができます。

solr_repl_master

Slave

Slaveの管理ツールも開いてみます。
SlaveのmasterUrlに存在しないサーバを指定したので「Invalid Server」となってしまいました。
正しく疎通ができればMasterの管理ツールのようにenabledになります。

solr_repl_slave

5.4. Master-Slaveで共通のsolrconfig.xmlを使うための工夫

solrconfig.xmlのレプリケーション設定をpropertyファイルに委譲して、Master-Slaveで共通のsolrconfig.xmlを使うことにしましょう。
こうすることで、masterが死んだときにすばやくslaveをmasterに昇格できたり、後で記述するRepeaterの役割をさせたりすることができます。

5.4.1. solrconfig.xmlのReplicationHandlerにパラメータを設定する

solrconfig.xmlを編集します。
ReplicationHandlerにMasterの項目とSlaveの項目両方を記述し、さらに値をパラメータ化します。

  <requestHandler name="/replication" class="solr.ReplicationHandler" >
    <!-- master向けの設定 -->
       <lst name="master">
         <str name="enable">${master.enable}</str>
         <str name="replicateAfter">${master.replicateAfter1}</str>
         <str name="replicateAfter">${master.replicateAfter2}</str>
         <str name="confFiles">${master.confFiles}</str>
         <str name="commitReserveDuration">${master.commitReserveDuration}</str>
       </lst>

    <!-- slave向けの設定 -->
      <lst name="slave">
         <str name="enable">${slave.enable}</str>
         <str name="masterUrl">${slave.masterUrl}</str>
         <str name="pollInterval">${slave.pollInterval}</str>
         <str name="compression">${slave.compression}</str>
         <str name="httpConnTimeout">${slave.httpConnTimeout}</str>
         <str name="httpReadTimeout">${slave.httpReadTimeout}</str>
      </lst>

    <!-- バックアップファイルの数を指定しました。 -->
    <str name="maxNumberOfBackups">${maxNumberOfBackups}</str>
  </requestHandler>

5.4.2. プロパティファイルを作成する

Master向けのプロパティファイルとSlave向けのプロパティファイルを作成します。

confの下にmaster.propertiesとslave.propertiesを作成します。

master.properties

# masterの設定
master.enable=true  # master向けの設定なのでtrueを指定します。
master.replicateAfter1=commit
master.replicateAfter2=startup
master.confFiles=schema.xml,stopwords.txt,elevate.xml
master.commitReserveDuration=00:00:10

# slaveの設定
slave.enable=false  # slave.enableにはfalseを指定します。
slave.masterUrl=http://master_host:port/solr/corename
slave.pollInterval=00:00:20
slave.compression=internal
slave.httpConnTimeout=5000
slave.httpReadTimeout=10000

slave.properties

# masterの設定
master.enable=false  # slave向けの設定なのでfalseを指定します。
master.replicateAfter1=commit
master.replicateAfter2=startup
master.confFiles=schema.xml,stopwords.txt,elevate.xml
master.commitReserveDuration=00:00:10

# slaveの設定
slave.enable=false  # slave向けの設定なのでtrueを指定します。
slave.masterUrl=http://master_host:port/solr/corename
slave.pollInterval=00:00:20
slave.compression=internal
slave.httpConnTimeout=5000
slave.httpReadTimeout=10000

で、Solrの起動時にプロパティファイルとしてこれらを指定します。

第1回目で/etc/default/jettyにJAVA_OPTIONSを設定しました。
つまり私の環境では、Solr起動時のJVMパラメータは/etc/default/jettyに記述するようになっています。
このJAVA_OPTIONS変数にプロパティファイルの指定を追加します。

/etc/default/jetty(Master向けの設定)

SOLR_OPTIONS="-Dsolr.solr.home=/opt/solr/server/solr -Dsolr.properties=master.properties"  # 追加しました
JAVA_HOME=/etc/alternatives/java_sdk
JAVA_OPTIONS="-Djava.awt.headless=true -server -XX:+UseGCOverheadLimit -XX:+UseConcMarkSweepGC -XX:+CMSIncrementalMode -XX:+UseTLAB -XX:MaxPermSize=128m -Xms512M -Xmx1024M $JAVA_OPTIONS $SOLR_OPTIONS"  # **$SOLR_OPTIONS**を追加しました。
JETTY_HOME=/opt/solr/server
JETTY_USER=root
JETTY_PORT=8983
JETTY_LOGS=/var/log/solr

/etc/default/jetty(Slave向けの設定)

SOLR_OPTIONS="-Dsolr.solr.home=/opt/solr/server/solr -Dsolr.properties=slave.properties"  # 追加しました
JAVA_HOME=/etc/alternatives/java_sdk
JAVA_OPTIONS="-Djava.awt.headless=true -server -XX:+UseGCOverheadLimit -XX:+UseConcMarkSweepGC -XX:+CMSIncrementalMode -XX:+UseTLAB -XX:MaxPermSize=128m -Xms512M -Xmx1024M $JAVA_OPTIONS $SOLR_OPTIONS"  # **$SOLR_OPTIONS**を追加しました。
JETTY_HOME=/opt/solr/server
JETTY_USER=root
JETTY_PORT=8983
JETTY_LOGS=/var/log/solr

Master, SlaveともにSolrを再起動します。

5.5. Repeaterを使う

SolrにはRepeaterという仕組みがあります。
Repeaterとは何かといいますと、その名の通り中継機の役割をします。
Masterサーバに対してはSlaveとして振る舞うことができ、Slaveサーバに対してはMasterサーバとして振る舞うことができます。

1台のMasterに対してたくさんのSlaveがいるケースや、MasterとSlaveの拠点間が物理的に遠い場合を想像してみてください。結構なネットワーク負荷がかかってしまいます。
そんなときにこのRepeaterサーバを設置します。

master_many_slaves

1台のmasterでたくさんのslaveの相手をしなくてはならない・

 

真のMasterと通信を行うのはRepeater、SlaveはRepeaterのみと通信を行うことでMasterにかかる負荷を低減することができます。

repeater

repeaterを追加して解決

 

あるサーバをRepeaterサーバとするには、solrconfig.xmlのReplicationHandlerに、Masterとしての設定とSlaveとしての設定の両方を記述します。

Repeaterのsolrconfig.xml

  <requestHandler name="/replication" class="solr.ReplicationHandler" >
    <!-- masterとしての設定 -->
       <lst name="master">
         <str name="enable">${master.enable}</str>
         <str name="replicateAfter">${master.replicateAfter1}</str>
         <str name="replicateAfter">${master.replicateAfter2}</str>
         <str name="confFiles">${master.confFiles}</str>
         <str name="commitReserveDuration">${master.commitReserveDuration}</str>
       </lst>

    <!-- slaveとしての設定 -->
      <lst name="slave">
         <str name="enable">${slave.enable}</str>
         <str name="masterUrl">${slave.masterUrl}</str>
         <str name="pollInterval">${slave.pollInterval}</str>
         <str name="compression">${slave.compression}</str>
         <str name="httpConnTimeout">${slave.httpConnTimeout}</str>
         <str name="httpReadTimeout">${slave.httpReadTimeout}</str>
      </lst>

    <!-- バックアップファイルの数を指定しました。 -->
    <str name="maxNumberOfBackups">${maxNumberOfBackups}</str>
  </requestHandler>

Repeaterのプロパティファイル( repeater.properties )

# masterとしての設定
master.enable=true  # repeaterなのでmasterもslaveもtrueにします。
master.replicateAfter1=commit
master.replicateAfter2=startup
master.confFiles=schema.xml,stopwords.txt,elevate.xml
master.commitReserveDuration=00:00:10

# slaveの設定
slave.enable=true  # repeaterなのでmasterもslaveもtrueにします。
slave.masterUrl=http://master_host:port/solr/corename
slave.pollInterval=00:00:20
slave.compression=internal
slave.httpConnTimeout=5000
slave.httpReadTimeout=10000

こちらも再起動して内容を反映させます。

以上でSolr4のレプリケーション設定についておしまいです。