应用链路超时故障排查实战指南

一、概述

在分布式系统中,应用链路超时是最常见且最复杂的故障类型之一。一次简单的用户请求可能涉及多个服务、数据库、缓存和外部 API 的调用,任何一个环节的延迟都可能导致整个链路超时。

超时故障的特点

  • 隐蔽性强:偶发性超时难以复现
  • 传播性广:单点超时可能引发雪崩效应
  • 定位困难:涉及多个系统组件
  • 影响面大:直接影响用户体验和业务指标

本文目标

  • 建立系统化的超时排查方法论
  • 掌握各层级超时的诊断工具
  • 学会设计和实施超时优化策略
  • 构建预防性的监控告警体系

二、超时故障分类

2.1 按发生层级分类

层级 典型场景 排查重点
客户端 浏览器/APP 请求超时 网络质量、CDN、DNS
负载均衡 L4/L7 负载均衡超时 连接池、健康检查
应用服务 业务逻辑处理超时 代码性能、资源竞争
数据库 SQL 执行超时 慢查询、锁等待
缓存 Redis/Memcached 超时 连接数、大 key
消息队列 消息消费超时 积压、消费者性能
外部 API 第三方服务超时 限流、熔断策略

2.2 按超时类型分类

类型 说明 典型表现
连接超时 (Connect Timeout) 建立 TCP 连接失败 无法连接到目标服务
读取超时 (Read Timeout) 等待响应数据超时 连接成功但无响应
写入超时 (Write Timeout) 发送请求数据超时 请求无法完整发送
整体超时 (Total Timeout) 整个请求处理超时 包含所有阶段的时间
空闲超时 (Idle Timeout) 空闲连接被回收 长连接被意外关闭

2.3 按影响范围分类

  • 单用户超时:个别用户遇到,可能是客户端网络问题
  • 局部超时:特定服务或区域,可能是服务实例问题
  • 全局超时:所有用户都遇到,可能是基础设施故障

三、排查方法论

3.1 黄金排查流程

1
1. 确认现象 → 2. 定位范围 → 3. 收集证据 → 4. 分析根因 → 5. 实施修复 → 6. 验证效果

3.2 信息收集清单

信息类型 具体内容 获取方式
时间信息 故障开始时间、持续时间、频率 监控图表、日志
范围信息 影响的用户、服务、地域 告警、用户反馈
性能指标 响应时间、错误率、吞吐量 APM、监控系统
变更历史 最近的发布、配置变更 发布记录、变更日志
依赖状态 上下游服务健康状态 服务网格、健康检查

3.3 故障定级标准

级别 影响范围 响应时间 升级路径
P0 全站不可用 5 分钟内响应 立即升级至技术负责人
P1 核心功能受损 15 分钟内响应 升级至团队负责人
P2 部分功能异常 1 小时内响应 团队内部处理
P3 轻微影响 24 小时内响应 常规工单处理

四、客户端超时排查

4.1 浏览器端排查

使用开发者工具分析:

1
2
3
4
5
6
7
8
9
10
// Chrome DevTools Network 面板
// 查看各个阶段耗时:
// - DNS Lookup
// - Initial Connection
// - SSL/TLS Handshake
// - Time to First Byte (TTFB)
// - Content Download

// Performance API 获取详细 timing
performance.getEntriesByType('navigation')[0]

关键指标分析:

指标 正常值 异常处理
DNS Lookup < 50ms 检查 DNS 服务器、本地缓存
TCP Connection < 100ms 检查网络路由、防火墙
TTFB < 500ms 检查服务端处理时间
Content Download 视内容大小 检查带宽、压缩

4.2 移动端排查

iOS (Network Framework):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 使用 NWConnection 监控
let parameters = NWParameters.tcp()
parameters.connectionTimeout = .after(5)

// 监控连接状态
connection.stateUpdateHandler = { state in
switch state {
case .waiting(let error):
print("连接等待:\(error)")
case .failed(let error):
print("连接失败:\(error)")
default:
break
}
}

Android (OkHttp):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
val client = OkHttpClient.Builder()
.connectTimeout(5, TimeUnit.SECONDS)
.readTimeout(10, TimeUnit.SECONDS)
.writeTimeout(10, TimeUnit.SECONDS)
.build()

// 添加事件监听器
client.eventListenerFactory { call ->
object : EventListener() {
override fun connectStart(call: Call, inetSocketAddress: InetSocketAddress, proxy: Proxy) {
// 记录连接开始时间
}
override fun connectFailed(call: Call, inetSocketAddress: InetSocketAddress, proxy: Proxy, socketAddress: SocketAddress, exception: IOException) {
// 记录连接失败
}
}
}

4.3 DNS 问题排查

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 检查 DNS 解析时间
time dig @8.8.8.8 api.example.com

# 检查 DNS 缓存
sudo systemd-resolve --flush-caches # Linux
sudo dscacheutil -flushcache # macOS
ipconfig /flushdns # Windows

# 检查 DNS 服务器响应
nslookup api.example.com
dig +trace api.example.com

# 检测 DNS 污染
dig @1.1.1.1 api.example.com
dig @8.8.8.8 api.example.com

五、网络层超时排查

5.1 TCP 连接问题

连接超时诊断:

1
2
3
4
5
6
7
8
9
10
11
12
# 测试 TCP 连接建立时间
time nc -vz api.example.com 443

# 检查 TCP 握手过程
tcpdump -i any -n host api.example.com and port 443 -w tcp_handshake.pcap

# 分析 TCP 重传
netstat -s | grep -i retrans

# 检查 SYN 队列
netstat -s | grep -i "listen queue"
ss -s

常见 TCP 问题:

问题 症状 解决方案
SYN Flood 连接建立失败 启用 SYN Cookie、增加队列
TCP 重传高 延迟增加、超时 检查网络质量、调整重传参数
TIME_WAIT 过多 端口耗尽 调整 tcp_tw_reuse
连接重置 RST 包 检查防火墙、服务状态

5.2 网络延迟分析

1
2
3
4
5
6
7
8
9
10
11
# 逐跳延迟检测
mtr -rwc 10 api.example.com

# 路径跟踪
traceroute -I api.example.com

# 带宽测试
iperf3 -c server.example.com -t 30

# 检查网络丢包
ping -c 100 api.example.com

MTR 输出分析:

1
2
3
4
5
Host              Loss%   Snt   Last   Avg  Best  Wrst StDev
1. 192.168.1.1 0.0% 100 1.2 1.5 0.8 5.2 0.6
2. 10.0.0.1 0.0% 100 5.3 6.1 4.9 15.3 2.1
3. 172.16.0.1 15.0% 100 45.2 52.3 38.1 120.5 18.7 ← 问题点
4. api.example.com 0.0% 100 55.1 58.2 50.3 85.2 8.9

5.3 防火墙和安全组

1
2
3
4
5
6
7
8
9
10
11
# 检查 iptables 规则
iptables -L -n -v | grep -i drop
iptables -L -n -v | grep -i reject

# 检查连接跟踪
cat /proc/sys/net/netfilter/nf_conntrack_count
cat /proc/sys/net/netfilter/nf_conntrack_max

# 云服务商安全组检查
# AWS: aws ec2 describe-security-groups
# 阿里云:aliyun ecs DescribeSecurityGroupAttribute

六、应用层超时排查

6.1 Java 应用排查

线程堆栈分析:

1
2
3
4
5
6
7
8
9
# 获取线程堆栈
jstack -l <pid> > thread_dump.txt

# 查找阻塞线程
grep -A 30 "BLOCKED" thread_dump.txt
grep -A 30 "WAITING" thread_dump.txt

# 使用 async-profiler 生成火焰图
./profiler.sh -d 30 -f flame.svg <pid>

JVM 监控:

1
2
3
4
5
6
7
8
# 查看 GC 情况
jstat -gcutil <pid> 1000

# 查看堆内存
jmap -heap <pid>

# 实时 GC 日志分析
# JVM 参数:-Xlog:gc*:file=gc.log:time,uptime:filecount=5,filesize=10M

常见 Java 超时原因:

原因 特征 排查方法
GC 停顿 周期性超时 分析 GC 日志、堆 dump
线程池耗尽 请求排队 检查线程池指标
锁竞争 线程 BLOCKED 分析 thread dump
外部调用慢 特定接口慢 APM 链路追踪

6.2 Go 应用排查

1
2
3
4
5
6
7
8
9
10
11
# 获取 goroutine 堆栈
kill -SIGQUIT <pid>

# 或使用 go tool pprof
go tool pprof http://localhost:6060/debug/pprof/goroutine?debug=1

# 查看阻塞情况
go tool pprof -top http://localhost:6060/debug/pprof/block

# 查看锁竞争
go tool pprof -top http://localhost:6060/debug/pprof/mutex

6.3 Python 应用排查

1
2
3
4
5
6
7
8
# 使用 py-spy 采样
py-spy record -o profile.svg --pid <pid>

# 查看线程状态
py-spy dump --pid <pid>

# 使用 cProfile 分析
python -m cProfile -o output.prof script.py

6.4 应用日志分析

关键日志模式:

1
2
3
4
5
6
7
8
9
10
11
# 搜索超时相关日志
grep -i "timeout" application.log
grep -i "read timed out" application.log
grep -i "connect timed out" application.log
grep -i "deadline exceeded" application.log

# 统计超时频率
grep -c "timeout" application.log

# 分析超时时间分布
grep "timeout" application.log | awk '{print $NF}' | sort -n | uniq -c

日志增强建议:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 添加请求 ID 追踪
MDC.put("requestId", UUID.randomUUID().toString());
log.info("Starting request", kv("endpoint", "/api/users"));

// 记录耗时
long start = System.currentTimeMillis();
try {
// 业务逻辑
} finally {
long duration = System.currentTimeMillis() - start;
log.info("Request completed",
kv("requestId", MDC.get("requestId")),
kv("duration_ms", duration));
}

七、数据库超时排查

7.1 MySQL 超时排查

检查慢查询:

1
2
3
4
5
6
7
8
9
10
11
-- 开启慢查询日志
SET GLOBAL slow_query_log = 'ON';
SET GLOBAL long_query_time = 1;
SET GLOBAL slow_query_log_file = '/var/log/mysql/slow.log';

-- 查看当前慢查询配置
SHOW VARIABLES LIKE 'slow_query%';
SHOW VARIABLES LIKE 'long_query_time';

-- 分析慢查询
mysqldumpslow -s t -t 10 /var/log/mysql/slow.log

检查锁等待:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
-- 查看当前锁等待
SELECT * FROM information_schema.INNODB_LOCK_WAITS;

-- 查看正在运行的事务
SELECT * FROM information_schema.INNODB_TRX;

-- 查看锁信息
SELECT * FROM performance_schema.data_locks;

-- 查找阻塞源
SELECT blocking_trx.trx_id AS blocking_trx_id,
blocking_trx.trx_mysql_thread_id AS blocking_thread,
blocked_trx.trx_id AS blocked_trx_id,
blocked_trx.trx_mysql_thread_id AS blocked_thread,
blocked_trx.trx_query AS blocked_query
FROM information_schema.INNODB_LOCK_WAITS
JOIN information_schema.INNODB_TRX blocking_trx
ON INNODB_LOCK_WAITS.blocking_engine_transaction_id = blocking_trx.trx_id
JOIN information_schema.INNODB_TRX blocked_trx
ON INNODB_LOCK_WAITS.requesting_engine_transaction_id = blocked_trx.trx_id;

