← Назад к вопросам

Какие знаешь способы сбора JVM метрик?

2.7 Senior🔥 61 комментариев
#Docker, Kubernetes и DevOps#JVM и управление памятью

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Способы сбора JVM метрик

Сбор метрик JVM (Java Virtual Machine) критически важен для мониторинга production приложений. Метрики показывают состояние памяти, потоков, сборки мусора и производительности. Я знаком со всеми основными подходами.

1. JMX (Java Management Extensions)

JMX — это встроенный механизм JVM для мониторинга и управления. Это самый базовый способ.

// JMX доступен по умолчанию
import java.lang.management.*;

public class JMXMetricsExample {
    public static void main(String[] args) {
        // Получить информацию о памяти
        MemoryMXBean memoryMXBean = ManagementFactory.getMemoryMXBean();
        MemoryUsage heapMemory = memoryMXBean.getHeapMemoryUsage();
        
        System.out.println("Heap Used: " + heapMemory.getUsed() / 1024 / 1024 + " MB");
        System.out.println("Heap Max: " + heapMemory.getMax() / 1024 / 1024 + " MB");
        
        // Информация о потоках
        ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
        System.out.println("Thread Count: " + threadMXBean.getThreadCount());
        System.out.println("Peak Thread Count: " + threadMXBean.getPeakThreadCount());
        
        // Информация о GC
        List<GarbageCollectorMXBean> garbageCollectors = 
            ManagementFactory.getGarbageCollectorMXBeans();
        for (GarbageCollectorMXBean gc : garbageCollectors) {
            System.out.println("GC: " + gc.getName());
            System.out.println("Collection Count: " + gc.getCollectionCount());
            System.out.println("Collection Time: " + gc.getCollectionTime() + "ms");
        }
    }
}

Запуск с JMX:

java -Dcom.sun.management.jmxremote \
     -Dcom.sun.management.jmxremote.port=9010 \
     -Dcom.sun.management.jmxremote.authenticate=false \
     -Dcom.sun.management.jmxremote.ssl=false \
     -jar application.jar

Подключение через JConsole:

jconsole localhost:9010

Преимущества:

  • Встроено в JVM
  • Нет зависимостей

Недостатки:

  • Сложно обрабатывать данные
  • Требует ручного подключения
  • Не scalable для больших систем

2. Micrometer (современный стандарт)

Micrometer — это фасад для сбора метрик, поддерживает различные backend'ы (Prometheus, DataDog, etc).

<!-- pom.xml -->
<dependency>
    <groupId>io.micrometer</groupId>
    <artifactId>micrometer-core</artifactId>
    <version>1.11.0</version>
</dependency>

<!-- Для Prometheus -->
<dependency>
    <groupId>io.micrometer</groupId>
    <artifactId>micrometer-registry-prometheus</artifactId>
    <version>1.11.0</version>
</dependency>
// Использование с Spring Boot (автоматическое)
@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

// Пользовательские метрики
@Component
public class CustomMetrics {
    private final MeterRegistry meterRegistry;
    
    public CustomMetrics(MeterRegistry meterRegistry) {
        this.meterRegistry = meterRegistry;
    }
    
    @PostConstruct
    public void init() {
        // Counter (счетчик)
        Counter.builder("orders.created")
            .description("Total orders created")
            .register(meterRegistry);
        
        // Gauge (значение)
        Gauge.builder("active.users", () -> getUserCount())
            .description("Number of active users")
            .register(meterRegistry);
        
        // Timer (время выполнения)
        Timer.builder("request.processing.time")
            .description("Request processing time")
            .register(meterRegistry);
    }
    
    public void recordOrderCreation() {
        meterRegistry.counter("orders.created").increment();
    }
    
    public long getUserCount() {
        return getUserRepository().count();
    }
}

// Использование в service
@Service
public class OrderService {
    private final MeterRegistry meterRegistry;
    private final Timer requestTimer;
    
    public OrderService(MeterRegistry meterRegistry) {
        this.meterRegistry = meterRegistry;
        this.requestTimer = Timer.builder("order.service.time").register(meterRegistry);
    }
    
    public Order createOrder(OrderRequest request) {
        return requestTimer.recordCallable(() -> {
            Order order = new Order(request);
            meterRegistry.counter("orders.created").increment();
            return order;
        });
    }
    
    // Или использовать Sample
    public void processOrder(Order order) {
        Timer.Sample sample = Timer.start(meterRegistry);
        try {
            // обработка заказа
        } finally {
            sample.stop(Timer.builder("order.process").register(meterRegistry));
        }
    }
}

// application.properties
management.endpoints.web.exposure.include=prometheus
management.metrics.export.prometheus.enabled=true
# Доступна на http://localhost:8080/actuator/prometheus
management:
  endpoints:
    web:
      exposure:
        include: prometheus,health,metrics
  metrics:
    export:
      prometheus:
        enabled: true

Метрики автоматически собираемые Spring Boot:

  • JVM memory
  • CPU usage
  • Thread count
  • GC metrics
  • HTTP requests
  • Database connections
  • Kafka producer/consumer metrics

Преимущества:

  • Лучше стандартов
  • Поддержка многих backend'ов
  • Spring Boot интеграция
  • Типизированная API

3. Spring Boot Actuator

Встроенный инструмент для мониторинга:

<!-- pom.xml -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
# application.yml
management:
  endpoints:
    web:
      exposure:
        include: health,metrics,info,prometheus
  endpoint:
    health:
      show-details: always  # Показывать подробности здоровья
  metrics:
    enable:
      jvm: true
      process: true
      system: true
