当你看到"504 Gateway Time-out"这个错误时,本质上是在说:网关等得太久了,但后端服务就是不给响应。这就像你点外卖,骑手在餐厅门口等了半小时还没取到餐,最后只能告诉你"超时了"。
在实际工程中,504错误通常发生在这些场景:
我遇到过最典型的案例是:一个订单查询接口,平时响应很快,但在大促时频繁出现504。后来发现是商品服务查询超时,连带导致网关超时。这种问题往往需要从整个调用链路来分析。
光靠看日志来查504问题就像大海捞针。建议建立三层监控:
推荐使用Prometheus+Grafana的组合,配置示例:
yaml复制# prometheus.yml 配置示例
scrape_configs:
- job_name: 'nginx'
static_configs:
- targets: ['nginx:9113']
- job_name: 'app'
metrics_path: '/actuator/prometheus'
static_configs:
- targets: ['app:8080']
避免告警疲劳很重要。我习惯用这些策略:
以Nginx日志为例,要特别关注这些字段:
code复制$time_local $upstream_response_time $request_time $status
典型问题日志长这样:
code复制2023-08-01T14:23:45 60.001 60.002 504
这表示上游服务整整60秒没响应(Nginx默认超时是60秒)。
建议的日志查询语句:
json复制{
"query": {
"bool": {
"must": [
{ "match": { "status": 504 }},
{ "range": { "@timestamp": { "gte": "now-1h" }}}
]
}
},
"aggs": {
"group_by_upstream": {
"terms": { "field": "upstream_addr.keyword" }
}
}
}
直接上我在生产环境验证过的Go代码:
go复制func RetryRequest(ctx context.Context, maxRetries int, fn func() error) error {
for i := 0; i < maxRetries; i++ {
err := fn()
if err == nil {
return nil
}
select {
case <-time.After(time.Second * time.Duration(math.Pow(2, float64(i)))):
case <-ctx.Done():
return ctx.Err()
}
}
return fmt.Errorf("max retries exceeded")
}
这个实现采用了指数退避策略,避免雪崩效应。
推荐使用Hystrix或Resilience4j这样的库。配置示例:
java复制// Resilience4j配置
CircuitBreakerConfig config = CircuitBreakerConfig.custom()
.failureRateThreshold(50)
.waitDurationInOpenState(Duration.ofMillis(1000))
.slidingWindowType(SlidingWindowType.COUNT_BASED)
.slidingWindowSize(5)
.build();
在K8s环境中,Istio的流量管理可以很好地预防504:
yaml复制# Istio VirtualService
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: product
spec:
hosts:
- product
http:
- route:
- destination:
host: product
subset: v1
timeout: 10s
retries:
attempts: 3
perTryTimeout: 2s
对于耗时操作,建议采用这种模式:
code复制客户端 → API网关 → 消息队列 → 工作进程 → 存储结果 → 客户端轮询结果
这是我总结的超时时间设置参考表:
| 组件 | 建议值 | 说明 |
|---|---|---|
| Nginx | 15s | 短于客户端超时 |
| 数据库 | 5s | 简单查询应更快 |
| RPC调用 | 3s | 微服务间调用 |
以Java的HikariCP为例:
properties复制spring.datasource.hikari.maximum-pool-size=20
spring.datasource.hikari.connection-timeout=3000
spring.datasource.hikari.idle-timeout=600000
去年我们电商系统在大促时遇到一个典型问题:支付页面频繁504。通过调用链分析发现:
最终解决方案:
改造后,支付成功率从92%提升到99.6%,504错误基本消失。这个案例告诉我们,解决504问题需要系统化思维。