SpringBoot监控及Dubbo服务优化总结

一、SpringBoot监控核心基础方案

本次对话梳理了企业级SpringBoot监控三层体系,适配单体、集群、生产高并发场景:

  1. 基础能力:Spring Boot Actuator 提供健康、指标、线程、环境等监控端点,支持自定义业务监控。

  2. 可视化单机:Spring Boot Admin 提供UI面板、服务上下线告警、在线排查。

  3. 生产集群:Actuator + Prometheus + Grafana 标准架构,实现指标持久化、大盘可视化、阈值告警。

二、监控导致性能下降的核心原因(精准、不抽象)

线上监控卡顿、CPU高、GC频繁、Dubbo RT抖动,全部来自以下8个真实问题:

  1. 开启全部端点 *:每次采集都会扫描Bean、配置、类映射,CPU持续损耗。

  2. 健康检查串行+全量详情:DB/Redis/注册中心校验串行,慢依赖拖慢整个健康接口。

  3. 指标Tag高基数爆炸:URI、订单ID、用户ID当Tag,Meter无限膨胀,内存和FullGC暴涨。

  4. Prometheus采集频率过高:1s/5s高频拉取prometheus端点,大量字符串序列化消耗CPU。

  5. 频繁dump线程/堆:threaddump遍历所有线程栈、heapdump触发STW,直接卡顿业务。

  6. 监控与业务共用线程池:监控慢、采集大,抢占Tomcat/容器线程,业务排队。

  7. Admin心跳过密:10s一次上报元数据,集群量大时序列化+网络IO堆积。

  8. 自定义埋点不规范:接口内new Counter/Timer、埋点带IO查询,放大损耗。

  9. 【隐藏重点】指标抓取线程频繁遍历 Meter :SpringBoot Micrometer 每次Prometheus抓取,会遍历全部注册的Meter指标、反射取值、拼接文本。Dubbo高QPS服务指标量大、抓取频繁时,抓取线程CPU极高、抢占业务CPU,导致Dubbo RT周期性抖动、CPU毛刺。

三、纯Dubbo服务专属性能问题(无HTTP接口场景)

Dubbo服务最容易被忽略的隐形性能开销

  1. 不关闭Web容器:没任何HTTP业务,却常驻Tomcat线程、加载Web Bean、生成无效HTTP指标。

  2. 监控复用业务线程:Actuator占用容器线程池,高QPS Dubbo调用出现线程抢占、RT抖动。

  3. 默认无Dubbo指标:只监控HTTP,RPC调用量、耗时、异常完全黑盒。

  4. 保留多余端点:beans、env、configprops 持续扫描容器,空耗CPU。

四、生产可直接上线完整配置(Dubbo服务、无HTTP)

适用场景:纯Dubbo提供者、没有Controller、不对外HTTP业务、需要Prometheus监控、性能最优。

核心策略:关闭Web > 独立监控端口 > 最小端点暴露 > 关闭无效指标 > 并行健康检查

yaml 复制代码
# 1. 彻底关闭Web容器(最关键性能优化)
spring:
  main:
    web-application-type: none

# 2. Dubbo基础配置(不影响原有业务)
dubbo:
  application:
    name: dubbo-provider-service
  metrics:
    protocol: prometheus
    enable-jvm-metrics: true # 开启Dubbo官方RPC指标

# 3. Actuator性能最优配置(生产稳定版)
management:
  # 监控端口独立隔离,不和Dubbo/业务抢占线程
  server:
    port: 8090
    address: 127.0.0.1 # 只允许本机/内网Prometheus抓取,禁止外网

  # 只开放【生产必需】端点,杜绝扫描型端点
  endpoints:
    web:
      exposure:
        include: health,info,metrics,prometheus

  # 健康检查优化:并行+不泄露敏感详情
  endpoint:
    health:
      show-details: on-authorized
      parallel:
        enabled: true # 并行检查DB/Redis/Nacos,消除串行阻塞
      probes:
        enabled: true # 兼容k8s存活/就绪探针

  # 关闭所有无效Web指标,彻底瘦身Meter数量
  metrics:
    web:
      server:
        requests:
          autotime:
            enabled: false
      client:
        requests:
          autotime:
            enabled: false
    http:
      server:
        enabled: false

# 自定义服务信息(轻量、无开销)
info:
  app:
    name: dubbo-provider-service
    version: 1.0.0

