Micrometer 实战案例详解
案例背景
假设我们要为一个电商订单服务添加可观测性,需要监控:

- 订单创建速率
- 订单处理耗时
- 订单状态分布
- 数据库连接池状态
- JVM 指标
环境准备
<!-- pom.xml -->
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-core</artifactId>
<version>1.12.5</version>
</dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-prometheus</artifactId>
<version>1.12.5</version>
</dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-jmx</artifactId>
<version>1.12.5</version>
</dependency>
基础配置
@Configuration
public class MicrometerConfig {
@Bean
public MeterRegistry meterRegistry() {
// 自定义 Registry 组合
CompositeMeterRegistry compositeRegistry = new CompositeMeterRegistry();
// Prometheus Registry
PrometheusMeterRegistry prometheusRegistry = new PrometheusMeterRegistry(
PrometheusConfig.DEFAULT
);
prometheusRegistry.config().commonTags("application", "order-service");
// JMX Registry
JmxMeterRegistry jmxRegistry = new JmxMeterRegistry(
JmxConfig.DEFAULT,
Clock.SYSTEM
);
compositeRegistry.add(prometheusRegistry);
compositeRegistry.add(jmxRegistry);
// 配置默认标签
compositeRegistry.config()
.commonTags("environment", "production")
.commonTags("region", "cn-north-1");
return compositeRegistry;
}
@Bean
public PrometheusMeterRegistry prometheusRegistry() {
return new PrometheusMeterRegistry(PrometheusConfig.DEFAULT);
}
}
核心业务指标埋点
1 计数器 Counter - 订单量统计
@Service
public class OrderService {
private final Counter orderCounter;
private final Counter failedOrderCounter;
private final MeterRegistry meterRegistry;
public OrderService(MeterRegistry meterRegistry) {
this.meterRegistry = meterRegistry;
// 创建计数器 - 总订单数
this.orderCounter = Counter.builder("order.total")
.description("Total number of orders")
.tags("type", "all")
.register(meterRegistry);
// 创建计数器 - 失败订单数
this.failedOrderCounter = Counter.builder("order.failed")
.description("Number of failed orders")
.register(meterRegistry);
}
public Order createOrder(OrderRequest request) {
try {
// 业务逻辑
Order order = doCreateOrder(request);
// 计数器自增
orderCounter.increment();
// 按省份统计
meterRegistry.counter("order.total",
"region", request.getRegion(),
"type", request.getOrderType()
).increment();
return order;
} catch (Exception e) {
failedOrderCounter.increment();
throw e;
}
}
/**
* 测试不同数值范围
*/
@PostConstruct
public void init() {
// 模拟批量创建订单计数(测试用途)
for (int i = 0; i < 100; i++) {
orderCounter.increment(1.5); // 支持小数增量
}
// 1.5 * 100 = 150
orderCounter.increment(50);
}
}
2 仪表盘 Gauge - 实时状态
@Service
public class OrderStatusService {
private final Map<String, Integer> orderStatusMap = new ConcurrentHashMap<>();
private final MeterRegistry meterRegistry;
public OrderStatusService(MeterRegistry meterRegistry) {
this.meterRegistry = meterRegistry;
initGuages();
}
private void initGuages() {
// 创建 Gauge - 订单状态数量
Gauge.builder("order.status.count", orderStatusMap,
map -> map.getOrDefault("PENDING", 0))
.description("Current pending orders")
.tag("status", "PENDING")
.register(meterRegistry);
Gauge.builder("order.status.count", orderStatusMap,
map -> map.getOrDefault("PROCESSING", 0))
.description("Current processing orders")
.tag("status", "PROCESSING")
.register(meterRegistry);
// 订单金额统计(无需额外线程)
Gauge.builder("order.amount.total", this,
OrderStatusService::getTotalAmount)
.description("Total order amount")
.register(meterRegistry);
}
private double getTotalAmount() {
return totalAmount.get();
}
private final AtomicLong totalAmount = new AtomicLong(0);
public void updateOrderStatus(String orderId, String status) {
// 更新数量
orderStatusMap.merge(status, 1, Integer::sum);
// 更新金额
totalAmount.addAndGet(getOrderAmount(orderId));
}
}
3 计时器 Timer - 耗时监控
@Service
public class OrderProcessingService {
private final Timer orderProcessTimer;
private final Timer dbQueryTimer;
private final MeterRegistry meterRegistry;
public OrderProcessingService(MeterRegistry meterRegistry) {
this.meterRegistry = meterRegistry;
// 订单处理计时器
this.orderProcessTimer = Timer.builder("order.process.time")
.description("Time taken to process order")
.publishPercentileHistogram() // 百分位直方图
.publishPercentiles(0.5, 0.95, 0.99) // 特定百分位
.register(meterRegistry);
// 数据库查询计时器
this.dbQueryTimer = Timer.builder("db.query.time")
.description("Database query execution time")
.register(meterRegistry);
}
// 方式一:手动计时
public void processOrder(String orderId) {
Timer.Sample sample = Timer.start(meterRegistry);
try {
// 订单处理逻辑
TimeUnit.MILLISECONDS.sleep(200); // 模拟耗时
processOrderInternal(orderId);
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
// 记录耗时
sample.stop(orderProcessTimer);
}
}
// 方式二:使用 runnable/callable
public void processOrderWithTimer(String orderId) {
orderProcessTimer.record(() -> {
// 订单处理逻辑
try {
TimeUnit.MILLISECONDS.sleep(300);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
});
}
// 方式三:记录指定持续时间
public void recordOrderDuration(long durationInMillis) {
orderProcessTimer.record(durationInMillis, TimeUnit.MILLISECONDS);
}
}
4 长任务计时器 LongTaskTimer - 长期运行任务
@Service
public class BatchProcessingService {
private final LongTaskTimer longTaskTimer;
public BatchProcessingService(MeterRegistry meterRegistry) {
// 批量处理计时器
this.longTaskTimer = LongTaskTimer.builder("batch.processing")
.description("Batch processing task duration")
.register(meterRegistry);
}
public void processBatch(List<Order> orders) {
// 开始计时
LongTaskTimer.Sample sample = longTaskTimer.start();
try {
// 处理数据 - 模拟长时间运行
for (Order order : orders) {
Thread.sleep(100); // 每个订单处理100ms
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} finally {
// 停止计时
sample.stop();
}
}
}
5 分发摘要 DistributionSummary - 分布统计
@Service
public class OrderPriceService {
private final DistributionSummary orderAmountSummary;
public OrderPriceService(MeterRegistry meterRegistry) {
// 订单金额分布
this.orderAmountSummary = DistributionSummary.builder("order.amount")
.description("Order amount distribution")
.baseUnit("CNY")
.publishPercentileHistogram()
.publishPercentiles(0.5, 0.95, 0.99)
.register(meterRegistry);
}
public void recordOrderAmount(double amount) {
orderAmountSummary.record(amount);
// 按订单类型单独记录
meterRegistry.summary("order.amount")
.record(amount);
}
}
自定义绑定器
@Component
public class CustomMetricsBinder implements MeterBinder {
@Override
public void bindTo(MeterRegistry registry) {
// 定义自定义指标
AtomicInteger activeSessions = new AtomicInteger(0);
Gauge.builder("app.active.sessions", activeSessions, AtomicInteger::get)
.description("Active user sessions")
.tag("type", "web")
.register(registry);
// 自定义功能指标
registry.counter("app.error.count", "type", "auth").increment();
// 自定义计时器
Timer timer = Timer.builder("app.request.latency")
.tags("method", "get", "endpoint", "/api/order")
.register(registry);
}
}
完整监控示例
@RestController
@RequestMapping("/api/orders")
public class OrderController {
private final MeterRegistry meterRegistry;
private final OrderService orderService;
public OrderController(MeterRegistry meterRegistry, OrderService orderService) {
this.meterRegistry = meterRegistry;
this.orderService = orderService;
}
@PostMapping
public Order createOrder(@RequestBody OrderRequest request) {
// 记录请求计数
meterRegistry.counter("api.requests",
"method", "POST",
"endpoint", "/api/orders"
).increment();
Timer.Sample sample = Timer.start(meterRegistry);
try {
// 创建订单
Order order = orderService.createOrder(request);
// 记录成功状态
meterRegistry.counter("api.requests.success",
"endpoint", "/api/orders"
).increment();
return order;
} catch (Exception e) {
// 记录异常
meterRegistry.counter("api.requests.error",
"endpoint", "/api/orders",
"error_type", e.getClass().getSimpleName()
).increment();
throw e;
} finally {
// 记录耗时
sample.stop(meterRegistry.timer("api.request.duration",
"method", "POST",
"endpoint", "/api/orders"
));
}
}
}
Spring Boot 集成示例
@SpringBootApplication
@EnableScheduling
public class OrderServiceApplication {
public static void main(String[] args) {
SpringApplication.run(OrderServiceApplication.class, args);
}
@Bean
public PrometheusMeterRegistry prometheusRegistry() {
return new PrometheusMeterRegistry(PrometheusConfig.DEFAULT);
}
@Bean
public MeterRegistryCustomizer<MeterRegistry> metricsCommonTags() {
return registry -> registry.config()
.commonTags("application", "order-service")
.commonTags("environment", "production");
}
@Bean
public TimedAspect timedAspect(MeterRegistry registry) {
return new TimedAspect(registry);
}
}
测试示例
@SpringBootTest
class OrderServiceMetricsTest {
@Autowired
private MeterRegistry meterRegistry;
@Test
void testCounterIncrement() {
// 获取计数器
Counter counter = meterRegistry.counter("order.total");
// 记录增量
counter.increment(10);
// 验证计数
assertEquals(10, counter.count());
}
@Test
void testTimerRecording() {
Timer timer = meterRegistry.timer("test.timer");
// 记录耗时
timer.record(100, TimeUnit.MILLISECONDS);
timer.record(Duration.ofMillis(200));
// 验证
assertEquals(2, timer.count());
assertTrue(timer.totalTime(TimeUnit.MILLISECONDS) >= 300);
}
@Test
void testSummary() {
DistributionSummary summary = meterRegistry.summary("test.summary");
summary.record(10.5);
summary.record(20.3);
assertEquals(30.8, summary.totalAmount(), 0.01);
assertEquals(2, summary.count());
}
}
Prometheus 输出格式
配置完成后,访问 /actuator/prometheus 可以看到:
# HELP order_total Total number of orders
# TYPE order_total counter
order_total{application="order-service",environment="production",} 150.0
# HELP order_process_time Time taken to process order
# TYPE order_process_time summary
order_process_time_count{quantile="0.5",} 5.0
order_process_time_sum{quantile="0.5",} 1234.0
最佳实践总结
1 命名规范
- 使用小写字母和点号分隔
- 前缀表示模块:
order.、user.、db. - 后缀表示类型:
_total、_duration、_max
2 标签使用
// 好的标签
timer = meterRegistry.timer("order.processing",
"status", "success",
"region", "cn-north"
);
// 避免高基数标签(如订单ID)
// 不要使用订单ID作为标签!
3 性能考虑
// 缓存 Meter 实例,避免重复创建
private final Timer timer;
// 在构造器中创建
// 使用定时上报而不是每次请求都上报
@Scheduled(fixedDelay = 60000)
public void reportMetrics() {
// 定期上报指标
}
4 监控告警
@EventListener
public void handleOrderFailedEvent(OrderFailedEvent event) {
// 触发告警
if (failedOrderCounter.count() > 100) {
// 发送告警通知
alertService.sendAlert("订单失败次数超过100");
}
}
十一、常见问题处理
// 处理线程安全
private final AtomicInteger concurrentOrders = new AtomicInteger(0);
@PostConstruct
public void setup() {
Gauge.builder("order.concurrent", concurrentOrders, AtomicInteger::get)
.register(meterRegistry);
}
// 动态标签(避免)
public void recordOrderMeter(String orderId) {
// 不要这样使用,会导致高基数
meterRegistry.counter("order.detail", "orderId", orderId).increment();
// 应该使用固定标签
meterRegistry.counter("order.detail").increment();
}
这个案例涵盖了 Micrometer 的大部分核心功能,你可以根据实际需求选择使用,记得根据监控系统的要求配置对应的 Registry。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播