CLOVER🍀

That was when it all began.

Infinispan Server 13.0とHot Rod Clientでメトリクスを取得する

これは、なにをしたくて書いたもの?

Infinispan Server、それからHot Rod Clientで、メトリクスを取得してみたいと思いまして。

なんとなく、Infinispan ServerにEclipse MicroProfile Metricsが入っているのは気づいていたので、主にこちらを
試してみたいという動機ですね。

Infinispan Serverとメトリクス

Infinispan Serverのメトリクスに関するドキュメントは、こちら。

Deploying and Configuring Infinispan Servers / Enabling and configuring Infinispan statistics and JMX monitoring

メトリクスに関する設定は、主に次の2つがあります。

CacheManagerのメトリクスに関しては、gauseとhistogramの設定もできます。

メトリクスは、Infinispan Serverの/metricsエンドポイントからEclipse MicroProfile Metricsのvendorスコープで
取得できます。

Project - MicroProfile

実装としては、SmallRye Metricsが使われています。

SmallRye

今回は主ではありませんが、Java APIを使ってメトリクスを取得したり、JMX MBeanとしても登録できます。

CacheManagerおよびCacheに関するXML Schemaの定義は、こちら。

urn:infinispan:config:13.0

メトリクスに関する設定は、それぞれ以下あたりです。

CacheManagerレベル。

f:id:Kazuhira:20211210235444p:plain

f:id:Kazuhira:20211210232802p:plain

Cacheレベル。

f:id:Kazuhira:20211210232911p:plain

Hot Rod Clientとメトリクス

Hot Rod Clientもメトリクスがあります。

Hot Rod Java Clients / Enabling Hot Rod client statistics

こちらは、Java APIまたはJMXでの取得になります。

取得できるメトリクス

取得対象のメトリクスは、CacheManagerやCacheについては主にJMX Beanの情報を参照することになるのですが。

JMX Components

完全に同じではないので、あとで少し補足しておきます。

Hot Rod Clientで取得できるメトリクスは、特にドキュメントには書かれていません。こちらについても、あとで補足します。

とりあえず、これらを使ってInfinispan ServerやHot Rod Clientからメトリクスを取得してみましょう。

環境

今回の環境はこちら。

$ java --version
openjdk 11.0.11 2021-04-20
OpenJDK Runtime Environment (build 11.0.11+9-Ubuntu-0ubuntu2.20.04)
OpenJDK 64-Bit Server VM (build 11.0.11+9-Ubuntu-0ubuntu2.20.04, mixed mode, sharing)


$ mvn --version
Apache Maven 3.8.4 (9b656c72d54e5bacbed989b64718c159fe39b537)
Maven home: $HOME/.sdkman/candidates/maven/current
Java version: 11.0.11, vendor: Ubuntu, runtime: /usr/lib/jvm/java-11-openjdk-amd64
Default locale: ja_JP, platform encoding: UTF-8
OS name: "linux", version: "5.4.0-91-generic", arch: "amd64", family: "unix"

Infinispan Serverは13.0.2.Finalを使い、3台(172.18.0.2、172.18.0.3、172.18.0.4)のクラスター構成とします。

また、メトリクスをPrometheusで取得する確認もしたいので、Prometheus 2.31.1を使います。Prometheusは
172.18.0.5で動作しているものとします。

準備

テストコード等で使う、Maven依存関係など。

    <dependencies>
        <dependency>
            <groupId>org.infinispan</groupId>
            <artifactId>infinispan-client-hotrod</artifactId>
            <version>13.0.2.Final</version>
        </dependency>

        <dependency>
            <groupId>org.infinispan</groupId>
            <artifactId>infinispan-core</artifactId>
            <version>13.0.2.Final</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter</artifactId>
            <version>5.8.2</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.assertj</groupId>
            <artifactId>assertj-core</artifactId>
            <version>3.21.0</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>2.22.2</version>
            </plugin>
        </plugins>
    </build>

基本的にはHot Rod Clientを使うのですが、CacheをJava APIで簡単に作成するためにinfinispan-coreも導入して
おきます。

Infinispan Serverも起動。

$ bin/server.sh \
    -b 0.0.0.0 \
    -Djgroups.tcp.address=`hostname -i`

各Infinispan Serverには、それぞれ管理用ユーザー、アプリケーション用ユーザーを作成しておきます。

$ bin/cli.sh user create -g admin -p password admin-user
$ bin/cli.sh user create -g application -p password app-user

このような操作や、Infinispan ServerのXMLの設定はすべてのサーバーに対して行う必要があります。

Infinispan ServerのメトリクスエンドポイントにアクセスするためにはREST Connectorを使う必要があり、認証を外すか、
REST Connectorに認証設定を正しく行うかのどちらかになります。今回は、認証設定を行うことにします。

デフォルトでこのようになっているendpointsの設定を

      <endpoints socket-binding="default" security-realm="default" />

このように変更。

      <endpoints socket-binding="default" security-realm="default">
         <endpoint>
            <hotrod-connector>
               <authentication>
                  <sasl mechanisms="SCRAM-SHA-512 SCRAM-SHA-384 SCRAM-SHA-256
                                    SCRAM-SHA-1 DIGEST-SHA-512 DIGEST-SHA-384
                                    DIGEST-SHA-256 DIGEST-SHA DIGEST-MD5 PLAIN"
                        server-name="infinispan"
                        qop="auth"/>
               </authentication>
            </hotrod-connector>
            <rest-connector>
               <authentication mechanisms="DIGEST BASIC"/>
            </rest-connector>
         </endpoint>
      </endpoints>

これで、REST ConnectorでDigest認証またはBasic認証が行えるようになります。
※Basic認証を有効にしているのは、PrometheusがDigest認証には対応していないからです(Basic認証ならOK)

また、このように設定するとHot Rod Connectorの設定も明示する必要があります。

起動した状態のInfinispan Serverからメトリクスを取得してみる

まずは、起動した状態のInfinispan Serverからメトリクスを取得してみましょう。クラスターは構成済みです。