# Доступные endpoints
GET /actuator                     # Все endpoints
GET /actuator/health             # Состояние приложения
GET /actuator/metrics            # Список доступных метрик
GET /actuator/metrics/{name}     # Значение конкретной метрики
GET /actuator/prometheus         # Prometheus формат
GET /actuator/info               # Информация о приложении

Пример ответа:

GET /actuator/health
{
  "status": "UP",
  "components": {
    "db": {"status": "UP"},
    "diskSpace": {"status": "UP"},
    "livenessState": {"status": "UP"},
    "readinessState": {"status": "UP"}
  }
}

GET /actuator/metrics
[
  "jvm.memory.used",
  "jvm.memory.max",
  "jvm.threads.live",
  "process.cpu.usage",
  "http.server.requests"
]

4. Prometheus + Grafana

С помощью Micrometer данные можно отправить в Prometheus и визуализировать в Grafana:

# prometheus.yml
global:
  scrape_interval: 15s

scrape_configs:
  - job_name: 'java-app'
    metrics_path: '/actuator/prometheus'
    static_configs:
      - targets: ['localhost:8080']
# Запустить Prometheus
docker run -p 9090:9090 -v $(pwd)/prometheus.yml:/etc/prometheus/prometheus.yml prom/prometheus

# Запустить Grafana
docker run -p 3000:3000 grafana/grafana

5. JFR (Java Flight Recorder)

Мощный профилировочный инструмент, встроенный в JVM:

# Записать JFR с помощью jcmd
jcmd <pid> JFR.start duration=60s filename=/tmp/recording.jfr

# Посмотреть результаты
jfr dump --xml /tmp/recording.jfr > /tmp/recording.xml
// Программное использование JFR (Java 14+)
import jdk.jfr.Event;
import jdk.jfr.Recording;

public class CustomEvent extends Event {
    public String message;
    public long value;
}

public class JFRExample {
    public static void main(String[] args) throws Exception {
        Recording recording = new Recording();
        recording.start();
        
        CustomEvent event = new CustomEvent();
        event.message = "Sample event";
        event.value = 42;
        event.commit();
        
        recording.stop();
        recording.dumpToFile(Paths.get("/tmp/recording.jfr"));
    }
}

Запуск с JFR:

java -XX:+UnlockCommercialFeatures \
     -XX:+FlightRecorder \
     -XX:StartFlightRecording=delay=0,duration=60s,filename=/tmp/recording.jfr \
     -jar application.jar

Преимущества:

  • Low overhead
  • Очень подробные данные
  • Встроено в JVM

6. OpenTelemetry

Современный стандарт для трейсинга и метрик:

<dependency>
    <groupId>io.opentelemetry</groupId>
    <artifactId>opentelemetry-api</artifactId>
</dependency>

<dependency>
    <groupId>io.opentelemetry</groupId>
    <artifactId>opentelemetry-exporter-prometheus</artifactId>
</dependency>
// Использование OpenTelemetry
import io.opentelemetry.api.GlobalOpenTelemetry;
import io.opentelemetry.api.metrics.Meter;

public class OpenTelemetryExample {
    private static final Meter meter = GlobalOpenTelemetry.getMeterProvider()
        .get("com.example");
    
    public static void main(String[] args) {
        var counter = meter.counterBuilder("requests.total")
            .build();
        
        counter.add(1);
    }
}

7. Custom Monitoring Service

Если нужно более специфичное решение:

@Service
public class MetricsCollector {
    private final MeterRegistry meterRegistry;
    
    public MetricsCollector(MeterRegistry meterRegistry) {
        this.meterRegistry = meterRegistry;
    }
    
    @Scheduled(fixedDelay = 5000)
    public void collectMetrics() {
        // Heap Memory
        MemoryMXBean memoryBean = ManagementFactory.getMemoryMXBean();
        long heapUsed = memoryBean.getHeapMemoryUsage().getUsed();
        meterRegistry.gauge("jvm.memory.heap.used.bytes", heapUsed);
        
        // CPU Usage
        OperatingSystemMXBean osBean = ManagementFactory.getOperatingSystemMXBean();
        double cpuUsage = osBean.getProcessCpuLoad() * 100;
        meterRegistry.gauge("process.cpu.usage.percent", cpuUsage);
        
        // Thread Count
        ThreadMXBean threadBean = ManagementFactory.getThreadMXBean();
        int threadCount = threadBean.getThreadCount();
        meterRegistry.gauge("jvm.threads.count", threadCount);
    }
}

Сравнение методов

МетодСложностьOverheadАвтоматизацияДля Production
JMXСредняяНизкийНетДа
MicrometerСредняяНизкийДа (Spring)Да
ActuatorНизкаяНизкийДаДа
PrometheusСредняяНизкийДаДа
JFRВысокаяОчень низкийНетДа (profiling)
OpenTelemetryВысокаяНизкийДаДа (будущее)

Лучшие практики

  1. Используй Micrometer + Prometheus — стандартное решение
  2. Spring Boot Actuator для базового мониторинга
  3. JFR для глубокого анализа проблем
  4. OpenTelemetry для новых проектов
  5. Мониторь важные метрики:
    • Heap memory usage
    • GC time и frequency
    • Thread count
    • CPU usage
    • Request latency
    • Error rate
    • Database connections

Заключение

Для большинства приложений оптимально использовать Spring Boot Actuator + Micrometer + Prometheus + Grafana. Это современный стек, который обеспечивает низкий overhead и хорошую наблюдаемость. Для глубокого профилирования используй JFR. OpenTelemetry становится стандартом, особенно в распределенных системах.