Update docs how to verify that a cluster has formed

Closes #40296

Signed-off-by: Pedro Ruivo <1492066+pruivo@users.noreply.github.com>
Signed-off-by: Alexander Schwartz <aschwart@redhat.com>
Co-authored-by: Pedro Ruivo <1492066+pruivo@users.noreply.github.com>
Co-authored-by: Alexander Schwartz <aschwart@redhat.com>
This commit is contained in:
Pedro Ruivo
2025-07-28 11:01:00 +01:00
committed by GitHub
parent d2e9b09ebc
commit cf21fa10fd
3 changed files with 77 additions and 1 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

View File

@@ -408,6 +408,46 @@ m|cache-embedded-network-external-address
|===
== Verify cluster and network health
This section provides methods to verify that your {project_name} cluster has formed correctly and that network communication between instances is functioning as expected.
It is crucial to perform these checks after deployment to ensure high availability and data consistency.
To verify if the cluster is formed properly, check one of these locations:
* Admin UI
+
Access the {project_name} Web UI, typically available at `++https://<your-host>/admin/master/console/#/master/providers++`.
Under the *Provider Info* section, locate the *connectionsInfinispan* entry.
Click on *Show more* to expand its details.
You should find information about the cluster status and the health of individual caches.
+
image:server/infinispan_info.png[Infinispan Cluster Information in Web UI]
* Logs
+
Infinispan logs a cluster view every time a new instance joins or leaves the cluster.
Search for log entries with the ID `ISPN000094`.
+
A healthy cluster view will show all expected nodes.
For example:
+
[source,text]
----
ISPN000094: Received new cluster view for channel ISPN: [node1-26186|1] (2) [node1-26186, node2-37007]
----
+
This log entry indicates that the cluster named "ISPN" currently has 2 nodes: `node1-26186` and `node2-37007`.
The `(2)` confirms the total number of nodes in the cluster.
* Metrics
+
{project_name} exposes Infinispan metrics via a Prometheus endpoint, which can be visualized in tools like Grafana.
The metric `vendor_cluster_size` shows the current number of instances in the cluster.
You should verify that this metric matches the expected number of running instances configured in your cluster.
+
Refer to <@links.observability id="metrics-for-troubleshooting-clustering-and-network" anchor="_cluster_size"/> for more information.
== Exposing metrics from caches
Metrics from caches are automatically exposed when the metrics are enabled.

View File

@@ -17,16 +17,23 @@
package org.keycloak.connections.infinispan;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.stream.Collectors;
import org.infinispan.client.hotrod.RemoteCacheManager;
import org.infinispan.commons.util.Version;
import org.infinispan.configuration.cache.Configuration;
import org.infinispan.eviction.EvictionStrategy;
import org.infinispan.health.CacheHealth;
import org.infinispan.manager.DefaultCacheManager;
import org.infinispan.manager.EmbeddedCacheManager;
import org.jboss.logging.Logger;
@@ -52,6 +59,7 @@ import org.keycloak.provider.InvalidationHandler.ObjectType;
import org.keycloak.provider.Provider;
import org.keycloak.provider.ProviderEvent;
import org.keycloak.provider.ProviderEventListener;
import org.keycloak.provider.ServerInfoAwareProviderFactory;
import org.keycloak.spi.infinispan.CacheEmbeddedConfigProvider;
import org.keycloak.spi.infinispan.CacheRemoteConfigProvider;
import org.keycloak.spi.infinispan.impl.embedded.CacheConfigurator;
@@ -73,7 +81,7 @@ import static org.keycloak.models.cache.infinispan.InfinispanCacheRealmProviderF
/**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
*/
public class DefaultInfinispanConnectionProviderFactory implements InfinispanConnectionProviderFactory, ProviderEventListener {
public class DefaultInfinispanConnectionProviderFactory implements InfinispanConnectionProviderFactory, ProviderEventListener, ServerInfoAwareProviderFactory {
private static final ReadWriteLock READ_WRITE_LOCK = new ReentrantReadWriteLock();
private static final Logger logger = Logger.getLogger(DefaultInfinispanConnectionProviderFactory.class);
@@ -278,4 +286,32 @@ public class DefaultInfinispanConnectionProviderFactory implements InfinispanCon
KeycloakModelUtils.runJobInTransaction(pme.getFactory(), this::registerSystemWideListeners);
}
}
@Override
public Map<String, String> getOperationalInfo() {
Map<String, String> info = new LinkedHashMap<>();
info.put("product", Version.getBrandName());
info.put("version", Version.getBrandVersion());
if (InfinispanUtils.isRemoteInfinispan()) {
addRemoteOperationalInfo(info);
} else {
addEmbeddedOperationalInfo(info);
}
return info;
}
private void addEmbeddedOperationalInfo(Map<String, String> info) {
var cacheManagerInfo = cacheManager.getCacheManagerInfo();
info.put("clusterSize", Integer.toString(cacheManagerInfo.getClusterSize()));
var cacheNames = Arrays.stream(InfinispanConnectionProvider.CLUSTERED_CACHE_NAMES)
.sorted()
.collect(Collectors.toCollection(LinkedHashSet::new));
for (CacheHealth health : cacheManager.getHealth().getCacheHealth(cacheNames)) {
info.put(health.getCacheName() + ":Cache", health.getStatus().toString());
}
}
private void addRemoteOperationalInfo(Map<String, String> info) {
info.put("connectionCount", Integer.toString(remoteCacheManager.getConnectionCount()));
}
}