server/conf/infinispan.xmlには以下のように設定されているため、デフォルトでメトリクスを取得できるようになっています。

   <cache-container name="default" statistics="true">

とりあえず、Infinspan Serverを起動した状態でメトリクスを取得してみましょう。REST Connectorに認証設定を
行ったので、Digest認証またはBasic認証で/metricsエンドポイントにアクセスできます。

## Digest認証
$ curl --digest -u app-user:password 172.18.0.2:11222/metrics


## Basic認証
$ curl -u app-user:password 172.18.0.2:11222/metrics

アクセスは、アプリケーション用のユーザーで大丈夫です。

特になにも使っていない状態でも、76メトリクスを取得できます。

$ curl -s --digest -u app-user:password 172.18.0.2:11222/metrics | grep -v '^#' | wc -l
76

こんな感じですね。デフォルトでは、OpenMetrics形式になります。
※コメントは表示していません

$ curl -s --digest -u app-user:password 172.18.0.2:11222/metrics | grep -v '^#'
base_classloader_loadedClasses_count 10743.0
base_classloader_loadedClasses_total 10743.0
base_classloader_unloadedClasses_total 0.0
base_cpu_availableProcessors 8.0
base_cpu_processCpuLoad 0.003523194362889019
base_cpu_processCpuTime_seconds 19.76
base_cpu_systemLoadAverage 1.34
base_gc_time_total_seconds{name="G1 Old Generation1"} 0.0
base_gc_time_total_seconds{name="G1 Young Generation1"} 0.163
base_gc_total{name="G1 Old Generation1"} 0.0
base_gc_total{name="G1 Young Generation1"} 12.0
base_jvm_uptime_seconds 191.06
base_memory_committedHeap_bytes 8.912896E7
base_memory_committedNonHeap_bytes 9.0177536E7
base_memory_initHeap_bytes 6.7108864E7
base_memory_initNonHeap_bytes 7667712.0
base_memory_maxHeap_bytes 5.36870912E8
base_memory_maxNonHeap_bytes -1.0
base_memory_usedHeap_bytes 4.3557496E7
base_memory_usedNonHeap_bytes 8.6275808E7
base_thread_count 44.0
base_thread_daemon_count 32.0
base_thread_max_count 50.0
base_thread_totalStarted 53.0
vendor_BufferPool_used_memory_direct_bytes 8.4861215E7
vendor_BufferPool_used_memory_mapped_bytes 0.0
vendor_cache_manager_default_cache_container_health_free_memory_kb{node="infinispan-server-59867"} 43742.0
vendor_cache_manager_default_cache_container_health_number_of_cpus{node="infinispan-server-59867"} 8.0
vendor_cache_manager_default_cache_container_health_number_of_nodes{node="infinispan-server-59867"} 3.0
vendor_cache_manager_default_cache_container_health_total_memory_kb{node="infinispan-server-59867"} 87040.0
vendor_cache_manager_default_cache_container_stats_average_read_time{node="infinispan-server-59867"} 0.0
vendor_cache_manager_default_cache_container_stats_average_read_time_nanos{node="infinispan-server-59867"} 0.0
vendor_cache_manager_default_cache_container_stats_average_remove_time{node="infinispan-server-59867"} 0.0
vendor_cache_manager_default_cache_container_stats_average_remove_time_nanos{node="infinispan-server-59867"} 0.0
vendor_cache_manager_default_cache_container_stats_average_write_time{node="infinispan-server-59867"} 0.0
vendor_cache_manager_default_cache_container_stats_average_write_time_nanos{node="infinispan-server-59867"} 0.0
vendor_cache_manager_default_cache_container_stats_current_number_of_entries_in_memory{node="infinispan-server-59867"} 0.0
vendor_cache_manager_default_cache_container_stats_data_memory_used{node="infinispan-server-59867"} 0.0
vendor_cache_manager_default_cache_container_stats_evictions{node="infinispan-server-59867"} 0.0
vendor_cache_manager_default_cache_container_stats_hit_ratio{node="infinispan-server-59867"} 0.0
vendor_cache_manager_default_cache_container_stats_hits{node="infinispan-server-59867"} 0.0
vendor_cache_manager_default_cache_container_stats_misses{node="infinispan-server-59867"} 0.0
vendor_cache_manager_default_cache_container_stats_number_of_entries{node="infinispan-server-59867"} 0.0
vendor_cache_manager_default_cache_container_stats_off_heap_memory_used{node="infinispan-server-59867"} 0.0
vendor_cache_manager_default_cache_container_stats_read_write_ratio{node="infinispan-server-59867"} 0.0
vendor_cache_manager_default_cache_container_stats_remove_hits{node="infinispan-server-59867"} 0.0
vendor_cache_manager_default_cache_container_stats_remove_misses{node="infinispan-server-59867"} 0.0
vendor_cache_manager_default_cache_container_stats_required_minimum_number_of_nodes{node="infinispan-server-59867"} -1.0
vendor_cache_manager_default_cache_container_stats_stores{node="infinispan-server-59867"} 0.0
vendor_cache_manager_default_cache_container_stats_time_since_reset{node="infinispan-server-59867"} 180.0
vendor_cache_manager_default_cache_container_stats_time_since_start{node="infinispan-server-59867"} 0.0
vendor_cache_manager_default_cluster_container_stats_memory_available{node="infinispan-server-59867"} 4.5823848E7
vendor_cache_manager_default_cluster_container_stats_memory_max{node="infinispan-server-59867"} 5.36870912E8
vendor_cache_manager_default_cluster_container_stats_memory_total{node="infinispan-server-59867"} 8.912896E7
vendor_cache_manager_default_cluster_container_stats_memory_used{node="infinispan-server-59867"} 4.3305112E7
vendor_cache_manager_default_cluster_container_stats_time_since_reset{node="infinispan-server-59867"} 13141.0
vendor_cache_manager_default_cluster_size{node="infinispan-server-59867"} 3.0
vendor_cache_manager_default_number_of_cache_configurations{node="infinispan-server-59867"} 11.0
vendor_cache_manager_default_number_of_created_caches{node="infinispan-server-59867"} 0.0
vendor_cache_manager_default_number_of_running_caches{node="infinispan-server-59867"} 0.0
vendor_memoryPool_CodeHeap__non_nmethods__usage_bytes 1451392.0
vendor_memoryPool_CodeHeap__non_nmethods__usage_max_bytes 1490304.0
vendor_memoryPool_CodeHeap__non_profiled_nmethods__usage_bytes 2523264.0
vendor_memoryPool_CodeHeap__non_profiled_nmethods__usage_max_bytes 2523264.0
vendor_memoryPool_CodeHeap__profiled_nmethods__usage_bytes 1.087744E7
vendor_memoryPool_CodeHeap__profiled_nmethods__usage_max_bytes 1.087744E7
vendor_memoryPool_Compressed_Class_Space_usage_bytes 7698304.0
vendor_memoryPool_Compressed_Class_Space_usage_max_bytes 7698304.0
vendor_memoryPool_G1_Eden_Space_usage_bytes 2097152.0
vendor_memoryPool_G1_Eden_Space_usage_max_bytes 4.2991616E7
vendor_memoryPool_G1_Old_Gen_usage_bytes 3.9363192E7
vendor_memoryPool_G1_Old_Gen_usage_max_bytes 3.9363192E7
vendor_memoryPool_G1_Survivor_Space_usage_bytes 3145728.0
vendor_memoryPool_G1_Survivor_Space_usage_max_bytes 5242880.0
vendor_memoryPool_Metaspace_usage_bytes 6.3726176E7
vendor_memoryPool_Metaspace_usage_max_bytes 6.3726176E7

