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


TIPS

本文基於Spring Cloud Hoxton,理論支持Spring Cloud所有版本。

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

Consul把InstanceId作為唯一標識,而Spring Cloud Consul默認的InstanceId是 ${spring.application.name}-${server.port} 。

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

方式1:拼接隨機值

添加配置:

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

目前市面上的一些文章也是這么玩的。但這樣做,在一些場景下還是有一點小問題的。

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

TIPS

${random.long} 是Spring Boot自帶的“擴展配置”,還有很多的使用姿勢。文檔可詳見 https://docs.spring.io/spring-boot/docs/2.2.0.M5/reference/html/spring-boot-features.html#boot-features-external-config-random-values

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


講到這里,聰明的同學一定會想到,一個合理的instanceid應該滿足以下兩點需求:

  • 不同實例的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自定義


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM