CLOVER🍀

That was when it all began.

Apache Geode(1.0.0-incubating.M1)ことはじめ

先日、Apache Geode 1.0.0-incubating.M1がリリースされました。

Apache Geode — Performance is key. Consistency is a must.

[ANNOUNCE] Apache Geode (incubating) release 1.0.0-incubating.M1

まだ1.0.0のM1という段階ではありますが、一応ディストリビューションのダウンロードなどもできるようになったので、試してみたいと思います。

Apache Geodeって?

Pivotal GemFireがOSSになったもの、という感じです。

Hello Geode: Pivotal GemFire is now open source | InfoWorld

Pivotal Releases “Geode” - The In-Memory Database Powering Pivotal GemFire | Press Release | Pivotal

Apache Geode自身のサイトは、こちら。

Apache Geode — Performance is key. Consistency is a must.

自分自身はGemFireは触ったことがないのですが、In Memory Data Gridの一種という位置づけで捉えればよさそうな感じですね。

説明としては、データを複数プロセスに跨って管理可能な、分散データ管理(主としてインメモリ)プラットフォームとなっています。

http://geode.docs.pivotal.io/docs/getting_started/geode_overview.html

主な機能は、こちらに記載があります。

http://geode.docs.pivotal.io/docs/getting_started/product_intro.html

  • Peer-to-Peer、Client/Serverによる構成をとることが可能
  • 分散システムに参加するメンバーを追加することで、スケール可能
  • キャッシュの同期/非同期更新
  • 低レイテンシによる非同期のイベント通知やメッセージ配送の保証
  • JTAサポート
  • クラスタの設定を、別のクラスタへ送ることができる
  • HTTPによるリモート管理
  • REST API
  • バージョンアップ時のRolling Upgrade

といったところ。

ソースパッケージとかドキュメントをさらっと見ている限りは、えらい物量の機能が出てきそうですが、とりあえず触りはこんなところで。

ドキュメントは、以下の2箇所から見ていくことになります。

Documentation
http://geode.docs.pivotal.io/

Wiki
Index - Geode - Apache Software Foundation

ただ、これだけではちょっと足りないので、現時点ではGemFireのものも必要に応じて参照した方がよいかもしれません。

Pivotal GemFire® Documentation | Pivotal GemFire Docs

Javadoc
GemFire Java API Documentation

それでは、使っていってみることにしましょう。

インストール

ここからは、Apache Geodeのインストールと、簡単なサンプルプログラムを書いて動作確認してみたいと思います。

このあたりを参考に。

Index - Geode - Apache Software Foundation

http://geode.docs.pivotal.io/docs/getting_started/15_minute_quickstart_gfsh.html

インストールの事前条件としては、JDK 8以上とJAVA_HOMEを設定してPATHを通しておくくらいです。

http://geode.docs.pivotal.io/docs/getting_started/system_requirements/host_machine.html

http://geode.docs.pivotal.io/docs/getting_started/installation/install_standalone.html

ただ、複数ホストで使う場合は、時刻同期と名前解決に気をつけてね、と。

では、進めます。

まずは、ディストリビューションをダウンロードします。

http://geode.incubator.apache.org/releases/

今回は、「apache-geode-1.0.0-incubating.M1.tar.gz」をダウンロードしました。展開。

$ tar -zxvf apache-geode-1.0.0-incubating.M1.tar.gz

インストールは、このくらいです。

サーバー側の用意

展開したディストリビューションのbinディレクトリにある、gfshというものを起動します。

$ apache-geode-1.0.0-incubating.M1/bin/gfsh
    _________________________     __
   / _____/ ______/ ______/ /____/ /
  / /  __/ /___  /_____  / _____  / 
 / /__/ / ____/  _____/ / /    / /  
/______/_/      /______/_/    /_/    v1.0.0-incubating.M1

Monitor and Manage GemFire
gfsh>

めっちゃGemFireって出ますね…。

ドキュメントに習い、LocatorとServerを開始します。

## Locatorを起動
gfsh>start locator --name=locator

## Serverを起動
gfsh>start server --name=server

この時、LocatorとServerは別プロセスで起動します。

続いて、Regionを作成します。
※ドキュメントからRegionの名前は変えていますが…

gfsh>create region --name=sampleRegion --type=REPLICATE
Member | Status
------ | ------------------------------------------
server | Region "/sampleRegion" created on "server"

ここまでで、サーバー側の準備はお終いです。

クライアント側のコードを書く

それでは、ここまでに用意したサーバーを利用するアプリケーションを書いてみます。

