CLOVER🍀

That was when it all began.

InfinispanとHazelcastを、memcachedサーバとして使う

ちょっとした好奇心で。

memcachedって実は使ったことがないのですが、InfinispanとHazelcastはmemcachedサーバとして使えるのでこれをちょっと試してみようと思います。Infinispanの方はtelnetで試したことはありますが、ここはJava系のクライアントで使ってみます。

クライアントには、spymemcachedを選びました。

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

サンプル
http://code.google.com/p/spymemcached/wiki/Examples

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

JavadocはなんかCouchbaseの方に統合されていたっぽいので、正しいバージョンがどれなのかはよくわかりません。

とりあえず、Maven Centralで確認するとspymemcachedの現時点での最新バージョンは2.10.1のようです。

build.sbt

name := "memcached-client"

version := "0.0.1-SNAPSHOT"

scalaVersion := "2.10.3"

organization := "littlewings"

libraryDependencies += "net.spy" % "spymemcached" % "2.10.1"

サンプルプログラム。
src/main/scala/SimpleMemcachedClient.scala

import java.net.InetSocketAddress

import net.spy.memcached.{AddrUtil, BinaryConnectionFactory, MemcachedClient}

object SimpleMemcachedClient {
  def main(args: Array[String]): Unit = {
    val client = new MemcachedClient(new InetSocketAddress("localhost", 11211))

    try {
      for (i <- 1 to 10)
      client.set(s"key$i", 3, s"value$i")  // Expireは3秒

      for (i <- 1 to 10)
        require(client.get(s"key$i") == s"value$i")

      // 5秒間待機
      println("Sleeping...")
      Thread.sleep(5 * 1000L)

      for (i <- 1 to 10)
        require(client.get(s"key$i") == null)  // 5秒後は、すべてExpire済み
    } finally {
      client.shutdown()
    }
  }
}

バイナリプロトコルとか試してみたのですが、いろいろあって結局この程度になりました。Expireを3秒で10個の要素を入れて、最初に取り出してスリープ入れて、要素がなくなったことを確認するプログラムです。

では、memcachedサーバを用意します。

Infinispan

オフィシャルサイトから、Server用のモジュールをダウンロードします。

http://infinispan.org/download/

現時点での最新安定版は、5.3.0.Finalです。

適当な場所に展開して

$ unzip infinispan-server-5.3.0.Final-bin.zip

今回はクラスタリングはしないので、スタンドアロンで起動。

$ infinispan-server-5.3.0.Final/bin/standalone.sh

起動時のログをよくよく見ると、

23:54:43,991 INFO  [org.jboss.as.clustering.infinispan] (MSC service thread 1-4) JBAS010281: Started memcachedCache cache from local container

とか

23:54:44,059 INFO  [org.infinispan.server.endpoint] (MSC service thread 1-4) JDGS010000: MemcachedServer starting
23:54:44,066 INFO  [org.infinispan.server.endpoint] (MSC service thread 1-4) JDGS010001: MemcachedServer listening on 127.0.0.1:11211

とか言われていて、memcachedとして起動しているコンテナがあることが確認できます。

では先ほどのプログラムを実行。