连接超时配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
-- 查看超时配置
SHOW VARIABLES LIKE '%timeout%';

-- 关键参数:
-- connect_timeout: 连接超时 (默认 10s)
-- net_read_timeout: 读取超时 (默认 30s)
-- net_write_timeout: 写入超时 (默认 60s)
-- wait_timeout: 空闲连接超时 (默认 28800s)
-- lock_wait_timeout: 锁等待超时 (默认 31536000s)

-- 临时调整
SET SESSION net_read_timeout = 60;
SET GLOBAL net_read_timeout = 60;

7.2 PostgreSQL 超时排查

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
-- 查看慢查询
SELECT query, calls, total_exec_time, mean_exec_time
FROM pg_stat_statements
ORDER BY mean_exec_time DESC
LIMIT 10;

-- 查看当前锁
SELECT blocked_locks.pid AS blocked_pid,
blocked_activity.usename AS blocked_user,
blocking_locks.pid AS blocking_pid,
blocking_activity.usename AS blocking_user,
blocked_activity.query AS blocked_query
FROM pg_catalog.pg_locks blocked_locks
JOIN pg_catalog.pg_stat_activity blocked_activity ON blocked_activity.pid = blocked_locks.pid
JOIN pg_catalog.pg_locks blocking_locks
ON blocking_locks.locktype = blocked_locks.locktype
AND blocking_locks.database IS NOT DISTINCT FROM blocked_locks.database
AND blocking_locks.relation IS NOT DISTINCT FROM blocked_locks.relation
AND blocking_locks.page IS NOT DISTINCT FROM blocked_locks.page
AND blocking_locks.tuple IS NOT DISTINCT FROM blocked_locks.tuple
AND blocking_locks.virtualxid IS NOT DISTINCT FROM blocked_locks.virtualxid
AND blocking_locks.transactionid IS NOT DISTINCT FROM blocked_locks.transactionid
AND blocking_locks.classid IS NOT DISTINCT FROM blocked_locks.classid
AND blocking_locks.objid IS NOT DISTINCT FROM blocked_locks.objid
AND blocking_locks.objsubid IS NOT DISTINCT FROM blocked_locks.objsubid
AND blocking_locks.pid != blocked_locks.pid
JOIN pg_catalog.pg_stat_activity blocking_activity ON blocking_activity.pid = blocking_locks.pid
WHERE NOT blocked_locks.granted;

-- 查看超时配置
SHOW statement_timeout;
SHOW lock_timeout;
SHOW idle_in_transaction_session_timeout;

7.3 连接池超时

HikariCP 配置:

1
2
3
4
5
6
7
8
9
spring:
datasource:
hikari:
connection-timeout: 30000 # 连接获取超时
validation-timeout: 5000 # 连接验证超时
idle-timeout: 600000 # 空闲连接超时
max-lifetime: 1800000 # 连接最大生命周期
maximum-pool-size: 20 # 最大连接数
minimum-idle: 10 # 最小空闲连接

连接池监控指标:

指标 正常值 告警阈值
活跃连接数 < 最大池大小 80% > 90%
等待获取连接时间 < 100ms > 1s
连接超时次数 0 > 1/min
连接创建速率 稳定 持续增长

八、缓存超时排查

8.1 Redis 超时排查

性能监控:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 查看 Redis 延迟
redis-cli --latency
redis-cli --latency-history

# 查看慢查询
redis-cli config set slowlog-log-slower-than 10000 # 10ms
redis-cli slowlog get 10

# 查看连接信息
redis-cli client list
redis-cli info clients

# 查看内存和大 key
redis-cli --bigkeys
redis-cli memory stats

常见问题:

问题 症状 解决方案
大 key 操作 单命令延迟高 拆分大 key、使用 SCAN
热 key 单分片负载高 本地缓存、key 分散
内存不足 写入失败、驱逐 扩容、优化数据结构
持久化阻塞 周期性延迟 调整 RDB/AOF 策略
连接数过多 新连接失败 连接池优化、增加 maxclients