vendor_cache_manager_default_cache_container_〜の部分が、CacheManagerレベルのメトリクスですね。

ちなみに、メトリクスの取得はデフォルトでは無効なので、たとえば以下のようにstatistics="true"を削除して
Infinispan Serverを起動しなおすと

   <cache-container name="default">

CacheManagerに関するメトリクスが取得できなくなります。

$ curl -s --digest -u app-user:password 172.18.0.2:11222/metrics | grep -v '^#' | grep cache_manager

また、デフォルトでは取得できるメトリクスはgaugeのみです。

gaugeかどうかは、コメントを見たらわかりますね。

# HELP vendor_cache_manager_default_cache_container_health_free_memory_kb The amount of free memory (KB) in the host
# TYPE vendor_cache_manager_default_cache_container_health_free_memory_kb gauge
vendor_cache_manager_default_cache_container_health_free_memory_kb{node="infinispan-server-52531"} 21701.0

histogramも有効にする場合は、こちら。

   <cache-container name="default" statistics="true">
      <metrics gauges="true"
               histograms="true" />

単に起動しただけだと、なにが増えるのかはわからないのですが…今回はhistogramとして登録されたメトリクスは
確認できませんでした。それは、あとで書きます。

メトリクスはAcceptヘッダーを付与することで、JSONでも取得できます。

$ curl --digest -u app-user:password -H 'Accept: application/json' 172.18.0.2:11222/metrics

