#chiroito ’s blog

Java を中心とした趣味の技術について

Infinispan をクライアントサーバモードで使ってみる

今回は、Infinispan をクライアントサーバモードでキャッシュを使用してみます。 デフォルト設定で作成してあるmycacheという名前のキャッシュを使用します。サンプルコードではまず、このキャッシュを取得します。最後にそのキャッシュにあるデータの件数やデータを取得・格納してみます。

クライアントサーバモードの環境構築についてはこちらを参照下さい。

Infinispan 10.1 の環境を構築する - #chiroito ’s blog

今回使うメソッドは以下のとおりです。使うクラスはライブラリモードと異なりますが、使うメソッドは同一です。

  • データの件数を取得するにはRemoteCache#size()メソッドを使用します。
  • データの取得にはRemoteCache#get(K)メソッドを使用し、Kには取得したいキーを指定します。
  • データの格納にはRemoteCache#put(K, V)メソッドを使用し、Kには格納したいキー、Vには格納したい値を指定します。

HotRodCacheAccess.java

import org.infinispan.client.hotrod.RemoteCache;
import org.infinispan.client.hotrod.RemoteCacheManager;

public class HotRodCacheAccess {
    public static void main(String[] args) {

        try(RemoteCacheManager manager = new RemoteCacheManager()) {
            RemoteCache<String, String> cache = manager.getCache("mycache");

            // キャッシュのサイズを出力します。
            System.out.println("Cache size is " + cache.size());

            // キャッシュに入れてないデータがない事を確認します。
            System.out.println("Value is " + cache.get("key"));

            // キャッシュにデータを入れます。
            cache.put("key", "value");

            // キャッシュのサイズを出力します。
            System.out.println("Cache size is " + cache.size());

            // キャッシュに入れたデータを確認します
            System.out.println("Value is " + cache.get("key"));
        }
    }
}

Hot Rodのクライアント側の設定は以下のとおりです。クライアントが接続するサーバの設定をinfinispan.client.hotrod.server_listでしています。

resouces/hotrod-client.properties

infinispan.client.hotrod.server_list=192.168.1.1:11222

出力結果は以下のとおりになります。最初のデータの件数は0で、値を取っても値がないのでnullが返されます。次にデータを投入してから同様の処理をします。すると、データの件数は1件になり、値を取るとvalueという値が返されています。

3 17, 2020 7:31:45 午後 org.infinispan.client.hotrod.RemoteCacheManager actualStart
INFO: ISPN004021: Infinispan version: Infinispan 'Turia' 10.1.3.Final
3 17, 2020 7:31:45 午後 org.infinispan.client.hotrod.impl.protocol.Codec20 readNewTopologyAndHash
INFO: ISPN004006: Server sent new topology view (id=1, age=0) containing 1 addresses: [192.168.1.1:11222]
Cache size is 0
Value is null
Cache size is 1
Value is value

クライアントサーバモードの場合は Prometheus に対応したメトリックを出力できます。その中で、キャッシュに入れたデータの数、キャッシュからデータが取れた数、キャッシュへデータを格納した数、キャッシュからデータが取れなかった数を可視化したのが以下の図になります。

f:id:chiroito:20200317193318p:plain

具体的なメトリック名は以下になります。

  • vendor_cache_manager_default_cache_mycache_statistics_number_of_entries
  • vendor_cache_manager_default_cache_mycache_statistics_hits
  • vendor_cache_manager_default_cache_mycache_statistics_stores
  • vendor_cache_manager_default_cache_mycache_statistics_misses

Infinispan のライブラリモードでget/putの性能測定

Infinispan をライブラリモードで動かした時の、実行回数をスレッド数を変えて性能測定してみました。

環境

Lenovo X1 Xtremeで、4コアのI5-9400H を搭載しています。

ベンチマーク

今回試した処理は get と put です。

以下が実行回数のグラフで、get は左軸、put は右軸です。数字は 100 万回を表しています。 見ると分かりますが、左軸と右軸で 10 倍違います。 スレッド数が増えるに従ってきちんとスケールしているのが分かります。 4スレッドでput も500万回実行できているのを見るとRDBMSと比べ圧倒的に更新できることが分かります。

