avatarReetesh Kumar

Summary

The provided content outlines the setup and benefits of using Spring Boot with Eureka for service registration and discovery in a microservices architecture.

Abstract

The article discusses the challenges of managing service-to-service communication in a microservices ecosystem and how Spring Boot, in conjunction with Netflix's Eureka, offers a streamlined solution for service registration and discovery. It explains the roles of Eureka Server as a service registry and Eureka Client for enabling service instances to register and discover other services. The post includes detailed instructions for setting up a Eureka Server and Client in Spring Boot, demonstrating how microservices can dynamically interact with each other, with the added benefits of load balancing and fault tolerance. The use of Eureka is presented as a means to enhance scalability and resilience in microservices architectures, ultimately allowing developers to focus more on implementing business logic.

Opinions

  • The author emphasizes the importance of service registration and discovery in microservices architectures, suggesting that Eureka significantly simplifies this process.
  • Eureka's client-side caching is highlighted as a feature that contributes to the system's fault tolerance, ensuring service discovery can still occur if the Eureka Server becomes unavailable.
  • The article conveys a positive view of integrating Eureka with Spring Boot, citing the ease of setup with annotations and configuration properties, and the robustness it adds to microservices communication.
  • The inclusion of the source code on GitHub indicates the author's support for open-source practices and encourages hands-on learning and experimentation with Eureka in Spring Boot applications.
  • The conclusion underscores the author's belief in the effectiveness of Eureka, stating that it is a "powerful ally" in the development and optimization of microservices.

Spring Boot Microservices: Registration and Discovery using Eureka

Introduction

In the era of microservices, managing service-to-service communication can be daunting. That’s where the concept of service registration and discovery comes into play, significantly simplifying the interaction between different services in a distributed system. Spring Boot, in combination with Eureka, provides an elegant solution to this challenge. This blog post will guide you through the process of setting up service registration and discovery using Spring Boot and Eureka.

Understanding Service Registration and Discovery

Service Registration and Discovery are key components of a microservices architecture, enabling services to dynamically discover and interact with each other. Here’s how they work:

Service Registration: When a service starts, it registers itself with a service registry, providing metadata such as its network location and health indicators.

Service Discovery: When a service wants to communicate with another service, it consults the service registry to retrieve the network locations of available service instances.

Understanding Eureka in Spring Boot

Eureka, developed by Netflix, is an integral part of the Spring Cloud services suite, designed to handle service registration and discovery effortlessly in a microservices ecosystem. It simplifies the process of microservices communicating with each other in a cloud environment. Eureka consists of two main components: the Eureka Server and Eureka Client.

Eureka Server: The Heartbeat of Service Registration

The Eureka Server acts as a service registry, a phone book for your microservices. When microservices start, they register themselves with the Eureka Server, announcing their presence to the world. The server maintains a catalogue of all available services, which is crucial for service discovery.

Setting up an Eureka Server in Spring Boot is straightforward. You need to add the spring-cloud-starter-netflix-eureka-server dependency and annotate your main application class with @EnableEurekaServer. This minimal setup is enough to get an Eureka Server running.

Eureka Client: Facilitating Service Discovery

On the other side, we have the Eureka Client, embedded within microservices. It’s responsible for registering the service with the Eureka Server and querying the server to discover other services. By using the spring-cloud-starter-netflix-eureka-client dependency and annotating the application class with @EnableEurekaClient, any Spring Boot application can become an Eureka Client.

The client regularly sends heartbeats to the Eureka Server to signify its availability. When a client needs to communicate with another service, it asks the Eureka Server for the service’s instances and details, enabling it to perform its operations.

Implementing Eureka in Spring Boot

What we will build?

We can use Netflix Eureka Server to create a Service Registry and make our microservices (spring-boot-eureka-client-rest-api and spring-boot-eureka-consumer-client-rest-api) as Eureka Clients so that as soon as we start a microservice it will get registered with Eureka Server automatically with a logical Service ID. Then, the other microservices, which are also Eureka Clients, can use Service ID to invoke REST endpoints.

Here is the sequence diagram illustrating the process of service registration and discovery in Spring Boot using Eureka:

