【问题标题】:Eureka never unregisters a serviceEureka 从不注销服务
【发布时间】:2015-12-13 11:54:46
【问题描述】:

我目前面临一个问题,即 Eureka 无法取消注册已注册的服务。我直接从 git hub 中提取了 Eureka 服务器示例,并且只进行了一项更改,eureka.enableSelfPreservation = false。我的 application.yml 看起来像这样:

server:
  port: 8761
eureka:
  enableSelfPreservation: false
  client:
    registerWithEureka: false
fetchRegistry: false
  server:
    waitTimeInMsWhenSyncEmpty: 0

我了解到,如果 85% 的已注册服务在 15 分钟内停止发送心跳,Eureka 会假定问题与网络相关,并且不会取消注册未响应的服务。就我而言,我只运行了一项服务,所以我禁用了自我保护模式。我突然终止了该进程,并且 Eureka 让服务注册了似乎无限期的时间。

我客户的 application.yml 如下所示:

eureka:
  instance:
    leaseRenewalIntervalInSeconds: 3
  client:
    healthcheck:
      enabled: true
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/
  appInfo:
    replicate:
      interval: 3
    initial:
      replicate:
        time: 3
spring:
  rabbitmq:
    addresses: ${vcap.services.${PREFIX:}rabbitmq.credentials.uri:amqp://${RABBITMQ_HOST:localhost}:${RABBITMQ_PORT:5672}}

我的目标是创建一个演示,让 Eureka 快速检测到服务不再运行,而另一个启动的服务可以快速注册自己。

截至目前,eureka客户端一旦启动,3秒就注册完成。当服务突然终止时,它永远不会取消注册。在我终止服务后,Eureka 仪表板显示:

紧急情况! EUREKA 可能不正确地声称实例已启动,但实际上并未启动。续订少于阈值,因此为了安全起见,实例不会过期。

如何防止这种行为?

【问题讨论】:

  • 你用的是什么版本的spring-cloud?
  • 我有两个项目正在进行,我在直接从 GitHub 提取的示例中使用 1.1.0。在我的实际项目中,我使用的是 spring-cloud-starter-config 1.0.3。也不是取消注册的客户。
  • 您实际等了多长时间?我可能需要一些时间来取消注册默认设置。
  • 我听说应该需要 90 秒到 4 分钟,但我已经等了一个多小时。我停止了服务并去吃午饭,刷新了 Eureka 仪表板,服务仍在显示。
  • 我遇到了同样的问题,经过大量搜索后我意识到我已经添加了 spring-boot-starter-tomcat,如果 spring-boot-starter-web 也存在则不需要(它在编译依赖项中有tomcat,因此可能会发生冲突)。

标签: spring-cloud netflix-eureka


【解决方案1】:

我意识到自我保护模式从未真正被禁用。原来实际的属性是

eureka.server.enableSelfPreservation=false

(参见DefaultEurekaServerConfig 代码),我在任何地方都没有找到相关文档。这解决了我的问题。

【讨论】:

  • 针对此问题向文档存储库提出拉取请求可能对许多其他人非常有帮助。 ...如果有人还没有这样做。
【解决方案2】:

我通过设置以下值使服务注销工作

尤里卡服务器应用程序.yml

eureka:
  server:
    enableSelfPreservation: false

服务应用程序.yml

eureka:
  instance:
    leaseRenewalIntervalInSeconds: 1
    leaseExpirationDurationInSeconds: 2

完整的例子在这里https://github.com/ExampleDriven/spring-cloud-eureka-example

【讨论】:

  • 这些值是不是太短了?
  • 这些值只是示例,根据您的用例,您必须找到正确的值。上述设置会给 eureka 服务器带来更多负载,但会降低将流量转发到非工作服务的风险
【解决方案3】:

经过一番苦苦挣扎,如果由于某些问题从 Eureka 服务器取消注册任何服务,我终于得到了解决方案。它将通过扩展 Eureka-Server API 的 HealthCallback 来通知管理员。 Let Say Service-A 向 Eureka 注册。因此,Eureka Client 与 Service-A 集成,并在 Service A 中实现以下回调。

Service-A [Eureka-Client] 在属性文件中添加以下属性。

#Eureka Configuration
eureka.client.eureka-server-port=8761
eureka.client.register-with-eureka=true
eureka.client.healthcheck.enabled=false
eureka.client.prefer-same-zone-eureka=true
eureka.client.fetchRegistry=true
eureka.client.serviceUrl.defaultZone=${eurekaServerURL1}, ${eurekaServerURL2}
eureka.client.eureka.service-url.defaultZone=${eurekaServerURL1}, ${eurekaServerURL2}
eureka.instance.hostname=${hostname}
eureka.client.lease.duration=30
eureka.instance.lease-renewal-interval-in-seconds=30
eureka.instance.lease-expiration-duration-in-seconds=30

添加以下java文件。

@Component
public class EurekaHealthCheckHandler implements HealthCheckHandler, ApplicationContextAware, InitializingBean {


    static Logger logger = LoggerFactory.getLogger(EurekaHealthCheckHandler.class);

    private static final Map<Status, InstanceInfo.InstanceStatus> healthStatuses = new HashMap<Status, InstanceInfo.InstanceStatus>() {{
        put(Status.UNKNOWN, InstanceInfo.InstanceStatus.UNKNOWN);
        put(Status.OUT_OF_SERVICE, InstanceInfo.InstanceStatus.OUT_OF_SERVICE);
        put(Status.DOWN, InstanceInfo.InstanceStatus.DOWN);
        put(Status.UP, InstanceInfo.InstanceStatus.UP);
    }};

@Autowired
ComunocationService comunocationService ;
    private final CompositeHealthIndicator healthIndicator;

    private ApplicationContext applicationContext;

    public EurekaHealthCheckHandler(HealthAggregator healthAggregator) {
        Assert.notNull(healthAggregator, "HealthAggregator must not be null");
        this.healthIndicator = new CompositeHealthIndicator(healthAggregator);

        Health health = healthIndicator.health();
        logger.info(" =========== Testing =========== {}", health.toString() );
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

    @Override
    public void afterPropertiesSet() throws Exception {

        final Map<String, HealthIndicator> healthIndicators = applicationContext.getBeansOfType(HealthIndicator.class);
        for (Map.Entry<String, HealthIndicator> entry : healthIndicators.entrySet()) {
            logger.info("======"+ entry.getKey() +"============= "+entry.getValue());
            healthIndicator.addHealthIndicator(entry.getKey(), entry.getValue());
        }
    }

    @Override
    public InstanceInfo.InstanceStatus getStatus(InstanceInfo.InstanceStatus instanceStatus) {
        logger.info("============== Custome Eureka Implementation ==================="+ getHealthStatus());
        return getHealthStatus();
    }

    protected InstanceInfo.InstanceStatus getHealthStatus() {
        final Status status = healthIndicator.health().getStatus();
        return mapToInstanceStatus(status);
    }

    protected InstanceInfo.InstanceStatus mapToInstanceStatus(Status status) {
        logger.info("============== Test Custome Eureka Implementation ==================={}", status);
        if(status.equals(InstanceInfo.InstanceStatus.UP)) {
            // Send mail after configured times
              comunocationService.sendEmail("ServiceName");
        }
        if(!healthStatuses.containsKey(status)) {
            return InstanceInfo.InstanceStatus.UNKNOWN;
        }
        return healthStatuses.get(status);
    }

    public void getstatusChangeListner() {
        ApplicationInfoManager.StatusChangeListener statusChangeListener = new ApplicationInfoManager.StatusChangeListener() {
            @Override
            public String getId() {
                return "statusChangeListener";
            }
            @Override
            public void notify(StatusChangeEvent statusChangeEvent) {
                if (InstanceStatus.DOWN == statusChangeEvent.getStatus() ||
                        InstanceStatus.DOWN == statusChangeEvent.getPreviousStatus()) {
                    // log at warn level if DOWN was involved
                    logger.warn("Saw local status change event {}", statusChangeEvent);
                } else {
                    logger.info("Saw local status change event {}", statusChangeEvent);
                }

            }
        };
    }


}

@Configuration
public class EurekaHealthCheckHandlerConfiguration {

    @Autowired(required = false)
    private HealthAggregator healthAggregator = new OrderedHealthAggregator();

    @Bean
    @ConditionalOnMissingBean
    public EurekaHealthCheckHandler eurekaHealthCheckHandler() {
        return new EurekaHealthCheckHandler(healthAggregator);
    }
}

这是绝对有效且经过良好测试的代码

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-05-22
    • 1970-01-01
    • 2013-08-28
    • 2017-10-11
    • 1970-01-01
    • 1970-01-01
    • 2018-04-29
    • 2020-07-27
    相关资源
    最近更新 更多