Spring Boot Actuator 运维监控教程

目录

  1. Actuator概述
  2. 端点配置
  3. 健康检查
  4. 指标监控
  5. 自定义指标
  6. 日志管理
  7. 生产环境配置
  8. 安全配置
  9. Prometheus集成
  10. Grafana可视化
  11. 告警配置
  12. 总结

Actuator概述

Actuator功能

Spring Boot Actuator提供了生产就绪的功能,帮助您监控和管理Spring Boot应用程序。

核心功能

  • 健康检查: 应用程序和依赖服务的健康状态
  • 指标收集: 应用程序的性能指标和业务指标
  • 端点暴露: HTTP/JMX端点获取应用程序信息
  • 日志管理: 动态日志级别调整和日志查看
  • 环境信息: 配置属性、系统属性、环境变量

Maven依赖配置

<dependencies>
    <!-- Spring Boot Actuator -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-actuator</artifactId>
        <version>2.7.5</version>
    </dependency>
    
    <!-- Micrometer for metrics -->
    <dependency>
        <groupId>io.micrometer</groupId>
        <artifactId>micrometer-core</artifactId>
        <version>1.9.5</version>
    </dependency>
    
    <!-- Prometheus metrics -->
    <dependency>
        <groupId>io.micrometer</groupId>
        <artifactId>micrometer-registry-prometheus</artifactId>
        <version>1.9.5</version>
    </dependency>
    
    <!-- JMX support -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter</artifactId>
    </dependency>
</dependencies>

基础配置

application.yml配置

management:
  endpoints:
    web:
      exposure:
        include: "*"  # 在生产环境中应该仅暴露必要的端点
        exclude: shutdown
      base-path: /actuator
      path-mapping:
        health: health-check
        
  endpoint:
    health:
      show-details: always
      show-components: always
    info:
      enabled: true
    metrics:
      enabled: true
    prometheus:
      enabled: true
      
  info:
    env:
      enabled: true
    java:
      enabled: true
    git:
      mode: full
    build:
      enabled: true

# 应用程序信息
info:
  app:
    name: Spring MVC Application
    description: 基于Spring MVC的企业级应用
    version: 1.0.0
    developer: Your Team
  java:
    vendor: ${java.vendor}
    version: ${java.version}
    
logging:
  level:
    org.springframework.boot.actuator: INFO

端点配置

内置端点管理

基础端点配置

@Configuration
public class ActuatorConfig {
    
    @Bean
    public EndpointMappingCustomEndpointMappingCustomizer endpointMappingCustomizer() {
        return endpointMapping -> {
            endpointMapping.setPrefix("/api/admin"); // 改变端点前缀
        };
    }
    
    // 自定义端点
    @Component
    @Endpoint(id = "custom")
    public class CustomEndpoint {
        
        @ReadOperation
        public Map<String, Object> custom() {
            Map<String, Object> result = new HashMap<>();
            result.put("timestamp", LocalDateTime.now());
            result.put("application", "Spring MVC App");
            result.put("status", "running");
            return result;
        }
        
        @WriteOperation
        public Map<String, Object> customWrite(String parameter) {
            Map<String, Object> result = new HashMap<>();
            result.put("parameter", parameter);
            result.put("timestamp", LocalDateTime.now());
            return result;
        }
    }
    
    // 控制器端点(简化HTTP方法)
    @RestControllerEndpoint(id = "customcontroller")
    public class CustomControllerEndpoint {
        
        @GetMapping("/custom-controller")
        public ResponseEntity<Map<String, Object>> customEndpoint() {
            Map<String, Object> result = new HashMap<>();
            result.put("message", "自定义控制器端点");
            result.put("timestamp", LocalDateTime.now());
            return ResponseEntity.ok(result);
        }
    }
}

Web端点安全

端点安全配置

@Configuration
public class ActuatorSecurityConfig {
    
