Microservices: Using Zuul proxy as a micro-proxy and api gateway

This is the 3rd part of the Developing Microservices with Spring Boot series. After having a configuration service, being able to create microservices that communicate between themselves and registering them on a service registry, we will have a look to how to have an abstraction of the services offered and how to proxy requests to other services. The full code is available on github.

Overview

When exposing services, you probably don’t want to expose the different machines, with different names, domains, etc…
A {frontend|mobile|…} client should be able to know the main entry point and from there, the backend does the rest.
On top of that, having a proxy/abstraction of our services would give us the possibility of start/stop/update services with new logic without having to change the endpoint.

As more logic gets added in future features, there could be also the subcase of composition of services on the backend. For all these cases, an edge service is something you probably want at some point. The main usages for an edge service are proxy to another service and composition of services.

For this post we will work on both cases. In order to understand the code, the following diagram may be helpful:

Microservices- Zuul proxy architecture example

Microservices- Zuul proxy architecture example

 

Zuul through example

During this article, we will focus on developing the proxy part (zuul-service).
There are two main sections that we will deal with:

  • Proxying http requests
    • Single requests
    • Composition of requests
  • Handling service failures

As a reminder, the code is available on github.

Proxying http requests

Http requests are easy to forward. You have a http input and you perform a http call to a certain service.
The benefit of using Zuul is that you can handle extra logic rather than just proxying.

On top of that, if you have Eureka running you may want to use Zuul to access to any of the services through the url.

Configuration microservice

The Zuul proxy service is going to be a service based on the properties of the configuration service. Hence, the configuration server will expose the following properties:

File: src/main/resources/config/zuul-service.properties

Zuul proxy microservice

The proxy service will be the main entry point for the clients. The service will be in charge of routing to other services, compose internal service responses, etc…

In order to do that, this entry service should be aware of where to locate the other services.
A connection with the Eureka service would be ideal for that.

Properties

As the zuul proxy server is going to be configured by the configuration service, we would need to point to the properties we previously created on the configuration service.

File: src/main/resources/bootstrap.properties

Application

The application will need to have the @EnableZuulProxy annotation. This could go on top of your configuration file.

Given this point, if we deploy the services, we should be able to access to any of the services that are registered on Eureka through the Zuul service:

Once we have the main setup, we will add an endpoint which will request data from other services (A and B) and get back the composed result of both services:

The connection to other services have been done through RestTemplate in this case. You could do it in any other way (even using an autogenerated client), although my recommendation would be to use a normal rest client and a dynamic model encapsulating only the information you need: You don’t need to be tight to a model that is used on the other side (the other services you are contacting).

To test this last change, we could hit the following urls:

 

Handling service failures

When working with services, the main issue is dealing with unavailability, server hanging up or error cascading.
Add these issues to several services and the logic to handle fallback strategies start getting a bit complex and unmaintenable.

The assumption the service is going to be at the other end running and that the network is going to work 100% could result in unavailability to the client.
The main thought about working with services is that even if your system is not working 100% you still have the chance to provide a meaningful response to the client.

For handling errors and fallback strategies,  Netflix open sourced Hystrix .

Hystrix is a latency and fault tolerance library designed to isolate points of access to remote systems, services and 3rd party libraries, stop cascading failure and enable resilience in complex distributed systems where failure is inevitable. (Netflix Github project description)

For this post, in order to provide a fallback strategy https://www.acheterviagrafr24.com/a-quoi-sert-le-viagra/ when composing the services, we will enable Hystrix.

We will need to incorporate Hystrix as a dependency on the pom.xml:

Maven dependency

Application

We will add the @EnableCircuitBreaker annotation to our top config file.

Controller

The way to declare fallback strategies could be done with the annotation @HystrixCommand. In our case, if the service is down, we may want to think the results are empty rather than cascade or make other services wait for the information.

 

Deployment

After having done the modifications to the projects (or checked out the code), we can run each of the services with the following:

mvn spring-boot:run

For this example, to run everything, the recommended way to deploy is:

  • Deploy config-service
  • Deploy service a
  • Deploy service b
  • Deploy Eureka service
  • Deploy Zuul proxy service

I normally use jps to check what is running:

 

Test

If you follow the configuration on this project you should be able to hit the port 9000 on your machine (localhost:9000) and be able to get redirected to other services from Zuul.

Here are some of the urls that would be interesting to test to reaffirm the concepts on this post:

Eureka - List of services for Zuul proxy example

Eureka – List of services for Zuul proxy example

 

Summary

  • On these examples, we have seen how to proxy requests from Zuul to other services. At the same time, a Zuul proxy could be used to compose services and have some extra logic on top of that.
  • It is good to have Eureka server running, so the access to services can be done by its name rather than by ips or other non human readable identification.
  • Zuul proxy let us isolate the clients from changes on the backend (related to name resolution, ips, etc…). Still, major changes on the backend implementation need to be planified accordingly. To overcome that, you could version an api and provide different versions through zuul accessing to different services.
  • In a distributed system, it is always good to consider fallback strategies. The use of Hystrix could help you recover a internal timeout or a service hanging.

5 thoughts on “Microservices: Using Zuul proxy as a micro-proxy and api gateway

Leave a Reply

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