Spring boot嵌入式nettey服务器在调用其他端点相同的服务时死锁

问题描述 投票:0回答:0

我正在使用 Spring Cloud 网关、Spring boot webflux starter 和默认的嵌入式 netty 服务器。

我创建了两条路线

Route1: /api/v1/task & 路线 2:/api/v1/general

Route1:它使用了几个过滤器,会更新请求路径,过滤器链会继续,spring cloud gateway会调用代理服务器,在收到响应后,自定义过滤器会修改响应并更新headers,然后返回修改后的响应。

Route2:有不同的过滤器集会做一些工作,使用 RestTemplate 调用 localhost/api/v1/task 并对响应做一些修改并返回修改后的响应。正在修改 RestTemplate 响应的过滤器停止过滤器链并使用

return exchange.mutate().response(res).build().getResponse().setComplete();
返回响应。由于没有可用的代理端点,我正在停止链。

在这里,我得到了正确的响应,但有时服务会陷入某种僵局。

我做了一些分析,我发现,如果路由 2 使用的内部 API 调用(使用 restTemplate 调用路由 1)使用同一个

reactor-http-nio
线程,那么服务就会卡住,不会有其他请求由服务提供。为了确认此行为,我将 netty workerCount 更新为 1 并看到如果我只调用 Route1,则服务总是返回响应。如果我使用 Route2,那么服务总是会卡住,我需要重新启动服务才能开始使用其他路由。

在我的应用程序中,我有 10 多个路由,对于上述 Route2,我必须使用不同的参数调用其他路由,这将使用本地主机进行 50 多个 API 调用。

通过观察netty服务器的行为,看起来第一个请求会先被服务,直到第一个请求没有被服务,在同一个线程上收到的第二个请求会卡住,其他线程不会去接它。因此,我面临僵局。

有人可以建议一种方法来满足第二个请求而无需等待前一个请求变得清晰吗?我查看了线程转储,发现 RestTemplate.execute 方法正在等待响应,即使其他线程空闲,在服务卡住后也没有其他请求被接受。

现在我已经应用了两件事来阻止死锁的发生。

  1. 工人数量增加到 80
  2. 在可完成的未来进行 RestTemplate 调用并保持超时,这样如果收到超时错误,我可以使 Route2 失败并出现 500 错误。
spring spring-webflux netty deadlock spring-cloud-gateway
© www.soinside.com 2019 - 2024. All rights reserved.