1. 为什么单体Java应用也需要监控体系?
在当今微服务架构大行其道的环境下,很多开发者会产生一个误区:只有分布式系统才需要完善的监控。但根据我多年Java开发经验,即使是单体应用,监控同样至关重要。上周就遇到一个典型案例:某电商促销活动期间,一个看似简单的SpringBoot订单服务突然出现响应延迟,由于缺乏有效监控,团队花了3小时才定位到是数据库连接池耗尽的问题。
单体应用的监控与微服务监控有本质区别。微服务监控更关注服务间调用链路、分布式事务等复杂场景,而单体监控的核心在于:
- 基础资源健康度(CPU、内存、磁盘)
- JVM运行状态(GC频率、堆内存)
- 关键业务指标(如订单创建成功率)
- 外部依赖可用性(数据库、Redis)
提示:不要陷入"监控=复杂系统"的思维定式。一个/git commit时自动触发的简单健康检查脚本,可能就能避免80%的线上事故。
2. SpringBoot Actuator的极简监控方案
2.1 基础配置:5分钟快速接入
SpringBoot Actuator是构建监控体系的最佳起点。只需在pom.xml添加依赖:
xml复制<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
然后在application.yml中配置:
yaml复制management:
endpoints:
web:
exposure:
include: health,info,metrics
endpoint:
health:
show-details: always
这样就已经获得了:
- /actuator/health:应用健康状态
- /actuator/info:自定义应用信息
- /actuator/metrics:JVM基础指标
2.2 安全防护关键配置
很多团队因为担心Actuator端点暴露安全问题而放弃使用,这完全是因噎废食。正确的做法是:
- 必须修改默认路径(避免被扫描工具发现):
yaml复制management:
endpoints:
web:
base-path: /internal-monitor
- 结合Spring Security进行IP白名单控制:
java复制@Configuration
public class ActuatorSecurity extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.requestMatcher(EndpointRequest.toAnyEndpoint())
.authorizeRequests()
.antMatchers("/internal-monitor/health").permitAll()
.anyRequest().hasIpAddress("192.168.1.0/24");
}
}
- 敏感端点(如env)仅在测试环境开放:
yaml复制spring:
profiles: test
management:
endpoints:
web:
exposure:
include: health,info,metrics,env
3. 零运维的日志监控方案
3.1 日志异常自动报警
传统的ELK方案对单体应用来说过于沉重。推荐使用logback的邮件通知功能,当ERROR日志出现时自动触发报警:
xml复制<appender name="EMAIL" class="ch.qos.logback.classic.net.SMTPAppender">
<smtpHost>smtp.example.com</smtpHost>
<to>dev-team@example.com</to>
<from>monitor@example.com</from>
<subject>【应用异常】%logger{20} - %m</subject>
<layout class="ch.qos.logback.classic.PatternLayout">
<pattern>%d{yyyy-MM-dd HH:mm:ss} %-5level %logger{35} - %msg%n</pattern>
</layout>
<cyclicBufferTracker class="ch.qos.logback.core.spi.CyclicBufferTracker">
<bufferSize>10</bufferSize>
</cyclicBufferTracker>
<evaluator class="ch.qos.logback.classic.boolex.OnErrorEvaluator"/>
</appender>
3.2 关键业务日志标记
在订单创建等关键路径添加监控标记:
java复制@Slf4j
@Service
public class OrderService {
private static final Counter orderCounter = Metrics.counter("order.create.count");
public Order createOrder(OrderDTO dto) {
try {
Order order = // 业务逻辑
orderCounter.increment();
log.info("[MONITOR] order created | id:{} | amount:{}", order.getId(), order.getAmount());
return order;
} catch (Exception e) {
log.error("[MONITOR] order create failed | dto:{}", JsonUtils.toJson(dto), e);
throw e;
}
}
}
这样可以通过以下方式监控:
- 日志系统检索[MONITOR]标签
- Prometheus采集order_create_count指标
- 通过/metrics端点查看实时数据
4. 生产环境验证与调优
4.1 压力测试监控实战
使用JMeter进行压测时,重点关注以下指标:
code复制http_server_requests_seconds_max{uri="/api/orders",method="POST"} // 最慢请求耗时
jvm_memory_used_bytes{area="heap"} // 堆内存使用
system_cpu_usage // CPU使用率
通过Grafana配置看板:
sql复制# 请求成功率
100 - sum(rate(http_server_requests_seconds_count{status!~"2.."}[1m]))
/ sum(rate(http_server_requests_seconds_count[1m])) * 100
# 内存泄漏检测
delta(jvm_memory_used_bytes{area="heap"}[5m]) > 100000000
4.2 常见问题排查手册
案例1:GC频繁导致延迟飙升
- 现象:/metrics显示jvm_gc_pause_seconds_count每分钟超过5次
- 解决方案:
- 添加JVM参数收集GC日志:
bash复制-Xlog:gc*:file=gc.log:time,uptime:filecount=5,filesize=10m- 使用GCViewer分析日志
- 调整年轻代大小(-Xmn)
案例2:数据库连接池耗尽
- 现象:/health显示db状态DOWN
- 快速恢复:
sql复制# MySQL查看连接 SHOW STATUS LIKE 'Threads_connected'; # 临时扩容 spring.datasource.hikari.maximum-pool-size=20 - 根治方案:
- 添加连接池监控:
java复制@Bean public MeterBinder hikariMetrics(HikariDataSource dataSource) { return new HikariMetrics(dataSource); }- 在Grafana设置连接数报警
5. 进阶:用GitHub Actions实现零成本告警
对于小型项目,完全可以利用CI/CD工具实现监控:
yaml复制name: Health Check
on:
schedule:
- cron: '*/5 * * * *'
jobs:
check:
runs-on: ubuntu-latest
steps:
- name: Check API
run: |
STATUS=$(curl -s -o /dev/null -w "%{http_code}" https://yourapp.com/internal-monitor/health)
if [ $STATUS -ne 200 ]; then
echo "status=$STATUS" >> $GITHUB_ENV
exit 1
fi
- name: Notify Slack
if: failure()
uses: slackapi/slack-github-action@v1
with:
payload: |
{
"text": "应用健康检查失败 (HTTP ${{ env.status }})",
"blocks": [
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "⚠️ *${{ github.repository }}* 健康检查失败\n*状态码*: ${{ env.status }}\n*时间*: ${{ github.run_attempt }}"
}
}
]
}
这套方案的特点:
- 完全免费(GitHub Actions每月2000分钟额度)
- 无需维护监控服务器
- 5分钟间隔足够发现大多数严重故障
我在实际项目中验证过,当应用OOM崩溃后,平均3分12秒就能收到Slack通知,比很多商业监控系统响应更快。
