【极简监控】告别 OAP 与 ES!一个 Agent 搞定全链路与 UI,探秘单体 APM 界的“核潜艇” Glowroot
文章摘要: 本文介绍了一款轻量级Java应用监控神器Glowroot,堪称单体极简监控的终极解决方案。相比传统APM工具复杂的部署架构,Glowroot仅需一个不到10MB的JAR包,通过-javaagent参数零侵入接入,即提供全链路追踪、火焰图分析和智能告警等能力。其独创的"慢请求优先存储"策略,在保证本地存储轻量的同时精准捕捉性能问题。与JavaMelody相比,Glow
专栏前言:
在本专栏 《极简模式下单体Java应用的监控落地思路》 的探索中,我们始终死守一条底线:坚决不为了监控去增加任何额外的服务器和外部存储组件。
|
之前,我们通过魔改SkyWalking-Local、引入Micrometer和JavaMelody等手段,拼凑出了一套堪称完美的“铁桶防御阵”。但如果你是一位有着极致“工程洁癖”的开发者,你可能会问:
有没有一种方案,不需要我东拼西凑,接入难度极低,只需要挂载一个包,就能拥有大厂级 APM(应用性能管理)的全部能力,自带极简 UI 甚至还能报警?
|
答案是肯定的。今天,我们要为大家隆重介绍一款在单体极简监控赛道上,更新极其活跃且堪称“终极标杆”的老牌神器——Glowroot - 一款开源、低开销、易上手的 Java 应用性能监控(APM)工具,通过 javaagent 无侵入部署,提供 Web 界面(默认 4000 端口)做事务追踪、慢请求分析与性能瓶颈定位。
目录
一、 APM 领域的“重武器”迷思
一提到全链路追踪和性能剖析,绝大多数 Java 开发者的脑海里立刻会浮现出 SkyWalking、Pinpoint 等赫赫有名的大厂框架。
它们固然强大,但架构却极其沉重:
- 你需要部署 OAP 接收端,维护吃内存的 ElasticSearch 存储集群,
- 还要搭个独立的 Web UI。
对于一个只需 java -jar 就能跑起来的常规单体应用来说,为了查个慢 SQL 去维护这套“航母舰队”,简直是本末倒置。
在极简监控的哲学里,我们渴望的是一艘隐蔽、轻量且具备毁灭性打击能力的“核潜艇”。而 Glowroot,正是为此而生。
二、 极度震撼的单兵作战能力:接入难度比 JavaMelody 还低!
Glowroot 的设计哲学简直霸道到了极致:All in One(一切皆在一处)。它摒弃了传统的 Agent -> OAP -> DB -> UI 复杂拓扑,将所有的功能全部浓缩在了不到 10MB 的 glowroot.jar 包里!
比 JavaMelody 更极致的零侵入接入:
之前我们介绍 JavaMelody 时,还需要去改 pom.xml 引入依赖。但在 Glowroot 面前,接入难度甚至降到了真正的零代码侵入。
你只需在启动应用时加上一句挂载参数:
java -javaagent:path/to/glowroot.jar -jar your-app.jar
就这一步,大功告成!不仅如此,这个开源项目至今依然保持着极高的更新活跃度,完美适配最新的 Java 生态。
你的应用一旦启动,Glowroot 就会在后台静默运行。它在这个 Jar 包里内嵌了 Web 服务器和一个微型本地数据库。直接在浏览器访问 http://localhost:4000,一个极其整洁、现代化的 APM 控制台就展现在了你面前。
没有 ES,没有 OAP,真正意义上的“零额外服务器部署”,就把分布式追踪的豪华座舱搬到了你面前。
三、 火力全开:为什么敢说它是“六边形战士”?
不用外接数据库,单体内存和磁盘扛得住吗?Glowroot 凭借极其精妙的设计给出了答案,它的“火力覆盖”完美契合我们专栏的排障诉求:
1. 极具智慧的存储策略:只抓“刺客”不记流水账
这是 Glowroot 敢于本地存储的核心秘诀!它默认只记录「慢请求(如耗时>2s)」和「错误请求」的完整 Trace 链路。
对于那些跑得飞快的正常请求,它只在内存里做轻量级的 Metrics 聚合统计(记个数、算个平均值),绝不存全量明细。这种智能截流的机制,让本地存储的压力微乎其微,同时又保证了在排障时“一抓一个准”,定位极快。
2. 极致精细的错误/慢请求剖析(Trace)
而当线上出现一个耗时 5 秒的慢请求,你不仅能在 Glowroot 的 UI 里看到这条 URL,点开它,你能看到极其详尽的“案发现场”:
- 这 5 秒里,有多少毫秒花在了 JDBC 等待上?有多少毫秒花在了执行具体的某条 SQL 上?每一条 SQL 执行了几次?扫了多少行?耗时多少?
- 有多少毫秒是因为 JVM 正在进行垃圾回收(GC)导致的停顿?
- 每条 SQL 执行了几次?甚至它底层调用的 HTTP 客户端去远端拿了什么数据?
所有的时序关系像手术刀一样被一层层解剖得清清楚楚。



