服务超时排查指南(全链路实战)

一、一句话定位思路

复制代码
从外向里排查:网络 → 前端 → 网关 → 服务 → 中间件 → 数据库
从简单到复杂:先看监控 → 再查日志 → 最后抓包

二、超时排查流程图

复制代码
用户报告超时
    ↓
1. 确认问题范围
   ├─ 单个用户 ❓ → 检查用户端
   ├─ 部分用户 ❓ → 检查地域/运营商
   └─ 所有用户 ❌ → 服务端问题
    ↓
2. 检查监控告警
   ├─ CPU/内存 ❌ → 扩容/重启
   ├─ 磁盘IO ❌ → 检查日志/磁盘
   ├─ 网络带宽 ❌ → 检查网络/流量
   └─ 都正常 ✓ → 继续排查
    ↓
3. 查看错误日志
   ├─ 网关日志 → 限流/熔断?
   ├─ 服务日志 → 异常/慢SQL?
   ├─ 中间件日志 → Redis/消息队列?
   └─ 数据库日志 → 锁/慢查询?
    ↓
4. 全链路追踪
   ├─ 哪个环节耗时?
   ├─ 哪个服务慢?
   └─ 哪个接口慢?
    ↓
5. 具体问题定位
   ├─ 代码问题:死循环、GC频繁
   ├─ 配置问题:超时时间、连接池
   ├─ 资源问题:内存泄漏、连接泄漏
   └─ 外部依赖:第三方接口慢
    ↓
6. 复现和验证

三、按可能性排序(最有可能在前)

1. 网络问题(最常见!)

复制代码
1️⃣ DNS解析慢
   - 现象:能ping通IP,但域名访问慢
   - 检查:nslookup、dig命令
   - 解决:DNS缓存、更换DNS

2️⃣ 网络延迟高
   - 现象:某些地域/运营商慢
   - 检查:traceroute、mtr
   - 解决:CDN、多机房部署

3️⃣ 连接数打满
   - 现象:新建连接失败
   - 检查:netstat、ss命令
   - 解决:调整连接数、复用连接

4️⃣ 带宽被打满
   - 现象:下载/上传速度慢
   - 检查:iftop、nethogs
   - 解决:限流、扩容带宽

2. 服务端问题

复制代码
5️⃣ 数据库慢查询
   - 现象:数据库CPU高,接口超时
   - 检查:慢查询日志、explain
   - 解决:加索引、优化SQL

6️⃣ 缓存失效/穿透
   - 现象:Redis响应慢,数据库压力大
   - 检查:Redis监控、缓存命中率
   - 解决:缓存预热、布隆过滤器

7️⃣ 线程池打满
   - 现象:线程等待,任务队列积压
   - 检查:线程池监控、JStack
   - 解决:调整线程池参数

8️⃣ 频繁Full GC
   - 现象:服务暂停,响应变慢
   - 检查:GC日志、JVM监控
   - 解决:内存调优、代码优化

3. 配置问题

复制代码
9️⃣ 超时时间设置不合理
   - 现象:调用链某个环节超时
   - 检查:各服务超时配置
   - 解决:合理设置超时时间

🔟 连接池配置不当
   - 现象:获取连接超时
   - 检查:数据库/Redis连接池
   - 解决:调整连接池参数

四、具体排查命令和步骤

步骤1:快速定位问题范围

复制代码
# 1. 检查是用户问题还是服务问题
# 从不同地方ping/telnet
ping 你的域名
telnet 你的域名 80

# 2. 用curl测试接口
time curl -v http://你的域名/api/test
# 关注:DNS时间、连接时间、SSL时间、首包时间

# 3. 检查网络链路
traceroute 你的域名
mtr 你的域名

步骤2:检查服务状态

复制代码
# 1. 查看服务是否存活
ps aux | grep java
systemctl status 你的服务

# 2. 检查端口监听
netstat -tlnp | grep 端口
ss -tlnp | grep 端口

# 3. 查看资源使用
top -c
htop
free -h
df -h
iostat -x 1

步骤3:查看日志

