#chiroito ’s blog

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

Infinispan のクライアントサーバモードでget/putの性能測定

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

環境

クライアントとサーバのマシンを1台ずつ用意しています。サーバマシンにはInfinispanを2プロセス起動しています。 使用したInfinispanは10.1.3.Finalです。

クライアント

Lenovo X1 Xtremeで、物理4コアのi5-9400H を搭載しています。クロックは2.5GHz-4.3GHzです。

サーバ

自作のPCで、物理8コアのi9-9900Kを搭載してます。クロックは3.6GHz-5.0GHzです。

※本来は複数のサーバマシン間で複製をとるため複製においてもネットワーク通信が発生します。しかし、今回は資材の都合上同じマシン上で複製処理が行われているためネットワークを介していません。そのため、put処理では実際のベンチマークとは異なる結果になると思います。

ベンチマーク

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

アプリケーションとキャッシュが同一のJVM内に存在するライブラリモードではGetが5000万回、Putが600万回ほど実行できました。クライアントサーバモードではアプリケーションとキャッシュの間にネットワーク通信が発生します。そのため、レイテンシが発生して性能面ではライブラリモードに比べて低下します。結果としては32スレッドが最大のスループットとなり、Get はおよそ66,000回、Putはおよそ62,000回実行しました。

今回の検証ではクライアント側は32スレッドでCPU4コアをすべて使い果たしました。この時、サーバ側は8コアすべてを使ったときに100%とすると、Getでは15%、Putでは90%程度の使用率でした。

f:id:chiroito:20200318170829p:plain

ソースコード

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

import org.infinispan.client.hotrod.RemoteCache;
import org.infinispan.client.hotrod.RemoteCacheManager;
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 HotRodCacheAccessBenchmark {

    private RemoteCache<String, String> c;
    private RemoteCacheManager manager;
    private String key = "key"+(System.nanoTime() % 128);

    @Setup(Level.Trial)
    public void setup() {
        manager = new RemoteCacheManager();
        c = manager.getCache("mycache");
        IntStream.range(0,128).forEach(i->c.put(key+i, "value"));
    }

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

    public static void main(String[] args) {
        IntStream.of(1, 2, 4, 8, 16, 32, 64).forEach(i -> run(i));
    }

    private static void run(int threadCount) {
        try {
            Options opt = new OptionsBuilder()
                    // 実行対象のベンチマークが定義された"クラス名.メソッド名"を正規表現で指定
                    .include(HotRodCacheAccessBenchmark.class.getSimpleName())
                    .forks(1)
                    .warmupIterations(5)
                    .measurementIterations(5)
                    .threads(threadCount)
                    .mode(Mode.Throughput)
                    .build();
            new Runner(opt).run();
        } catch (RunnerException e) {
            e.printStackTrace();
        }
    }

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

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