Microservices platform with Spring Cloud – part 2

In the previous post, we managed to set up simple microservices infrastructure, and create two simple services. In this post, we will see how microservices can call each others to perform some useful tasks.

What is the problem?

Microservices system is a highly volatile environment. Services run on different machines on the network, and they can come up and down at any time. Reasons for service disruption can be arbitrary, from hardware or network failure, to bugs in code. In any case, the system must be resilient enough to handle those cases.

Spring Cloud uses Hystrix for such cases. Hystrix is Netflix library which  implements circuit breaker pattern, and provides latency, fault tolerance and concurrency for distributed systems. We will use Hystrix to facilitate communication between microservices.

Another tool which we will use is Netflix Ribbon. Ribbon provides client-side load balancing for distributed applications, which means that if there are more then one instance of a service, Ribbon will try to distribute the load evenly among the instances. Spring Cloud support both Hystrix and Ribbon out of the box.

Communication using Ribbon

First, we will show how communication between services can be achieved using Ribbon. For this purpose, we will create one endpoint in user-service , which will call another endpoint in messaging-service .

Messaging service endpoint

This endpoint would send email to address specified in request. To keep things simple, we will not really send email, but just output a message to console. For this simple task, we just need to add new endpoint to messaging service:

If you now POST something to http://localhost:8900/send-email , you will see a message in console.

User service endpoint

This endpoint is a mock of user registration process. User submits his name and email, and gets registered. After that, an email is sent to address specified. Of course, we will not implement all of this, just output user information and then call /send-email  endpoint in messaging service which will mock sending email.

First, we need to add dependency to Ribon to POM:

Next, we will create User  object and add new endpoint to UserController :

In UserController , we autowire instance of RestTemplate , which is used for invoking messaging service. Note the name parameter in @RibbonClient  annotation. This is the name under which messaging service is registered with Eureka. We use this name in URL to invoke sending message.

We can now send POST request with body like {"name": "John Smith","email": "john@domain.com"}  to http://localhost:8800/users . In console, we can see that messages are logged for both services:

Now we have complete, load balanced communication between services. But, what happens if messaging service goes down? To try this, let’s shutdown the service, and try the above call again. We get the 500 status and the following error message:

Since the service we depend on is unavailable, the request can not complete successfully, and so we get an error. We need a way to get around this problem.

Enter Hystrix

Hystrix provides a solution for this kind of problem. Instead of failing the request, we can provide a fallback option, like performing some task to handle failure gracefully. Spring Cloud supports Hystrix out of the box, so we can wrap communication with messaging service in Hystrix command. First, we need to add new dependency for Hystrox to user service POM:

Next, we will create new Component HystrixMessageService , which will contain Hystrix annotated methods:

We use @HystrixCommand  annotation to specify the method managed by Hystrix. Inside this annotation, we set the name of fallback method, which will be called in case this method fails. Note that fallback method must have the same signature as the annotated method. One last thing to note is that @HystrixCommand  annotation must be inside class annotated with @Component  or @Service , so it can be processed by Hystrix.

Now we need to change our UserController  to reference Hystrix command instead of using Ribbon directly:

The last thing remaining is to annotate the application class with @EnableCircuitBreaker  annotation, so it can process Hystrix related annotations:

If you now send the request, and messaging service is not running, you will note in the console that fallback method is run instead of getting an exception and 500 HTTP status.

Monitoring Hystrix data

Spring Cloud provides a dashboard for monitoring execution of  Hystrix commands. It is useful tool for monitoring and troubleshooting services. In order to add this feature, we need to add two new dependencies to user service:

Finally, we need to annotate application class with @EnableHystrixDashboard . After this, we can rebuild and run user service, and visit http://localhost:8800/hsytrix . Here we can see a form in which we should input http://localhost:8800/hystrix.stream , so we can monitor Hystrix data stream. Next, click “Monitor” button, and we are shown a page with Hystrix commands and their execution data:

Every time you invoke user service endpoint, you can see a change in execution data. This tool can be useful in real-time service monitoring since you can track how many times commands were called, how long it takes to execute them, how many times circuit breakers are tripped etc.

In real-world applications of Hystrix, you almost always have multiple instances of services running, so monitoring one service in isolation is not very useful. Spring Cloud provides a tool called Turbine, which aggregates metrics from multiple instances and show them in single dashboard. For now, this is out of scope of this article, but you can see a sampe configuration in this DZone post.

Conclusion

In this second post of the series, we’ve seen how to implement fault-tolerant, load-balanced communication between microservices. You can browse the complete source code of the examples on Github, or download it and run by yourself.

In the next installment, we will implement a gateway to our microservices system, so external clients can call our API.

List of all posts in this series

Leave a Reply

Your email address will not be published. Required fields are marked *