{
    "base": {
        "gc.total;name=G1 Young Generation1": 17,
        "gc.total;name=G1 Old Generation1": 0,
        "cpu.systemLoadAverage": 1.26,
        "classloader.loadedClasses.count": 10898,
        "thread.count": 46,
        "memory.initNonHeap": 7667712,
        "gc.time;name=G1 Old Generation1": 0,
        "gc.time;name=G1 Young Generation1": 207,
        "classloader.unloadedClasses.total": 2,
        "cpu.processCpuTime": 24330000000,
        "jvm.uptime": 226578,
        "memory.committedNonHeap": 92209152,
        "thread.max.count": 47,
        "memory.committedHeap": 67108864,
        "classloader.loadedClasses.total": 10900,
        "cpu.availableProcessors": 8,
        "thread.daemon.count": 33,
        "memory.usedNonHeap": 88160384,
        "memory.initHeap": 67108864,
        "memory.maxHeap": 536870912,

〜省略〜

Cacheを作成・利用してから、メトリクスを取得する

次に、Cacheを作成して、使ってみてからメトリクスを取得しましょう。

これには、テストコードを利用します。雛形を、以下のように準備。

src/test/java/org/littlewings/infinispan/remote/metrics/MetricsTest.java

package org.littlewings.infinispan.remote.metrics;

import java.util.stream.IntStream;

import org.infinispan.client.hotrod.RemoteCache;
import org.infinispan.client.hotrod.RemoteCacheManager;
import org.infinispan.client.hotrod.RemoteCacheManagerAdmin;
import org.infinispan.client.hotrod.ServerStatistics;
import org.infinispan.client.hotrod.configuration.Configuration;
import org.infinispan.client.hotrod.configuration.ConfigurationBuilder;
import org.infinispan.client.hotrod.jmx.RemoteCacheClientStatisticsMXBean;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;

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

public class MetricsTest {
    static String createUri(String userName, String password) {
        return String.format("hotrod://%s:%s@172.18.0.2:11222,172.18.0.3:11222,172.18.0.4:11222", userName, password);
    }

    // ここに、テストを書く
}

とりあえず、Infinispan ServerにアクセスするためのURIを作るメソッドだけ用意…。

Cacheがないと始まらないので、テストの前にCacheを作成することにします。

    @BeforeAll
    public static void setupAll() {
        String uri = createUri("admin-user", "password");

        try (RemoteCacheManager manager = new RemoteCacheManager(uri)) {
            RemoteCacheManagerAdmin admin = manager.administration();

            org.infinispan.configuration.cache.Configuration distCacheConfiguration =
                    new org.infinispan.configuration.cache.ConfigurationBuilder()
                            .clustering()
                            .cacheMode(org.infinispan.configuration.cache.CacheMode.DIST_SYNC)
                            .encoding().key().mediaType("application/x-protostream")
                            .encoding().value().mediaType("application/x-protostream")
                            .statistics().enable()
                            .build();

            admin.getOrCreateCache("distCache", distCacheConfiguration);

            org.infinispan.configuration.cache.Configuration replCacheConfiguration =
                    new org.infinispan.configuration.cache.ConfigurationBuilder()
                            .clustering()
                            .cacheMode(org.infinispan.configuration.cache.CacheMode.REPL_SYNC)
                            .encoding().key().mediaType("application/x-protostream")
                            .encoding().value().mediaType("application/x-protostream")
                            .statistics().enable()
                            .build();

            admin.getOrCreateCache("replCache", replCacheConfiguration);
        }
    }

Cacheは、Distributed CacheとReplicated Cacheの2種類を用意。

デフォルトではCacheのメトリクス記録は無効となっているのですが、今回の方法で作るとデフォルトで
statistics="true"のCacheがInfinispan Server側に作成されます。明示的に無効にもできます。

これで、Infinispan Server側に作成されるCacheの定義はこのようになります。

server/data/caches.xml

<?xml version="1.0"?>
<infinispan xmlns="urn:infinispan:config:13.0">
    <cache-container>
        <caches>
            <replicated-cache name="replCache" mode="SYNC" remote-timeout="17500" statistics="true">
                <encoding>
                    <key media-type="application/x-protostream"/>
                    <value media-type="application/x-protostream"/>
                </encoding>
                <locking concurrency-level="1000" acquire-timeout="15000" striping="false"/>
                <state-transfer timeout="60000"/>
            </replicated-cache>
            <distributed-cache name="distCache" mode="SYNC" remote-timeout="17500" statistics="true">
                <encoding>
                    <key media-type="application/x-protostream"/>
                    <value media-type="application/x-protostream"/>
                </encoding>
                <locking concurrency-level="1000" acquire-timeout="15000" striping="false"/>
                <state-transfer timeout="60000"/>
            </distributed-cache>
        </caches>
    </cache-container>
</infinispan>

CacheのメトリクスとCacheManagerのメトリクス、それぞれの記録設定は独立しているので、Cacheだけを
記録してCacheManagerは無効にすることもできます。…あまり意味はないと思いますが。

こちらを使うテストコードを書いて、実行。

    @Test
    public void distributedCache() {
        String uri = createUri("app-user", "password");

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

            IntStream
                    .rangeClosed(1, 100)
                    .forEach(i -> cache.put("key" + i, "value" + i));

            IntStream
                    .rangeClosed(1, 50)
                    .forEach(i -> assertThat(cache.get("key" + i)).isNotNull());

            IntStream
                    .rangeClosed(101, 125)
                    .forEach(i -> assertThat(cache.get("key" + i)).isNull());
        }
    }

    @Test
    public void replicatedCache() {
        String uri = createUri("app-user", "password");

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

            IntStream
                    .rangeClosed(1, 100)
                    .forEach(i -> cache.put("key" + i, "value" + i));

            IntStream
                    .rangeClosed(1, 50)
                    .forEach(i -> assertThat(cache.get("key" + i)).isNotNull());

            IntStream
                    .rangeClosed(101, 125)
                    .forEach(i -> assertThat(cache.get("key" + i)).isNull());
        }
    }

書き込み、取得(取得失敗含む)を行います。

では、メトリクスを取得してみましょう。一気に数が増えました。

$ curl -s --digest -u app-user:password 172.18.0.2:11222/metrics | grep -v '^#' | wc -l
364

Cacheのメトリクスも、CacheManagerのメトリクスとprefixは同じようなので絞り込んでみます。

$ curl -s --digest -u app-user:password 172.18.0.2:11222/metrics | grep -v '^#' | grep vendor_cache_manager
vendor_cache_manager_default_cache_container_health_free_memory_kb{node="infinispan-server-56615"} 20802.0
vendor_cache_manager_default_cache_container_health_number_of_cpus{node="infinispan-server-56615"} 8.0
vendor_cache_manager_default_cache_container_health_number_of_nodes{node="infinispan-server-56615"} 3.0
vendor_cache_manager_default_cache_container_health_total_memory_kb{node="infinispan-server-56615"} 65536.0
vendor_cache_manager_default_cache_container_stats_average_read_time{node="infinispan-server-56615"} 0.0
vendor_cache_manager_default_cache_container_stats_average_read_time_nanos{node="infinispan-server-56615"} 53899.0
vendor_cache_manager_default_cache_container_stats_average_remove_time{node="infinispan-server-56615"} 0.0
vendor_cache_manager_default_cache_container_stats_average_remove_time_nanos{node="infinispan-server-56615"} 0.0
vendor_cache_manager_default_cache_container_stats_average_write_time{node="infinispan-server-56615"} 1.0
vendor_cache_manager_default_cache_container_stats_average_write_time_nanos{node="infinispan-server-56615"} 1408448.0
vendor_cache_manager_default_cache_container_stats_current_number_of_entries_in_memory{node="infinispan-server-56615"} 0.0

〜省略〜

