由于Eureka宣告进入维护模式,所以抽空研究下Spring Cloud Consul做为服务注册中心。

此处不再赘述Consul原理、安装、使用等步骤,具体可以在网络查询,详细教程到处都是。主要描述下问题和解决方式:

问题描述

新建了一个微服务 service-a,从ip为【192.168.1.10】的机器启动,查看Consul一切正常,不关闭当前服务,再从ip为【192.18.1.20】的机器启动一个实例,查看Consul发现原来的注册实例还是只有一个,服务实例的ip地址被覆盖了;

分析解决

服务注册时,Consul是通过【instance-id】来区分服务实例的,出现服务实例注册被覆盖的情况,很有可能是因为多个实例【instance-id】重复导致。跟踪下源码,发现该字段默认是通过【application name】+ 【port】组成,所以服务注册会被覆盖;

解决方法1

通过查询官方文档,给出了解决方案:

By default a consul instance is registered with an ID that is equal to its Spring Application Context ID. By default, the Spring Application Context ID is spring.application.name:comma,separated,profiles:{spring.application.name}:comma,separated,profiles:spring.application.name:comma,separated,profiles:{server.port}. For most cases, this will allow multiple instances of one service to run on one machine. If further uniqueness is required, Using Spring Cloud you can override this by providing a unique identifier in spring.cloud.consul.discovery.instanceId.

将【instance-id】属性增加随机数,可以解决以上重复问题:

spring:
  cloud:
    consul:
      discovery:
        instanceId: ${spring.application.name}:${vcap.application.instance_id:${spring.application.instance_id:${random.value}}}

解决方法2

通过查看类【HostInfoEnvironmentPostProcessor】,发现能够取到IP地址,可以改为以下方式:

instance-id: ${spring.application.name}:${spring.cloud.client.ip-address}
prefer-ip-address: true

解决方法3

通过扩展【ConsulServiceRegistry】类,自定义consul注册默认的实例名:

package com.irootech.config;

import com.ecwid.consul.v1.ConsulClient;
import org.springframework.cloud.consul.discovery.ConsulDiscoveryProperties;
import org.springframework.cloud.consul.discovery.HeartbeatProperties;
import org.springframework.cloud.consul.discovery.TtlScheduler;
import org.springframework.cloud.consul.serviceregistry.ConsulRegistration;
import org.springframework.cloud.consul.serviceregistry.ConsulServiceRegistry;

public class CustomConsulServiceRegistry extends ConsulServiceRegistry {

    public CustomConsulServiceRegistry(ConsulClient client, ConsulDiscoveryProperties properties, TtlScheduler ttlScheduler, HeartbeatProperties heartbeatProperties) {
        super(client, properties, ttlScheduler, heartbeatProperties);
    }

    @Override
    public void register(ConsulRegistration reg) {
        reg.getService().setId(reg.getService().getName() + ":" + reg.getService().getAddress() + ":" + reg.getService().getPort());
        super.register(reg);
    }
}

注入spring即可

package com.irootech.config;

import com.ecwid.consul.v1.ConsulClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.consul.discovery.ConsulDiscoveryProperties;
import org.springframework.cloud.consul.discovery.HeartbeatProperties;
import org.springframework.cloud.consul.discovery.TtlScheduler;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class ConsulServiceRegistryConfig {

    @Autowired(required = false)
    private TtlScheduler ttlScheduler;

    @Bean
    public CustomConsulServiceRegistry consulServiceRegistry(ConsulClient consulClient, ConsulDiscoveryProperties properties, HeartbeatProperties heartbeatProperties) {
        return new CustomConsulServiceRegistry(consulClient, properties, ttlScheduler, heartbeatProperties);
    }
}

注意:使用这个方法无需在配置文件配置【instance-id】节点

版权声明:本文为CSDN博主「加斯特独挨踢」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/zhangjin530/article/details/90911940