Microservices (Part 2) – Inter Service Communication – Service Registry, discovery and Load Balancing.

Prerequisite : Read ( Micro services generic reference architecture )

Friends , Let us recall our reference architecture ( Micro services generic reference architecture ). We had two services, Service registry , Load-balancer  and gateway. In this blog i will address the following

  • Two Services ( One Consumes the other )
  • Service Registry  
  • Load-balancer 

This is a fairly a long read because it encompasses  the major core concepts of Microservices architecture! So please have patience 🙂 

How will it look like ?

This example will have following 

  1. Eureka Service ( Service Registry )
  2. Demo Service ( REST Service Multiple instances registered with Eureka Service )
  3. Demo Consumer Service with REST Template and Load Balancer ( REST Service + REST Template Client to call Demo Service and Ribbon Load Balancer for Demo Service written in step 1 )

Now let us try and get our hands dirty with implementation in the following sections

1. Service Registry ( Eureka )

In this section we will be setting up Netflix Eureka service registry .

This is  the naming server which is also called service registry. It’s Job to give names to each microservice.  This is required  for the following reasons: 

  1. No need to hardcode the IP addresses of microservices.
  2. Manage and map  services use dynamic IP addresses/ports; when auto-scaling to a single key/name

In our case, every service  will be implemented as eureka client and registers itself with Eureka, and pings Eureka server to notify that it’s alive.

If Eureka server didn’t receive any notification from a service. This service is unregistered from the Eureka server automatically ( With a Lag ).

Now let us create our own Eureka Server ( This will be a spring boot application and very easy to create ) 

Creating Eureka Server

Create create a spring boot maven project, or use spring initializr. Call the artifact EjyleEurekaServer’   and  group-d  as ‘com.ejyle’ .

In the pom.xml file, make sure to include these dependencies: Web, Eureka Server as shown below 

<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-server</artifactId>
       <version>2.2.3.RELEASE</version>
</dependency>

Next, in the application.properties file, we need to set some configurations. See the inline comments for explanation.

# Give a name to the eureka server
spring.application.name=ejyle-eureka-server

# default port for eureka server
server.port=8761

# eureka by default will register itself as a client. So, we need to set it to #false.

eureka.client.register-with-eureka=false
eureka.client.fetch-registry=false

Finally, in your spring boot main application class, enable Eureka server using @EnableEurekaServer annotation.

package com.ejyle.eureka;

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

@SpringBootApplication
@EnableEurekaServer
public class EjyleEurekaServerApplication {

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

}

So far so good? Let us run our Eureka service and check if it is working.

  • Run the EjyleEurekaServer’  spring boot app.
  • Check if the Server is running from the browser by accessing the url http://localhost:8761/ . If the Server is running you will see the following in the browser .

You can see no services have been registered yet, now let us create a demo REST Service and register multiple running instances with just created Eureka Server 

 

2 . Demo Service

Register with Eureka – EjyleSpringRestDemo

Now let us create a simple REST service  run multiple instances  and register it with Eureka. 

Create create a spring boot maven project, or use spring initializr. Call the artifact ‘ EjyleSpringRestDemo   and  group-d  as ‘com.ejyle’ .

In the pom.xml file, make sure to include these dependencies: Web, Eureka client ( Notice this is a client ) as shown below 

<dependency>
     <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web-services</artifactId>
</dependency>

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

Next, in the application.properties file, we need to set some configurations. See the inline comments for explanation.

  • spring.application.name :  is the name given to service in Eureka. 
  • ${PORT:0} will dynamically assign tomcat port when this is run as spring boot app. 
  • id=${spring.application.name}:${spring.application.instance_id:${random.value}}  will create a new instance id for the service every time it registers on Eureka Service , so we have have multiple instances of the same service running and mapped to same service name. 
  • eureka.client.service-url.default-zone : URL against which the service needs to be registered against Eureka
# serivce name  to identify in Eureka Service.
spring.application.name=ejyle-demo-service


# port dynamically selects ports
server.port=${PORT:0}

# creates different instance id ( Random ) for registering with eureka Server
eureka.instance.instance-id=${spring.application.name}:${spring.application.instance_id:${random.value}}

# eureka server url
eureka.client.service-url.default-zone=http://localhost:8761/ejyle-eureka-server

Next, in your spring boot main application class, enable Eureka Client @EnableEurekaClient and @EnableDiscoveryClient. annotation, So when the app starts it registers to Eureka Server configured in Application.properties 

package com.example.demo;

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

@SpringBootApplication
@EnableEurekaClient // Enable eureka client. It inherits from @EnableDiscoveryClient.
public class EjyleSpringRestDemoApplication {

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

}

Now let us create a Rest Controller as shown below to implement the service; Note there are two calls   one for the root and the other one /getUser ..  The code is self explanatory.

 

@CrossOrigin(origins = "*")
@RestController
public class DemoRestController {

private static final Logger logger = LoggerFactory.getLogger(DemoRestController.class);

@Autowired
private Environment env;

public DemoRestController() {
super();
}


@RequestMapping("/")
public String home() {
// This is useful for debugging
// When having multiple instance of gallery service running at different ports.
// We load balance among them, and display which instance received the request.
return "Hello from Demo REST Service running at port: " + env.getProperty("local.server.port");
}




@RequestMapping(value = "/getUser", method = RequestMethod.GET)
public ResponseEntity<String> getUser(@RequestParam String name) {

logger.info("/getuser for id = " + name);;
ResponseEntity response = null;

if (null == name || name.trim().length() == 0 )
{
// this is error
String msg = "Invalid Name";
response = new ResponseEntity(msg,HttpStatus.OK);

}
else
{
String user = new String("{'name':"
+ "'"
+ name
+ "',"
+ "'id':'"
+ "007"
+ "' }");

response = new ResponseEntity(user,HttpStatus.OK);

}

return response;

}
}