    @Bean
    public SecurityFilterChain actuatorFilterChain(HttpSecurity http) throws Exception {
        http
            .requestMatcher(EndpointRequest.toAnyEndpoint())
            .authorizeRequests(authorize -> 
                authorize
                    .requestMatchers(EndpointRequest.to("health", "info")).permitAll()
                    .requestMatchers(EndpointRequest.to("prometheus")).hasRole("METRICS")
                    .requestMatchers(EndpointRequest.to("shutdown")).hasRole("ADMIN")
                    .anyRequest().authenticated())
            .httpBasic(withDefaults());
            
        return http.build();
    }
}

// 信息端点自定义
@Component
public class CustomInfoContributor implements InfoContributor {
    
    @Override
    public void contribute(Info.Builder builder) {
        builder.withDetail("custom", Map.of(
            "deployedBy", "DevOps Team",
            "deploymentTime", LocalDateTime.now(),
            "environment", "Production",
            "instanceId", System.getProperty("instance.id", "unknown")
        ));
    }
}

健康检查

内置健康指示器

健康检查配置

@Configuration
public class HealthConfig {
    
    @Autowired
    private DataSource dataSource;
    
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
    
    // 数据库健康指示器
    @Bean
    public HealthIndicator databaseHealthIndicator() {
        return () -> {
            try (Connection connection = dataSource.getConnection()) {
                DatabaseMetaData metaData = connection.getMetaData();
                String database = metaData.getDatabaseProductName();
                
                return Health.up()
                    .withDetail("database", database)
                    .withDetail("version", metaData.getDatabaseProductVersion())
                    .withDetail("url", metaData.getURL())
                    .build();
            } catch (Exception e) {
                return Health.down()
                    .withDetail("database", "Unknown")
                    .withDetail("error", e.getMessage())
                    .build();
            }
        };
    }
    
    // Redis健康指示器
    @Bean
    public HealthIndicator redisHealthIndicator() {
        return () -> {
            try {
                String pong = redisTemplate.getConnectionFactory()
                    .getConnection()
                    .ping();
                    
                return Health.up()
                    .withDetail("redis", "Redis")
                    .withDetail("ping", pong)
                    .build();
            } catch (Exception e) {
                return Health.down()
                    .withDetail("redis", "Redis")
                    .withDetail("error", e.getMessage())
                    .build();
            }
        };
    }
    
    // 外部API健康检查
    @Component
    public class ExternalApiHealthIndicator implements HealthIndicator {
        
        @Autowired
        private RestTemplate restTemplate;
        
        @Override
        public健康状况 health() {
            try {
                ResponseEntity<String> response = restTemplate.getForEntity(
                    "https://api.external.com/health", String.class);
                    
                if (response.getStatusCode().is2xxSuccessful()) {
                    return Health.up()
                        .withDetail("externalApi", "https://api.external.com/health")
                        .withDetail("status", "Available")
                        .build();
                } else {
                    return Health.down()
                        .withDetail("externalApi", "https://api.external.com/health")
                        .withDetail("status", "Unavailable")
                        .build();
                }
            } catch (Exception e) {
                return Health.down()
                    .withDetail("externalApi", "https://api.external.com/health")
                    .withDetail("error", e.getMessage())
                    .build();
            }
        }
    }
    
    // 自定义业务健康检查
    @Component
    public class BusinessHealthIndicator implements HealthIndicator {
        
        @Autowired
        private UserService userService;
        
        @Autowired
        private OrderService orderService;
        
        @Override
        public Health health() {
            try {
                // 检查用户服务
                long userCount = userService.getTotalUserCount();
                boolean canCreateUser = userCount < 1000000; // 业务规则:用户数量限制
                
                // 检查订单服务
                long pendingOrders = orderService.getPendingOrderCount();
                boolean ordersHealthy = pendingOrders < 10000; // 业务规则:待处理订单限制
                
                if (canCreateUser && ordersHealthy) {
                    return Health.up()
                        .withDetail("userService", "Healthy")
                        .withDetail("orderService", "Healthy")
                        .withDetail("totalUsers", userCount)
                        .withDetail("pendingOrders", pendingOrders)
                        .build();
                } else {
                    return Health.down()
                        .withDetail("userService", canCreateUser ? "Healthy" : "Overloaded")
                        .withDetail("orderService", ordersHealthy ? "Healthy" : "Overloaded")
                        .withDetail("totalUsers", userCount)
                        .withDetail("pendingOrders", pendingOrders)
                        .withDetail("reason", "Business rules violated")
                        .build();
                }
            } catch (Exception e) {
                return Health.down()
                    .withDetail("error", e.getMessage())
                    .withDetail("businessHealth", "Failed")
                    .build();
            }
        }
    }
}