> run
[info] Running SimpleMemcachedClient 
2013-10-17 23:57:44.000 INFO net.spy.memcached.MemcachedConnection:  Added {QA sa=localhost/127.0.0.1:11211, #Rops=0, #Wops=0, #iq=0, topRop=null, topWop=null, toWrite=0, interested=0} to connect queue
2013-10-17 23:57:44.006 INFO net.spy.memcached.MemcachedConnection:  Connection state changed for sun.nio.ch.SelectionKeyImpl@1f399537
Sleeping...
2013-10-17 23:57:49.092 INFO net.spy.memcached.MemcachedConnection:  Shut down memcached client
[success] Total time: 5 s, completed 2013/10/17 23:57:49

requireで確認しているので、結果が特に表示されませんが…一応、ちゃんと動作しています。

Hazelcast

続いて、Hazelcast。こちらはInfinispanと違ってServer用のモジュールなどないので、簡単なプログラムを作成します。

memcached_server.clj

(require '[leiningen.exec :as exec])

(exec/deps '[[com.hazelcast/hazelcast "3.1"]])

(ns hazelcast-memcached
  (:import (com.hazelcast.config Config NetworkConfig)
           (com.hazelcast.core Hazelcast HazelcastInstance)))

(try
  (let [^Config config (. (Config.)
                          setNetworkConfig
                          (. (NetworkConfig.) setPort 11211))
        ^HazelcastInstance hazelcast (Hazelcast/newHazelcastInstance config)]
    (println "Server Startup.")
    ;; Enter待ち
    (read-line)

    ;; HazelcastInstanceをシャットダウン
    (.. hazelcast getLifecycleService shutdown))

  ;; 全Hazelcastインスタンスをシャットダウン
  (finally (Hazelcast/shutdownAll)))

めっちゃ簡単なプログラムです。Enterキーを入力するか、シグナル等で止めてしまうまで浮いたままのサーバとなります。

が、ポートをInfinispanの時と合わせるために、リッスンポートを変更しています。

  (let [^Config config (. (Config.)
                          setNetworkConfig
                          (. (NetworkConfig.) setPort 11211))

デフォルトポートは、5701ですので。

では、起動。lein-execプラグインを使用しています。

$ lein exec memcached_server.clj 
10 18, 2013 12:00:38 午前 com.hazelcast.instance.DefaultAddressPicker
情報: Prefer IPv4 stack is true.
10 18, 2013 12:00:38 午前 com.hazelcast.instance.DefaultAddressPicker
情報: Picked Address[192.168.129.128]:11211, using socket ServerSocket[addr=/0:0:0:0:0:0:0:0,localport=11211], bind any local is true
10 18, 2013 12:00:38 午前 com.hazelcast.system
情報: [192.168.129.128]:11211 [dev] Hazelcast Community Edition 3.1 (20131011) starting at Address[192.168.129.128]:11211
10 18, 2013 12:00:38 午前 com.hazelcast.system
情報: [192.168.129.128]:11211 [dev] Copyright (C) 2008-2013 Hazelcast.com
10 18, 2013 12:00:38 午前 com.hazelcast.instance.Node
情報: [192.168.129.128]:11211 [dev] Creating MulticastJoiner
10 18, 2013 12:00:38 午前 com.hazelcast.core.LifecycleService
情報: [192.168.129.128]:11211 [dev] Address[192.168.129.128]:11211 is STARTING
10 18, 2013 12:00:43 午前 com.hazelcast.cluster.MulticastJoiner
情報: [192.168.129.128]:11211 [dev] 


Members [1] {
	Member [192.168.129.128]:11211 this
}

10 18, 2013 12:00:43 午前 com.hazelcast.core.LifecycleService
情報: [192.168.129.128]:11211 [dev] Address[192.168.129.128]:11211 is STARTED
Server Startup.

先ほどのspymemcachedを使ったプログラムも、同様に動作させることができます。

> run
[info] Running SimpleMemcachedClient 
2013-10-18 00:01:19.537 INFO net.spy.memcached.MemcachedConnection:  Added {QA sa=localhost/127.0.0.1:11211, #Rops=0, #Wops=0, #iq=0, topRop=null, topWop=null, toWrite=0, interested=0} to connect queue
2013-10-18 00:01:19.545 INFO net.spy.memcached.MemcachedConnection:  Connection state changed for sun.nio.ch.SelectionKeyImpl@58cc0b23
Sleeping...
2013-10-18 00:01:24.781 INFO net.spy.memcached.MemcachedConnection:  Shut down memcached client
[success] Total time: 5 s, completed 2013/10/18 0:01:24

ホントに、ちょっと使ってみました的なネタでした。

InfinispanやHazelcastのようなデータグリッドを使うと、分散できたり永続化できたりしていろいろ便利?でもまあ、実際にリモートアクセスするならInfinispanならHot Rod使うでしょうし、HazelcastならNative Client使いますよねー。