Spring Cloud 应用程序 - 在 Tomcat 上部署后 zuul 超时

Posted

技术标签:

【中文标题】Spring Cloud 应用程序 - 在 Tomcat 上部署后 zuul 超时【英文标题】:Spring Cloud app - zuul timeout after deploying on Tomcat 【发布时间】:2016-06-24 06:46:32 【问题描述】:

我正在尝试使用 Spring Cloud 设置几个服务,在我将 Eureka 客户端服务部署到 Tomcat 之前,一切似乎都运行良好。当我通过网关应用调用服务时,出现以下错误:

o.s.c.n.z.filters.post.SendErrorFilter   : Error during filtering
com.netflix.zuul.exception.ZuulException: Forwarding error
...
Caused by: com.netflix.hystrix.exception.HystrixRuntimeException: hello timed-out and no fallback available.
...
Caused by: java.util.concurrent.TimeoutException: null

然而,它在 Eclipse 中完美运行。当我从 Tomcat 运行发现和网关服务并从 eclipse 运行 Eureka 客户端服务时,它甚至可以工作。但是一旦我在 tomcat 上运行相同的服务,我就会得到错误。

我正在使用 Brixton.M5、Java 8 和 Tomcat 8。

再次,代码似乎可以工作,问题是它在部署到 Tomcat 后无法工作。

我有一个用于发现和网关服务的 Tomcat 实例,还有一个用于 Eureka 客户端服务的 Tomcat 实例。

这是一些代码和配置..

DiscoveryServerApp

@SpringBootApplication
@EnableEurekaServer
public class DiscoveryServerApp extends SpringBootServletInitializer

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

DiscoveryServer - application.yml

# Configure this Discovery Server
eureka:
  instance:
    hostname: discovery
  client:  # Not a client, don't register with yourself
    registerWithEureka: false
    fetchRegistry: false
    serviceUrl:
      defaultZone: http://localhost:1111/discovery/eureka/

server:
  port: 1111   # HTTP (Tomcat) port
  context-path: /discovery

DiscoveryServer - bootstrap.yml

spring:
  application:
    name: discovery
  jmx: 
    default-domain: com.example.cloud.discovery

网关应用程序

@SpringCloudApplication
@EnableZuulProxy
public class GatewayApplication extends SpringBootServletInitializer

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

GatewayApplication - application.yml

# Discovery Server Access
eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:1111/discovery/eureka/
  instance:
    instanceId: $spring.application.name:$spring.application.instance_id:$random.value

# HTTP Server
server:
  port: 4444   # HTTP (Tomcat) port
  context-path: /api

GatewayApplication - bootstrap.yml

# Spring properties
spring:
  application:
    name: gateway-service  # Identify this application
  jmx: 
    default-domain: com.example.cloud.gateway

encrypt:
  failOnError: false

虚拟应用程序

@SpringCloudApplication
@RestController
public class DummyApplication extends SpringBootServletInitializer

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

    @RequestMapping( path = "/hello-resource", method = RequestMethod.GET )
    public String hello()
    
        return "hello";
    

DummyApplication - application.yml

# Discovery Server Access
eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:1111/discovery/eureka/
  instance:
    instanceId: $spring.application.name:$spring.application.instance_id:$random.value # Unique id for multiple instances

# HTTP Server
server:
  port: 3333   # HTTP (Tomcat) port
  context-path: /hello-context

DummyApplication - bootstrap.yml

# Spring properties
spring:
  application:
     name: hello-service  # Service registers under this name
  jmx: 
    default-domain: com.example.cloud.hello

encrypt:
  failOnError: false

【问题讨论】:

您从客户端/浏览器调用什么 URL? GET localhost:1111/api/hello/hello/hello 是的,我知道,我只是喜欢问候......感谢您的快速回复! 【参考方案1】:

我偶然发现...原来 server.port 的值需要与部署它的 Tomcat 实例的端口匹配。现在看起来很明显,但我认为 Spring 会以某种方式神奇地从它运行的容器中找出这一点。我想从外部位置读取该配置以处理不同的环境而不需要进行“代码更改”是个好主意.

无论如何,答案是:确保 application.yml 中的 server.port 与目标容器上的端口匹配。

感谢所有花时间帮助我的人!

【讨论】:

或者只使用嵌入式 TC 服务器从命令行运行 Spring Boot 应用程序。 是的,但这正是我要避免的。我想用尽可能少的 jvm 运行多个微服务【参考方案2】:

好的,@SpringCloudApplication 包装 @EnableDiscoveryClient 导致 DummyApplication 在启动时向 Eureka 注册。您可以通过 Eureka 仪表板确认这是否正在发生。

假设DummyApplication 在 Eureka 注册为服务名称“hello-service”,那么 Zuul / Ribbon 将为该服务名称创建一个路由。因此,您的“/hello-resource”端点应该通过 Zuul 在以下位置代理: http://localhost:4444/api/hello-service/hello-resource/

【讨论】:

感谢您的意见。请记住,Hello 应用程序部署在 /hello-context/ 下,因此 Zuul 端点看起来像 http://localhost:4444/api/hello-service/hello-context/hello-resource【参考方案3】:

您应该将 Bowser 指向端口 4444(网关),而不是 1111(eureka)。

【讨论】:

我的错误.. 我在 1111 上的 tomcat 实例同时具有网关和尤里卡服务器。当我从 eclipse 运行所有东西时,我确实在 4444 上调用它 不过,我在您的示例中看不到第三个 /hello 。端口是 4444。第一个上下文路径是 /api,然后是来自网关的 /hello,然后是来自 REST 的 /hello。第三个 /hello 来自哪里?此外,尝试从 eureka 中删除 /discovery 以进行调试,然后只指向 ip/eureka。 我知道这有多令人困惑。我更新了我的配置,所以现在我的调用看起来像 localhost:port/api/hello-service/hello-context/hello-resource ..我也试过你的将 /discovery 移动到 ROOT 的建议,但不幸的是我仍然得到相同的行为

以上是关于Spring Cloud 应用程序 - 在 Tomcat 上部署后 zuul 超时的主要内容,如果未能解决你的问题,请参考以下文章

Spring Cloud Config - 客户端使用

Spring Cloud Config客户端使用

Spring Cloud Config客户端使用

如何在本地使用 spring-cloud-starter-aws 运行应用程序?

如何在 spring-cloud-gateway 合约测试中从 spring-cloud-contract 中设置带有 StubRunner 端口的 url

Spring Cloud Config教程客户端使用