健康检查通知

健康状态变更通知

@Component
public class HealthStatusNotifier {
    
    private static final Logger logger = LoggerFactory.getLogger(HealthStatusNotifier.class);
    
    private final Map<String, Health> previousStatus = new HashMap<>();
    
    @EventListener
    public void onHealthStatusChange(HealthStatusChangeEvent event) {
        String healthIndicatorName = event.getHealthIndicatorName();
        Health currentHealth = event.getHealth();
        Health previousHealthStatus = previousStatus.get(healthIndicatorName);
        
        if (previousHealthStatus != null && 
            !previousHealthStatus.getStatus().equals(currentHealth.getStatus())) {
            
            logHealthStatusChange(healthIndicatorName, previousHealthStatus, currentHealth);
            
            // 发送通知
            sendHealthNotification(healthIndicatorName, previousHealthStatus, currentHealth);
        }
        
        previousStatus.put(healthIndicatorName, currentHealth);
    }
    
    private void logHealthStatusChange(String name, Health previous, Health current) {
        logger.warn("健康状态变更 - {}: {} -> {}", 
                   name, previous.getStatus(), current.getStatus());
    }
    
    private void sendHealthNotification(String name, Health previous, Health current) {
        // 发送邮件通知
        emailService.sendHealthAlert(name, previous.getStatus(), current.getStatus());
        
        // 发送Slack通知
        slackService.sendHealthAlert(name, previous.getStatus(), current.getStatus());
        
        // 记录到监控系统
        monitoringService.recordHealthEvent(name, previous, current);
    }
}

指标监控

Micrometer指标

自定义指标配置

@Configuration
public class MetricsConfig {
    
    @Bean
    public MeterRegistry meterRegistry() {
        PrometheusMeterRegistry registry = new PrometheusMeterRegistry(PrometheusConfig.DEFAULT);
        return registry;
    }
    
    @Bean
    public TimedAspect timedAspect(MeterRegistry meterRegistry) {
        return new TimedAspect(meterRegistry);
    }
    
    @Bean
    public CountedAspect countedAspect(MeterRegistry meterRegistry) {
        return new CountedAspect(meterRegistry);
    }
}

@Service
public class BusinessMetricsService {
    
    private final MeterRegistry meterRegistry;
    private final Counter userRegistrationCounter;
    private final Counter orderCreationCounter;
    private final Timer orderProcessingTimer;
    private final Gauge activeUsersGauge;
    
    public BusinessMetricsService(MeterRegistry meterRegistry) {
        this.meterRegistry = meterRegistry;
        
        // 用户注册计数器
        this.userRegistrationCounter = Counter.builder("user.registrations")
            .description("用户注册总数")
            .tag("application", "ecommerce")
            .register(meterRegistry);
            
        // 订单创建计数器
        this.orderCreationCounter = Counter.builder("orders.created")
            .description("订单创建总数")
            .tag("application", "ecommerce")
            .register(meterRegistry);
            
        // 订单处理计时器
        this.orderProcessingTimer = Timer.builder("orders.processing.time")
            .description("订单处理耗时")
            .tag("application", "ecommerce")
            .register(meterRegistry);
            
        // 活跃用户数仪表
        this.activeUsersGauge = Gauge.builder("users.active")
            .description("当前活跃用户数")
            .tag("application", "ecommerce")
            .register(meterRegistry, this, BusinessMetricsService::getActiveUserCount);
    }
    
    public void recordUserRegistration(String userType) {
        userRegistrationCounter.increment(
            Tags.of("user.type", userType)
        );
    }
    
    public void recordOrderCreation(String orderType, BigDecimal amount) {
        orderCreationCounter.increment(
            Tags.of("order.type", orderType,
                   "amount.range", categorizeAmount(amount))
        );
    }
    
    public void recordOrderProcessingTime(Duration processingTime, String orderType) {
        orderProcessingTimer.record(processingTime,
            Tags.of("order.type", orderType)
        );
    }
    
