Performance Metrics - dennisholee/notes GitHub Wiki
Use Micrometer API for Performance Metrics: Create performance metrics using Micrometer’s API to ensure compatibility with monitoring systems like Prometheus, assisting SLAs for throughput and availability. SLAs Assisted: Throughput (e.g., 1000 req/s), Availability (99.9% uptime).
java
import io.micrometer.core.instrument.MeterRegistry; MeterRegistry registry; // Injected registry.counter("app.request.count").increment(); // Tracks throughput for SLA
Integrate with Spring Boot for Performance Metrics: Use spring-boot-starter-actuator to auto-configure and expose performance metrics via /actuator/prometheus, assisting SLAs for monitoring and observability. SLAs Assisted: Observability (p99 latency < 500ms).
java
// application.properties management.endpoints.web.exposure.include=metrics,prometheus // Exposes metrics for SLA monitoring
Standardize Performance Metric Names: Follow Micrometer’s convention (e.g., myapp.service.latency, lowercase, dot-separated) for consistent performance metric naming, assisting SLA tracking. SLAs Assisted: Latency (avg latency < 200ms).
java
registry.timer("myapp.service.latency", "endpoint", "/login").record(() -> process()); // Latency for SLA
Add Tags for Performance Metric Context: Include tags (e.g., endpoint=/login, topic=my-topic) for granular performance metric analysis, assisting endpoint-specific SLAs. SLAs Assisted: Endpoint latency (e.g., /login < 300ms).
java
registry.counter("api.requests.total", "endpoint", "/login", "status", "200").increment(); // Throughput by endpoint
Ensure Thread Safety for Performance Metrics: Use Micrometer’s thread-safe Counter, Timer, etc., to collect performance metrics in concurrent environments, assisting high-concurrency SLAs. SLAs Assisted: Throughput (5000 concurrent users).
java
Counter counter = registry.counter("api.calls.total"); // Thread-safe for SLA counter.increment();
Minimize Overhead for Performance Metrics: Avoid excessive performance metric creation in hot paths to reduce impact, assisting performance SLAs. SLAs Assisted: Latency (metric overhead < 1ms).
java
private final Counter requestCounter = registry.counter("api.requests.total"); // Reuse for SLA public void handleRequest() { requestCounter.increment(); }
Implement Counter for Performance Metrics: Track occurrences of performance-related events (e.g., API requests, Kafka messages) using Counter to measure throughput for SLAs. SLAs Assisted: Throughput (1000 req/s).
java
registry.counter("api.requests.count", "endpoint", "/login").increment(); // Throughput for SLA
Implement Timer for Performance Metrics: Measure duration and count of operations (e.g., method execution, Kafka processing) using Timer for latency SLAs. SLAs Assisted: Latency (p95 < 500ms).
java
registry.timer("service.process.latency", "method", "process").record(() -> service.process()); // Latency for SLA
Implement Gauge for Performance Metrics: Monitor dynamic performance metrics (e.g., queue size, active threads) using Gauge for resource usage SLAs. SLAs Assisted: Resource usage (queue size < 1000).
java
Queue queue = new LinkedList<>(); Gauge.builder("queue.size", queue, Queue::size).register(registry); // Resource usage for SLA
Implement DistributionSummary for Performance Metrics: Record distributions of performance-related values (e.g., response sizes) using DistributionSummary for payload size SLAs. SLAs Assisted: Payload size (avg response < 1MB).
java
registry.summary("response.size.bytes", "endpoint", "/data").record(response.length()); // Payload size for SLA
Annotate Methods for Performance Metrics: Use @Timed or custom annotations to collect performance metrics (e.g., latency) with Spring AOP or AspectJ, assisting latency SLAs. SLAs Assisted: Method latency (< 200ms).
java
@Timed(value = "service.process.latency", percentiles = {0.95, 0.99}) public String process(String input) { return input.toUpperCase(); } // Latency for SLA
Use AspectJ for Performance Metrics: Apply AspectJ aspects to collect performance metrics (e.g., execution time) across methods, assisting cross-cutting latency SLAs. SLAs Assisted: Latency (p99 < 1s).
java
@Aspect @Component public class MetricsAspect { private final MeterRegistry registry; public MetricsAspect(MeterRegistry registry) { this.registry = registry; } @Around("@annotation(com.example.Timed)") public Object measure(ProceedingJoinPoint joinPoint) throws Throwable { return registry.timer("custom.method.latency").record(() -> joinPoint.proceed()); // Latency for SLA } }
Manually Instrument Code for Performance Metrics: Add manual performance metrics in critical paths (e.g., Kafka consumers) to meet latency and throughput SLAs. SLAs Assisted: Kafka consumer latency (< 100ms).
java
public void consume(ConsumerRecord<String, String> record) { registry.timer("kafka.consume.latency", "topic", record.topic()) .record(() -> process(record.value())); // Consumer latency for SLA }
Configure Spring Boot for Performance Metrics: Set management.endpoints.web.exposure.include=metrics,prometheus to expose performance metrics endpoints for SLA monitoring. SLAs Assisted: Availability (99.9% uptime).
java
// application.properties management.endpoints.web.exposure.include=metrics,prometheus
Instrument Kafka Performance Metrics: Measure Kafka producer/consumer latency, throughput, and errors to meet Kafka-specific SLAs. SLAs Assisted: Kafka throughput (10,000 msg/s), Latency (< 50ms).
java
public void send(String topic, String message) { registry.timer("kafka.produce.latency", "topic", topic) .record(() -> producer.send(new ProducerRecord<>(topic, message))); // Producer latency for SLA }
Validate Performance Metric Inputs: Use Java Bean Validation to ensure performance metric names/tags are valid, assisting data integrity SLAs. SLAs Assisted: Data integrity (no invalid metrics).
java
public class MetricConfig { @NotBlank private String metricName; @NotEmpty private Map<String, String> tags; // Getters/setters } public void record(@Valid MetricConfig config) { registry.counter(config.getMetricName(), config.getTags()).increment(); // Validated metric }
Enable Percentile Performance Metrics: Configure Timer and DistributionSummary for percentiles (e.g., p95, p99) to analyze performance metric distributions for SLA compliance. SLAs Assisted: Latency (p99 < 1s).
java
Timer.builder("service.latency").publishPercentiles(0.95, 0.99).register(registry); // Percentiles for SLA
Track Error Performance Metrics: Use Counter for error rates (e.g., HTTP 500s, Kafka failures) to monitor performance issues against error SLAs. SLAs Assisted: Error rate (< 0.1%).
java
registry.counter("api.errors.total", "endpoint", "/login", "status", "500").increment(); // Error rate for SLA
Monitor Resource Performance Metrics: Collect JVM/system performance metrics (e.g., memory, threads) to meet resource usage SLAs. SLAs Assisted: Resource usage (memory < 80%).
java
registry.gauge("jvm.memory.used", ManagementFactory.getMemoryMXBean().getHeapMemoryUsage().getUsed()); // Memory for SLA
Write Unit Tests for Performance Metrics: Verify performance metrics with JUnit 5, Hamcrest, and SimpleMeterRegistry to ensure SLA compliance. SLAs Assisted: Metric accuracy for SLA reporting.
java
@Test void testProcessMetric() { SimpleMeterRegistry registry = new SimpleMeterRegistry(); MyService service = new MyService(registry); service.process("test"); assertThat(registry.counter("service.process.count").count(), equalTo(1.0)); // Throughput test }
Mock Dependencies for Performance Metrics: Use Mockito to isolate dependencies in performance metric tests, ensuring SLA-related metrics are accurate. SLAs Assisted: Kafka throughput reliability.
java
@Test void testKafkaMetric(@Mock KafkaProducer<String, String> producer) { SimpleMeterRegistry registry = new SimpleMeterRegistry(); KafkaService service = new KafkaService(producer, registry); service.send("test-topic", "msg"); assertThat(registry.counter("kafka.produce.count").count(), equalTo(1.0)); // Producer throughput }
Test AspectJ Performance Metrics: Test AspectJ advice for performance metrics to verify latency SLAs. SLAs Assisted: Latency (p95 < 500ms).
java
@Test void testMetricsAspect(@Mock MeterRegistry registry, @Mock ProceedingJoinPoint joinPoint) throws Throwable { when(joinPoint.proceed()).thenReturn("result"); MetricsAspect aspect = new MetricsAspect(registry); aspect.measure(joinPoint); verify(registry).timer(eq("custom.method.latency"), any()); // Aspect latency }
Configure MeterRegistry for Performance Metrics: Inject MeterRegistry (e.g., PrometheusMeterRegistry) for performance metrics collection. SLAs Assisted: Latency, Throughput SLAs.
java
@Bean public MeterRegistry meterRegistry() { return new PrometheusMeterRegistry(PrometheusConfig.DEFAULT); }
Set Common Tags for Performance Metrics: Apply common tags (e.g., application=myapp) to all performance metrics for SLA context. SLAs Assisted: Application-specific SLA context.
java
registry.config().commonTags("application", "myapp");
Environment-Specific Performance Metrics: Enable/disable performance metrics collection by environment to meet testing SLAs. SLAs Assisted: SLA accuracy in test environments.
java
@Value("${metrics.enabled:true}") private boolean metricsEnabled; public void record() { if (metricsEnabled) registry.counter("example.count").increment(); // Conditional throughput }
Export Performance Metrics to Prometheus/Grafana: Ensure performance metrics are collectable by Prometheus and visualizable in Grafana for SLA analysis. SLAs Assisted: Real-time SLA monitoring.
java
// application.properties management.endpoints.web.exposure.include=prometheus // Metrics scraped by Prometheus
Define Alerts for Performance Metrics: Create alerting rules for performance metric thresholds to enforce SLAs (e.g., p99 latency > 1s). SLAs Assisted: Latency, Error SLAs.
yaml
groups:
- name: alerts
rules:
- alert: HighLatency expr: histogram_quantile(0.99, rate(service_latency_seconds_bucket[5m])) > 1 for: 5m
Document Performance Metrics: Follow a naming standard (e.g., namespace.component.metric) and provide a developer guide for performance metrics to ensure SLA compliance. SLAs Assisted: Clear SLA tracking.
java
// README.md // Performance Metrics: namespace.component.metric (e.g., myapp.api.request.latency)
Scan Annotations for Performance Metrics: Use annotation scanning to document performance metric-related annotations (e.g., @Timed) for SLA-related methods. SLAs Assisted: Latency SLAs for annotated methods.
java
Set<Class<?>> timedClasses = AnnotationScanner.findClassesWithAnnotation( "com.example", Timed.class, ClassLoader.getSystemClassLoader()); // Find timed methods
Handle Exceptions for Performance Metrics: Catch and log performance metric recording errors to prevent application failures, ensuring SLA reliability. SLAs Assisted: Availability (99.9% uptime).
java
try { registry.counter("example.count").increment(); // Throughput metric } catch (Exception e) { log.error("Failed to record performance metric", e); }
Example Implementation java
import io.micrometer.core.annotation.Timed; import io.micrometer.core.instrument.MeterRegistry; import org.springframework.stereotype.Service; import javax.validation.constraints.NotBlank;
@Service public class MyService { private final MeterRegistry registry;
public MyService(MeterRegistry registry) { this.registry = registry; }
@Timed(value = "service.process.latency", percentiles = {0.95, 0.99})
public String process(@NotBlank String input) {
registry.counter("service.process.count", "input", input).increment(); // Throughput for SLA
return input.toUpperCase();
}
}
Test java
import io.micrometer.core.instrument.simple.SimpleMeterRegistry; import org.junit.jupiter.api.Test; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.*;
class MyServiceTest { private final SimpleMeterRegistry registry = new SimpleMeterRegistry(); private final MyService service = new MyService(registry);
@Test
void testProcessMetrics() {
service.process("test");
assertThat(registry.counter("service.process.count", "input", "test").count(), equalTo(1.0)); // Throughput for SLA
assertThat(registry.timer("service.process.latency").totalTime(TimeUnit.MILLISECONDS), greaterThan(0.0)); // Latency for SLA
}
}