f:id:chiroito:20200316191820p:plain

ソースコード

ベンチマークに使用した JMH のコードは以下です。

import org.infinispan.Cache;
import org.infinispan.configuration.cache.ConfigurationBuilder;
import org.infinispan.manager.DefaultCacheManager;
import org.infinispan.manager.EmbeddedCacheManager;
import org.openjdk.jmh.annotations.*;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.RunnerException;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;

import java.io.IOException;
import java.util.stream.IntStream;

@State(Scope.Thread)
public class EmbeddedCacheAccessBenchmark {

    private Cache<String, String> c;
    private EmbeddedCacheManager manager;

    @Setup(Level.Trial)
    public void setup() {
        manager = new DefaultCacheManager();
        manager.defineConfiguration("mycache", new ConfigurationBuilder()
                .build());
        c = manager.getCache("mycache");
        c.put("key", "value");
    }

    @TearDown
    public void tearDown() throws IOException {
        manager.close();
    }

    public static void main(String[] args) {
        IntStream.rangeClosed(1, 4).forEach(i -> run(i));
    }

    private static void run(int threadCount) {
        try {
            Options opt = new OptionsBuilder()
                    .include(EmbeddedCacheAccessBenchmark.class.getSimpleName())
                    .forks(1)
                    .warmupIterations(3)
                    .measurementIterations(5)
                    .threads(threadCount)
                    .mode(Mode.Throughput)
                    .build();
            new Runner(opt).run();
        } catch (RunnerException e) {
            e.printStackTrace();
        }
    }

    @Benchmark
    public void put() {
        c.put("key", "value");
    }

    @Benchmark
    public void get() {
        c.get("key");
    }
}

Infinispan をライブラリモードで使ってみる

今回は、Infinispan をライブラリモードでキャッシュを使用してみます。 デフォルト設定でキャッシュを作成し、そのキャッシュにmycacheという名前を付けます。そして、mycacheというキャッシュを取得します。最後にそのキャッシュにあるデータの件数やデータを取得・格納してみます。

ライブラリモードの環境構築についてはこちらを参照下さい。

Infinispan 10.1 の環境を構築する - #chiroito ’s blog

今回使うメソッドは以下のとおりです。

  • データの件数を取得するにはCache#size()メソッドを使用します。
  • データの取得にはCache#get(K)メソッドを使用し、Kには取得したいキーを指定します。
  • データの格納にはCache#put(K, V)メソッドを使用し、Kには格納したいキー、Vには格納したい値を指定します。
import org.infinispan.Cache;
import org.infinispan.configuration.cache.ConfigurationBuilder;
import org.infinispan.manager.DefaultCacheManager;
import org.infinispan.manager.EmbeddedCacheManager;

import java.io.IOException;

public class EmbeddedSingleSample {

    public static void main(String[] args) {

        // ライブラリモードでやる時のおまじないです。
        // ここではauto closeされるので、tryで囲わない場合は自分でcloseしてください。
        try (EmbeddedCacheManager manager = new DefaultCacheManager()) {

            // キャッシュを定義(作成)します
            manager.defineConfiguration("mycache", new ConfigurationBuilder().build());

            // キャッシュを取得します
            Cache<String, String> cache = manager.getCache("mycache");

            // キャッシュのサイズを出力します。
            System.out.println("Cache size is " + cache.size());

            // キャッシュに入れてないデータがない事を確認します。
            System.out.println("Value is " + cache.get("key"));

            // キャッシュにデータを入れます。
            cache.put("key", "value");

            // キャッシュのサイズを出力します。
            System.out.println("Cache size is " + cache.size());

            // キャッシュに入れたデータを確認します
            System.out.println("Value is " + cache.get("key"));

        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

出力結果は以下のとおりになります。最初のデータの件数は0で、値を取っても値がないのでnullが返されます。次にデータを投入してから同様の処理をします。すると、データの件数は1件になり、値を取るとvalueという値が返されています。

3 16, 2020 4:44:42 午後 org.infinispan.factories.GlobalComponentRegistry preStart
INFO: ISPN000128: Infinispan version: Infinispan 'Turia' 10.1.3.Final
Cache size is 0
Value is null
Cache size is 1
Value is value