Micro-services are all good until they come with their distributed challenges which normally we don't face in monolithic based applications. Just like this one!

Understanding the problem

In order to fully get the main purpose of the solution let us first understand the underlying problem.

As the diagram above shows, we have to micro-services communicating via a certain network:

  • Micro-service I with the IP address 10.10.10.10, and port 8080
  • Micro-service II with the IP address 20.20.20.20, and port 8090

All working peacefully until the second micro-service changed its address and port for some reason.

As result the micro-service I cannot communicate with micro-service II since it doesn't have the new address and port (30.30.30.30:5000). To resolve this we need to provide manually the micro-service I with the micro-service II's new address and port. What if we can do that automatically?

The answer is YES, and that's exactly what Netflix Eureka does.

Eureka under the hood

The first thing MS2 will do is to register to the naming registry server (Eureka server) providing mainly its IP, port and status (UP or DOWN). [A]

Before MS1 makes the call to MS2 [D], it will fetch the MS2 coordinates from the naming registry [B] which will allow the communication to happen even if MS2 changes its location a million times as long as its registers to the Eureka server. The server will respond with the required data. [C]

You should also understand that by fetching the naming registry or registering to it, the micro-service becomes its client (Eureka client).

Let's talk code

For this tutorial I'll be using:

Spring Boot 2.6.2

<parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.6.2</version>
        <relativePath/> <!-- lookup parent from repository -->
</parent>

Java 8 && Spring cloud 2021.0.0

<properties>
        <java.version>1.8</java.version>
        <spring-cloud.version>2021.0.0</spring-cloud.version>
</properties>

and of course the dependency management for the spring cloud modules

<dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
</dependencyManagement>

Eureka server configuration

The Eureka server require the Spring Cloud starter netflix eureka server dependency

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>

Then, we need a set of properties as the following

# Setting a name for out app
spring:
  application:
    name: registry-server

# Simply telling Eureka server to NOT fetch or register to any server since it's not a client.
eureka:
  client:
    register-with-eureka: false
    fetch-registry: false

Finally, we need to declare our app as a registry service using the @EnableEurekaServer annotation:

@SpringBootApplication
@EnableEurekaServer
public class RegistryEurekaServerApplication {

    public static void main(String[] args) {
        SpringApplication.run(RegistryEurekaServerApplication.class, args);
    }

}

You can find a user interface generated by Eureka, for our case is on localhost:8099

Eureka client configuration

The Eureka client require the Spring Cloud starter netflix eureka client dependency

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>

Also for this one, we need a set of properties:

# Setting a name for out app
spring:
  application:
    name: registry-eureka-client

eureka:
  client:
    # To register to the eureka server
    registerWithEureka: true

    # To fetch the registry from the eureka server
    fetchRegistry: true

    # The location of the eureka server
    serviceUrl:
      defaultZone: http://localhost:8099/eureka/

  instance:
    # The instance hostname
    hostname: localhost
  
    # The instance unique id
    instanceId: ${eureka.instance.hostname}:${spring.application.name}

    # A bench of health information end-points provided by eureka
    statusPageUrl: http://${eureka.hostname}/
    healthCheckUrl: http://${eureka.hostname}/actuator/health
    secureHealthCheckUrl: http://${eureka.hostname}/actuator/health

Finally, we need to declare our app as a discovery client (Eureka client) using the @EnableDiscoveryClient annotation:

@SpringBootApplication
@EnableDiscoveryClient
public class RegistryEurekaClientApplication {

  public static void main(String[] args) {
      SpringApplication.run(RegistryEurekaClientApplication.class, args);
  }
}

Once, we start our client app, we will notice that it successfully registered to the running eureka server.

And on the UI dashboard, you can see this:

This may seem incomplete, actually it is, since we're not fetching the eureka server for registered service instances and exploit them. That's the main purpose of the next article when we will be doing so using a reverse proxy called Netflix Zuul.

More articles Here.


React to this article
and see more on Dev Community