Skip to content

Monitor client performance

For the complete documentation index see: llms.txt

All documentation pages available in markdown.

Applies to

  • Aerospike Developer SDK (Java 21+ and Python 3.11+)
  • Aerospike Database 8.2.0 or later, unless a section states otherwise

Client-side performance monitoring helps you detect regressions, troubleshoot timeouts and connection issues, and correlate application behavior with cluster health. Typical signals include operation volume, error and retry rates, latency distributions, and connection pool usage, aggregated by cluster, node, or namespace.

Both SDKs have a built-in, cluster-scoped metrics collector, like the classic Aerospike clients. It’s off by default. In the Java SDK, turn it on in the cluster definition’s metrics settings and poll cluster.getMetricsSnapshot(). In the Python SDK, call cluster.enable_metrics(MetricsPolicy(operational_enabled=True)) and poll cluster.metrics_snapshot(). A snapshot holds latency histograms, byte counts, connection lifecycle, and retry and timeout counters; without the operational tier, the collector records only connection and node gauges. Both SDKs can also write the snapshots to a periodic metrics log file. The sections below cover the built-in collector and its metrics, and manual instrumentation for exporting measurements to the tools your team already uses (for example Prometheus, OpenTelemetry, Datadog, or structured logs). For complementary request-level detail during development, see Configure logging.

Except where noted, snippets on this page use the imports below. A snippet lists additional import lines only when it needs a type not shown here. When this page includes a Complete example section, that block is fully self-contained with every import required to run it.

import com.aerospike.client.sdk.Cluster;
import com.aerospike.client.sdk.ClusterDefinition;
import com.aerospike.client.sdk.DataSet;
import com.aerospike.client.sdk.Session;
import com.aerospike.client.sdk.metrics.LatencySnapshot;
import com.aerospike.client.sdk.metrics.LatencyType;
import com.aerospike.client.sdk.metrics.MetricsExporterType;
import com.aerospike.client.sdk.metrics.MetricsSnapshot;
import com.aerospike.client.sdk.metrics.NamespaceMetricsSnapshot;
import com.aerospike.client.sdk.metrics.NodeMetricsSnapshot;
import com.aerospike.client.sdk.policy.Behavior;
import java.time.Clock;
import java.time.Duration;
import java.util.Arrays;
import java.util.Map;

Available metrics

Collection comes in tiers, so the cost of measuring is opt-in. The tiers are the same in both SDKs.

TierContentsEnabled by
Always onPer-node connection counts (in use, in pool, opened, closed) and node membershipenabled(true) / enabled=True
OperationalPer-namespace latency histograms (conn, write, read, batch, query), bytes in and out, errors, timeouts, key-busy and retry countersoperational(o -> o.enabled(true)) / operational_enabled=True
UsageCounts of which SDK features the application usesusage(u -> u.enabled(true)) / usage_enabled=True

Enabling metrics without the operational tier records no per-command timing, so the latency histograms stay empty.

Latency histograms default to milliseconds with 7 columns and a shift of 1, giving the buckets <=1, >1, >2, >4, >8, >16 and >32 ms. Snapshot values are cumulative since metrics were enabled, not deltas since the last export.

The metric names below are the columns of the metrics log file.

Standard metrics

Enabling metrics records these.

MetricTypeDescription
conns_in_useGaugeConnections executing a command, per node
conns_in_poolGaugeIdle connections in the pool, per node
conns_openedCounterConnections opened, per node
conns_closedCounterConnections closed, per node
cpuGaugeCPU use of the client process, as a percentage
memGaugeMemory use of the client process, in bytes

Extended metrics

Extended metrics come in two tiers, each turned on separately. The operational tier records the first eight rows, and the usage tier the last four.

MetricTypeDescription
command_countCounterCommands issued, cluster-wide
command_retriesCounterCommand retries, cluster-wide
errorsCounterFailed commands that no more specific counter records, per namespace
timeoutsCounterCommands that timed out, per namespace. The Python SDK counts only the timeouts the server reports.
key_busyCounterCommands that failed with KEY_BUSY (14), per namespace
bytes_inCounterBytes received from the server, per namespace
bytes_outCounterBytes sent to the server, per namespace
latencyHistogramCommand latency per namespace, one histogram each for conn, write, read, batch and query
blocking_countCounterCalls that return once their result is ready
deferred_countCounterAsynchronous calls
background_countCounterBackground tasks started
tran_countCounterTransactions

Enable metrics

ClusterDefinition definition = new ClusterDefinition("localhost", 3000)
.withSystemSettings(settings -> settings
.metrics(metrics -> metrics
.enabled(true)
.exporter(MetricsExporterType.NONE)
.extended(extended -> extended
.operational(operational -> operational.enabled(true)))));
try (Cluster cluster = definition.connect()) {
Session session = cluster.createSession(Behavior.DEFAULT);
DataSet users = DataSet.of("test", "users");
session.query(users.id("user-1")).execute().getFirstRecord();
}

📖 API reference: ClusterDefinition(String,int) | ClusterDefinition.withSystemSettings(...) | ClusterDefinition.connect() | Cluster.enableMetrics(...) | Cluster.disableMetrics() | MetricsExporterType

