3、应用层监控:JVM监控(JMX)、HTTP接口监控、数据库连接池监控、业务指标埋点

应用层监控,说白了就是盯着你的代码跑得怎么样。我见过太多团队,基础设施监控做得漂漂亮亮,一到应用层面就两眼一抹黑。服务器CPU才用了20%,但用户就是反馈卡得要死——为什么?因为你的应用层出了问题。

这一章,我们重点聊四个方向:JVM监控、HTTP接口监控、数据库连接池监控、业务指标埋点。嗯,都是实战中绕不开的硬骨头。

核心观点:应用层监控是发现「慢」和「错」的第一道防线。基础设施监控告诉你机器还活着,应用层监控告诉你代码还健康。

3.1 JVM监控:从JMX到可视化

JVM监控,Java应用的老本行。我个人习惯用JMX(Java Management Extensions)作为数据源。你想想看,JVM内部那些堆内存、GC次数、线程数、类加载信息,JMX全都暴露出来了。

我在项目中遇到过一个问题:某次线上OOM,但监控系统只报了内存高,没告诉我具体是哪个区域爆了。后来我补上了JMX的详细指标,才发现是Metaspace泄漏。嗯,从那以后,我的JVM监控清单就固定下来了。

3.1.1 核心JVM指标

指标类别 具体指标 说明
堆内存 Heap Used / Max / Committed 看内存使用率,接近Max就要警惕
非堆内存 Metaspace / CodeCache / Compressed Class Space Metaspace泄漏是常见坑
GC Young GC次数/耗时, Full GC次数/耗时 Full GC频繁=系统在「世界暂停」
线程 活跃线程数、阻塞线程数、死锁检测 死锁会导致服务完全卡死
类加载 已加载类总数、卸载类数 类加载过多可能是框架问题

我的小技巧:不要只监控Heap Used。我建议同时监控GC暂停时间。有一次我看到Heap Used才60%,但GC暂停时间已经飙到5秒了——说明对象晋升太快,老年代在频繁GC。

3.1.2 JMX接入实战

JMX接入其实不复杂。Spring Boot应用默认就开启了JMX,你只需要暴露端口就行。但要注意安全——我曾经见过有人把JMX端口直接暴露到公网,结果被人远程调用了System.exit()。

# application.yml 配置JMX
spring:
  jmx:
    enabled: true
    default-domain: myapp

# JVM参数开启远程JMX(仅内网使用)
-Dcom.sun.management.jmxremote
-Dcom.sun.management.jmxremote.port=1099
-Dcom.sun.management.jmxremote.authenticate=false
-Dcom.sun.management.jmxremote.ssl=false
-Djava.rmi.server.hostname=192.168.1.100

警告:生产环境一定要开启JMX认证!我见过不止一次因为JMX未认证导致的安全事故。至少加上用户名密码,或者用SSH隧道转发。

3.2 HTTP接口监控:不只是「通不通」

HTTP接口监控,很多人只盯着「200 OK」。但说实话,接口返回200不代表没问题。我遇到过接口返回200,但响应体是空的——因为业务逻辑抛了异常被全局捕获了,返回了一个空对象。

所以,我建议的HTTP监控要分三层:

  • 可用性层:接口是否返回了预期的HTTP状态码(200、302等)
  • 性能层:响应时间P50、P90、P99,以及超时率
  • 正确性层:响应体结构是否完整,关键字段是否非空

3.2.1 接口监控的指标设计

我个人习惯用Prometheus的Histogram来记录接口响应时间。为什么?因为Histogram可以算百分位,比平均值靠谱多了。平均值会被长尾请求拉高,但P99能告诉你「最慢的那1%用户」体验如何。

# 伪代码:接口监控指标埋点
# 使用Micrometer + Prometheus

@Timed(value = "api.orders.create", 
       histogram = true,
       percentiles = {0.5, 0.9, 0.99})
public Order createOrder(OrderRequest request) {
    // 业务逻辑
}

关键点:接口监控的告警阈值不要用固定值。我建议用「同比/环比」的方式。比如:P99响应时间比昨天同一时段上涨了50%就告警。这样能自动适应业务高峰。

3.3 数据库连接池监控:被忽视的隐形杀手