vendor_cache_manager_default_cache_distCache_cluster_cache_stats_activations{node="infinispan-server-56615"} 0.0
vendor_cache_manager_default_cache_distCache_cluster_cache_stats_average_read_time{node="infinispan-server-56615"} 0.0
vendor_cache_manager_default_cache_distCache_cluster_cache_stats_average_read_time_nanos{node="infinispan-server-56615"} 55086.0
vendor_cache_manager_default_cache_distCache_cluster_cache_stats_average_remove_time{node="infinispan-server-56615"} 0.0
vendor_cache_manager_default_cache_distCache_cluster_cache_stats_average_remove_time_nanos{node="infinispan-server-56615"} 0.0
vendor_cache_manager_default_cache_distCache_cluster_cache_stats_average_write_time{node="infinispan-server-56615"} 1.0
vendor_cache_manager_default_cache_distCache_cluster_cache_stats_average_write_time_nanos{node="infinispan-server-56615"} 1537324.0
vendor_cache_manager_default_cache_distCache_cluster_cache_stats_cache_loader_loads{node="infinispan-server-56615"} 0.0
vendor_cache_manager_default_cache_distCache_cluster_cache_stats_cache_loader_misses{node="infinispan-server-56615"} 0.0
vendor_cache_manager_default_cache_distCache_cluster_cache_stats_current_number_of_entries_in_memory{node="infinispan-server-56615"} -1.0
vendor_cache_manager_default_cache_distCache_cluster_cache_stats_data_memory_used{node="infinispan-server-56615"} 0.0
vendor_cache_manager_default_cache_distCache_cluster_cache_stats_evictions{node="infinispan-server-56615"} 0.0
vendor_cache_manager_default_cache_distCache_cluster_cache_stats_hit_ratio{node="infinispan-server-56615"} 0.6666666666666666
vendor_cache_manager_default_cache_distCache_cluster_cache_stats_hits{node="infinispan-server-56615"} 100.0
vendor_cache_manager_default_cache_distCache_cluster_cache_stats_invalidations{node="infinispan-server-56615"} 0.0
vendor_cache_manager_default_cache_distCache_cluster_cache_stats_misses{node="infinispan-server-56615"} 50.0
vendor_cache_manager_default_cache_distCache_cluster_cache_stats_number_of_entries{node="infinispan-server-56615"} 100.0
vendor_cache_manager_default_cache_distCache_cluster_cache_stats_number_of_locks_available{node="infinispan-server-56615"} 0.0
vendor_cache_manager_default_cache_distCache_cluster_cache_stats_number_of_locks_held{node="infinispan-server-56615"} 0.0
vendor_cache_manager_default_cache_distCache_cluster_cache_stats_off_heap_memory_used{node="infinispan-server-56615"} 0.0

〜省略〜

vendor_cache_manager_default_cache_replCache_cluster_cache_stats_hit_ratio{node="infinispan-server-56615"} 0.6666666666666666
vendor_cache_manager_default_cache_replCache_cluster_cache_stats_hits{node="infinispan-server-56615"} 50.0
vendor_cache_manager_default_cache_replCache_cluster_cache_stats_invalidations{node="infinispan-server-56615"} 0.0
vendor_cache_manager_default_cache_replCache_cluster_cache_stats_misses{node="infinispan-server-56615"} 25.0
vendor_cache_manager_default_cache_replCache_cluster_cache_stats_number_of_entries{node="infinispan-server-56615"} 100.0
vendor_cache_manager_default_cache_replCache_cluster_cache_stats_number_of_locks_available{node="infinispan-server-56615"} 0.0
vendor_cache_manager_default_cache_replCache_cluster_cache_stats_number_of_locks_held{node="infinispan-server-56615"} 0.0
vendor_cache_manager_default_cache_replCache_cluster_cache_stats_off_heap_memory_used{node="infinispan-server-56615"} 0.0
vendor_cache_manager_default_cache_replCache_cluster_cache_stats_passivations{node="infinispan-server-56615"} 0.0
vendor_cache_manager_default_cache_replCache_cluster_cache_stats_read_write_ratio{node="infinispan-server-56615"} 1.33
vendor_cache_manager_default_cache_replCache_cluster_cache_stats_remove_hits{node="infinispan-server-56615"} 0.0
vendor_cache_manager_default_cache_replCache_cluster_cache_stats_remove_misses{node="infinispan-server-56615"} 0.0
vendor_cache_manager_default_cache_replCache_cluster_cache_stats_required_minimum_number_of_nodes{node="infinispan-server-56615"} 1.0
vendor_cache_manager_default_cache_replCache_cluster_cache_stats_store_writes{node="infinispan-server-56615"} 0.0
vendor_cache_manager_default_cache_replCache_cluster_cache_stats_stores{node="infinispan-server-56615"} 100.0
vendor_cache_manager_default_cache_replCache_cluster_cache_stats_time_since_reset{node="infinispan-server-56615"} 1885.0
vendor_cache_manager_default_cache_replCache_cluster_cache_stats_time_since_start{node="infinispan-server-56615"} 170.0
vendor_cache_manager_default_cache_replCache_configuration_eviction_size{node="infinispan-server-56615"} -1.0
vendor_cache_manager_default_cache_replCache_lock_manager_number_of_locks_available{node="infinispan-server-56615"} 0.0
vendor_cache_manager_default_cache_replCache_lock_manager_number_of_locks_held{node="infinispan-server-56615"} 0.0
vendor_cache_manager_default_cache_replCache_passivation_passivations{node="infinispan-server-56615"} 0.0
vendor_cache_manager_default_cache_replCache_rpc_manager_average_replication_time{node="infinispan-server-56615"} 0.0
vendor_cache_manager_default_cache_replCache_rpc_manager_average_xsite_replication_time{node="infinispan-server-56615"} -1.0
vendor_cache_manager_default_cache_replCache_rpc_manager_cross_site_replication_times_rate_per_second{node="infinispan-server-56615"} 0.0
vendor_cache_manager_default_cache_replCache_rpc_manager_cross_site_replication_times_one_min_rate_per_second{node="infinispan-server-56615"} 0.0

〜省略〜

vendor_cache_manager_default_cluster_container_stats_memory_available{node="infinispan-server-56615"} 1.796532E7
vendor_cache_manager_default_cluster_container_stats_memory_max{node="infinispan-server-56615"} 5.36870912E8
vendor_cache_manager_default_cluster_container_stats_memory_total{node="infinispan-server-56615"} 6.7108864E7
vendor_cache_manager_default_cluster_container_stats_memory_used{node="infinispan-server-56615"} 4.9143544E7
vendor_cache_manager_default_cluster_container_stats_time_since_reset{node="infinispan-server-56615"} 1885.0
vendor_cache_manager_default_cluster_size{node="infinispan-server-56615"} 3.0
vendor_cache_manager_default_number_of_cache_configurations{node="infinispan-server-56615"} 13.0
vendor_cache_manager_default_number_of_created_caches{node="infinispan-server-56615"} 2.0
vendor_cache_manager_default_number_of_running_caches{node="infinispan-server-56615"} 2.0