Setting Up the Eureka Server

Let us create a Service Registry using Netflix Eureka which is nothing but a SpringBoot application with an Eureka Server starter.

  1. Add Dependencies: Include spring-cloud-starter-netflix-eureka-server in your build configuration. Here is the pom.xml file for your reference:
<?xml version="1.0" encoding="UTF-8"?>
<project
 xmlns="http://maven.apache.org/POM/4.0.0"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
 <modelVersion>4.0.0</modelVersion>
 <parent>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-parent</artifactId>
  <version>3.2.3</version>
  <relativePath/>
  <!-- lookup parent from repository -->
 </parent>
 <groupId>com.example</groupId>
 <artifactId>spring-boot-eureka-service-registry-demo</artifactId>
 <version>0.0.1-SNAPSHOT</version>
 <name>spring-boot-eureka-service-registry-demo</name>
 <description>Demo project for Spring Boot Service Registration With Eureka</description>
 <properties>
  <java.version>17</java.version>
  <spring-cloud.version>2023.0.0</spring-cloud.version>
 </properties>
 <dependencies>
  <dependency>
   <groupId>org.springframework.cloud</groupId>
   <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
  </dependency>
  <dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-test</artifactId>
   <scope>test</scope>
  </dependency>
 </dependencies>
 <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>
 <build>
  <plugins>
   <plugin>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-maven-plugin</artifactId>
   </plugin>
  </plugins>
 </build>
</project>

2. Annotate Application: Use @EnableEurekaServer on your main application class. We need to add @EnableEurekaServer annotation to make our SpringBoot application an Eureka Server-based Service Registry.

package com.example.reet.service.registry;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;

@EnableEurekaServer
@SpringBootApplication
public class SpringBootEurekaServiceRegistryDemoApplication {

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

}

3. Configure Properties: Define necessary configurations in application.properties or application.yml. By default, each Eureka Server is also an Eureka client and needs at least one service URL to locate a peer. As we are going to have a single Eureka Server node (Standalone Mode), we are going to disable this client-side behaviour by configuring the following properties in the application.yml file.

spring:
  application:
    name: spring-boot-eureka-service-registry-demo
server:
  port: 8761
eureka:
  client:
    register-with-eureka: false
    fetch-registry: false

4. Launch Eureka Server: Netflix Eureka Service provides a UI where we can see all the details about registered services.

Now run SpringBootEurekaServiceRegistryDemoApplication and access http://localhost:8761 which will display the UI similar to the below screenshot.

Setting Up a Eureka Client

  1. Add Client Dependency: Add spring-cloud-starter-netflix-eureka-client to your project. Here is the pom.xml file for your reference:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
 <modelVersion>4.0.0</modelVersion>
 <parent>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-parent</artifactId>
  <version>3.2.3</version>
  <relativePath/> <!-- lookup parent from repository -->
 </parent>
 <groupId>com.example.spring.crud</groupId>
 <artifactId>spring-boot-eureka-client-rest-api</artifactId>
 <version>0.0.1-SNAPSHOT</version>
 <name>spring-boot-eureka-client-rest-api</name>
 <description>Demo project for Spring Boot Eureka Service Client</description>
 <properties>
  <java.version>17</java.version>
  <spring-cloud.version>2023.0.0</spring-cloud.version>
 </properties>
 <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>
 <dependencies>
  <dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-web</artifactId>
  </dependency>
  <dependency>
   <groupId>org.springframework.cloud</groupId>
   <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
  </dependency>
  <dependency>
   <groupId>org.projectlombok</groupId>
   <artifactId>lombok</artifactId>
   <optional>true</optional>
  </dependency>
  <dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-test</artifactId>
   <scope>test</scope>
  </dependency>
 </dependencies>

 <build>
  <plugins>
   <plugin>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-maven-plugin</artifactId>
    <configuration>
     <excludes>
      <exclude>
       <groupId>org.projectlombok</groupId>
       <artifactId>lombok</artifactId>
      </exclude>
     </excludes>
    </configuration>
   </plugin>
  </plugins>
 </build>

</project>

2. Configure Client Properties: Specify the Eureka Server’s URL and other settings in your configuration file.