So far so good? Let us run our Eureka service and check if it is working.

  • Run the EjyleEurekaServer’  spring boot app.
  • Check if the Server is running from the browser by accessing the url http://localhost:8761/ . If the Server is running you will see the following in the browser .
  • Run EjyleSpringRestDemo multiple times  and you  can see  multiple Services instances registered under the same service name ( This is first step towards Load balancing ) 

3. Demo Consumer Service

Register with Eureka – Use Rest Template and Load Balancing – EjyleSpringRestDemoConsumerService

Now let us create a simple REST service  Which registers it with Eureka , uses  REST Template +  Load Balancer to call Demo Service created in step 2  

Create create a spring boot maven project, or use spring initializr. Call the artifact ‘ EjyleSpringRestDemoConsumerService   and  group-d  as ‘com.ejyle’ .

In the pom.xml file, make sure to include these dependencies: Web, Eureka client ( Notice this is a client ) as shown below 

<dependency>
      <groupId>org.springframework.boot</groupId>
       <artifactId>spring-boot-starter-web-services</artifactId>
</dependency>

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

Next, in the application.properties file, we need to set some configurations. See the inline comments for explanation.

  • spring.application.name :  is the name given to service in Eureka. 
  • server.port :  assign tomcat port when this is run as spring boot app. 
  • eureka.client.service-url.default-zone : URL against which the service needs to be registered against Eureka
# serivce name
spring.application.name=ejyle-demo-consumer-service
# port
server.port=8300
# eureka server url
eureka.client.service-url.default-zone=http://localhost:8761/ejyle-eureka-server

Next, in your spring boot main application class, enable Eureka Client @EnableEurekaClient and @EnableDiscoveryClient. annotation, So when the app starts it registers to Eureka Server configured in Application.properties

Also notice an additional class RestTemplateConfig :

The calls from this REST client to the other services can be done using:

  1. RestTemplate. An object that’s capable of sending requests to REST API services.
  2. FeignClient (acts like a proxy), and provides another approach to RestTemplate.

Both, load balance requests across the services. here we will used Rest Template.

So in the spring boot main application class, besides enabling the eureka client, we need to create a bean for RestTemplate to call the demo service and also configure load Balancer ( read https://dzone.com/articles/microservices-tutorial-ribbon-as-a-load-balancer-1 )

 

@SpringBootApplication
@EnableEurekaClient
public class EjyleSpringRestDemoConsumerServiceApplication {

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

}

@Configuration
class RestTemplateConfig {

// Create a bean for restTemplate to call services
@Bean
@LoadBalanced // Load balance between service instances running at different ports.
public RestTemplate restTemplate() {
return new RestTemplate();
}
}

Now let us create a Rest Controller as shown below to implement the service; Note there are two calls   one for the root and the other one /getUser ..  The code is self explanatory and it uses RestTemplate to make the call .

 

@CrossOrigin(origins = "*")
@RestController
public class DemoRestConsumerController {

@Autowired
private RestTemplate restTemplate;

@Autowired
private Environment env;

public DemoRestConsumerController() {
super();
}



@RequestMapping("/")
public String home() {
// This is useful for debugging
// When having multiple instance of gallery service running at different ports.
// We load balance among them, and display which instance received the request.
String message = restTemplate.getForObject("http://ejyle-demo-service/", String.class);
String response = "Hello from Demo Rest Consumer Service running at port: " + env.getProperty("local.server.port") +
" Message from demo Service " + message;
return response;
}

@RequestMapping(value = "/getConsumer", method = RequestMethod.GET)
public ResponseEntity<String> getUser(@RequestParam String name) {
ResponseEntity<String> response = null;
String message = restTemplate.getForObject("http://ejyle-demo-service/getUser?name="
+ name
+ "", String.class);
response = new ResponseEntity<String>(message,HttpStatus.OK);
return response;
}

}

Ok, here’s one thing to note. Since we are using restTemplate — which in turn uses Eureka Server for naming of services, and Ribbon for load balancing. So, we can use the service name (like ejyle-demo-service) instead of localhost:port.

Also Notice the call using RestTemplate 

String message = restTemplate.getForObject(“http://ejyle-demo-service/”, String.class);

String message = restTemplate.getForObject(“http://ejyle-demo-service/getUser?name=”
+ name
+ “”, String.class);

 

Now,let us run our Eureka service and two services  and check if it is working.

  • Run the EjyleEurekaServer’  spring boot app.
  • Run EjyleSpringRestDemo multiple times  and you  can see  multiple Services instances registered under the same service name .
  • Run EjyleSpringRestDemoConsumerService as spring boot app 
  • Check if the Server is running from the browser by accessing the url http://localhost:8761/ . If the Server is running you will see the following in the browser .

Now Let us call the consumer Service  using http://localhost:8300/  , run it multiple times and notice the message  every time you can see the request going to different instance of Demo Service as shown below.

Conclusion

Thank you for reading! If you enjoyed it and If you have any questions or comments  you know where to reach me! Part 3 with Zulu Gateway  to the Demo Consumer Service can be found at https://www.ejyle.com/blog/technology/microservices-part-3-gateway-to-consumer-service/



Author: Goutham Ramesh
A passionate Photo artist and a technology student ! Responsible for Ejyle's Technology Practice and Digital Solutions , Goutham has collective experience of two decades in the area of Solution Architecture, Business Analysis, execution of complex engineering projects and team management.