Liferayによるマルチキャストクラスタリングがうまくいかない場合の調査方法
Liferayが内部で使用しているEHCache,Luceneなどのクラスタリングは、マルチキャストにより実装されています。
マルチキャストで実装することにより、自ホスト以外のサーバ台数や接続情報を気にすることなく、新たなサーバをクラスタに追加させることができます。
しかし、単純にLiferayのクラスタリング設定をするだけではうまくいかないことが多く調査に手間取ったたため、調査方法をメモします。
環境
現象
2台のLiferay(host1, host2)でクラスタリング設定をしてみましたが、"host1→host2の通信はうまくいくがhost2→host1の通信に失敗する"という現象が発生しました。
調査1:グループアドレス・ポートの設定を見直し
マルチキャストでは、全ホストで同じグループアドレス・ポートを指定する必要があります。
Liferayの標準では下記の設定となっていますが、私の環境では変更していたため全ホストで確認を行いました。
${liferay.home}/portal-ext.properties:
#
# See the property "cluster.link.channel.properties.control".
#
multicast.group.address["cluster-link-control"]=233.0.0.1
multicast.group.port["cluster-link-control"]=23301#
# See the properties "cluster.link.channel.properties.transport.0" and
# "cluster.link.channel.system.properties".
#
multicast.group.address["cluster-link-udp"]=233.0.0.2
multicast.group.port["cluster-link-udp"]=23302#
# See the property "cluster.link.channel.system.properties".
#
multicast.group.address["cluster-link-mping"]=233.0.0.3
multicast.group.port["cluster-link-mping"]=23303#
# See the properties "net.sf.ehcache.configurationResourceName" and
# "net.sf.ehcache.configurationResourceName.peerProviderProperties".
#
multicast.group.address["hibernate"]=233.0.0.4
multicast.group.port["hibernate"]=23304#
# See the properties "ehcache.multi.vm.config.location" and
# "ehcache.multi.vm.config.location.peerProviderProperties".
#
multicast.group.address["multi-vm"]=233.0.0.5
multicast.group.port["multi-vm"]=23305
調査2: マルチキャストが有効であるか
使用しているOSでマルチキャスト通信ができるか調査するために、Javaでマルチキャスト通信用のクラスを作成して通信の確認を行いました。
作成したMulticastNodeクラスをjar化して、調査対象のホストでそれぞれ実行しました。
MulticastNode.java:
package com.example.multicast;import java.io.IOException;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.MulticastSocket;public class MulticastNode {
private static final String ADDRESS = "228.0.0.4";
private static final int PORT = 60000;
private InetAddress group;
private MulticastSocket sock;public static void main(String args) throws IOException {
if (args.length == 0) {
System.out.println("Need an argument string to send.");
System.exit(1);
}String msg = args[0];
System.out.printf("Sending message: %s\n", msg);
MulticastNode node = new MulticastNode();
node.send(msg);
node.receive();
}public MulticastNode() throws IOException {
group = InetAddress.getByName(ADDRESS);
sock = new MulticastSocket(PORT);
sock.joinGroup(group);
}public void send(String msg) throws IOException {
DatagramPacket hi = new DatagramPacket(msg.getBytes(),
msg.length(),
group,
PORT);
sock.send(hi);
}public void receive() throws IOException {
byte buf;while (true) {
buf = new byte[1024];
DatagramPacket recv = new DatagramPacket(buf, buf.length);
sock.receive(recv);
System.out.printf("Received: %s\n", new String(buf));
}
}
}
実行コマンド:
$ java -jar multicast.jar `hostname`
調査対象の全ホストの標準出力に各ホストからのメッセージが出力されていることが確認できたため、マルチキャスト通信は正常に行なえていると判断しました。
調査3:名前解決はできているか
Liferayではマルチキャストのグループアドレスに参加する場合、他ホストから自ホストへの接続方法にhostnameを使用するようです。
つまり、hostnameはクラスタ内の全ホストで名前解決できる名称でないとうまく動作しません。
/etc/sysconfig/network:
NETWORKING=yes
HOSTNAME=host1.example.com
GATEWAY=xxx.xxx.xxx.xx
調査4:UDP通信
tcpdumpでUDP通信を調べてみました。
すると表示されているホスト名に、他のホストでは解決できないホスト名が含まれていました。
$ sudo tcpdump -i eth0 port 23305 -vv
原因
原因は、名前解決できないホスト名をhostnameに設定してあるホストで、ホスト名の名前解決にhostsを使用していたことでした。
これにより、"host1ではhost1の名前解決ができるが、host2ではhost1の名前解決ができない"という症状になっていました。
対策
hostsのホスト名を削除して、全ホストから名前解決できるhostnameに変更するとうまく動作しました。
# 名前解決できれば問題ないので、クラスタにある全ホストのhostsにそれぞれのホストのIPアドレスを書いても動作しました。