8.2 连接池配置

Lettuce (Spring Boot):

1
2
3
4
5
6
7
8
9
spring:
redis:
lettuce:
pool:
max-active: 20
max-idle: 10
min-idle: 5
max-wait: 3000ms # 连接获取等待超时
shutdown-timeout: 100ms

Jedis:

1
2
3
4
5
6
JedisPoolConfig config = new JedisPoolConfig();
config.setMaxTotal(20);
config.setMaxIdle(10);
config.setMinIdle(5);
config.setMaxWaitMillis(3000);
config.setTestOnBorrow(true);

九、消息队列超时排查

9.1 Kafka 超时排查

消费者超时:

1
2
3
4
5
6
7
# 查看消费者组延迟
kafka-consumer-groups.sh --bootstrap-server localhost:9092 \
--describe --group my-consumer-group

# 查看分区分配
kafka-consumer-groups.sh --bootstrap-server localhost:9092 \
--describe --group my-consumer-group --members --verbose

关键配置:

1
2
3
4
5
6
7
8
9
10
# 消费者配置
consumer.max.poll.interval.ms=300000 # 最大轮询间隔
consumer.session.timeout.ms=45000 # 会话超时
consumer.heartbeat.interval.ms=15000 # 心跳间隔
consumer.max.poll.records=500 # 单次拉取数量

# 生产者配置
producer.request.timeout.ms=30000 # 请求超时
producer.delivery.timeout.ms=120000 # 投递超时
producer.acks=all # 确认级别

9.2 RabbitMQ 超时排查

1
2
3
4
5
6
7
8
9
10
11
# 查看队列状态
rabbitmqctl list_queues name messages consumers

# 查看连接
rabbitmqctl list_connections name state

# 查看通道
rabbitmqctl list_channels name state

# 监控队列积压
rabbitmqctl list_queues name messages_ready messages_unacknowledged

消费者超时配置:

1
2
3
4
5
6
7
8
9
10
11
spring:
rabbitmq:
listener:
simple:
acknowledge-mode: manual
prefetch: 10
retry:
enabled: true
initial-interval: 1000
max-attempts: 3
max-interval: 10000

十、外部 API 超时排查

10.1 超时策略设计

分层超时配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Configuration
public class TimeoutConfig {

// 总超时 = 连接超时 + 读取超时 + 处理时间缓冲
@Bean
public RestTemplate restTemplate() {
HttpComponentsClientHttpRequestFactory factory =
new HttpComponentsClientHttpRequestFactory();
factory.setConnectTimeout(5000); // 连接超时 5s
factory.setConnectionRequestTimeout(5000); // 连接请求超时 5s
factory.setReadTimeout(30000); // 读取超时 30s
return new RestTemplate(factory);
}
}

10.2 熔断器配置

Resilience4j:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@Bean
public CircuitBreakerConfig circuitBreakerConfig() {
return CircuitBreakerConfig.custom()
.failureRateThreshold(50) // 失败率阈值
.waitDurationInOpenState(30000) // 打开状态等待时间
.slidingWindowSize(10) // 滑动窗口大小
.minimumNumberOfCalls(5) // 最小调用数
.permittedNumberOfCallsInHalfOpenState(3) // 半开状态允许调用数
.build();
}

@Bean
public TimeLimiterConfig timeLimiterConfig() {
return TimeLimiterConfig.custom()
.timeoutDuration(Duration.ofSeconds(10)) // 超时时间
.cancelRunningFuture(true) // 超时取消
.build();
}

10.3 重试策略

1
2
3
4
5
6
7
8
9
10
@Bean
public RetryConfig retryConfig() {
return RetryConfig.custom()
.maxAttempts(3)
.waitDuration(Duration.ofMillis(500))
.retryOnException(throwable -> throwable instanceof TimeoutException
|| throwable instanceof ConnectException
|| throwable instanceof SocketTimeoutException)
.build();
}

