Nginx作反向代理时超时重试配置

java 文章 2022-07-20 10:01 0 全屏看文

这里只讨论作反向代理时,当上游服务发生如接口超时、返回指定状态码等状况时而导致nginx超时重试。

这里使用的nginx版本为1.16.1,可通过nginx -V查看版本。

超时重试主要通过配置ngx_http_upstream_modulengx_http_proxy_module模块中字段实现的。

这两个模块的官方文档:

准备的工作:

  1. 准备一个后台服务,向外暴露访问地址,服务收到请求后,处理的时间为5s(当然你可以设置为其它大小),随后返回结果。这是用来模拟nginx访问上游服务接口时超时场景。
  2. 运行两个这样相同的后台服务实例,对外暴露的端口分别为9090和9091,用来模拟nginx作负载均衡的场景。
  3. nginx配置一个server,暴露端口9000,用于接收请求,并把请求分发到9090和9091的两台实例上。

具体配置:

upstream RETRY_TEST_SERVER {        server 127.0.0.1:9090;        server 127.0.0.1:9091;}server {        listen 9000;        server_name localhost;        location / {   proxy_pass http://RETRY_TEST_SERVER;   proxy_next_upstream timeout;   proxy_read_timeout 3;        }}

配置字段解释:

  • proxy_pass

    即分发到哪个upstream上

  • proxy_next_upstream

    用来配置哪些情景下会重试。当nginx收到请求,并把请求转发到RETRY_TEST_SERVER,upstream默认的负载均衡策略为轮询,第一次请求转到9090端口,若9090服务实例响应超时,那么将会将请求转到9091,这个“响应超时”,就是这个字段配置的触发场景。可配置的字段有:

    • timeout
    • error
    • http_500

    默认的配置为 proxy_next_upstream error timeout

    所有的配置列表及含义:https:/ginx.org/en/docs/httpgx_http_proxy_module.html#proxy_next_upstream

  • proxy_read_timeout

    配置从上游服务读取的超时时间。

    官方解释为:

    Defines a timeout for reading a response from the proxied server. The timeout is set only between two successive read operations, not for the transmission of the whole response. If the proxied server does not transmit anything within this time, the connection is closed.

运行

由于设置了proxy_read_timeout为3秒,实例的响应时间为5秒,所以当访问地址curl localhost:9000/test/delay(这是实例的接口测试地址)时:

  1. 请求路由到9090端口,9090接收到请求,3秒后请求超时
  2. 由于配置了proxy_next_upstream timeout,即在发生超时时,会路由到下一节点,这时请求会路由到9091
  3. 3秒过后请求再次超时,nginx返回给客户端错误信息:Gateway Timeout;

注意

  1. 由于作测试用,为方便会将多个相同的实例部署到本机通过端口作负载均衡测试,如:

    upstream RETRY_TEST_SERVER {        server 127.0.0.1:9090;        server 127.0.0.1:9091;}

    我在测试时,server 后的 127.0.0.1 一开始是写成localhost,测试9090发生超时时,没有路由到9091,而是又在9090执行了一次,改成127.0.0.1后正常。

  2. upstream 的 server 模块后还可以添加其它属性字段:

    upstream RETRY_TEST_SERVER {        server 127.0.0.1:9090 max_fails=2 fail_timeout=10s;        server 127.0.0.1:9091 max_fails=2 fail_timeout=10s;}

    官方文档:https:/ginx.org/en/docs/httpgx_http_upstream_module.html#server

    • max_failsfail_timeout

      max_failsfail_timeout须结合使用,意为“在多长时间内访问server多少次不可用”时,标记这个server节点不可用,若不可用则在此周期内当该server收到请求后直接返回错误,即nginx会直接返回给客户端 "Bad Gateway",等到下一个 "fail_timeout"周期,才会再次尝试该server是否可用。(至于"如何判断是否可用",则根据字段proxy_next_upstream的配置。)

      这一点相当重要。如实例有两个请求地址,一个耗时较长 /test/slow,一个耗时较短 /test/fast;当接口/test/slow超时时,指定时间(fail_timeout)超过最大尝试次数(max_fails)时,此时9090标记为不可用,此时请求/tset/fast路由到9090上时,nginx 会直接返回错误(Bad Gateway),即超时接口影响了正常接口的调用。

      我建议有两种方式:

      1. 提高检测是否可用的频率

        即使 fail_timeout/max_fails变小。如max_fails=5 fail_timeout=10 要比 max_fails=2 fail_timeout=10可靠

      2. 为耗时长的接口单独配置upstream和server(推荐)

-EOF-