linuxgeek

Java经典面试解析:服务器卡顿、CPU飙升、接口负载剧增(实战必看!!!)


(图注:服务器性能问题三连击 - 每个开发者都逃不过的噩梦!)

一、服务器卡顿:突然变慢为哪般?

1.1 现象特征

  • 请求响应时间从200ms飙升到5s+
  • 服务器监控面板"全屏飘红"(CPU、内存、磁盘三高)
  • 日志中频繁出现Connection timed out警告

1.2 排查三板斧

第一斧:top命令看全局
bash
top -H -p <PID> # (超级重要)一定要加-H显示线程信息!!!
重点关注:
- %CPU > 300% 的线程(可能是死循环)
- WAIT状态的线程数(I/O阻塞预警)

第二斧:jstack抓线程快照
java
jstack -l <PID> > thread_dump.log
快速定位技巧:
1. 把线程ID转成16进制(printf "%x\n" 21742)
2. 在dump文件搜索nid=0x54ee

第三斧:jstat看GC情况
bash
jstat -gcutil <PID> 1000 # 每秒打印一次GC数据
关键指标:
- FGC > 5次/分钟(Full GC太频繁!)
- OU超过90%(老年代要溢出了)

1.3 实战案例

某电商系统凌晨突然卡顿,通过jstack发现:
java
"Thread-15" #32 prio=5 os_prio=0 tid=0x00007f48740d5000 nid=0x54ee runnable [0x00007f486b7ec000]
java.lang.Thread.State: RUNNABLE
at java.util.HashMap.putVal(HashMap.java:634)
at java.util.HashMap.put(HashMap.java:611)
at com.example.CacheManager.addToLocalCache(CacheManager.java:127)
(破案了!)本地缓存没有设置过期时间,HashMap无限膨胀导致OOM前兆!

二、CPU 100%飙车现场

2.1 经典死循环代码

java
// 错误示例(千万别学!)
while(true) {
// 没有break条件!!
processData();
}

2.2 高级排查技巧

神器Arthas出场:
```bash

1. 启动arthas

java -jar arthas-boot.jar

2. 监控最忙线程

thread -n 3

3. 方法执行监控

watch com.example.Service * '{params,returnObj}' -x 3
```

2.3 意想不到的坑

  • 正则表达式灾难:String.matches("(a+)+")处理长字符串
  • 序列化/反序列化:Jackson解析多层嵌套JSON
  • 数学计算:BigDecimal.divide()未指定精度模式

(血泪教训)某金融系统CPU突然100%,最终发现是证书验证时的BCrypt.checkpw方法被频繁调用!

三、接口负载暴增:从崩溃到优雅

3.1 限流方案对比

| 方案 | 优点 | 缺点 |
|--------------|----------------------|-----------------------|
| 令牌桶 | 平滑突发流量 | 实现稍复杂 |
| 漏桶 | 绝对速率控制 | 响应延迟增加 |
| Sentinel | 整合Spring Cloud | 需要额外依赖 |
| Resilience4j | 功能全面 | 学习曲线陡峭 |

3.2 代码级优化技巧

缓存穿透解决方案:
```java
// 布隆过滤器伪代码
public class BloomFilter {
private BitSet bitset = new BitSet(DEFAULT_SIZE);

}
```

连接池配置(Tomcat版):
```properties

application.properties

server.tomcat.max-threads=200
server.tomcat.min-spare-threads=20
server.tomcat.accept-count=100
server.tomcat.connection-timeout=5000
```

3.3 架构级防御

  • 服务降级:Hystrix fallback快速返回兜底数据
  • 流量染色:区分正常流量和爬虫请求
  • 弹性扩容:K8s HPA自动扩展Pod数量

(真实案例)某社交APP突发热点事件,通过提前设置的熔断规则,自动降级非核心功能,保住核心链路!

四、防患于未然:监控体系搭建

4.1 必备监控项

  1. 基础指标:CPU/Memory/Disk
  2. JVM监控:GC次数/内存池使用率
  3. 业务指标:QPS/平均RT/错误率

4.2 Prometheus + Grafana配置示例

```yaml

prometheus.yml

scrape_configs:
- job_name: 'spring_app'
metrics_path: '/actuator/prometheus'
static_configs:
- targets: ['localhost:8080']
```

4.3 报警规则设置

```sql

钉钉报警规则示例

groups:
- name: critical-alert
rules:
- alert: HighErrorRate
expr: sum(rate(http_server_requests_seconds_count{status!~"2.."}[5m])) / sum(rate(http_server_requests_seconds_count[5m])) > 0.5
for: 2m
annotations:
summary: "高错误率报警"
description: "当前错误率已达{{ $value }}!"
```

五、终极解决方案:从灭火到防火

  1. 混沌工程:定期进行故障演练(比如拔网线、杀进程)
  2. 压测常态化:每周执行全链路压测
  3. 代码审查:重点检查资源关闭操作(Connection/Stream必须finally!)
  4. 技术债务看板:技术债可视化,限期偿还

(最后的大招)建立容量规划模型:
所需机器数 = (总QPS × 平均RT) / (单机线程数 × 目标利用率)

总结与思考

通过这三个经典问题的深度解析,我们可以总结出性能优化的黄金法则:

  1. 监控先行:没有度量就没有优化
  2. 分层排查:从全局到局部,从现象到代码
  3. 防御性设计:把故障当作必然发生的事件来预防

最后送大家一句口诀(建议贴在显示器上):
"早压测、早限流,监控报警不能丢;线程池、连接数,配置不当要吃苦!"

遇到问题不要慌,按照本文的排查路线图一步步来,你也能成为团队里的"救火英雄"!如果觉得有用,赶紧收藏转发,说不定明天就用上了呢?(眨眼)

posted on 2025-06-20 23:06  linuxgeek  阅读(41)  评论(0)    收藏  举报

导航