十一、链路追踪与诊断

11.1 OpenTelemetry 集成

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
// Spring Boot 配置
// 添加依赖
// io.opentelemetry:opentelemetry-api
// io.opentelemetry:opentelemetry-sdk
// io.opentelemetry:opentelemetry-exporter-otlp

@Configuration
public class ObservabilityConfig {

@Bean
public OpenTelemetry openTelemetry() {
Resource resource = Resource.getDefault()
.merge(Resource.create(Attributes.of(
ResourceAttributes.SERVICE_NAME, "my-service",
ResourceAttributes.SERVICE_VERSION, "1.0.0"
)));

SdkTracerProvider tracerProvider = SdkTracerProvider.builder()
.setResource(resource)
.addSpanProcessor(BatchSpanProcessor.builder(
OtlpGrpcSpanExporter.builder()
.setEndpoint("http://otel-collector:4317")
.build())
.build())
.build();

return OpenTelemetrySdk.builder()
.setTracerProvider(tracerProvider)
.build();
}
}

11.2 关键 Span 属性

1
2
3
4
5
6
7
8
9
10
11
12
13
// 记录关键 timing 信息
Span span = tracer.spanBuilder("database-query")
.setAttribute("db.system", "mysql")
.setAttribute("db.name", "mydb")
.setAttribute("db.statement", sanitizedQuery)
.startSpan();

try (Scope scope = span.makeCurrent()) {
// 执行业务逻辑
span.setAttribute("db.query.duration_ms", duration);
} finally {
span.end();
}

11.3 链路分析

Jaeger 查询:

1
2
3
4
5
# 查询慢调用
curl 'http://jaeger-query:16686/api/services'

# 查询特定服务的 traces
curl 'http://jaeger-query:16686/api/traces?service=my-service&minDuration=1s'

关键分析维度:

维度 分析内容
耗时分布 找出最慢的 Span
错误率 定位频繁失败的环节
依赖关系 识别关键路径
时间序列 发现周期性异常

十二、监控告警设计

12.1 核心监控指标

应用层指标:

1
2
3
4
5
6
7
8
# Prometheus 指标
- http_request_duration_seconds # 请求耗时分布
- http_requests_total # 请求总数
- http_request_timeout_total # 超时请求数
- db_connection_pool_active # 活跃连接数
- db_connection_pool_wait_seconds # 连接等待时间
- cache_operation_duration_seconds # 缓存操作耗时
- external_api_latency_seconds # 外部 API 延迟

12.2 告警规则

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
groups:
- name: timeout-alerts
rules:
# 高错误率告警
- alert: HighTimeoutRate
expr: |
rate(http_request_timeout_total[5m])
/ rate(http_requests_total[5m]) > 0.05
for: 2m
labels:
severity: warning
annotations:
summary: "请求超时率过高"
description: "服务 {{ $labels.service }} 超时率 {{ $value | humanizePercentage }}"

# P99 延迟告警
- alert: HighP99Latency
expr: |
histogram_quantile(0.99,
rate(http_request_duration_seconds_bucket[5m])) > 2
for: 5m
labels:
severity: warning
annotations:
summary: "P99 延迟过高"
description: "服务 {{ $labels.service }} P99 延迟 {{ $value }}s"

# 连接池耗尽告警
- alert: ConnectionPoolExhausted
expr: |
db_connection_pool_active / db_connection_pool_max > 0.9
for: 1m
labels:
severity: critical
annotations:
summary: "数据库连接池即将耗尽"
description: "连接池使用率 {{ $value | humanizePercentage }}"

# 外部 API 超时告警
- alert: ExternalAPITimeout
expr: |
rate(external_api_timeout_total[5m]) > 0
for: 1m
labels:
severity: warning
annotations:
summary: "外部 API 调用超时"
description: "API {{ $labels.api }} 出现超时"

