2

最近我一直在做一个 API 网关项目。然而,对于服务注册和发现,我遇到了一些关于 Zuul 故障转移和动态部署多个 Eureka 实例的问题。以下是我的项目。

尤里卡服务器项目

EurekaBootstrap.java

package com.plateno.cloud.netflix.eureka;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;

@SpringBootApplication
@EnableEurekaServer
public class EurekaBootstrap {
public static void main(String[] args) {
    SpringApplication.run(EurekaBootstrap.class, args);
 }
}

配置:应用程序.yml

#spring.application.name=plateno-cloud-netflix-eureka
#server.port=9000
#eureka.instance.hostname=localhost
#eureka.client.registerWithEureka=false
#eureka.client.fetchRegistry=false
#eureka.client.serviceUrl.defaultZone=http://${eureka.instance.hostname}:${server.port}/eureka/
#spring.profiles.active: dev

server:
    port: 9000
spring.application.name: localhost
eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:${server.port}/eureka/
  instance:
    hostname: localhost
eureka.client.register-with-eureka: false
eureka.client.fetch-registry: false
---
spring:
    profiles: peer1
server:
    port: 9001
peer2:
    port: 9002    
spring.application.name: peer1
eureka:
  client:
    serviceUrl:
      defaultZone: http://peer2:${peer2.port}/eureka/  
  instance:
    hostname: peer1
eureka.client.register-with-eureka: true
eureka.client.fetch-registry: true
---
spring:
    profiles: peer2
server:
    port: 9002
spring.application.name: peer2
peer1:
    port: 9001 
eureka:
  client:
    serviceUrl:
      defaultZone: http://peer1:${peer1.port}/eureka/
  instance:
    hostname: peer2
eureka.client.register-with-eureka: true
eureka.client.fetch-registry: true
---
spring:
  profiles:
    active: peer1

我将 peer1 和 peer2 配置为主机中的 localhost

zuul 带丝带项目

ZuulBootstrap.java

package com.plateno.cloud.netflix.zuul;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.cloud.netflix.ribbon.RibbonClient;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
import org.springframework.cloud.netflix.zuul.filters.ZuulProperties;
import org.springframework.cloud.netflix.zuul.filters.discovery.PatternServiceRouteMapper;
import org.springframework.context.annotation.Bean;

import com.netflix.zuul.exception.ZuulException;

@SpringBootApplication
@EnableZuulProxy
public class ZuulBootstrap {
    public static void main(String[] args) {
        SpringApplication.run(ZuulBootstrap.class, args);
    }

    @Bean
    public SimpleFilter simpleFilter() {
        return new SimpleFilter();
    }

    @Bean
    public PatternServiceRouteMapper serviceRouteMapper() {
        return new PatternServiceRouteMapper("(?<name>^.+)", "${name}") {
            @Override
            public String apply(final String serviceId) {
                String route = super.apply(serviceId);
                return route;
            }
        };
    }

    @RefreshScope
    @ConfigurationProperties("zuul")
    public ZuulProperties zuulProperties() {
        ZuulProperties zuulProperties = new ZuulProperties();
        return zuulProperties;
    }
}

预过滤器:SimpleFilter.java

package com.plateno.cloud.netflix.zuul;

import javax.servlet.http.HttpServletRequest;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;

public class SimpleFilter extends ZuulFilter {

    private static Logger log = LoggerFactory.getLogger(SimpleFilter.class);

    @Override
    public String filterType() {
        return "pre";
    }

    @Override
    public int filterOrder() {
        return 1;
    }

    @Override
    public boolean shouldFilter() {
        return true;
    }

    @Override
    public Object run() {
        RequestContext ctx = RequestContext.getCurrentContext();
        HttpServletRequest request = ctx.getRequest();
        log.info(String.format("%s request to %s", request.getMethod(), request.getRequestURL().toString()));
        return null;
    }
}

zuul 配置:application.yml

#default_charset=utf-8
#spring.application.name=plateno-cloud-netflix-zuul
#server.port=9030
#ribbon.eureka.enabled=true
#eureka.client.serviceUrl.defaultZone=http\://localhost\:9001/eureka/

---
default_charset: utf-8
spring:
  application:
    name: plateno-cloud-netflix-zuul
server:
  port: 9030
ribbon: 
  eureka:
    enabled: true

eureka:
  client:
    service-url:
      defaultZone: http://localhost:9001/eureka/,http://localhost:9002/eureka/

目标服务项目 只是带有 yml 配置的普通项目

我没有解析这个项目的源代码,而是配置配置文件

#default_charset=utf-8
#spring.application.name=plateno-app0
#server.port=9010
#eureka.client.serviceUrl.defaultZone=http\://localhost\:9000/eureka/
server:
    port: 8080
default_charset: utf-8
spring:
  application:
    name: plateno-app0

eureka.client.serviceUrl.defaultZone: http://peer1:9001/eureka/,http://peer2:9002/eureka/

源代码结束,附件是源代码

我通过更改活动启动了2个eureka实例,然后启动了zuul服务器。最后,我通过更改服务器端口启动了 2 个目标服务。我使用 JMeter 进行了一些测试。我在并发测试中停止了一个目标服务,然后一些请求失败了关于socket closed

所以问题是为什么 zuul 和ribbon 无法处理故障转移,或者我应该如何配置才能达到这种效果?

第二个问题是每次部署另一个eureka server时,需要编辑eureka server配置、zuul配置和目标服务配置。因此,所有这些项目都需要重新启动。我不能接受,那么有没有办法在不编辑其他项目的配置并重新启动它们的情况下动态更改 eureka 服务器的数量?

最后,我希望 Pivotal 团队可以更新 Spring Cloud 的文档以提供更详细的信息。

4

1 回答 1

0

您必须为所有客户端应用程序提供所有实例(逗号分隔列表),如下所示 - bootstrap.properties- eureka.client.serviceUrl.defaultZone=http://localhost:8761/eureka,http://localhost:8762/eureka

因为如果您只让 eureka 服务器相互了解,那么它们可以复制所有实例,这是完美的一部分。现在假设在客户端应用程序中,如果你只传递一个实例假设 - eureka.client.serviceUrl.defaultZone=http://localhost:8761/eureka 假设这个应用程序将重新启动,那时你的这个尤里卡实例已关闭所以发生了什么在这种情况下,它会检查另一个 eureka 服务器实例,但是您如何在客户端应用程序中只提供一个实例。

因此,出于这个原因,您必须在客户端应用程序中提供所有 eureka 服务器实例。谢谢

于 2021-05-31T19:33:10.940 回答