    private double getActiveUserCount() {
        // 返回当前活跃用户数
        return userService.getActiveUserCount();
    }
    
    private String categorizeAmount(BigDecimal amount) {
        if (amount.compareTo(new BigDecimal("100")) < 0) {
            return "low";
        } else if (amount.compareTo(new BigDecimal("500")) < 0) {
            return "medium";
        } else {
            return "high";
        }
    }
}

// 使用注解自动指标收集
@Timed(description = "用户搜索耗时")
@Counted(description = "用户搜索次数")
@RestController
public class UserController {
    
    @GetMapping("/users/search")
    public ResponseEntity<List<User>> searchUsers(@RequestParam String keyword) {
        // 自动记录执行时间和调用次数
        List<User> users = userService.searchUsers(keyword);
        
        // 记录业务指标
        businessMetrics.recordUserSearch(keyword, users.size());
        
        return ResponseEntity.ok(users);
    }
}

生产环境配置

生产环境安全配置

生产环境配置

# application-prod.yml
management:
  endpoints:
    web:
      exposure:
        include: health,info,metrics,prometheus
        exclude: shutdown,env,configprops
      base-path: /actuator
      
  endpoint:
    health:
      show-details: when-authorized
      show-components: never
    shutdown:
      enabled: false
    env:
      show-values: never
    configprops:
      show-values: never
      
  info:
    env:
      enabled: false
    java:
      enabled: false
    git:
      mode: simple
      
  security:
    enabled: true
    roles: ADMIN,METRICS
    
  server:
    port: 8081
    servlet:
      context-path: /management

# 日志配置
logging:
  level:
    org.springframework.boot.actuator: WARN
    org.springframework.security: WARN
  pattern:
    console: "%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n"
    file: "%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n"
    
# 指标配置
management:
  metrics:
    export:
      prometheus:
        enabled: true
        step: 30s
    distribution:
      percentiles-histogram:
        "[http.server.requests]": true
      sla:
        "[http.server.requests]": 50ms, 100ms, 200ms, 500ms, 1s, 2s, 5s
    tags:
      application: ${spring.application.name:unknown}
      instance: ${HOSTNAME:unknown}

自定义安全配置

生产环境安全

@Configuration
@Profile("prod")
public class ProductionActuatorSecurityConfig {
    
    @Value("${management.security.username:admin}")
    private String actuatorUsername;
    
    @Value("${management.security.password}")
    private String actuatorPassword;
    
    @Bean
    @Primary
    public SecurityFilterChain actuatorSecurityFilterChain(HttpSecurity http) throws Exception {
        http
            .requestMatcher(EndpointRequest.toAnyEndpoint())
            .authorizeRequests(authorize ->
                authorize
                    .requestMatchers(EndpointRequest.to("health")).permitAll()
                    .requestMatchers(EndpointRequest.to("info")).permitAll()
                    .requestMatchers(EndpointRequest.to("prometheus")).hasRole("METRICS")
                    .requestMatchers(EndpointRequest.toPattern("heapdump")).hasRole("ADMIN")
                    .requestMatchers(EndpointRequest.toClass(ShutdownEndpoint.class)).hasRole("SUPER_ADMIN")
                    .anyRequest().authenticated()
            )
            .httpBasic(withDefaults())
            .sessionManagement(session ->
                session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
            )
            .csrf(csrf -> csrf.disable());
            
        return http.build();
    }
    
    @Bean
    public InMemoryUserDetailsManager actuatorUserDetailsManager() {
        UserDetails metricsUser = User.withDefaultPasswordEncoder()
            .username(actuatorUsername)
            .password(actuatorPassword)
            .roles("METRICS", "ADMIN")
            .build();
            
        return new InMemoryUserDetailsManager(metricsUser);
    }
}

Prometheus监控

Prometheus配置

prometheus.yml配置

global:
  scrape_interval: 15s
  evaluation_interval: 15s

rule_files:
  - "alert_rules.yml"

alerting:
  alertmanagers:
    - static_configs:
        - targets:
          - alertmanager:9093

