暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

Nginx proxy如何缓解504错误

上一篇文章描述了504大部分是读取超时导致的,那么有什么办法能缓解呢?可以在调用端或proxy上进行重试,比如第一次读取超时是10s,如果失败重试一次,超时时间配置为30s。

本文介绍在proxy端进重试的解决方案,这种方式无需调用端修改,更透明。

ngx_http_upstream_module 模块可以针对不同的upstream做很多的策略,包括负载均衡、重试、权重等各种策略,如果upstream是自己能控制的服务,那么使用该模块是非常合适的,但在本文的场景中,proxy的后端是一个第三方服务,那么是否可以配置呢?做了个尝试:

upstream up {
   server   api.test.com:443 ;
}

location / {
   proxy_pass https://up;
   # proxy_pass https://api.test.com;
   proxy_ssl_server_name on;
   proxy_read_timeout 160;
   proxy_connect_timeout 5;
   proxy_buffering off;
}

但不管怎么测试,总是返回502错误,如果把upstream换成baidu.com则没问题,所以百思不得其解,那还有其他方法吗?

下面这种方法是利用proxy_intercept_errors和error_page指令:

location / {

   proxy_set_header Host api.test.com ;
   proxy_ssl_server_name on;
   proxy_read_timeout 10;
   proxy_connect_timeout 5;
   proxy_buffering off;
   proxy_redirect  off;
   proxy_pass https://api.test.com;
   proxy_intercept_errors on;
   error_page 504 = @retry;
}

location @retry {
   proxy_ssl_server_name on;
   proxy_read_timeout 30;
   proxy_connect_timeout 5;
   proxy_buffering off;
   proxy_redirect off;
   proxy_pass https://api.test.com;
   proxy_next_upstream off;
}

proxy_intercept_errors 定义:

Determines whether proxied responses with codes greater than or equal to 300 should be passed to a client or be intercepted and redirected to nginx for processing with the error_page directive.

大概的意思就是对于300以上的http错误,如果proxy_intercept_errors指令打开,会拦截错误交给error_page指令。

那error_page指令的定义呢:

Defines the URI that will be shown for the specified errors. A uri value can contain variables.

可以配置不同的http错误码对应的url地址,在这个例子中就是跳转到@retry location,从而进行一次重试。

测试了下,确实能成功,504 重试成功的例子:

[08/Nov/2023:18:01:17 +0800] 121.40.211.190 - - - _ 47.252.35.171 to: 104.1.7.192:443 : 104.1.6.192:443: POST /v1/ HTTP/1.1 200 upstream_response_time 10.015 : 10.037 msec 1699437677.553 request_time 20.051 

仔细观察,日志中保存了每一次请求ip地址,共两个,总的消耗时间是20.051秒。

504重试失败的例子:

[07/Nov/2023:16:08:11 +0800] 21.40.211.190 - - - _ 47.252.35.171 to: 104.1.7.192:443 : 104.1.6.192:443: POST / HTTP/1.1 504 upstream_response_time 10.006 : 30.006 msec 1699344491.239 request_time 40.013 

可以看出第一次尝试10s失败了,第二次尝试30s,最终还是失败了,大家觉得这种方案怎么样,可以留言聊一聊。

文章转载自虞大胆的叽叽喳喳,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论