Microservices (Part 2) – Inter Service Communication
- July 14, 2020
- Posted by: Goutham Ramesh
- Category: Application Development
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:
- Eureka Service ( Service Registry )
- Demo Service ( REST Service Multiple instances registered with Eureka Service )
- 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:
- No need to hardcode the IP addresses of microservices.
- 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 initializer. 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:
- RestTemplate. An object that’s capable of sending requests to REST API services.
- 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://ejyle.com/blog/microservices-part-3-gateway-to-consumer-service/
how can we help you?
Contact us at the Consulting WP office nearest to you or submit a business inquiry online.