scrape_configs:
  - job_name: 'spring-mvc-app'
    static_configs:
      - targets: ['localhost:8080']
    metrics_path: '/actuator/prometheus'
    scrape_interval: 10s
    
  - job_name: 'spring-actuator'
    static_configs:
      - targets: ['localhost:8081']
    metrics_path: '/actuator/prometheus'
    scrape_interval: 10s
    basic_auth:
      username: 'metrics'
      password: 'metrics123'

告警规则配置

# alert_rules.yml
groups:
- name: spring-mvc-alerts
  rules:
  - alert: HighErrorRate
    expr: rate(http_server_requests_seconds_count{status=~"5.."}[5m]) > 0.1
    for: 2m
    labels:
      severity: critical
    annotations:
      summary: "高错误率告警"
      description: "应用错误率超过10%"
      
  - alert: HighMemoryUsage
    expr: jvm_memory_used_bytes{area="heap"} / jvm_memory_max_bytes{area="heap"} > 0.8
    for: 5m
    labels:
      severity: warning
    annotations:
      summary: "内存使用率告警"
      description: "应用内存使用率超过80%"
      
  - alert: ApplicationDown
    expr: up{job="spring-mvc-app"} == 0
    for: 1m
    labels:
      severity: critical
    annotations:
      summary: "应用宕机告警"
      description: "应用服务不可访问"
      
  - alert: HighResponseTime
    expr: histogram_quantile(0.95, rate(http_server_requests_seconds_bucket[5m])) > 2
    for: 3m
    labels:
      severity: warning
    annotations:
      summary: "响应时间告警"
      description: "95%的请求响应时间超过2秒"

Grafana可视化

仪表板配置

应用监控仪表板

{
  "dashboard": {
    "title": "Spring MVC Application Monitoring",
    "panels": [
      {
        "title": "请求速率",
        "type": "graph",
        "targets": [
          {
            "expr": "rate(http_server_requests_seconds_count[5m])",
            "legendFormat": "{{method}} {{uri}}"
          }
        ]
      },
      {
        "title": "响应时间",
        "type": "graph",
        "targets": [
          {
            "expr": "histogram_quantile(0.50, rate(http_server_requests_seconds_bucket[5m]))",
            "legendFormat": "50th percentile"
          },
          {
            "expr": "histogram_quantile(0.95, rate(http_server_requests_seconds_bucket[5m]))",
            "legendFormat": "95th percentile"
          }
        ]
      },
      {
        "title": "JVM内存使用",
        "type": "graph",
        "targets": [
          {
            "expr": "jvm_memory_used_bytes{area=\"heap\"}",
            "legendFormat": "Heap Used"
          },
          {
            "expr": "jvm_memory_max_bytes{area=\"heap\"}",
            "legendFormat": "Heap Max"
          }
        ]
      },
      {
        "title": "活跃用户",
        "type": "stat",
        "targets": [
          {
            "expr": "users_active",
            "legendFormat": "Active Users"
          }
        ]
      }
    ]
  }
}

总结

Spring Boot Actuator为企业级应用提供了完整的生产监控解决方案:

核心技术要点

  1. 端点管理 - 丰富的应用程序信息暴露
  2. 健康检查 - 依赖服务和业务逻辑监控
  3. 指标收集 - 全面的应用程序性能指标
  4. 自定义指标 - 业务特定的监控指标
  5. Prometheus集成 - 时序数据存储和分析
  6. Grafana可视化 - 直观的监控仪表板
  7. 告警机制 - 主动的问题检测和通知

生产环境价值

  • 可观测性:全面的应用程序监控能力
  • 问题诊断:快速定位和解决生产问题
  • 性能优化:基于数据的性能调优
  • 业务监控:业务指标与系统指标关联

最佳实践建议

  1. 安全性:严格限制端点的访问权限
  2. 性能影响:选择低开销的指标收集方式
  3. 数据处理:合理设置指标采样和聚合
  4. 告警设计:设置合理的告警阈值和沉默期
  5. 存储优化:配置适当的指标保留时间

通过这些教程的深入学习,您已经构建了一个完整的Spring MVC技术栈知识体系,具备了企业级应用开发的全面能力!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序员小凯

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值