こういうのがCacheManagerレベルのメトリクスで

vendor_cache_manager_default_cluster_container_stats_memory_available{node="infinispan-server-56615"} 1.7898104E7
vendor_cache_manager_default_cluster_container_stats_memory_max{node="infinispan-server-56615"} 5.36870912E8
vendor_cache_manager_default_cluster_container_stats_memory_total{node="infinispan-server-56615"} 6.7108864E7
vendor_cache_manager_default_cluster_container_stats_memory_used{node="infinispan-server-56615"} 4.921076E7
vendor_cache_manager_default_cluster_container_stats_time_since_reset{node="infinispan-server-56615"} 1969.0
vendor_cache_manager_default_cluster_size{node="infinispan-server-56615"} 3.0

こういうのがCacheレベルのメトリクスですね。

vendor_cache_manager_default_cache_distCache_statistics_hit_ratio{node="infinispan-server-56615"} 0.7222222222222222                                                                      
vendor_cache_manager_default_cache_distCache_statistics_hit_times_rate_per_second{node="infinispan-server-56615"} 0.08678744496381509                                                     
vendor_cache_manager_default_cache_distCache_statistics_hit_times_one_min_rate_per_second{node="infinispan-server-56615"} 0.04139170801327364                                             
vendor_cache_manager_default_cache_distCache_statistics_hit_times_five_min_rate_per_second{node="infinispan-server-56615"} 1.9778135342641445                                             
vendor_cache_manager_default_cache_distCache_statistics_hit_times_fifteen_min_rate_per_second{node="infinispan-server-56615"} 3.767593253736332                                           
vendor_cache_manager_default_cache_distCache_statistics_hit_times_min_seconds{node="infinispan-server-56615"} 2.4353E-5                                                                   
vendor_cache_manager_default_cache_distCache_statistics_hit_times_max_seconds{node="infinispan-server-56615"} 6.66696E-4                                                                  
vendor_cache_manager_default_cache_distCache_statistics_hit_times_mean_seconds{node="infinispan-server-56615"} 7.20586195756265E-5                                                        
vendor_cache_manager_default_cache_distCache_statistics_hit_times_stddev_seconds{node="infinispan-server-56615"} 1.190356387895132E-4                                                     
vendor_cache_manager_default_cache_distCache_statistics_hit_times_seconds_count{node="infinispan-server-56615"} 26.0                                                                      
vendor_cache_manager_default_cache_distCache_statistics_hit_times_seconds_sum{node="infinispan-server-56615"} 0.001879469                                                                 
vendor_cache_manager_default_cache_distCache_statistics_hit_times_seconds{node="infinispan-server-56615",quantile="0.5"} 4.7805E-5                                                        
vendor_cache_manager_default_cache_distCache_statistics_hit_times_seconds{node="infinispan-server-56615",quantile="0.75"} 5.6925E-5
vendor_cache_manager_default_cache_distCache_statistics_hit_times_seconds{node="infinispan-server-56615",quantile="0.95"} 7.0515E-5
vendor_cache_manager_default_cache_distCache_statistics_hit_times_seconds{node="infinispan-server-56615",quantile="0.98"} 6.66696E-4
vendor_cache_manager_default_cache_distCache_statistics_hit_times_seconds{node="infinispan-server-56615",quantile="0.99"} 6.66696E-4
vendor_cache_manager_default_cache_distCache_statistics_hit_times_seconds{node="infinispan-server-56615",quantile="0.999"} 6.66696E-4

Cacheレベルのメトリクスには、Cache名が入っているのでわかりやすいですね。

vendor_cache_manager_default_cache_distCache_statistics_hit_ratio{node="infinispan-server-56615"} 0.7222222222222222

CacheManagerレベルのメトリクスは、どうなっているんでしょうね。

vendor_cache_manager_default_cache_container_health_free_memory_kb{node="infinispan-server-56615"} 20802.0

というか、cache_managerの後のdefaultという名前の意味がわかりません。

これは、Infinispan Serverに設定されている、デフォルトのCacheManager(CacheContainer)の名前が入って
いるわけですね。

https://github.com/infinispan/infinispan/blob/13.0.2.Final/core/src/main/java/org/infinispan/metrics/impl/AbstractMetricsRegistration.java#L72-L77

   <cache-container name="default" statistics="true">

とりあえず、Infinispan Serverはひと区切り。

Hot Rod Clientでメトリクスを取得する

次は、Hot Rod Clientでメトリクスを取得してみましょう。

確認は、テストコードとJConsoleで行うことにします。SmallRye Metricsで取得できるようにする…というのは
今回はパスします。

テストコードはこちら。

    @Test
    public void clientMetrics() {
        String uri = createUri("app-user", "password");

        Configuration configuration =
                new ConfigurationBuilder()
                        .uri(uri)
                        .statistics().enable().jmxEnable()
                        .build();

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

            IntStream
                    .rangeClosed(1, 100)
                    .forEach(i -> cache.put("key" + i, "value" + i));

            IntStream
                    .rangeClosed(1, 50)
                    .forEach(i -> assertThat(cache.get("key" + i)).isNotNull());

            IntStream
                    .rangeClosed(101, 125)
                    .forEach(i -> assertThat(cache.get("key" + i)).isNull());

            ServerStatistics serverStatistics = cache.serverStatistics();
            System.out.println(serverStatistics.getStatsMap());
            RemoteCacheClientStatisticsMXBean clientStatistics = cache.clientStatistics();
            assertThat(clientStatistics.getRemoteStores()).isEqualTo(100);
            assertThat(clientStatistics.getRemoteHits()).isEqualTo(50);
            assertThat(clientStatistics.getRemoteMisses()).isEqualTo(25);
        }
    }

メトリクスもJMXもデフォルトでは無効なので、それぞれ有効にしておきます。

        Configuration configuration =
                new ConfigurationBuilder()
                        .uri(uri)
                        .statistics().enable().jmxEnable()
                        .build();

