CLOVER🍀

That was when it all began.

Payara Microに実は(分散)Memcached Serverが混じってたり

単なるネタです。別に活用しようとか、そういうわけではないです。いつ使えなくなるとも限りませんし。

HazelcastがPayaraに同梱されていることと、設定まわりの実装を見ているとこの機能はオフにされていなさそうだったので。

Hazelcastには、Memcachedプロトコルを話す機能があります。

Memcache Client
http://docs.hazelcast.org/docs/3.4/manual/html-single/hazelcast-documentation.html#memcache-client

インメモリ・データグリッドって、Memcachedプロトコルを使えるものがけっこう多いですよね。Memcachedプロトコルのうち、だいたいのものはテキストプロトコルのみのサポートですが、Apache Igniteは珍しくバイナリプロトコルのみのサポートだったり(Coherenceも?)。

Hazelcastは、テキストプロトコルのみのサポートです。ただ、クラスタ化ができるので、分散構成で利用することができます。

では、ちょっと試してみましょう。

Payara MicroでHazelcastクラスタを構成する

まずはPayara Microをダウンロードします。

Downloads
http://www.payara.co.uk/downloads

で、特に何もアプリケーションをデプロイせず、2つNodeを起動してみます。

## Node 1
$ java -jar payara-micro-4.1.152.1.jar

## Node 2
$ java -jar payara-micro-4.1.152.1.jar --port 8180

HTTPリッスンポートはNode 2でずらしました。

この時、Hazelcastの機能でクラスタが構成されますが

Members [2] {
	Member [192.168.254.129]:5900
	Member [192.168.254.129]:5901 this
}

ここで表示されるポートが、Memcachedとして使えるポートになります。

また、Payara Microの起動引数「--startPort」で変えることもできます。以下の例だと、7000ポートになります。

--startPort 7000

今回は、デフォルトと自動インクリメントの結果である、5900、5901ポートを使います。

アクセスしてみる

では、telnetを使って試してみましょう。

コマンドは

## データの保存
# set key,flag,expires,byte
# value

## データの取得
# get

なので、まずはNode 1にデータの保存、取得。

$ telnet localhost 5900
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
set key1 0 120 6
value1
STORED
get key1
VALUE key1 0 6
value1
END
quit
Connection closed by foreign host.

有効期限は、120秒。

続いて、Node 2側でNode 1で保存したデータを読み出して、さらにデータを追加してみます。

$ telnet localhost 5901
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
get key1
VALUE key1 0 6
value1
END
set key2 0 120 6
value2
STORED
quit
Connection closed by foreign host.

Node 2で追加したデータを、Node 1で読み出してみます。

$ telnet localhost 5900
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
get key2
VALUE key2 0 6
value2
END
quit
Connection closed by foreign host.

OKそうですね。

Javaクライアントでも試してみましょう。

spymemcached
https://code.google.com/p/spymemcached/

Javadoc
http://www.couchbase.com/autodocs/couchbase-java-client-1.4.4/index.html

        <dependency>
            <groupId>net.spy</groupId>
            <artifactId>spymemcached</artifactId>
            <version>2.11.7</version>
        </dependency>

テストコード。データを登録して、別のNodeから読み出すようなコードになっています。

package org.littlewings.memcached;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.util.concurrent.TimeUnit;

import net.spy.memcached.MemcachedClient;
import org.junit.Test;

import static org.assertj.core.api.Assertions.assertThat;

public class MemcachedClientTest {
    @Test
    public void testSpyMemcachedClient() throws IOException, InterruptedException {
        MemcachedClient clientNode1 =
                new MemcachedClient(new InetSocketAddress("localhost", 5900));
        MemcachedClient clientNode2 =
                new MemcachedClient(new InetSocketAddress("localhost", 5901));


        clientNode1.set("key-from-node1", 5, "value-from-node1");
        clientNode2.set("key-from-node2", 5, "value-from-node2");

        TimeUnit.MILLISECONDS.sleep(100);  // たまに読み出しに失敗する…

        assertThat(clientNode1.get("key-from-node2"))
                .asString()
                .isEqualTo("value-from-node2");
        assertThat(clientNode2.get("key-from-node1"))
                .asString()
                .isEqualTo("value-from-node1");

        TimeUnit.SECONDS.sleep(5);

        assertThat(clientNode1.get("key-from-node1"))
                .isNull();
        assertThat(clientNode2.get("key-from-node2"))
                .isNull();

        clientNode1.shutdown();
        clientNode2.shutdown();
    }
}

こちらもOKです。が、データ登録後あまりもすぐに他Nodeにアクセスすると、たまにNGな時がありました…。

途中でNodeを減らしてみる

せっかくなので、Nodeを減らした時の挙動もみてみましょう。

まず、Node 1にデータ登録。

$ telnet localhost 5900
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
set key1 0 120 6
value1
STORED
set key2 0 120 6
value2
STORED
quit
Connection closed by foreign host.

Node 1をシャットダウンします。

当然、Node 2だけが残ります。

Members [1] {
	Member [192.168.254.129]:5901 this
}

この状態で、Node 2にアクセスすると

$ telnet localhost 5901
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
get key1
VALUE key1 0 6
value1
END
get key2
VALUE key2 0 6
value2
END
quit
Connection closed by foreign host.

Node 1で登録したデータを、失われずに見ることができます。

Hazelcast側で、バックアップも持っているので。

終わりに

Payara MicroにHazelcastが搭載されていることを利用して、Memcachedサーバーとして遊んでみました。

Payara MicroだとHazelcastクラスタの設定はほとんど触れないので有効なままですが、Payara ServerではHazelcastの設定ファイルが使えそうな雰囲気です。

そもそもこういう使い方を想定していないと思うので、いつ使えなくなるとも限りませんが、簡易Memcached的な扱いとして試してみるのも…?

同じ理屈で、Hazelcast Clientからも接続できそうですね、これ。