3. 内置连续性能剖析与火焰图(Continuous Profiling & Flame Graph)
这是 Glowroot 的终极大招!过去排查 CPU 飙升,我们需要用 Arthas 去抓线程,或者导出 ThreadDump 慢慢看。
而 Glowroot 会在后台以极低的开销持续抓取线程快照。当接口变慢但又找不到明显慢 SQL 时,它能直接在页面上为你生成该请求的“火焰图(Flame Graph)”!
哪怕是你业务代码里的一个毫无特征的死循环,或者是某个工具类里的低效正则匹配,在火焰图中都会变成一座显眼的“平顶山”。你不需要任何系统级运维权限,看着网页就能揪出耗尽 CPU 的具体代码行。
4. 极低的性能开销(微秒级)
能把这么多重火力塞进一个单体进程里,开销会不会很大?
Glowroot 官方给出的测试数据极其自信:它的核心数据抓取开销在 微秒(microseconds)级别,甚至为了保护业务系统,当系统负载过高时,它会自动降级丢弃部分追踪数据,绝对不当拖累业务的“猪队友”。
5. 开箱即用的告警与通知(Alerts)
极简监控不代表被动挨打!Glowroot 自带了极其完善的 Alerting 机制。你可以在界面上直接配置:“当 P95 响应时间超过 3 秒”,或者“当每分钟错误数大于 5”时,直接通过 Webhook 或邮件发出告警。这让单体应用真正实现了从“被动查日志”到“主动防御”的跨越。

