CLOVER🍀

That was when it all began.

Apache GeodeをMemcached/Redisサーバーとして使う

さらさらとApache Geodeのソースツリーやドキュメントを眺めていて、Apache GeodeMemcachedやRedisとしても使えそうだったので、試してみました。

Moving from memcached to gemcached - Geode - Apache Software Foundation

Geode Redis Adapter - Geode - Apache Software Foundation

「gemcached」、ときましたか…。

RedisAdapterは、GemFireの頃にはなかったのかな?

今回、Apache Geode 1.0.0-incubating.M1を使って、これらの機能を動かしてみます。

gemcached

Server起動時に、以下のようなオプションを付けてあげればMemcachedとして使えるようになります。
※Locatorは起動済みとします

gfsh>start server --name=server --memcached-port=11211 --memcached-bind-address=localhost --memcached-protocol=BINARY

memcached-bind-address」は付けなくてもいいんですが、デフォルトだとそのホストのIPアドレスでリッスンしようとするので、localhostとかでつなげたければ明示してあげる必要があります。

ASCII、BINARYプロトコル、両方対応してるみたいですね。すごい。

「gemcached」というRegionにデータが保存されるようなので、細かく設定する場合はキャッシュの設定ファイル用意するっぽい感じです。
https://github.com/apache/incubator-geode/blob/rel/v1.0.0-incubating.M1/gemfire-core/src/main/java/com/gemstone/gemfire/memcached/GemFireMemcachedServer.java#L76

GeodeをMemcachedサーバーとして使うことで、通常のMemcachedとは異なり「cache-aside」、「write-through」が使えたり、可用性を高められることが利点みたいです。

とりあえず、クライアント側のサンプルも書いてみます。

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

spymemcached、あとはJUnitとAssertJを利用します。

確認コード。
src/test/java/org/littlewings/geode/GeodeMemcachedTest.java

package org.littlewings.geode;

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

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

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

public class GeodeMemcachedTest {
    @Test
    public void test() throws IOException, InterruptedException {
        MemcachedClient client = null;

        try {
            client = new MemcachedClient(new BinaryConnectionFactory(),
                    AddrUtil.getAddresses("localhost:11211"));

            client.set("key1", 5, "value1");

            assertThat(client.get("key1"))
                    .isEqualTo("value1");

            TimeUnit.SECONDS.sleep(5);

            assertThat(client.get("key1"))
                    .isNull();
        } finally {
            if (client != null) {
                client.shutdown();
            }
        }
    }
}

OKそうですね。

Redis Adapter

続いて、Redisとして使ってみます。Serverを、こんな感じで起動。
※Locatorは起動済みとします

gfsh>start server --name=server --redis-port=6379 --redis-bind-address=localhost

「redis-bind-address」にlocalhostを指定しているのは、Memcachedの時と同じ理由です。

サポートしているコマンドはWikiに書いてあるので、こちらを読みましょう。
https://cwiki.apache.org/confluence/display/GEODE/Geode+Redis+Adapter

Redis Adapterが利用するRegionは…なんかすごい名前な気がします。
https://github.com/apache/incubator-geode/blob/rel/v1.0.0-incubating.M1/gemfire-core/src/main/java/com/gemstone/gemfire/redis/GemFireRedisServer.java#L223-L239

では、動作確認してみます。Maven依存関係。

        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
            <version>2.8.0</version>
        </dependency>

Jedisを使います。

確認コード。
src/test/java/org/littlewings/geode/GeodeRedisTest.java

package org.littlewings.geode;

import java.util.HashMap;
import java.util.Map;

import org.junit.Test;
import redis.clients.jedis.Jedis;

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

public class GeodeRedisTest {
    @Test
    public void test() {
        try (Jedis jedis = new Jedis("localhost", 6379, 10 * 000)) {
            jedis.set("key1", "value1");
            assertThat(jedis.get("key1"))
                    .isEqualTo("value1");

            jedis.lpush("lkey1", "lvalue1", "lvalue2");
            assertThat(jedis.lpop("lkey1"))
                    .isEqualTo("lvalue2");
            assertThat(jedis.lpop("lkey1"))
                    .isEqualTo("lvalue1");

            jedis.sadd("skey1", "svalue1", "svalue2");
            assertThat(jedis.scard("skey1"))
                    .isEqualTo(2L);

            jedis.zadd("zkey1", 1.0, "zvalue1");
            jedis.zadd("zkey1", 2.0, "zvalue2");
            assertThat(jedis.zcard("zkey1"))
                    .isEqualTo(2L);

            Map<String, String> data = new HashMap<>();
            data.put("key1", "value1");
            data.put("key2", "value2");
            jedis.hmset("hmkey1", data);
            assertThat(jedis.hgetAll("hmkey1"))
                    .isEqualTo(data);
        }
    }
}

うちの環境だとちょっと時間がかかることがあり(特に起動直後)ReadTimeoutすることがあったので、ソケットのタイムアウトを伸ばしています…。

動作自体は、この範囲だと普通に使えそうな感じで。

まとめ

とりあえず、本線の機能でもないのに気になったので試してみた感じです。これ、たぶん組み込みでも使えるんだろうなぁと思うのですが、それはまたの機会に。