12.3 仪表盘设计

关键面板:

  1. 概览面板

    • 请求总量和错误率趋势
    • P50/P90/P99 延迟趋势
    • 超时请求数趋势
  2. 服务依赖面板

    • 各依赖服务调用量
    • 各依赖服务延迟分布
    • 各依赖服务错误率
  3. 资源面板

    • 连接池使用率
    • 线程池使用率
    • 缓存命中率
  4. 链路分析面板

    • Top 慢调用链路
    • 错误链路分布
    • 关键路径分析

十三、优化策略

13.1 超时时间设置原则

场景 建议超时 说明
内部服务调用 100-500ms 低延迟、高可靠
数据库查询 1-5s 考虑复杂查询
缓存操作 50-200ms 快速失败
外部 API 5-30s 考虑第三方稳定性
文件上传/下载 根据文件大小 动态计算
批处理任务 根据数据量 单独配置

13.2 超时时间计算公式

1
2
3
4
5
6
推荐超时 = P99 延迟 × 安全系数 + 网络缓冲

安全系数建议:
- 内部服务:2-3 倍
- 外部服务:3-5 倍
- 关键路径:1.5-2 倍

13.3 降级策略

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@Service
public class UserService {

@CircuitBreaker(name = "userProfile", fallbackMethod = "getUserProfileFallback")
@TimeLimiter(name = "userProfile")
public CompletableFuture<UserProfile> getUserProfile(String userId) {
return CompletableFuture.supplyAsync(() ->
userProfileClient.getProfile(userId));
}

// 降级方法
public CompletableFuture<UserProfile> getUserProfileFallback(String userId, Throwable t) {
log.warn("获取用户画像失败,使用默认值", t);
return CompletableFuture.completedFuture(UserProfile.defaultProfile());
}
}

13.4 缓存策略

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
@Cacheable(value = "userProfile", 
key = "#userId",
unless = "#result == null",
cacheManager = "redisCacheManager")
@CacheConfig(cacheNames = "userProfile")
public UserProfile getUserProfileWithCache(String userId) {
return userProfileClient.getProfile(userId);
}

// 缓存配置
@Configuration
@EnableCaching
public class CacheConfig {

@Bean
public CacheManager cacheManager(RedisConnectionFactory factory) {
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
.entryTtl(Duration.ofMinutes(10)) // 缓存过期时间
.disableCachingNullValues() // 不缓存空值
.serializeValuesWith(
RedisSerializationContext.SerializationPair
.fromSerializer(new GenericJackson2JsonRedisSerializer()));

return RedisCacheManager.builder(factory)
.cacheDefaults(config)
.build();
}
}

十四、实战案例

案例 1:电商下单接口超时

现象:

  • 下单接口 P99 延迟从 200ms 上升到 5s
  • 超时率从 0.1% 上升到 15%
  • 数据库连接池使用率 95%

排查过程:

  1. 链路追踪定位:通过 Jaeger 发现数据库查询耗时占 80%
  2. 慢查询分析:发现 SELECT * FROM orders WHERE user_id = ? 无索引
  3. 锁等待检查:发现大量事务等待 orders 表的行锁
  4. 根因确认:新上线的批量导入功能导致表锁竞争

解决方案:

  1. user_id 添加索引
  2. 批量导入改为分批处理,每批 1000 条
  3. 增加数据库连接池大小
  4. 添加查询超时限制

效果:

  • P99 延迟恢复到 250ms
  • 超时率降至 0.2%
  • 连接池使用率降至 40%

案例 2:第三方支付回调超时

现象:

  • 支付回调接口偶发超时
  • 超时集中在每天 10:00-11:00
  • 第三方支付平台反馈我方响应慢

排查过程:

  1. 时间模式分析:超时与业务高峰时间吻合
  2. 资源监控:发现 GC 停顿时间与超时时段吻合
  3. 堆分析:发现大量临时对象导致频繁 Full GC
  4. 根因确认:回调处理中创建了大量未复用的对象