6. 免重启的动态诊断黑科技(在线字节码增强)
如果你还记得本专栏之前重点介绍的仿 Jenkins Script Console,那你一定对“免重启、保现场”的动态排障理念印象深刻。而这,恰好也是 Glowroot 极其恐怖的一个杀手锏特性!
在排障时,如果我们突然怀疑某个没有任何埋点和日志的私有业务方法耗时极长,传统的做法是:改代码加日志 -> 重新打包 -> 重启发布。但在 Glowroot 中,你只需要打开它的 Web UI 中的 Instrumentation 菜单,动态添加你需要监控的类名和方法名(即自定义 Pointcut),点击 Save。
底层它会极其巧妙地利用 Java 原生的 Instrumentation.retransformClasses() API,瞬间重塑内存中的字节码!完全不需要重启 JVM,没有任何业务中断,下一秒,这个原本处于盲区里的方法耗时和调用栈,就会清清楚楚地出现在你的 Trace 链路中。
🎯 实战神级例证:破解 Undertow/Spring Boot 启动慢的监控盲区
为了让你直观感受到这个黑科技有多强,我们来看一个真实的痛点。
Glowroot 自带了一个
Startup(启动分析)标签页,但官方默认只写了 Tomcat,WebLogic,WebSphere 的底层 Hook。如果你的 Spring Boot 应用使用的是 Undertow 容器,这个页面会空空如也,导致“应用启动慢”成了排障盲区。
官方没给的 Hook,我们利用动态增强功能,在 UI 上花 10 秒钟就能自己捏出来,完全不需要改一行代码:
- 打开
Configuration -> Instrumentation,点击Add new。 - 精准打切点: 输入类名
org.springframework.boot.SpringApplication,方法名run。 - 配置抓取规则(What to capture): 选择
Transaction(抓取为一个完整事务)。 - 施展魔法(填写核心属性):
Transaction type(事务类型):手动填入Startup(极其关键,这会让它归类到启动面板)。Transaction name:填Spring Boot Bootstrapping。Trace headline(大标题):填Starting Spring Boot Application。Timer name(耗时分类标签):填spring boot startup。
- 点击 Save 瞬间生效!
- 重启应用。
// ===================================== 也可在glowroot的 `Configuration -> Instrumentation`配置页导入以下JSON字符
{
"className": "org.springframework.boot.SpringApplication",
"methodName": "run",
"methodParameterTypes": [
".."
],
"captureKind": "transaction",
"transactionType": "Startup",
"transactionNameTemplate": "Spring Boot Bootstrapping",
"alreadyInTransactionBehavior": "capture-trace-entry",
"traceEntryMessageTemplate": "SpringApplication.run",
"timerName": "spring boot startup"
}
降维打击级的收益:
下次你重启应用时,你会震撼地发现,整个 Spring Boot 的启动全生命周期(包括 Undertow 的内置启动、所有 Spring Bean 的疯狂实例化、数据库连接池的温水煮青蛙式初始化)全部被 Glowroot 抓取到了 Startup 标签页里!
如果某次启动特别慢,直接点开对应的 火焰图(Flame Graph),谁在拖慢应用启动(比如某个 Bean 在 @PostConstruct 里做了一个极其耗时的外部网络请求),在“平顶山”上暴露无遗。
用极简的配置,突破官方的局限,把整个黑盒炸得粉碎,这就是 Glowroot 赋予单体应用的顶级外科手术能力!