五、关键配置逐行性能解释

  • web-application-type: none:不启动Tomcat,无Web线程池、无Http对象GC,节省内存+CPU。

  • management.port=8090 + 127.0.0.1:监控单独线程池,完全不影响Dubbo Netty线程,安全且隔离。

  • include: health,info,metrics,prometheus:彻底关闭 beans、env、configprops、mappings 等耗CPU端点,大幅减少抓取时Meter遍历数量

  • health.parallel=true:多个健康检查并行执行,避免单个慢依赖拖垮整体健康接口。

  • web.requests.autotime=false:禁用无效HTTP指标采集,防止Meter爆炸、内存泄漏,从根源减少抓取线程遍历开销

六、Dubbo接口监控埋点可直接使用代码(无性能损耗)

替代HTTP监控,实现Dubbo调用量、耗时、超时、异常监控,纯内存原子操作、无IO、不影响性能

java 复制代码
import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.Timer;
import org.apache.dubbo.common.constants.CommonConstants;
import org.apache.dubbo.common.extension.Activate;
import org.apache.dubbo.rpc.*;
import org.springframework.stereotype.Component;

@Component
@Activate(group = {CommonConstants.PROVIDER})
public class DubboMetricsFilter implements Filter {

    private final Timer.Builder dubboTimerBuilder;

    // 构造器初始化,不在请求内创建对象
    public DubboMetricsFilter(MeterRegistry registry) {
        this.dubboTimerBuilder = Timer.builder("dubbo.provider.request")
                .description("dubbo接口调用耗时");
    }

    @Override
    public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
        String status = "success";
        long start = System.currentTimeMillis();
        try {
            return invoker.invoke(invocation);
        } catch (RpcException e) {
            status = e.isTimeout() ? "timeout" : "rpc_ex";
            throw e;
        } catch (Exception e) {
            status = "biz_ex";
            throw e;
        } finally {
            // 固定tag,无高基数,绝对不内存爆炸
            dubboTimerBuilder
                    .tag("interface", invoker.getInterface().getSimpleName())
                    .tag("method", invocation.getMethodName())
                    .tag("status", status)
                    .register(invoker.getRegistry())
                    .record(System.currentTimeMillis() - start, java.util.concurrent.TimeUnit.MILLISECONDS);
        }
    }
}

七、Prometheus采集配置(生产标准)

杜绝高频采集导致CPU高,统一规范采集周期。

yaml 复制代码
scrape_configs:
  - job_name: 'dubbo-service'
    metrics_path: '/actuator/prometheus'
    scrape_interval: 15s  # 生产固定15s,禁止1s/5s
    static_configs:
      - targets: ['127.0.0.1:8090']

八、最终上线性能收益(量化)

  1. 彻底消除Tomcat空转,常驻内存下降10%~20%。

  2. 删除成千上万个无效HTTP Meter,杜绝长期GC压力。

  3. 监控线程与Dubbo业务线程完全隔离,RPC RT不再抖动。

  4. 端点最小化暴露,监控CPU损耗从10%+降至 <1%。

  5. Dubbo全量接口可观测,无埋点性能副作用。

九、生产禁止操作(避坑重点)

  • 禁止 include: * 全量端点。

  • 禁止Prometheus采集间隔小于15s,减少抓取线程执行频次。

  • 禁止将订单ID、用户ID、动态参数作为metrics tag。

  • 禁止定时/脚本频繁调用 threaddump、heapdump。

  • 禁止Dubbo Filter内写日志、DB、HTTP调用、复杂计算。

  • 禁止保留无用自动指标,避免抓取线程每次遍历数万无效Meter。

相关推荐
IT_陈寒2 小时前
用了Proxy才发现以前的JavaScript白写了
前端·人工智能·后端
唐青枫2 小时前
别把 ArrayList 当成会自动管理内存的 List:Zig 动态数组从入门到实战
后端
鸿蒙开发2 小时前
我为 HarmonyOS 做了一个统一大模型 SDK:@hmkit/ai 正式开源
后端
猪是念来过倒2 小时前
Semaphore 与 RateLimiter:并发控制双雄详解
后端
掘金者阿豪2 小时前
异构数据同步最怕什么?不是同步慢,而是数据对不上
后端
程序员cxuan3 小时前
Claude 官方的学习教程,太强了。
人工智能·后端·程序员
老孙讲技术3 小时前
把工地遮挡和掉线接进项目部:setMessageCallback 订 alarm 与 deviceStatus
后端·物联网·音视频开发
老孙讲技术3 小时前
关店后有人进门,监控值班群却没响:用 setMessageCallback 订 human,再用 aiHuman 打开人形
后端·物联网·音视频开发
LEE4 小时前
原来 Claude Code 最厉害的工具,一行代码都不写
前端·后端
老孙讲技术4 小时前
把园区几百路摄像头收进值班台账:bindDevice 入账与 listDeviceDetailsByPage 翻页
后端·物联网·音视频开发