Use Consul to implement service discovery: instance-id customization (3 ways)

Posted by zsxdcfv21 on Thu, 19 Dec 2019 09:50:32 +0100

TIPS

This article is based on Spring Cloud Hoxton, supporting all versions of Spring Cloud in theory.

This article explores how to customize the InstanceId registered with Consul for microservices.

Consul uses InstanceId as its unique identity, while Spring Cloud Consul defaults to InstanceId of ${spring.application.name}-${server.port}.

The problem with this is that even if there are multiple instances of a microservice, as long as the ports are the same, only one data will remain on Consul!To solve this problem, you only need to have different InstanceId s for different instances.

Mode 1: Stitching random values

Add Configuration:

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

So are some articles on the market today.However, in some scenarios there is still a minor problem.

For example, suppose a microservice instance crashes and then within a short period of time (Consul hasn't had time to delete this instance); a restart of the application results in two pieces of data on Consul, but it actually represents one instance (although after a while, Consul deletes unused instances, two pieces of data still appear bizarre over time).

TIPS

${random.long} yes Spring Boot With its own Extended Configuration, there are many positions to use.The documentation is detailed https://docs.spring.io/spring-boot/docs/2.2.0.M5/reference/html/spring-boot-features.html#boot-features-external-config-random-values

Mode 2: Unique identification of stitching machine

Talking about this, smart classmates must think that a reasonable instanceid should meet the following two needs:

  • Different instanceid s;
  • The instanceid should be the same if the same instance is started multiple times.

To fulfill these two demands, simply add the unique identifier of the machine on the instanceid to OK, such as IP or hostname.

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

Or:

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

TIPS

Here, ${spring.cloud.client.hostname} and ${spring.cloud.client.ip-address} make use of the Spring Boot configuration file to read environment variables.

Your application can view all environment variables through/actuator/env by integrating Spring Boot Actuator!Key values for environment variables can be written to the configuration file.

Mode 3: Code extension

If the above two methods still don't meet your needs, you can also extend them by writing code.

Code:

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());
    }
}

To configure:

@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

  • This is a more flexible way to play as you like.You can stitch mac addresses or anything else on InstanceId...However, just to customize a unique label, it's a bit expensive to play with, I suggest: If you don't have to work hard, you can toss around.
  • This is how my personal project, Spring Cloud Wii (now Spring Cloud Alibaba Sidecar), customizes InstanceId.But Wii does this because Wii itself extends WiiConsulAutoRegistration and customizes InstanceId just by hand.The code is interesting to see here: https://github.com/eacdy/spring-cloud-wii/blob/master/spring-cloud-wii/src/main/java/com/itmuch/wii/consul/WiiConsulAutoRegistration.java

Future...

If this Pull Request is merged in the future, you won't have to worry about it...See: https://github.com/spring-cloud/spring-cloud-consul/pull/570

Beginning of this article

Use Consul to implement service discovery: instance-id customization

Topics: Programming Spring github Java Mac