复制代码
# 1. 查看错误日志
tail -f /var/log/你的服务/error.log
grep "timeout" /var/log/你的服务/*.log
grep "ERROR" /var/log/你的服务/*.log

# 2. 查看慢查询日志
tail -f /var/log/mysql/slow.log
mysqldumpslow -s t /var/log/mysql/slow.log

# 3. 查看Nginx/Apache访问日志
tail -f /var/log/nginx/access.log
awk '{print $1}' access.log | sort | uniq -c | sort -nr

步骤4:检查中间件

复制代码
# 1. Redis状态
redis-cli info | grep -E "(used_memory|connected_clients|instantaneous_ops)"
redis-cli slowlog get 10

# 2. MySQL状态
mysql -e "show processlist;"
mysql -e "show status like 'Threads_connected';"
mysql -e "show variables like '%timeout%';"

# 3. Kafka状态
kafka-topics.sh --list --zookeeper localhost:2181
kafka-consumer-groups.sh --bootstrap-server localhost:9092 --list

五、Java服务专项排查

1. JVM问题排查

复制代码
# 1. 查看GC情况
jstat -gc pid 1000
jstat -gccause pid 1000

# 2. 查看线程堆栈
jstack pid > thread_dump.log
# 查找:BLOCKED、WAITING状态的线程

# 3. 内存分析
jmap -heap pid
jmap -histo:live pid | head -20

# 4. 生成堆转储(谨慎使用)
jmap -dump:format=b,file=heap.hprof pid

2. 使用Arthas诊断

复制代码
# 安装Arthas
curl -L https://arthas.aliyun.com/arthas-boot.jar -o arthas-boot.jar
java -jar arthas-boot.jar

# 常用命令
dashboard          # 仪表板
thread             # 查看线程
watch 类 方法      # 监控方法调用
trace 类 方法      # 追踪方法耗时
profiler start     # 开始性能分析

六、全链路追踪排查

1. 使用SkyWalking/Pinpoint

复制代码
如果接入了全链路追踪,可以:
1. 找到超时的Trace ID
2. 查看调用链,定位慢的span
3. 分析各环节耗时
4. 定位具体慢的方法/服务

2. 手动添加Trace

复制代码
// 在关键位置添加日志
@RestController
public class OrderController {
    
    @GetMapping("/order/{id}")
    public Order getOrder(@PathVariable Long id) {
        long start = System.currentTimeMillis();
        
        try {
            // 1. 查询数据库
            log.info("开始查询数据库");
            Order order = orderDao.findById(id);
            log.info("数据库查询耗时: {}ms", System.currentTimeMillis() - start);
            
            // 2. 调用其他服务
            long rpcStart = System.currentTimeMillis();
            userInfo = userService.getUser(order.getUserId());
            log.info("用户服务调用耗时: {}ms", System.currentTimeMillis() - rpcStart);
            
            return order;
            
        } finally {
            log.info("总耗时: {}ms", System.currentTimeMillis() - start);
        }
    }
}

七、常见场景和解决方案

场景1:数据库慢查询导致超时

复制代码
-- 1. 开启慢查询日志
SET GLOBAL slow_query_log = 'ON';
SET GLOBAL long_query_time = 2;  -- 2秒

-- 2. 查找慢查询
SELECT * FROM mysql.slow_log ORDER BY query_time DESC LIMIT 10;

-- 3. 使用explain分析
EXPLAIN SELECT * FROM orders WHERE user_id = 1001;

-- 4. 优化方案
-- 加索引
CREATE INDEX idx_user_id ON orders(user_id);
-- 优化SQL
-- 分页查询
-- 读写分离

场景2:Redis连接池耗尽

复制代码
// Spring Boot配置
spring:
  redis:
    lettuce:
      pool:
        max-active: 20     # 最大连接数
        max-idle: 10       # 最大空闲连接
        min-idle: 5        # 最小空闲连接
        max-wait: 1000ms   # 获取连接最大等待时间
    
# 监控命令
redis-cli info | grep connected_clients
# 如果connected_clients接近maxclients,需要扩容

场景3:外部接口调用超时

复制代码
// 合理设置超时时间
@Configuration
public class HttpClientConfig {
    
    @Bean
    public RestTemplate restTemplate() {
        return new RestTemplateBuilder()
            .setConnectTimeout(Duration.ofSeconds(5))   // 连接超时
            .setReadTimeout(Duration.ofSeconds(10))     // 读取超时
            .build();
    }
}

// 使用熔断器
@HystrixCommand(
    fallbackMethod = "fallbackMethod",
    commandProperties = {
        @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "5000")
    }
)
public String callExternalApi() {
    // 调用外部接口
}

场景4:线程池配置问题

复制代码
@Configuration
public class ThreadPoolConfig {
    
    @Bean
    public ThreadPoolTaskExecutor taskExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(10);      // 核心线程数
        executor.setMaxPoolSize(20);       // 最大线程数
        executor.setQueueCapacity(100);    // 队列容量
        executor.setKeepAliveSeconds(60);  // 线程空闲时间
        executor.setThreadNamePrefix("async-");
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        executor.initialize();
        return executor;
    }
}

// 监控线程池
ThreadPoolExecutor executor = (ThreadPoolExecutor) taskExecutor.getThreadPoolExecutor();
System.out.println("活跃线程数: " + executor.getActiveCount());
System.out.println("队列大小: " + executor.getQueue().size());
System.out.println("完成任务数: " + executor.getCompletedTaskCount());

八、面试回答模板

回答结构

复制代码
**面试官您好,我会按照以下步骤排查服务超时问题:**

**第一步:快速定位问题范围**
1. 确认是单个用户、部分用户还是所有用户的问题
2. 从不同网络环境测试,排除客户端/网络问题
3. 查看监控告警,看CPU、内存、磁盘、网络是否异常

**第二步:检查服务端状态**
1. 查看服务日志,找ERROR或Timeout关键字
2. 检查服务进程状态和资源使用
3. 查看数据库、Redis等中间件状态

**第三步:深度分析(如果前两步没找到)**
1. 使用全链路追踪定位慢的环节
2. 分析慢查询日志,优化SQL
3. 检查线程状态,看是否有死锁或阻塞
4. 分析GC日志,看是否频繁Full GC
5. 检查连接池配置,看是否连接泄漏

**第四步:具体问题定位**
根据排查结果,最常见的问题可能是:
1. **数据库慢查询**(最可能):加索引、优化SQL
2. **外部依赖超时**:设置合理超时、熔断降级
3. **资源不足**:CPU/内存打满,需要扩容
4. **配置问题**:超时时间、连接池配置不当
5. **代码问题**:死循环、内存泄漏

**第五步:解决和预防**
1. 临时解决:重启、扩容、限流
2. 长期解决:优化代码、调整架构
3. 预防措施:完善监控、压测、容量规划

**我的经验是:80%的超时问题都是数据库或外部依赖引起的,**
**所以我会优先排查这两个方向。**

针对不同职级的侧重点

复制代码
初级工程师:
- 重点:会看日志、会用基本命令
- 回答:我知道要检查日志、监控、数据库

中级工程师:
- 重点:有系统化的排查思路
- 回答:有完整的排查流程,能定位常见问题

高级工程师:
- 重点:能深入分析根本原因
- 回答:能分析JVM、系统内核、网络协议

九、一句话总结

超时排查 = 快速定位范围 + 分层排查 + 工具辅助 + 经验判断

最可能的问题排序

  1. 数据库慢查询(索引、SQL优化)

  2. 外部依赖超时(第三方接口、中间件)

  3. 资源不足(CPU、内存、连接数)

  4. 网络问题(DNS、带宽、延迟)

  5. 配置问题(超时时间、连接池)

记住:先看监控,再查日志,从外向里,从简单到复杂。

相关推荐
汽车仪器仪表相关领域3 小时前
ZRT-I 精密减速器测试系统
大数据·运维·功能测试·安全·单元测试·负载均衡·压力测试
汽车仪器仪表相关领域1 天前
ZRT-II 机器人减速器性能测试系统
功能测试·测试工具·安全·机器人·压力测试·可用性测试
汽车仪器仪表相关领域1 天前
ZRT-III 机器人减速器出厂检测平台
人工智能·功能测试·安全·机器人·压力测试·可用性测试
码luffyliu2 天前
系统优化:从压测到性能飞升
后端·压力测试
汽车仪器仪表相关领域2 天前
GZCVL T-II 安全防坠器测试系统
功能测试·测试工具·安全·单元测试·压力测试·可用性测试
chalmers_152 天前
基于该 WebSocket 脚本开展专业的压力测试
服务器·websocket·压力测试
write19945 天前
并发测试,压力测试,稳定性测试对比分析
压力测试
无名小卒Rain6 天前
Jmeter性能测试-用JSON表达式获取关联参数
jmeter·压力测试·性能测试
旺仔Sec6 天前
2025年安徽省职业院校技能大赛(高职组)软件测试赛项规程及竞赛样题(附评分标准)
功能测试·单元测试·压力测试