使用Consul實現服務發現:instance-id自定義(3種方式)

TIPS

本文基於Spring Cloud Hoxton,理論支持Spring Cloud全部版本。html

本文探討如何自定義微服務註冊到Consul的InstanceId。java

Consul把InstanceId做爲惟一標識,而Spring Cloud Consul默認的InstanceId是 ${spring.application.name}-${server.port}git

這樣致使的問題是:某個微服務即便有多個實例,只要端口相同,那麼Consul上依然只會保留1條數據!要想解決這個問題,只須要讓不一樣實例,擁有不一樣的InstanceId便可。github

方式1:拼接隨機值

添加配置:spring

spring:
  cloud:
    consul:
      discovery:
        instance-id: ${spring.application.name}-${server.port}-${random.long}

目前市面上的一些文章也是這麼玩的。但這樣作,在一些場景下仍是有一點小問題的。app

舉個例子:假設某個微服務實例崩潰了,而後在很短的時間內(Consul還沒來得及把這個實例刪除);應用重啓了,就會致使Consul上出現兩條數據,但其實表明的是一個實例(雖然過段時間後,Consul會把沒用的實例刪除,但在一段時間內出現2條數據仍是很詭異的)。dom

TIPS

${random.long} 是Spring Boot自帶的「擴展配置」,還有不少的使用姿式。文檔可詳見 https://docs.spring.io/spring...ide

方式2:拼接機器惟一標識


講到這裏,聰明的同窗必定會想到,一個合理的instanceid應該知足如下兩點需求:spring-boot

  • 不一樣實例的instanceid不一樣;
  • 相同實例啓動屢次,instanceid應該相同。

要想實現這兩點訴求,只要在instanceid上加上機器的惟一標示就OK了,好比IP或者是主機名等等。微服務

spring:
  cloud:
    consul:
      discovery:
        instance-id: ${spring.application.name}-${server.port}-${spring.cloud.client.hostname}

或者:

spring:
  cloud:
    consul:
      discovery:
        instance-id: ${spring.application.name}-${server.port}-${spring.cloud.client.ip-address}
TIPS

這裏,${spring.cloud.client.hostname} 以及 ${spring.cloud.client.ip-address} ,是利用了Spring Boot配置文件能夠讀取環境變量的特色。

你的應用只要集成Spring Boot Actuator ,就能夠經過 /actuator/env 查看全部環境變量啦!環境變量的Key值,均可以寫到配置文件中。

方式3:代碼擴展

若是上面兩種方式依然知足不了你的需求,那麼你還能夠經過寫代碼的方式去擴展。

代碼:

public class WiiConsulAutoRegistration extends ConsulAutoRegistration {
    public WiiConsulAutoRegistration(NewService service, AutoServiceRegistrationProperties autoServiceRegistrationProperties, ConsulDiscoveryProperties properties, ApplicationContext context, HeartbeatProperties heartbeatProperties, List<ConsulManagementRegistrationCustomizer> managementRegistrationCustomizers) {
        super(service, autoServiceRegistrationProperties, properties, context, heartbeatProperties, managementRegistrationCustomizers);
    }
    
    public static String getInstanceId(WiiProperties wiiProperties,
                                       Environment environment) {
        return String.format("%s-%s-%s",
                environment.getProperty("spring.application.name"),
                wiiProperties.getIp(),
                wiiProperties.getPort());
    }
}

配置:

@Configuration
public class XXXConfiguration {
    @Bean
    public ConsulAutoRegistration consulRegistration(
            AutoServiceRegistrationProperties autoServiceRegistrationProperties,
            ConsulDiscoveryProperties properties,
            ApplicationContext applicationContext,
            ObjectProvider<List<ConsulRegistrationCustomizer>> registrationCustomizers,
            ObjectProvider<List<ConsulManagementRegistrationCustomizer>> managementRegistrationCustomizers,
            HeartbeatProperties heartbeatProperties) {
        return WiiConsulAutoRegistration.registration(autoServiceRegistrationProperties,
                properties, applicationContext, registrationCustomizers.getIfAvailable(),
                managementRegistrationCustomizers.getIfAvailable(), heartbeatProperties);
    }
}

TIPS

  • 這種方式更加靈活,你想怎麼玩就怎麼玩。你能夠在InstanceId上拼接mac地址或者其餘什麼玩意兒……不過,只是爲了定製個惟一標示而已,這麼玩成本有點高了,我建議:若是沒有不得已的苦衷,就甭折騰了
  • 個人我的項目 Spring Cloud Wii (也就是如今的Spring Cloud Alibaba Sidecar)就是使用的這種方式自定義InstanceId的。但Wii之因此採用這種方式,是由於Wii自己就要擴展 WiiConsulAutoRegistration ,定製一下InstanceId只是順手而爲。相關代碼在這裏,有興趣能夠看下: https://github.com/eacdy/spring-cloud-wii/blob/master/spring-cloud-wii/src/main/java/com/itmuch/wii/consul/WiiConsulAutoRegistration.java

將來...

將來若是這個Pull Request被合併,就不用折騰了……詳見:https://github.com/spring-cloud/spring-cloud-consul/pull/570

本文首發

使用Consul實現服務發現:instance-id自定義

相關文章
相關標籤/搜索