メトリクスは、こんな感じでJava APIで取得できます。

            ServerStatistics serverStatistics = cache.serverStatistics();
            System.out.println(serverStatistics.getStatsMap());
            RemoteCacheClientStatisticsMXBean clientStatistics = cache.clientStatistics();
            assertThat(clientStatistics.getRemoteStores()).isEqualTo(100);
            assertThat(clientStatistics.getRemoteHits()).isEqualTo(50);
            assertThat(clientStatistics.getRemoteMisses()).isEqualTo(25);

System.out.printlnしている、ServerStatisticsの部分はこんな感じになります。

{currentNumberOfEntries=-1, globalRemoveHits=0, removeMisses=0, globalRetrievals=150, stores=68, retrievals=40, globalHits=100, globalRemoveMisses=0, hits=30, removeHits=0, timeSinceStart=1, globalCurrentNumberOfEntries=100, totalNumberOfEntries=68, misses=10, globalMisses=50, globalStores=200}

この時に、JConsoleで見るとこんな感じになります。

f:id:Kazuhira:20211211001745p:plain

これで、Infinispan ServerとHot Rod Clientでメトリクスを確認できました。

Prometheusでメトリクスを取得する

最後に、PrometheusからInfinispan Serverのメトリクスを取得してみましょう。

こんな感じで設定。

prometheus.yml

global:
  scrape_interval: 5s
  evaluation_interval: 5s

scrape_configs:
  - job_name: "infinispan-server"
    static_configs:
      - targets:
        - 172.18.0.2:11222
        - 172.18.0.3:11222
        - 172.18.0.4:11222
    basic_auth:
      username: app-user
      password: password
  - job_name: "prometheus"
    static_configs:
      - targets: ["localhost:9090"]

今回は、Nodeを固定で指定。Basic認証も設定しています。

  - job_name: "infinispan-server"
    static_configs:
      - targets:
        - 172.18.0.2:11222
        - 172.18.0.3:11222
        - 172.18.0.4:11222
    basic_auth:
      username: app-user
      password: password

設定したら、PrometheusのWeb UIで確認。

f:id:Kazuhira:20211213234703p:plain

OKですね。

もう少し中身を

Infinispanのメトリクスは?

JMX寄りで。

メトリクスに関するインターフェースやクラスは、このあたりにあるのが確認できます。

https://github.com/infinispan/infinispan/tree/13.0.2.Final/core/src/main/java/org/infinispan/stats

https://github.com/infinispan/infinispan/tree/13.0.2.Final/core/src/main/java/org/infinispan/stats/impl

これ以外にも存在するのはドキュメントで確認できるのですが。

JMX Components

特にJMXの属性や操作は、以下のアノテーションで指定されているものが対象みたいです。

https://github.com/infinispan/infinispan/blob/13.0.2.Final/component-annotations/src/main/java/org/infinispan/jmx/annotations/ManagedAttribute.java

https://github.com/infinispan/infinispan/blob/13.0.2.Final/component-annotations/src/main/java/org/infinispan/jmx/annotations/ManagedOperation.java

これを、ビルド時にPluggable Annotation Processing APIで処理してソースコードを生成します。

https://github.com/infinispan/infinispan/blob/13.0.2.Final/component-processor/src/main/java/org/infinispan/component/processor/ComponentAnnotationProcessor.java#L384-L407

https://github.com/infinispan/infinispan/blob/13.0.2.Final/component-processor/src/main/java/org/infinispan/component/processor/ComponentAnnotationProcessor.java#L409-L424

https://github.com/infinispan/infinispan/blob/13.0.2.Final/component-processor/src/main/java/org/infinispan/component/processor/Generator.java#L224-L261

まずは、JMX MBeanに関する話でした。

Eclipse MicroProfile Metricsで取得できるメトリクス

Infinispanのドキュメントを見ると、JMX MBeanとしてこれだけの情報が確認できることは書きました。
ただ、Eclipse MicroProfile Metricsで取得できるメトリクスの数はもっと少ないです。

JMX Components

どういうことでしょう?

メトリクスを登録しているのは、こちらです。

https://github.com/infinispan/infinispan/blob/13.0.2.Final/core/src/main/java/org/infinispan/metrics/impl/MetricsCollector.java#L115-L174

ここを見ると、gaugeとhistogramのみが対象みたいですね。

これには、@ManagedAttributeアノテーションのdataType属性が関係します。

https://github.com/infinispan/infinispan/blob/13.0.2.Final/component-annotations/src/main/java/org/infinispan/jmx/annotations/ManagedAttribute.java#L44

gaugeに対応するものはMEASUREMENTで、かつ整数・小数のものみたいです。

https://github.com/infinispan/infinispan/blob/13.0.2.Final/component-annotations/src/main/java/org/infinispan/jmx/annotations/DataType.java#L15-L20

https://github.com/infinispan/infinispan/blob/13.0.2.Final/component-processor/src/main/java/org/infinispan/component/processor/Generator.java#L263-L274

histogramはHISTOGRAMおよびTIMERが対応すると思うのですが…

https://github.com/infinispan/infinispan/blob/13.0.2.Final/component-annotations/src/main/java/org/infinispan/jmx/annotations/DataType.java#L22-L30

https://github.com/infinispan/infinispan/blob/13.0.2.Final/component-processor/src/main/java/org/infinispan/component/processor/Generator.java#L276-L283

使われている箇所が、ここくらいしかありません。

https://github.com/infinispan/infinispan/blob/13.0.2.Final/core/src/main/java/org/infinispan/interceptors/impl/CacheMgmtInterceptor.java

この点については、今回はここまでにしておきます…。

というわけで、JMX MBeanのドキュメントに記載されている対象すべてからメトリクスが取得できるわけではないですし、
その差はソースコードを見ないとわからないわけですが。

まあ、実際にメトリクスを取得して確認した方が早いでしょうね。

Eclipse MicroProfile Metricsのエンドポイント

Eclipse MicroProfile Metricsのエンドポイントと