Disabling metrics, or closing the cluster, exports one final snapshot so the activity since the last export is not lost.

Access metrics snapshots

Get current metric values programmatically:

// NONE: poll snapshots and export nothing.
try (Cluster cluster = new ClusterDefinition("localhost", 3000)
.withSystemSettings(s -> s.metrics(m -> m
.enabled(true)
.exporter(MetricsExporterType.NONE)
.extended(e -> e.operational(o -> o.enabled(true)))))
.connect()) {
// ... application traffic runs here ...
MetricsSnapshot snapshot = cluster.getMetricsSnapshot();
long reads = 0;
for (NodeMetricsSnapshot node : snapshot.nodes) {
for (NamespaceMetricsSnapshot ns : node.namespaces) {
for (LatencySnapshot latency : ns.latencies) {
if (latency.type == LatencyType.READ) {
for (long count : latency.bucketCounts) {
reads += count;
}
}
}
}
}
System.out.printf("%d reads%n", reads);
// Per-node connection pool detail:
for (NodeMetricsSnapshot node : snapshot.nodes) {
System.out.printf("%s: %d connections in use, %d in pool%n",
node.nodeName, node.connections.inUse, node.connections.inPool);
}
}

📖 API reference: ClusterDefinition.withSystemSettings() | Cluster.getMetricsSnapshot() | MetricsSnapshot

Poll on an interval (for example every 30 seconds) rather than per operation.

Metrics log files

The file exporter writes the line-oriented metrics log format under a report directory: a header line that declares the schema, then one line per export. It is the default exporter type (FILE in Java, learn_metrics_file in Python), and it writes nothing unless a report directory is set. To send snapshots somewhere else, select CUSTOM and add an IMetricsExporter (Java), or register an AsyncMetricsExporter with cluster.add_exporter() (Python).

// Each export interval appends a snapshot line to metrics-<yyyyMMddHHmmss>.log in reportDir.
try (Cluster cluster = new ClusterDefinition("localhost", 3000)
.withSystemSettings(s -> s.metrics(m -> m
.enabled(true)
.reportDir("/var/log/aerospike/metrics")
.exportInterval(Duration.ofSeconds(30))))
.connect()) {
// ... application traffic runs here ...
}

📖 API reference: ClusterDefinition.withSystemSettings() | MetricsSettings.MetricsTweaks

Client identification labels

Add labels to identify metrics by application or environment. Labels are attached to every snapshot and written to every log line.

// Labels go on every metrics snapshot and metrics log line.
try (Cluster cluster = new ClusterDefinition("localhost", 3000)
.withSystemSettings(s -> s.metrics(m -> m
.enabled(true)
.reportDir("/var/log/aerospike/metrics")
.labels(Map.of("app", "my-service", "env", "production", "region", "us-west-2"))))
.connect()) {
// ... application traffic runs here ...
}

📖 API reference: ClusterDefinition.withSystemSettings() | MetricsSettings.MetricsTweaks

Instrument your own calls

You can also time application operations yourself and export them to the tools your team already uses, for example Prometheus, OpenTelemetry, Datadog, or structured logs.

// Additional imports for this example:
import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.Timer;
import io.micrometer.prometheus.PrometheusConfig;
import io.micrometer.prometheus.PrometheusMeterRegistry;
// Application-owned registry (not provided by the Aerospike JAR)
MeterRegistry registry = new PrometheusMeterRegistry(PrometheusConfig.DEFAULT);
try (Cluster cluster = new ClusterDefinition("localhost", 3000).connect()) {
Timer.Sample sample = Timer.start(registry);
try {
// session.query(...).execute(); etc.
} finally {
sample.stop(registry.timer("aerospike.sdk.requests"));
}
}

📖 API reference: ClusterDefinition(String,int) | ClusterDefinition.connect() | Cluster.close() | ChainableQueryBuilder.execute()

Integration with monitoring systems

Prometheus + Grafana

  1. Export metrics using an HTTP endpoint
  2. Configure Prometheus to scrape your application
  3. Import the Aerospike client dashboard in Grafana

Datadog

// Additional imports for this example:
import io.micrometer.datadog.DatadogConfig;
import io.micrometer.datadog.DatadogMeterRegistry;
DatadogMeterRegistry registry = new DatadogMeterRegistry(
DatadogConfig.DEFAULT, Clock.SYSTEM);
// Register timers/counters around your own Aerospike calls; the SDK does not wire this for you.

📖 API reference: com.aerospike.client.sdk

Performance impact

Built-in collection is cheap enough that it is not a reason to leave metrics off. The operational tier, which times every command, is the part with a per-command cost. For latency-critical applications, leave it off, or record only a sample of commands:

// Gauges only: with the operational tier off, no latency histograms are recorded.
try (Cluster cluster = new ClusterDefinition("localhost", 3000)
.withSystemSettings(s -> s.metrics(m -> m
.enabled(true)
.exporter(MetricsExporterType.NONE)))
.connect()) {
// ... application traffic runs here ...
}

📖 API reference: ClusterDefinition.withSystemSettings()

Next steps

Configure Logging

Set up client-side logging for debugging.

Logging →

Tune Performance

Optimize client configuration with Behaviors.

Behaviors →