上图的解读如下:
### 1. 核心大盘信息(顶部 Header)
* **Transaction type & name(事务类型与名称):** `Startup` 和 `Spring Boot Bootstrapping`。这完美对应了我们刚才在界面上手动填写的分类和名称,成功让这次启动作为一个完整事务被记录。
* **Duration(总耗时):`2,817.1 milliseconds`。** 这是本次 Spring Boot 启动(`SpringApplication.run` 涵盖的生命周期)在主线程上消耗的总绝对时间,不到 3 秒,非常清晰。
### 2. Breakdown(耗时切片饼图明细)
这里 Glowroot 将漫长的启动时间像切蛋糕一样切开了,分为**主线程(Main Thread)**和**辅助线程(Auxiliary Threads)**:
* **Breakdown (Main Thread):**
* `spring boot startup` (2,817.1 ms):**还记得我们上一节填的 `Timer name` 吗?就是它!** 它作为总入口包含了整个耗时。
* `container initializer` / `startup`:Web 容器(Undertow/Tomcat)的初始化和启动耗时。
* `jdbc get connection` (150.9 ms, 3次) & `jdbc query`:极其硬核!它精准抓取到了 Spring Boot 在启动阶段为了初始化数据库连接池(如 Druid/HikariCP)或执行启动校验 SQL 所耗费的连接时间和查询时间。
* `logging`, `filter init`, `listener init`:各种框架组件加载的精细耗时。
* **Breakdown (Auxiliary Threads):**
* 显示耗时 `6,552.4 ms`,Count 为 8。你会发现辅助线程耗时竟然比主线程总耗时(2.8s)还长!为什么?因为 Spring Boot 在启动时会开启多个**后台并发线程**(比如后台预热连接池、并行加载某些 Bean)。这 8 个并发线程的绝对耗时加起来就是 6.5 秒。
### 3. JVM Thread Stats(JVM 线程级硬核指标)
这是绝大多数 APM 工具给不到的底层数据!它告诉你在启动的这 3 秒里,CPU 和内存到底经历了什么:
* **CPU time(CPU 真实计算耗时):** 主线程花了 2,484.4 ms 在疯狂利用 CPU 计算。
* **Blocked time & Waited time(阻塞与等待):** 主线程几乎没有被阻塞(3.0 ms),但**辅助线程的 Waited time 高达 5,837.0 ms**!这说明很多后台线程在启动时其实处于 `wait` 状态(比如等待连接池建立、或者等待某个主线程的 CountDownLatch 锁)。
* **Allocated memory(极其关键的内存分配):**
* 主线程在短短 3 秒内,**疯狂在堆上分配了 `751.5 MB` 的对象!** (虽然大部分会作为垃圾在 YGC 时被回收掉)。这直观地解释了为什么 Java 应用启动时 CPU 会飙高,因为不仅要初始化 Bean,还要频繁触发年轻代 GC。
### 4. 深度探查的“手术刀”入口(底部四大链接)
这是 Glowroot 从“宏观”走向“微观”的传送门:
* **Trace entries (31):** 点进去,你能看到这 3 秒钟内,方法的层级调用树,精确到具体是哪个 Spring Bean 的 `@PostConstruct` 或者哪个 Starter 耗时最长。
* **Query stats (6):** 刚才提到启动时执行了 SQL。点这里,你能直接看到启动阶段到底执行了哪 6 条具体的 SQL 语句(比如是否执行了 Flyway/Liquibase 的表结构同步脚本)。
* **Main / Auxiliary Thread Profile (View flame graph 🚀):**
**这就是我们心心念念的“火焰图”入口!** 如果你觉得这 2.8 秒还是太慢了,点击 `View flame graph`,Glowroot 会立刻根据底层采样数据,为你渲染出一张交互式的火焰图。“平顶山”在哪里,你下一步的代码优化点就在哪里!
7. 拒绝“一刀切”的细粒度配置与“全盘界面化热生效”
在真实的单体业务场景中,“慢请求”的定义从来不是绝对的。比如后台的大数据导出接口耗时 5 秒很正常,但前台的用户登录接口耗时 2 秒就是严重超时。Glowroot 提供了极其丰富的细粒度配置项,最典型的就是慢请求阈值覆盖(slowThresholdOverrides),它允许你针对特定的 URI 量身定制不同的超时认定标准,极大地提升了监控的信噪比。
更让人拍案叫绝的是两点:
- 全盘界面化操作: 以上所有复杂的采集规则,甚至是控制 UI 暴露端口和绑定网卡地址的底层网络配置,你都不需要去后台手动编辑枯燥的
config.json或admin.json。Glowroot 将它们全部做成了直观的 Web 界面表单! 这不仅极大降低了团队的学习门槛,更从根源上杜绝了因为手滑写错一个 JSON 逗号而导致监控瘫痪的低级错误。 - 配置实时热生效: 你在界面上点击保存的瞬间,所有配置都是“实时热生效”的!底层只会极其轻量地重置对应的监听器,而主业务 JVM 毫发无损。这种“连换引擎都不用熄火”的硬核设计,彻底免去了我们“为了修改一点监控配置而被迫重启应用,最终导致宝贵的故障现场上下文(Context)灰飞烟灭”的终极担忧。
四、 架构师的“骚操作”:用单体 Glowroot 破解“伪微服务”困局
如果你以为 Glowroot 单机版只能监控纯粹的单体应用,那你就小看这艘“核潜艇”的实战潜力了。在真实的甲方项目中,我们利用它的极简特性,成功破解了一个极度尴尬的行业痛点——“伪微服务”困局。
过去几年微服务风气盛行,导致无数原本结构清晰的单体应用,被硬生生拆成了微服务的形式。而很多研发也只是“面向简历编程”,根本没有驾驭微服务全局复杂性的能力,最终导致了三个极其滑稽的妥协结果:
- 链路极浅: 所谓的微服务,其实就是过了一个 Gateway(网关),就直接打到了最终的业务系统,只有两层。
- 同机同席: 甲方业务量有限,根本不会批几十台机器给你搭 K8s,最终所有的“微服务”模块其实还是部署在同一台物理机上。
- 运维“裸奔”: 团队依然是单体应用思维,加上运维成本太高、团队早已精疲力竭,系统根本没有全链路日志收集(ELK)和分布式追踪(SkyWalking OAP)等基础设施支撑。
面对这种部署在一台机器上、又被拆成了几个独立 JVM 进程的“伪微服务”,出了 Bug 怎么查?互相推诿扯皮简直是灾难。
既然都在一台机器上,我们果断放弃了搭建重型分布式追踪系统的幻想,祭出了 Glowroot 单机版的“骚操作”:一套探针,多开追踪,手工串联!
5.1 DRY 原则:共享二进制,独立配置
为了最大化减少制品体积和维护成本(DRY 原则 - Don’t Repeat Yourself),我们绝不在每个微服务目录下都复制一份 glowroot.jar。
我们在物理机上只放置一份公共的 glowroot.jar,但在各个微服务的启动参数中,通过 -Dglowroot.base.dir 将它们的工作目录隔离开来:
# Gateway 服务启动
java -javaagent:/opt/glowroot/glowroot.jar -Dglowroot.base.dir=/opt/glowroot-base/gateway -jar gateway.jar
# 业务系统 A 启动
java -javaagent:/opt/glowroot/glowroot.jar -Dglowroot.base.dir=/opt/glowroot-base/service-a -jar service-a.jar
这样一来,每个微服务进程共用同一套底层探针代码,但各自拥有独立的 config.json(配置独立的 UI 端口,如 4001、4002)和独立的本地微型 H2 数据库。井水不犯河水,运维成本降到了冰点。
5.2 TraceID 注入与手工串联
既然缺乏集中的 OAP 服务端帮我们画拓扑图,我们就用最原始也最有效的手段:HTTP Header 注入 TraceID。
- 网关生成: 在 Gateway 层生成一个全局唯一的
X-Trace-ID,并在向下游转发时放入 HTTP Header 中。 - Glowroot 捕获: 在各个业务服务的 Glowroot
config.json中,配置 Servlet 插件去抓取这个 Header("captureRequestHeaders": ["X-Trace-ID"])。 - 极速排障闭环: 当页面卡顿时,打开 Gateway 的 Glowroot UI(如端口 4001),找到耗时最长的那个请求,复制它的
X-Trace-ID。然后切换到业务系统 A 的 Glowroot UI(端口 4002),在搜索框里粘贴这个 ID。
Boom!整条跨 JVM 的请求链路瞬间被你手工串联了起来。
不仅能看到网关的耗时,还能顺藤摸瓜看到业务系统里导致卡顿的那条具体慢 SQL。
在这种特殊的局域生态下,这套“土法炼钢”的微服务链路追踪方案,不仅彻底避免了引入 OAP 和 ES 带来的高昂运维成本,还能让整个研发团队对应用的运行状态做到绝对的“心里有数”。哪怕是面对满地鸡毛的“伪微服务”,你依然能从容不迫地精准排障!
相关代码示例 – 我个人也是让Codex生成的整体结构,读者也可以直接尝试下
五、 架构师点评:它与 JavaMelody 到底怎么选?
看到这里,一路追更的老读者一定会抛出一个极其尖锐的实战问题:“既然 Glowroot 这么猛,自带 UI 还能看链路,那它和咱们专栏之前隆重推荐的 JavaMelody 到底怎么选?我是不是该把 JavaMelody 删了?”
作为架构师,针对你所处的不同业务场景,我给你两套界限分明的选型定论:
方案一(新手极速开荒局):Glowroot 是现代化全能升级版
如果你是刚接触极简监控的新手,或者追求用最快速度拿到结果,我给你一个最清晰的定论:Glowroot 堪称 JavaMelody 的现代化全能升级版。
- 功能维度的降维打击: JavaMelody 的核心侧重于“指标统计与宏观报表”(虽然很精巧,但链路追踪能力偏弱);而 Glowroot 不仅涵盖了极强的 Metrics 指标统计,它更是一套硬核的全链路追踪系统(Trace),还附带了报警(Alert)功能。
- 审美与交互的代差: JavaMelody 的界面充满了浓厚的千禧年“年代感”;而 Glowroot 的 UI 设计极其简洁、现代化,图表交互丝滑顺畅,排障体验极佳。
- 进可攻退可守的架构拓展: 别看 Glowroot 单机版这么猛,如果有一天你的单体应用膨胀了,走向了微服务架构,Glowroot 原生完美支持集群微服务模式(Central Collector)。你完全可以平滑过渡到集中存储架构,前期极简探索的知识和习惯绝不会浪费!
新手终极建议:
如果你正在接手一个毫无监控的裸奔单体应用,老板给你的时间只有半天,且绝不允许申请新服务器。别折腾了,直接把 glowroot.jar 挂上去!一分钟后,你不仅获得了现代化的大厂级排障座舱,连告警机制都顺手配好了。这,才是我们在 AI 时代极速救火的最强法宝!
方案二(老鸟极致自保局):小孩子才做选择,成年人“双核共存”
但在极其复杂的生产环境中,如果你追求的是极致的防御体系,这两者绝不是非此即彼的替代关系,而是完美共存、互补长短的“双核引擎”!
- 探针冲突时的“终极替补”: 生产环境极其复杂,如果你的系统已经被公司强制挂载了安全 Agent,再挂 Glowroot 可能会引发未知的字节码冲突。这时候,JavaMelody 的绝对优势就凸显出来了——它不需要 Agent! 当 Agent 方案走不通时,JavaMelody 这个纯 Jar 包依然能稳稳为你守住底线。
- 微观定损与宏观报表的互补: Glowroot 是微观的“显微镜”,为了省空间它默认只存“慢请求/错误”的 Trace,擅长抓刺客;而 JavaMelody 是宏观的“大盘账本”,它基于 JRobin 存储长达一年的大盘趋势图、全局 SQL 频率统计报表,让你对系统容量演进有极度清晰的把控。
- 无懈可击的交叉验证: 这又回到了我们专栏反复强调的核心哲学——孤证不立。
- 当上下游跑来甩锅时。你先掏出 Glowroot 甩出火焰图和慢请求 Trace,证明:“是执行你们的 RPC 接口超时了。”
- 对方如果死鸭子嘴硬质疑大盘,你再点开 JavaMelody 甩出宏观报表:“大盘作证,昨天下午除了调你们的接口,其他接口极其平稳。”
- 微观 Trace 溯源 + 宏观报表兜底,这种底层机制完全不同的数据形成的“交叉验证”,将会打造出一条让任何人都无法反驳的铁证链!
| 特性维度 | Glowroot | JavaMelody |
|---|---|---|
| 项目状态与活跃度 | 活跃,持续更新维护 | 活跃,社区论坛讨论热烈 |
| 核心定位与设计哲学 | 追求极致的 “开箱即用” 现代APM,强调简洁、低开销、直观 | 轻量级,快速集成,适合中小型应用 |
| 数据存储 | 内置 嵌入式H2数据库 | 默认使用JRobin (或RRD4J) |
| 内置UI与可视化 | 有,非常现代,界面美观,设计清晰 | 有,但较简单,以图表和表格为主的界面 |
| Java版本要求 | Agent端Java8+;UI侧则需要Java 11+ | Java 8+ |
| 部署复杂度 | 极低,只需添加-javaagent参数即可 | 很低,引入依赖并配置Filter即可 |
| 性能开销 | 极低 | 较低 |
| 核心优点 | 现代化UI,开箱即用;性能开销极低 | 部署简单,轻量级;核心功能齐全,维护活跃 |
| 核心缺点 | UI侧强依赖Java 11+,在旧环境无法使用 | 功能相对基础和“传统”,UI过于简单 |
总结
在单体极简监控的兵器谱上,JavaMelody 是一面厚重的“塔盾”,而 Glowroot 是一把极其锋利的“刺剑”。你可以先用 Glowroot 快速武装自己;但当你准备打造滴水不漏的铁桶阵时,一手举盾,一手持剑,才是能让你开开心心准点下班的终极形态!
六 相关
更多推荐


所有评论(0)