本文目录导读:

- 总体架构图(核心思想)
- 第一阶段:数据采集(核心拦截逻辑)
- 第二阶段:指标定义(该监控什么?)
- 第三阶段:存储与可视化(搭建监控看板)
- 第四阶段:告警规则(发现问题并通知)
- 第五阶段:日志与全链路追踪(Troubleshooting)
- 第六阶段:规整与持续优化(闭环)
- 总结:自己搭 vs. 使用现成框架
我们来系统地规整Java接口监控流程,这不仅仅是“写代码打日志”,而是一个涉及数据采集、指标定义、可视化、告警的完整链路工程体系。
为了让你有一个清晰、可落地的框架,我将整个流程拆解为 6个核心阶段,并给出每种实现方式的最佳实践。
总体架构图(核心思想)
flowchart LR
subgraph 1.数据采集层
A[Java应用] -->|拦截器/Filter/AOP| B(打印请求参数,耗时)
A -->|指标SDK| C[Micrometer / Prometheus SDK]
end
subgraph 2.指标存储层
B -->|结构化日志| D[ELK / Loki]
C -->|时序数据| E[Prometheus / VictoriaMetrics]
end
subgraph 3.可视化与告警层
D --> F[Grafana / Kibana]
E --> F
F --> G{alert: 耗时>500ms?错误率>5%?}
end
第一阶段:数据采集(核心拦截逻辑)
这是最关键的环节,在Java中,通常采用 AOP + 自定义注解 或 Spring Cloud Gateway Filter 来统一拦截,而不是在每个Controller里写重复逻辑。
最佳实践代码(Spring AOP + 注解)
定义注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Monitor {
String apiName() default "";
boolean logParams() default true;
boolean logResult() default false;
}
编写切面(核心拦截器)
@Aspect
@Component
public class MonitorAspect {
@Autowired
private MeterRegistry meterRegistry; // Micrometer 实例
@Around("@annotation(monitor)")
public Object around(ProceedingJoinPoint joinPoint, Monitor monitor) throws Throwable {
long start = System.currentTimeMillis();
String apiName = monitor.apiName().isEmpty() ?
joinPoint.getSignature().toShortString() : monitor.apiName();
// 采集: 开始时间
Timer.Sample sample = Timer.start(meterRegistry);
Object result = null;
try {
result = joinPoint.proceed();
// 采集: 成功计数
Counter.builder("api.call.success")
.tag("api", apiName)
.register(meterRegistry).increment();
return result;
} catch (Exception e) {
// 采集: 失败计数 + 异常类型
Counter.builder("api.call.error")
.tag("api", apiName)
.tag("exception", e.getClass().getSimpleName())
.register(meterRegistry).increment();
throw e;
} finally {
long duration = System.currentTimeMillis() - start;
// 采集: 耗时 (直方图)
Timer.builder("api.call.duration")
.tag("api", apiName)
.register(meterRegistry)
.record(Duration.ofMillis(duration));
// 结构化日志 (用于ELK分析)
log.info("API_MONITOR: api={}, duration={}ms, status={}",
apiName, duration, result==null?"ERROR":"SUCCESS");
}
}
}
第二阶段:指标定义(该监控什么?)
不要只监控“接口通了没”,一个规整的监控系统至少需要以下 4类关键指标:
| 指标类型 | 指标名 (建议命名规范) | 说明 |
|---|---|---|
| 流量 | api.request.total (总量) |
统计QPS、PV |
| 成功率 | api.request.success.rate |
成功率 < 99.9% 算严重 |
| 延迟 | api.request.duration.p99 |
重点关注P99(99%的请求都在多少ms内完成) |
| 饱和度 | api.request.active.threads |
线程池、数据库连接池使用率 |
注意:不要只监控平均值,平均值会掩盖问题,一定要监控 P50、P95、P99。
第三阶段:存储与可视化(搭建监控看板)
指标采集后,需要存储到时序数据库。
推荐技术栈组合
- Prometheus + Grafana (标准方案,开源,生态好)
- 阿里云ARMS / 腾讯云CM (托管服务,省心)
关键配置:在Grafana中看到的仪表盘
一个成熟的接口监控仪表盘应该包含以下面板:
- 全局总览
- Requests per second (QPS)
- Error Rate (%)
- Average Latency & P99 Latency
- Top N 接口
- 最慢的10个接口
- 错误最多的10个接口
- 依赖关系
- 调用数据库、Redis、外部HTTP API的耗时 (通过
@Monitor或 HttpTrace 实现)
- 调用数据库、Redis、外部HTTP API的耗时 (通过
第四阶段:告警规则(发现问题并通知)
没有告警的监控是无效的,需要设置合理的阈值,并避免“告警风暴”。
告警策略(最佳实践)
- 一般告警:(WARN,发到内部群)
- P99耗时 > 1秒,持续5分钟
- 错误率 > 1%,持续3分钟
- 严重告警:(PAGER,电话/钉钉机器人@负责人)
- P99耗时 > 5秒
- 错误率 > 5%
- 接口完全不可用(0成功请求超过1分钟)
避免噪声:增加连续N次判断,而不是单次采样就告警。
第五阶段:日志与全链路追踪(Troubleshooting)
指标只能告诉你“系统慢了”,日志和Trace才能告诉你“为什么慢”。
规整方案:MDC + 日志打印
// 在Filter或AOP中注入TraceId
MDC.put("traceId", UUID.randomUUID().toString());
logger.info("开始处理请求: params={}", params);
请求链路的日志结构
[2024-01-01 12:00:00,000] [request-id=abc123] [api=/user/get] [耗时=250ms] - 开始查询数据库...
[2024-01-01 12:00:00,020] [request-id=abc123] [api=/user/get] [耗时=270ms] - 数据库查询完成, 返回结果
这样当你发现 api=/user/get 的P99很高时,可以通过 request-id 去ELK中搜索具体是哪一步慢了。
第六阶段:规整与持续优化(闭环)
监控流程不是搭好就不管的,需要定期迭代:
- 定义SLO(服务等级目标):核心交易接口 P99 < 200ms,可用性 > 99.99%”。
- 错误巡检:定期分析监控数据,剔除“非致命错误”(比如用户输入错误导致的400,不应该算作服务故障)。
- 降噪:定期修改告警规则,清除“永远不发”的无效告警。
自己搭 vs. 使用现成框架
| 阶段 | 小项目 / 快速搭建 | 中大型项目 / 标准方案 |
|---|---|---|
| 采集 | Spring Boot Actuator | AOP + Micrometer + 自定义注解 |
| 存储 | 直接打印日志 | Prometheus + VictoriaMetrics |
| 展示 | 命令行 curl |
Grafana |
| 告警 | 手动看 | Alertmanager + 钉钉/飞书机器人 |
| 链路 | 无 | SkyWalking / Jaeger |
最关键的一句话:规整的流程 = 精确的数据采集 + 清晰的指标定义 + 自动化的告警 + 可追踪的日志。
按照这个6阶段框架去实施,你的接口监控流程将会非常专业和健壮。