Maven依存関係には、以下のように設定します。
※JUnitとAssertJはテストコード用です

        <dependency>
            <groupId>org.apache.geode</groupId>
            <artifactId>gemfire-core</artifactId>
            <version>1.0.0-incubating.M1</version>
        </dependency>

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.assertj</groupId>
            <artifactId>assertj-core</artifactId>
            <version>3.3.0</version>
            <scope>test</scope>
        </dependency>

artifactId、「gemfire-core」なんですね…。

import文などは、こんな感じで用意しました。
src/test/java/org/littlewings/geode/ClientServerSimpleTest.java

package org.littlewings.geode;

import com.gemstone.gemfire.cache.Region;
import com.gemstone.gemfire.cache.RegionDestroyedException;
import com.gemstone.gemfire.cache.client.ClientCache;
import com.gemstone.gemfire.cache.client.ClientCacheFactory;
import com.gemstone.gemfire.cache.client.ClientRegionShortcut;
import com.gemstone.gemfire.cache.client.ServerOperationException;
import org.junit.Test;

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

public class ClientServerSimpleTest {
    // ここに、テストコードを書く!
}

まずは、Getting Startedに載っているようなサンプルを記載。

    @Test
    public void gettingStarted() {
        ClientCache cache =
                new ClientCacheFactory()
                        .addPoolLocator("localhost", 10334)  // デフォルト(localhost:10334)なら、書かなくてもOK
                        .create();

        try {
            Region<String, String> region =
                    cache
                            .<String, String>createClientRegionFactory(ClientRegionShortcut.CACHING_PROXY)
                            .create("sampleRegion");

            region.put("key1", "value1");
            assertThat(region.get("key1"))
                    .isEqualTo("value1");

            region.put("key2", "value2");
            assertThat(region.get("key2"))
                    .isEqualTo("value2");
            region.remove("key2");
            assertThat(region.get("key2"))
                    .isNull();

            assertThat(region.containsKey("key1"))
                    .isTrue();

            region.close();
        } finally {
            cache.close();
        }
    }

Regionがjava.util.ConcurrentMapを継承していて、Mapと同様な操作を行うことができます。

また、事前にRegionを作成していましたが、存在しないRegionを指定すると、Regionの操作時にエラーになるようです。

    @Test
    public void missingRegion() {
        ClientCache cache =
                new ClientCacheFactory()
                        .create();

        try {
            Region<String, String> region =
                    cache
                            .<String, String>createClientRegionFactory(ClientRegionShortcut.CACHING_PROXY)
                            .create("notFoundRegion");

            assertThatThrownBy(() -> region.put("key1", "value1"))
                    .isInstanceOf(ServerOperationException.class)
                    .hasMessageContaining("While performing a remote put")
                    .hasCauseInstanceOf(RegionDestroyedException.class);

            region.close();
        } finally {
            cache.close();
        }
    }

環境さえ整えてしまえば、動かすこと自体はそう難しくなさそうです。

で

とまあ、Getting Startedの写しみたいな感じで進めましたが、説明を飛ばしたものがありますね。これらについて、ちょっとドキュメントを見た程度ですが書いていきます。

Locator

最初に起動したプロセスです。

http://geode.docs.pivotal.io/docs/configuring/running/running_the_locator.html

分散システムにおける、メンバーを管理するプロセスになります。このプロセスがいないと、他のプロセス(ServerやClient)がうまく動作できません。
というか、1番最初に接続しにいこうとします。

停止する場合は
※--name以外にも、--pidでPIDを指定しての停止も可能です

gfsh>stop locator --name=locator

と実行しますが、この時Serverプロセスが起動したままだと、gfshからServerを操作できなくなります…。

また、起動時に(ディレクトリを指定しなければ)カレントディレクトリに、Locator向けのディレクトリができるようです。作られるディレクトリ名は、Locatorの名前(--nameで指定した値)が反映されます。

$ ll locator/
合計 172
drwxrwxr-x 5 xxxxx xxxxx   4096  2月 14 15:36 ./
drwxrwxr-x 6 xxxxx xxxxx   4096  2月 14 15:21 ../
drwxrwxr-x 2 xxxxx xxxxx   4096  2月 14 15:36 ConfigDiskDir_locator/
drwxrwxr-x 3 xxxxx xxxxx   4096  2月 14 15:21 GemFire_xxxxx/
drwxrwxr-x 3 xxxxx xxxxx   4096  2月 14 15:21 cluster_config/
-rw-rw-r-- 1 xxxxx xxxxx 139424  2月 14 15:36 locator.log
-rw-rw-r-- 1 xxxxx xxxxx    312  2月 14 15:36 locator10334view.dat
-rw-rw-r-- 1 xxxxx xxxxx   1290  2月 14 15:36 locator10334views.log
-rw-rw-r-- 1 xxxxx xxxxx      5  2月 14 15:36 vf.gf.locator.pid