With spring-cloud-starter-netflix-eureka-client on the classpath, we just need to configure the eureka.client.service-url.defaultZone property in application.properties or application.yml to automatically register with the Eureka Server as shown below:

spring:
  application:
    name: spring-boot-eureka-client-rest-api


server:
  port: 8083

eureka:
  instance:
    hostname: localhost
  client:
    register-with-eureka: true
    fetch-registry: true
    service-url:
      default-zone: http://localhost:8761/eureka

When a service is registered with Eureka Server it keeps sending heartbeats for certain intervals. If the Eureka server doesn’t receive a heartbeat from any service instance it will assume the service instance is down and take it out from the pool.

3. Run spring-boot-eureka-client-rest-api Eureka Client: With this configuration in place, start spring-boot-eureka-client-rest-api and visit http://localhost:8761.

We should see that spring-boot-eureka-client-rest-api is registered with SERVICE ID as SPRING-BOOT-EUREKA-CLIENT-REST-API. We can also notice the status as UP(1) which means the services are up and running and one instance of spring-boot-eureka-client-rest-api is running.

Similarly, we will set up spring-boot-eureka-consumer-client-rest-api and after starting this app, we can see that spring-boot-eureka-consumer-client-rest-api is registered with SERVICE ID as SPRING-BOOT-EUREKA-CONSUMER-CLIENT-REST-API.

Suppose we want to invoke the spring-boot-eureka-client-rest-api REST endpoint from the spring-boot-eureka-consumer-client-rest-api. We can use RestTemplate to invoke the REST endpoint.

We can register RestTemplate as a Spring bean with @LoadBalanced annotation:

 @Bean
 @LoadBalanced
 public RestTemplate restTemplate(){
  return new RestTemplate();
 }

The RestTemplate with @LoadBalanced annotation will internally use Ribbon LoadBalancer to resolve the ServiceID and invoke the REST endpoint using one of the available servers.

    private final RestTemplate restTemplate;


    private static HttpEntity<?> getHeaders() {
        HttpHeaders headers = new HttpHeaders();
        headers.set("Accept", MediaType.APPLICATION_JSON_VALUE);
        return new HttpEntity<>(headers);
    }

    @GetMapping("/message")
    public String getMessage() throws RestClientException {

        String baseUrl = "http://SPRING-BOOT-EUREKA-CLIENT-REST-API/hello";
        ResponseEntity<String> response = null;
        try {
            response = restTemplate.getForEntity(baseUrl, String.class);
        } catch (Exception ex) {
            System.out.println(ex.getMessage());
        }
        return Objects.requireNonNull(response).getBody();
    }

Note: If multiple instances of spring-boot-eureka-client-rest-api are running then also there will be no issue as it is load balanced and one of the running instances of spring-boot-eureka-client-rest-api will be invoked.

When we run the spring-boot-eureka-consumer-client-rest-api and hit the endpoint http://localhost:8084/message it returns Hello World as a response after invoking spring-boot-eureka-client-rest-api http://localhost:8083/hello endpoint.

Benefits of Using Eureka in Spring Boot

  1. Dynamic Service Registration and Discovery: Eureka simplifies the dynamic discovery of services, allowing for flexible, resilient microservices communication.
  2. Load Balancing: Eureka supports load balancing, distributing requests efficiently across available service instances.
  3. Fault Tolerance: Eureka clients can cache service information, enabling them to operate even when the Eureka Server is unavailable.

Conclusion

Integrating Eureka into Spring Boot applications paves the way for efficient service registration and discovery, which are crucial in a microservices architecture. This combination not only enhances service-to-service communication but also contributes to the overall resilience and scalability of your application. By mastering Eureka in Spring Boot, developers can focus more on business logic, leaving the complexities of service discovery and registration to this robust, proven solution. Whether you’re transitioning to microservices or optimizing existing systems, Eureka with Spring Boot is a powerful ally in your microservices journey.

The source code of this blog is available on the Eureka Server, client-API and consumer client API.

Happy Learning !!

Spring
Spring Boot
Software Development
Programming
Technology
Recommended from ReadMedium