Monitoring và Profiling Tools
Tổng quan về Monitoring
Monitoring và profiling là essential practices để đảm bảo Java applications chạy efficiently và identify performance bottlenecks trong production environment.
Spring Boot Actuator
Basic Configuration
@Configuration
public class ActuatorConfig {
@Bean
public HealthIndicator customHealthIndicator() {
return new HealthIndicator() {
@Override
public Health health() {
boolean isHealthy = checkDatabaseConnection() &&
checkMemoryUsage();
if (isHealthy) {
return Health.up()
.withDetail("status", "All systems operational")
.build();
} else {
return Health.down()
.withDetail("status", "System issues detected")
.build();
}
}
private boolean checkDatabaseConnection() {
return true;
}
private boolean checkMemoryUsage() {
Runtime runtime = Runtime.getRuntime();
long maxMemory = runtime.maxMemory();
long totalMemory = runtime.totalMemory();
long freeMemory = runtime.freeMemory();
long usedMemory = totalMemory - freeMemory;
double memoryUsagePercentage = (double) usedMemory / maxMemory * 100;
return memoryUsagePercentage < 90;
}
};
}
}
Micrometer Metrics
Custom Metrics
@Service
public class UserService {
private final Counter userCreationCounter;
private final Timer userFetchTimer;
public UserService(MeterRegistry meterRegistry) {
this.userCreationCounter = Counter.builder("users.created")
.description("Number of users created")
.register(meterRegistry);
this.userFetchTimer = Timer.builder("users.fetch.duration")
.description("Time taken to fetch user")
.register(meterRegistry);
}
@Timed(value = "users.create", description = "Time taken to create user")
public User createUser(CreateUserRequest request) {
try {
User user = new User();
user.setName(request.getName());
user.setEmail(request.getEmail());
User savedUser = userRepository.save(user);
userCreationCounter.increment(Tags.of("status", "success"));
return savedUser;
} catch (Exception e) {
userCreationCounter.increment(Tags.of("status", "error"));
throw e;
}
}
}
JProfiler và VisualVM
Performance Monitoring
@Component
public class PerformanceService {
public void expensiveOperation() {
List<String> largeList = new ArrayList<>();
for (int i = 0; i < 1000000; i++) {
largeList.add("Item " + i);
}
try {
Thread.sleep(100);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
Distributed Tracing
OpenTelemetry Configuration
@Configuration
public class TracingConfig {
@Bean
public OpenTelemetry openTelemetry() {
return OpenTelemetrySDK.builder()
.setTracerProvider(
SdkTracerProvider.builder()
.setResource(Resource.getDefault()
.merge(Resource.builder()
.put(ResourceAttributes.SERVICE_NAME, "myapp")
.build()))
.build())
.build();
}
@Bean
public Tracer tracer(OpenTelemetry openTelemetry) {
return openTelemetry.getTracer("myapp");
}
}
Structured Logging
@Service
@Slf4j
public class UserService {
public User createUser(CreateUserRequest request) {
String correlationId = UUID.randomUUID().toString();
MDC.put("correlation.id", correlationId);
MDC.put("operation", "user.create");
try {
log.info("Starting user creation for email: {}", request.getEmail());
User user = new User();
user.setEmail(request.getEmail());
User savedUser = userRepository.save(user);
log.info("User created successfully with ID: {}", savedUser.getId());
return savedUser;
} finally {
MDC.clear();
}
}
}
Best Practices
- Baseline Metrics: Establish performance baselines
- Memory Monitoring: Monitor heap usage và GC metrics
- Error Tracking: Track và analyze exceptions
- Alerting: Set up alerts for critical metrics