使用Spring Cloud Gateway和Nginx作为反向代理的网关超时

时间:2019-04-01 07:40:59

标签: java nginx spring-cloud nginx-reverse-proxy spring-cloud-gateway

我为我的应用程序创建了API网关,它将充当其他微服务的前端控制器。 在生产设置中,我将Nginx用户用作网关的反向代理

API网关在端口8080上运行

Nginx配置如下

gateway-api.conf:

server {
    listen 80;
    server_name api.example.com;
    location / {
        proxy_set_header        X-Real-IP       $remote_addr;
        proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_http_version 1.1;
        proxy_set_header Connection "";
        proxy_pass http://localhost:30010/;
        keepalive_timeout 500s;
    }
    keepalive_timeout 500s;
    access_log /var/log/nginx/api.log;  
    error_log /var/log/nginx/api_error.log;
}
nginx.conf中的

超时设置

proxy_connect_timeout 300;
proxy_send_timeout 300;
proxy_read_timeout 300;
send_timeout 300;

Spring云网关gradle文件:

compile('org.springframework.cloud:spring-cloud-starter-gateway')
 compile('org.springframework.cloud:spring-cloud-starter-openfeign')
 compile("org.springframework.boot:spring-boot-starter-actuator")
 compile('org.springframework.boot:spring-boot-starter-security')

springBootVersion=2.0.3.RELEASE
springDMPVersion=1.0.4.RELEASE
springPlatformBomVersion=Cairo-SR2
springCloudVersion=Finchley.RELEASE

网关应用程序:

@SpringBootApplication
@ComponentScan(basePackages = {"com.example"})
@EntityScan(basePackages = {"com.example"})
@EnableFeignClients(basePackages = "com.example")
public class GatewayApplication {

    public static void main(String[] args) {
        SpringApplication.run(GatewayApplication.class, args);
    }
}

问题陈述:

在我的一项微服务中,一个REST API花费了3分钟以上的时间才能完成。 如果我通过nginx(api.example.com)调用此API,则恰好在1分钟后失败,并显示HTTP状态504

卷曲:

curl --request GET \
  --url http://api.example.com/hellomicroservice/api/take/moretime

错误:

504 Timeout while reading the response from Server

nginx和API网关中没有错误日志

来自nginx的访问日志:

203.129.213.102 - - [01/Apr/2019:08:14:33 +0000] "GET hellomicroservice/api/take/moretime HTTP/1.1" 499 0 "-" "PostmanRuntime/7.3.0"

但是当我直接向网关(在网关端口8080上)调用相同的API时,请求过程成功

具有网关端口的卷曲:

curl --request GET \
  --url http://api.example.com:8080/hellomicroservice/api/take/moretime

编辑: 如果我将Nginx超时设置应用为少于60秒(例如30秒),则请求将在指定的时间间隔内超时。但是,如果我将Nginx超时设置为超过60秒,即300秒,则请求将在60秒后超时。

4 个答案:

答案 0 :(得分:0)

看来请求超时对您来说不是问题。它的连接超时。 我认为我们需要查看

的标题
  

连接

AFAIK,Connection标头定义,连接应该是持久的,或者谁有权维护/关闭该连接。如果连接为keep-alive,则该连接将是持久的。对于保持活动的连接,客户端偶尔会发送TCP ping,以确保服务器仍处于活动状态并保持连接。根据 curl ,默认情况下,这次是每60秒一次。

现在必须将nginx配置为接受连接,并使用 keepalive_timeout 指令将其保持一段时间。如果不存在,那么nginx将不会keep the connections alive

这应该是nginx在日志中显示 499 的原因。 HTTP499 是nginx中的一个通用错误,表示客户端已关闭连接。在您的情况下,curl将其关闭。为什么curl将其关闭?因为nginx由于未启用keep-alive而没有响应60秒的TCP ping。

keepalive_timeout 添加到〜500或大于应用程序超时值可以解决您的问题。

现在,为什么它直接与tomcat一起使用?我认为spring使活动超时成为无限或更高的值。通常在tomcat中也要60秒。

我希望这可以解决您的问题。

答案 1 :(得分:0)

由于您的配置缺少proxy_http_version密钥,可能仍无法为上游启用保持活动状态。

引用来自:https://www.nginx.com/blog/tuning-nginx/#proxy_http_version

  

要启用与上游服务器的保持连接,您还必须在配置中包括以下指令:

proxy_http_version 1.1;
proxy_set_header Connection "";

我还将按照Kris的建议将keepalive_timeout保留在配置中。

答案 2 :(得分:0)

尝试将您的超时设置放在/etc/nginx/conf.d/timeout.conf中(如果不存在,请创建一个)。设置以下设置,

const request = require('request')
const delay = (ms) => {
  return new Promise((resolve) => {
    setTimeout(resolve, ms)
  })
}

async function report(){
  let accounts = await getAccountsForTimezone('Eastern Time (US & Canada)');
  const promises = accounts.map((account) => {
      return new Promise(async (resolve, reject) => {
        await delay(1000)  
        const param1 = await scope1(account)
        const param2 = await scope2(account)
        const param3 = await scope3(account)
        const response = insertData(param1, param2, param3).catch(reject)
        resolve(response)
     })
  })
};

答案 3 :(得分:0)

我想这是由于许多其他事情而可能发生的问题之一。这是一个对我有用的解决方案(我也在 /var/log/nginx/error.log 中遇到错误:

<块引用>

2020/12/30 21:47:47 [错误] 26765#26765:*13064 上游超时 (110:连接超时)同时连接到上游,客户端:XXX, 服务器:example.com,请求:“GET /eshop HTTP/1.0”,上游: “http://[::1]:8080/error_50x.html”,主机:“example.com”

奇怪的是,这并没有发生在我的笔记本电脑上,而只发生在我的服务器上。所以我检查了 IP,结果发现这可能是因为缺少 ::1 地址。当我将它添加到 lo 网络设备时,我无法复制超时。

sudo ip a add ::1/128 dev lo

下一步:(这是我的理解,我不是 100% 确定:)此外,由于保持与 localhost Java 服务的连接的开销似乎比仅断开该连接并在另一个请求时再次连接要高制作完成后,建议对代理使用以下设置(在您的 nginx 站点 .conf 中):

proxy_http_version 1.1;
proxy_set_header Connection "";

https://stackoverflow.com/a/10396874/3223505