というわけで、Node間の通信時に必要なプロセスっぽいですね。

Client/ServerのNode Discoveryの雰囲気は、こちらのドキュメントを見ればよさそうです。

http://geode.docs.pivotal.io/docs/topologies_and_comm/topology_concepts/how_server_discovery_works.html

Locatorを開始する時には、たくさんのオプションが指定できるようなのです…。

gfsh>start locator --name=locator --
 --bind-address                           --classpath                              --force                                  --group                                 
 --hostname-for-clients                   --include-system-classpath               --locators                               --log-level                             
 --mcast-address                          --mcast-port                             --port                                   --dir                                   
 --properties-file                        --security-properties-file               --initial-heap                           --max-heap                              
 --J                                      --connect                                --enable-cluster-configuration           --load-cluster-configuration-from-dir   
 --cluster-config-dir

Server

続いて、Server。

http://geode.docs.pivotal.io/docs/configuring/running/running_the_cacheserver.html

こちらは、主としてデータを管理するプロセスになるようです。Regionにputしたりしたデータは、こちらが持っているようです。このため、今回書いたプログラムだとClientが終了してもデータは残りますが、Serverを再起動するとデータは失われます。

Locatorと同じく、Serverを停止する場合は以下のコマンドで。
※--name以外にも、--pidでPIDを指定しての停止も可能です

gfsh>stop server --name=server

上記コマンドで停止する場合は、Locatorが動作していないとうまくいきません。その場合は、PIDを指定して(--pid)止めるとよいでしょう。

Server側も、--nameで指定した名前でディレクトリができあがります。

$ ll server/
合計 36
drwxrwxr-x 2 xxxxx xxxxx  4096  2月 14 15:21 ./
drwxrwxr-x 7 xxxxx xxxxx  4096  2月 14 15:38 ../
-rw-rw-r-- 1 xxxxx xxxxx 21984  2月 14 15:36 server.log
-rw-rw-r-- 1 xxxxx xxxxx     5  2月 14 15:21 vf.gf.server.pid

こちらも、設定できるオプション多いですね。

gfsh>start server --name=server --
 --assign-buckets                     --bind-address                       --cache-xml-file                     --classpath                          --critical-heap-percentage          
 --critical-off-heap-percentage       --dir                                --disable-default-server             --disable-exit-when-out-of-memory    --enable-time-statistics            
 --eviction-heap-percentage           --eviction-off-heap-percentage       --force                              --group                              --hostname-for-clients              
 --include-system-classpath           --initial-heap                       --J                                  --locators                           --locator-wait-time                 
 --lock-memory                        --log-level                          --max-connections                    --max-heap                           --max-message-count                 
 --max-threads                        --mcast-address                      --mcast-port                         --memcached-port                     --memcached-protocol                
 --memcached-bind-address             --redis-port                         --redis-bind-address                 --redis-password                     --message-time-to-live              
 --off-heap-memory-size               --properties-file                    --rebalance                          --security-properties-file           --server-bind-address               
 --server-port                        --socket-buffer-size                 --spring-xml-location                --statistic-archive-file             --use-cluster-configuration

Region

Apache Geodeのコアブロック、だそうで。

http://geode.docs.pivotal.io/docs/basic_config/data_regions/chapter_overview.html#data_regions

キャッシュに登録されたデータを持ち、put/get/queryなどの各種操作を実行することができます。

Regionの種類はReplicated、Partitionedなどたくさんありますが

http://geode.docs.pivotal.io/docs/developing/region_options/region_types.html

今回は、REPLICATEをRegion Shortcutを使って指定しました。

http://geode.docs.pivotal.io/docs/reference/topics/region_shortcuts_table.html

本来なら、データを全Nodeに持つタイプの設定ですが、今回はServerが1Nodeしかいないのであんまり関係ないですけどね…。

ちなみに、他のIn Memory Data GridだとApache GeodeでいうRegionがCacheなどの名前になっていたり、CacheがCacheManagerとかの名前になっていたりするイメージがあったので、最初戸惑いました…。

まとめ

というわけで、Apache Geodeをさらっとですが使って、ここまでの説明を簡単に書いてみました。

なかなか機能が多そうなのと、慣れるまで時間がかかりそうな気がするのですが…マイペースに見ていこうかなと。

あと、まだ1.0.0-incubating.M1という段階なので、今後もけっこう変わるんだろうなぁと思いつつ。早く1.0.0がリリースされるといいなぁと思います。