数据库连接池,嗯,这个坑我踩过不止一次。连接池用完了,应用就卡死了——所有请求都在等连接,线程池也满了,最后整个应用雪崩。

你想想看,数据库连接池的监控其实很简单,但很多人就是不做。核心指标就几个:

  • 活跃连接数:当前正在使用的连接
  • 空闲连接数:池中空闲的连接
  • 等待队列大小:有多少请求在等连接
  • 连接获取耗时:从池中拿一个连接花了多久

3.3.1 HikariCP监控示例

HikariCP是目前最主流的连接池,它自带JMX监控。你只需要开启就行了。

# HikariCP配置开启JMX
spring:
  datasource:
    hikari:
      pool-name: MyPool
      register-mbeans: true  # 开启JMX监控

# 通过JMX暴露的指标
# - HikariPool.MyPool.ActiveConnections
# - HikariPool.MyPool.IdleConnections
# - HikariPool.MyPool.PendingThreads
# - HikariPool.MyPool.ConnectionTimeoutRate

我的经验:连接池的「等待队列大小」是最敏感的指标。只要这个值大于0持续超过10秒,基本可以判定数据库有问题或者连接池太小了。我曾经就因为没监控这个指标,导致一次线上事故排查了整整4个小时。

3.4 业务指标埋点:让监控有「业务视角」

业务指标埋点,说白了就是把你业务里的关键事件变成数字。比如:订单创建量、支付成功率、用户注册数、购物车加购率。

我见过很多团队,技术指标监控得滴水不漏,但业务指标一片空白。结果呢?技术一切正常,但业务量跌了50%都没人发现——因为没人埋点。

3.4.1 埋点的最佳实践

我个人习惯用注解+AOP的方式做埋点。这样业务代码零侵入,维护起来也方便。

// 自定义注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface BusinessMetric {
    String name();
    String[] tags() default {};
}

// AOP切面实现埋点
@Aspect
@Component
public class MetricAspect {
    
    private final MeterRegistry meterRegistry;
    
    @Around("@annotation(metric)")
    public Object recordMetric(ProceedingJoinPoint pjp, BusinessMetric metric) throws Throwable {
        long start = System.currentTimeMillis();
        boolean success = true;
        try {
            return pjp.proceed();
        } catch (Exception e) {
            success = false;
            throw e;
        } finally {
            long duration = System.currentTimeMillis() - start;
            // 记录计数
            meterRegistry.counter(metric.name() + ".total", 
                "success", String.valueOf(success)).increment();
            // 记录耗时
            meterRegistry.timer(metric.name() + ".duration")
                .record(duration, TimeUnit.MILLISECONDS);
        }
    }
}

// 使用示例
@BusinessMetric(name = "order.create", tags = {"channel", "web"})
public Order createOrder(OrderRequest request) {
    // 业务逻辑
}

核心原则:业务指标埋点要遵循「三不原则」——不影响业务性能、不侵入业务逻辑、不增加运维复杂度。用AOP或者消息队列异步上报都是好办法。

3.5 本章知识体系总览

下面这张图,是我梳理的应用层监控核心逻辑。你可以看到,四个监控维度各有侧重,但最终都汇聚到「告警」和「可视化」两个出口。

应用层监控知识体系 JVM监控 堆内存 / GC / 线程 类加载 / JMX HTTP接口监控 可用性 / 性能 / 正确性 P50 / P90 / P99 连接池监控 活跃 / 空闲 / 等待 HikariCP / Druid 业务指标埋点 订单量 / 支付成功率 AOP埋点 / 注解 数据采集层 JMX / Prometheus SDK / Micrometer 告警引擎 → 可视化看板 告警通知 四个监控维度 → 统一采集 → 告警与可视化

总结一下:应用层监控的核心就四个字——「由内而外」。JVM是应用的内核,HTTP是应用的接口,连接池是应用的骨架,业务指标是应用的血肉。缺一个,你的监控体系就不完整。

我曾经帮一个团队做监控体系重构,他们之前只做了HTTP接口监控。结果呢?接口响应时间突然变慢,查了半天才发现是JVM Full GC导致的。从那以后,我坚持「四件套」必须一起上。


公众号:蓝海资料掘金营,微信deep3321