解决方案:

  1. 优化对象创建,使用对象池
  2. 调整 JVM 堆大小和 GC 参数
  3. 异步处理回调,快速响应第三方
  4. 添加回调超时告警

效果:

  • GC 停顿时间从 500ms 降至 50ms
  • 回调超时率从 5% 降至 0.1%

案例 3:微服务雪崩

现象:

  • A 服务超时导致 B、C、D 服务连锁超时
  • 整个系统响应变慢
  • 部分服务实例宕机

排查过程:

  1. 依赖分析:发现 B、C、D 服务都同步调用 A 服务
  2. 超时配置:发现没有设置合理的超时和熔断
  3. 线程池:发现调用方线程池被耗尽
  4. 根因确认:缺少隔离和熔断机制

解决方案:

  1. 为所有外部调用添加超时配置
  2. 部署熔断器,失败率超过 50% 自动熔断
  3. 使用线程池隔离不同依赖
  4. 添加舱壁模式,限制并发调用数

效果:

  • 故障影响范围缩小 80%
  • 系统自动恢复时间从 30 分钟降至 2 分钟

十五、预防体系

15.1 开发规范

超时配置规范:

1
2
3
4
5
6
7
8
9
10
11
// 必须显式配置超时
// ❌ 错误示例
RestTemplate restTemplate = new RestTemplate();

// ✅ 正确示例
RestTemplate restTemplate = new RestTemplate(
new HttpComponentsClientHttpRequestFactory() {{
setConnectTimeout(5000);
setReadTimeout(30000);
}}
);

异步调用规范:

1
2
3
4
5
6
7
// 避免同步阻塞调用
// ❌ 错误示例
Response response = client.call(); // 可能永久阻塞

// ✅ 正确示例
CompletableFuture<Response> future = client.callAsync();
Response response = future.get(30, TimeUnit.SECONDS);

15.2 测试策略

超时测试用例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@Test
@Timeout(value = 5, unit = TimeUnit.SECONDS)
public void testApiTimeout() {
// 测试必须在 5 秒内完成
service.processRequest();
}

@Test
public void testSlowDependency() {
// Mock 慢依赖
when(dependency.call()).thenAnswer(invocation -> {
Thread.sleep(10000);
return result;
});

// 验证超时处理
assertThrows(TimeoutException.class, () -> {
service.withTimeout();
});
}

混沌工程测试:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# Chaos Mesh 实验配置
apiVersion: chaos-mesh.org/v1alpha1
kind: NetworkChaos
metadata:
name: network-delay
spec:
action: delay
mode: one
selector:
namespaces: ["production"]
delay:
latency: "100ms"
correlation: "25"
jitter: "10ms"
duration: "5m"

15.3 容量规划

压测指标:

指标 目标值 测量方法
单实例 QPS > 1000 压力测试
P99 延迟 < 500ms 压测监控
超时率 < 0.1% 压测监控
恢复时间 < 1 分钟 故障注入

容量公式:

1
2
3
所需实例数 = (峰值 QPS × P99 延迟) / (单实例 QPS × 安全系数)

安全系数建议:1.5-2.0

十六、总结

超时故障排查是一项系统性工程,需要:

  1. 建立完整的监控体系:从客户端到服务端,从网络到应用
  2. 掌握各层级的诊断工具:网络、应用、数据库、缓存
  3. 设计合理的超时策略:分层配置、动态调整
  4. 实施有效的防护措施:熔断、降级、限流
  5. 建立预防性机制:规范、测试、混沌工程

关键要点:

  • 超时配置必须显式设置,避免默认值
  • 链路追踪是定位问题的关键工具
  • 监控告警要覆盖所有关键指标
  • 定期进行故障演练和混沌测试
  • 建立完善的故障复盘机制

参考文档: