服务覆盖:昆明·曲靖·玉溪·保山·昭通·丽江·普洱·临沧·楚雄·红河·文山·西双版纳·大理·德宏·怒江·迪庆

线上服务突然卡死?我用这五步排查法30分钟定位根因

eycit 2026-04-24 1 次阅读 系统安装
---

theme: default themeName: "默认主题" title: "线上服务突然卡死?我用这五步排查法30分钟定位根因"


线上服务突然卡死?我用这五步排查法30分钟定位根因

上周三凌晨两点,监控群突然炸了——核心交易接口P99延迟从50ms飙升到8秒,用户投诉电话打爆了客服。整个值班组被叫醒,一堆人盯着Grafana大屏发呆。

我接手的时候,现场已经乱了:有人在重启服务,有人在回滚代码,还有人在群里问"是不是数据库挂了"。我做的第一件事就是让所有人停下——瞎操作只会让现场更混乱。

今天把这次排查的全过程写出来,不是要炫耀什么,而是这套方法论确实帮我在多次故障中快速定位问题。希望对你也有用。

第一步:确认故障范围,别急着动手

很多人一看到报警就慌了,上来就开始操作。但你要做的第一件事,是搞清楚"到底哪里出了问题"。

我问了三个问题:

1. 是所有接口都慢,还是特定接口? — 答案是只有涉及订单查询的接口慢,其他接口正常。 2. 是从什么时候开始的? — 监控显示从凌晨1:47开始,之前一切正常。 3. 有没有最近的变更? — 当天下午6点有一次发布,但已经运行了7个多小时没问题。

范围缩小了:问题出在订单查询这条链路上,而且大概率不是代码发布导致的(延迟了7小时才出问题,不像是代码bug)。

这一步的核心思路:先画圈,再找点。 确认故障范围比盲目排查效率高十倍。

第二步:看资源水位,排除硬件瓶颈

确认范围后,我立刻看了服务器资源使用情况:

# CPU使用率
top -bn1head -20

内存使用

free -h

磁盘IO

iostat -x 1 5

网络连接状态

ss -s

结果让人意外——CPU才30%,内存用了60%,磁盘IO也不高。硬件资源完全不是瓶颈。

很多人到这里就卡住了,资源没问题那问题出在哪?别急,往下看。

关键点:资源水位正常不代表系统没问题,瓶颈可能在应用层。

第三步:看线程栈,找到阻塞点

既然硬件没问题,那一定是代码层面阻塞了。我用了最原始但最有效的方法——dump线程栈:

# 获取Java进程PID

jps -l

连续dump三次,间隔5秒

jstack > /tmp/dump1.txt sleep 5 jstack > /tmp/dump2.txt sleep 5 jstack > /tmp/dump3.txt

对比三次dump结果,我发现大量线程卡在同一个位置:

"http-nio-8080-exec-45" #145 daemon prio=5 os_prio=0 tid=0x00007f8c3412e800 nid=0x3e4a waiting on condition [0x00007f8c1f7fe000]

java.lang.Thread.State: WAITING (parking) at sun.misc.Unsafe.park(Native Method) at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175) at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:836) at java.util.concurrent.locks.AbstractQueuedSynchronizer.doAcquireSharedInterruptibly(AbstractQueuedSynchronizer.java:997) at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireSharedInterruptibly(AbstractQueuedSynchronizer.java:1304) at java.util.concurrent.CountDownLatch.await(CountDownLatch.java:231) at com.xxx.order.service.OrderQueryService.queryByCondition(OrderQueryService.java:87)

200多个HTTP线程,有170多个都卡在`OrderQueryService.queryByCondition`的`CountDownLatch.await`上!

找到阻塞点了:订单查询服务在等待一个CountDownLatch,而Latch迟迟没有被countDown。

线程dump是最直接的定位手段,没有之一。 很多人觉得它老土,但在紧急排查中,它比任何APM工具都快。

第四步:追踪Latch上游,找到根因

接下来就是看代码了。打开`OrderQueryService.queryByCondition`,逻辑是这样的:

public OrderResult queryByCondition(OrderQuery query) {

CountDownLatch latch = new CountDownLatch(3); CompletableFuture orderFuture = CompletableFuture.supplyAsync(() -> { try { return orderMapper.selectById(query.getOrderId()); } finally { latch.countDown(); } }, executor);

CompletableFuture userFuture = CompletableFuture.supplyAsync(() -> { try { return userClient.getUser(query.getUserId()); } finally { latch.countDown(); } }, executor);

CompletableFuture payFuture = CompletableFuture.supplyAsync(() -> { try { return payClient.getPayInfo(query.getPayId()); } finally { latch.countDown(); } }, executor);

latch.await(30, TimeUnit.SECONDS); // 最多等30秒 // 组装结果... }

代码逻辑是并发查三个服务,用CountDownLatch等结果。问题是——如果某个服务一直不返回,Latch就永远等不到。

我立刻去查了支付服务的监控,果然:支付服务的接口从1:47开始超时率飙升到95%!

根因找到了:支付服务的连接池满了,新请求进不去,导致`payClient.getPayInfo`一直超时,Latch的countDown一直不执行,HTTP线程全被占满,其他正常请求也进不来了。

第五步:止血与修复

定位到根因后,止血方案就很清晰了:

紧急止血(5分钟内):

1. 把支付查询的超时时间从30秒改成3秒,快速释放线程 2. 对支付服务做熔断,直接返回降级结果(支付信息暂不可查)

// 熔断降级配置

@HystrixCommand( fallbackMethod = "getPayInfoFallback", commandProperties = { @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "3000"), @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "20"), @HystrixProperty(name = "circuitBreaker.errorThresholdPercentage", value = "50") } )

根因修复(当天完成):

1. 支付服务的连接池从50调到200 2. 加了合理的超时和重试机制 3. 把CountDownLatch.await的超时从30秒降到5秒

故障在3:15完全恢复,从定位到止血用时不到30分钟。

这五步排查法的完整框架

总结一下,我把这套方法叫"五步快速定位法":

步骤动作关键命令/工具时间目标
1. 确认范围画出故障边界监控大盘、日志时间线5分钟
2. 资源水位排除硬件瓶颈top/free/iostat/ss3分钟
3. 线程栈分析找到阻塞点jstack/arthas/pstack10分钟
4. 追踪上游定位根因代码审查+依赖服务监控10分钟
5. 止血修复先恢复再根治熔断/降级/扩容5分钟
核心原则:先止损,再查因,最后根治。 很多新手犯的错误是上来就查根因,查着查着故障越来越大。

几个实战心得

1. 不要在故障现场做实验。 有人喜欢在出问题的服务器上跑各种命令"试试看",这很可能让问题更复杂。先收集信息,再分析,最后操作。

2. 线程dump至少连续做三次。 一次dump可能是巧合,三次都卡在同一位置才是真问题。

3. 监控要提前建好。 这次能快速定位,很大程度上是因为我们有完整的服务调用链监控。如果你现在的系统还没接入APM,赶紧搞,出了事再来建就晚了。

4. 超时是最大的隐患。 这次故障的根因本质上就是超时设置不合理——30秒的Latch等待 + 没有熔断 = 线程池被耗尽。你的系统里可能也埋着类似的雷。

5. 写故障复盘文档。 每次故障处理完,一定要写复盘文档,记录时间线、根因、修复方案、后续改进。这不是走过场,这是给未来的自己和同事留保命指南。

做IT这么多年,见过太多"早知道就好了"的情况。

希望这篇文章能帮你少走弯路。如果真的遇到问题,别一个人扛着——易云城IT服务随时待命。

📞 服务热线:13708730161 💬 微信:eyc1689 📧 邮箱:service@eycit.com 🌐 https://www.eycit.com

您身边的IT专家。

上一篇
【2026最新】BIOS/UEFI设置全攻略:2026年...
下一篇
磁盘IO突然爆满?别急着加硬件,先查这几个常见坑...