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。

相关推荐
GetcharZp15 小时前
SRS实战:一个开源流媒体服务,支持6大协议,80ms低延迟,轻松搭建自己的直播平台
后端
Csvn15 小时前
📊 SQL 入门 Day 7:子查询 — 查询中的查询
后端·sql
IT_陈寒18 小时前
为什么我的JavaScript异步代码总是不按顺序执行?
前端·人工智能·后端
星栈18 小时前
Node 框架怎么选?Express、Koa、Egg、NestJS 场景化选型指南
后端·node.js
锋行天下19 小时前
打造企业内部知识库系统RAG全栈项目
前端·后端·架构
音符犹如代码19 小时前
后端视角看 EventBus:发布订阅总线的原理、场景与用法
java·spring boot·guava
码事漫谈19 小时前
Kimi K3 真实体验:全网评价整理,优缺点一次性说清楚
后端
Fanta丶19 小时前
16.Activiti8 SpringBoot3.X 部署与测试
后端
用户2080468045619 小时前
Python3 数据类型转换新手实战指南
后端
苏三说技术20 小时前
为什么Spring要“抛弃”Feign?
后端