https://github.com/infinispan/infinispan/blob/13.0.2.Final/server/rest/src/main/java/org/infinispan/rest/resources/MetricsResource.java

関連するSmallRye Metricsのソースコードはこちら。

https://github.com/smallrye/smallrye-metrics/blob/3.0.1/implementation/src/main/java/io/smallrye/metrics/MetricsRequestHandler.java

https://github.com/smallrye/smallrye-metrics/blob/main/implementation/src/main/java/io/smallrye/metrics/exporters/OpenMetricsExporter.java

Hot Rod Clientのメトリクスに関するインターフェースとクラス

Hot Rod Clientのメトリクスに関するインターフェースとクラスの組み合わせは、こちら。

インターフェース。

https://github.com/infinispan/infinispan/blob/13.0.2.Final/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/jmx/RemoteCacheClientStatisticsMXBean.java

https://github.com/infinispan/infinispan/blob/13.0.2.Final/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/jmx/RemoteCacheManagerMXBean.java

https://github.com/infinispan/infinispan/blob/13.0.2.Final/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/ServerStatistics.java

クラス、というか実装。

https://github.com/infinispan/infinispan/blob/13.0.2.Final/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/ClientStatistics.java

https://github.com/infinispan/infinispan/blob/13.0.2.Final/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/RemoteCacheManager.java

https://github.com/infinispan/infinispan/blob/13.0.2.Final/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/ServerStatisticsImpl.java

どうも、Hot Rod Clientで取得できるメトリクス自体には、ドキュメントがない気がします…。

オマケ: Infinispan ServerのEndpointに認証設定を行う

どうも、Infinispan 13でEndpoint要素の設定方法が変わった気がします。

ドキュメントに従って

Deploying and Configuring Infinispan Servers / Manually Configuring Hot Rod Authentication

Deploying and Configuring Infinispan Servers / Manually Configuring REST Authentication

このように設定すると

      <endpoints socket-binding="default" security-realm="default">
         <hotrod-connector>
            <authentication>
               <sasl mechanisms="SCRAM-SHA-512 SCRAM-SHA-384 SCRAM-SHA-256
                                 SCRAM-SHA-1 DIGEST-SHA-512 DIGEST-SHA-384
                                 DIGEST-SHA-256 DIGEST-SHA DIGEST-MD5 PLAIN"
                     server-name="infinispan"
                     qop="auth"/>
            </authentication>
         </hotrod-connector>
         <rest-connector>
            <authentication mechanisms="DIGEST BASIC"/>
         </rest-connector>
      </endpoints>

例外になるので

2021-12-13 15:11:47,501 FATAL (main) [org.infinispan.SERVER] ISPN080028: Infinispan Server failed to start org.infinispan.commons.configuration.io.ConfigurationReaderException: Unexpected element 'hotrod-connector' encountered[53,28]
at org.infinispan.configuration.parsing.ParseUtils.unexpectedElement(ParseUtils.java:36)
at org.infinispan.server.configuration.ServerConfigurationParser.parseEndpoints(ServerConfigurationParser.java:1482)
at org.infinispan.server.configuration.ServerConfigurationParser.parseServerElements(ServerConfigurationParser.java:129)
at org.infinispan.server.configuration.ServerConfigurationParser.readElement(ServerConfigurationParser.java:101)
at org.infinispan.configuration.parsing.ParserRegistry.parseElement(ParserRegistry.java:204)
at org.infinispan.configuration.parsing.ConfigurationBuilderHolder.handleAnyElement(ConfigurationBuilderHolder.java:160)
at org.infinispan.commons.configuration.io.AbstractConfigurationReader.handleAny(AbstractConfigurationReader.java:57)
at org.infinispan.configuration.parsing.Parser.readElement(Parser.java:98)
at org.infinispan.configuration.parsing.ParserRegistry.parseElement(ParserRegistry.java:204)
at org.infinispan.configuration.parsing.ParserRegistry.parse(ParserRegistry.java:182)
at org.infinispan.configuration.parsing.ParserRegistry.parse(ParserRegistry.java:170)
at org.infinispan.configuration.parsing.ParserRegistry.parse(ParserRegistry.java:164)
at org.infinispan.server.Server.parseConfiguration(Server.java:306)
at org.infinispan.server.Server.<init>(Server.java:224)
at org.infinispan.server.Bootstrap.runInternal(Bootstrap.java:163)
at org.infinispan.server.tool.Main.run(Main.java:98)
at org.infinispan.server.Bootstrap.main(Bootstrap.java:50)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at org.infinispan.server.loader.Loader.run(Loader.java:106)
at org.infinispan.server.loader.Loader.main(Loader.java:51)

ソースコードとドキュメントを見て

https://github.com/infinispan/infinispan/blob/13.0.2.Final/server/runtime/src/main/java/org/infinispan/server/configuration/ServerConfigurationParser.java#L1478-L1483

このようにendpointを追加。

      <endpoints socket-binding="default" security-realm="default">
         <endpoint>
            <hotrod-connector>
               <authentication>
                  <sasl mechanisms="SCRAM-SHA-512 SCRAM-SHA-384 SCRAM-SHA-256
                                    SCRAM-SHA-1 DIGEST-SHA-512 DIGEST-SHA-384
                                    DIGEST-SHA-256 DIGEST-SHA DIGEST-MD5 PLAIN"
                        server-name="infinispan"
                        qop="auth"/>
               </authentication>
            </hotrod-connector>
            <rest-connector>
               <authentication mechanisms="DIGEST BASIC"/>
            </rest-connector>
         </endpoint>
      </endpoints>

XML Schema定義を書いたドキュメントには、反映されているんですけどね。

urn:infinispan:server:13.0

f:id:Kazuhira:20211214003019p:plain

まとめ

Infinispan ServerおよびHot Rod Clientでのメトリクス取得を試してみました。

中身を追ったのでやや大変でしたが、いろいろ仕掛けがわかって良かったかなと思います。

今回作成したソースコードは、こちらに置いています。

https://github.com/kazuhira-r/infinispan-getting-started/tree/master/remote-create-cache