A common challenge when building microservices is providing a unified interface to the consumers of your system. The fact that your services are split into small composable apps shouldn’t be visible to users or result in substantial development effort.
To solve this problem, Netflix (a major adopter of microservices) created and open-sourced its Zuul proxy server. Zuul is an edge service that proxies requests to multiple backing services. It provides a unified “front door” to your system, which allows a browser, mobile app, or other user interface to consume services from multiple hosts without managing cross-origin resource sharing (CORS) and authentication for each one. You can integrate Zuul with other Netflix projects like Hystrix for fault tolerance and Eureka for service discovery, or use it to manage routing rules, filters, and load balancing across your system.
Thanks to Netflix and the Spring Cloud project, you can deploy a Zuul server on Heroku in just a few minutes. This service requires very little code, and can be used with microservices written in any language--not just Java.
Create the Zuul Server
To begin, deploy the Heroku Zuul server demo project by clicking this button:
When the deployment is complete, click the “View” link at the bottom of the page. When the app opens, it will display links to the services that Zuul exposes. Click a few to give them a try.
It will appear to you that the services are running in the app you just deployed but you are actually viewing services from another application (httpbin.org), which are proxied through the Zuul server.
The demo uses the following configuration located in the src/main/resources/application.yml
file of the demo project:
zuul:
routes:
get:
path: /get/**
url: http://httpbin.org/get
links:
path: /links/**
url: http://httpbin.org/links
images:
path: /image/**
url: http://httpbin.org/image
The configuration contains three named routes. Each route has a path
, which defines the URL mapping in the Zuul server, and a url
, which defines the URL of the remote service to proxy. There is also an entry that disables Eureka service discovery, but that has been omitted here.
This is the simplest and easiest way to configure the proxy, but it’s also very static and can’t adjust to changes or failures in your system. Zuul has the ability to load-balance its services and failover to an alternative service if the primary host goes down.
Adding load balancing and failover
The Zuul server you deployed comes pre-packaged with Ribbon, a client-side load-balancer, and Hystrix, a fault tolerance library. Both projects are part of the Netflix OSS suite, which means they integrate seamlessly with Zuul. All you need to do is enable them.
First, make sure you have the Heroku toolbelt installed. Then clone the app you deployed earlier by running this command (but replace “<app-name>” with the name of your Heroku app):
$ heroku git:clone <app-name>
$ cd <app-name>
Open the src/main/resources/application.yml
and replace the zuul
configuration with this code:
zuul:
routes:
httpbin:
path: /**
serviceId: httpbin
httpbin:
ribbon:
listOfServers: httpbin.org,eu.httpbin.org
ribbon:
eureka:
enabled: false
This configuration tells Zuul to forward all requests to the httpbin
service, which is defined after the zuul
entry. The httpbin
entry defines the available servers: httpbin.org and its European counterpart, eu.httpbin.org. If the first host goes down, the proxy will failover to the second host. It also disables Eureka discovery for Ribbon because you don’t have a Eureka server.... yet.
Now you can run the Zuul server locally. Build the project by running this command:
$ ./mvnw clean package
Then launch the server locally by executing this command:
$ heroku local web
After a few moments, the embedded Tomcat server will be ready to handle requests. Open a browser to http://localhost:5000
and you’ll see the complete httpbin.org site.
Manually configuring Ribbon to load balance your services is a great feature, but it’s just the beginning of what the Spring Cloud suite can do. If Zuul is connected to a Eureka server, it can automatically add fault tolerance and client-side load balancing to the services it proxies.
Connecting to Eureka
Eureka, another Netflix OSS project, is a service registry. It's like a phone book for your microservices. Each microservice registers itself with Eureka, and then consumers of that service know how to find it. This is similar in spirit to a DNS service but with additional features such as host-side load-balancing and region-isolation. Eureka also keeps track of health, availability and other metadata about the service, which makes it an ideal component to integrate with your Zuul proxy.
For this example, you’ll need to deploy both a Eureka server and a Eureka client service by following our blog post on Managing your Microservices on Heroku with Netflix's Eureka. Once you have both components deployed, you can connect them to Zuul, which can discover the Eureka client service from the Eureka server and proxy requests to it.
From your local Zuul repository, open the src/main/resources/application.yml
again, and replace its contents with this code:
zuul:
routes:
my-service:
path: /my-service/**
serviceId: my-service
eureka:
client:
serviceUrl:
defaultZone: ${EUREKA_URL:http://user:password@localhost:5000}/eureka/
The configuration defines a single service route, my-service
, which uses a serviceId
with the same name. But unlike the Ribbon configuration, you have not defined the my-service
details in this file. Instead, Zuul will retrieve them from the Eureka server, which is configured under the eureka
entry. It defines the Eureka server’s location at $EUREKA_URL
and falls back to a localhost address if it’s not set.
Now set the $EUREKA_URL
on your Heroku app using the URL and credentials of the Eureka server you deployed earlier by running a command like this:
$ heroku config:set EUREKA_URL=”http://user:<password>@<your-eureka-app>.herokuapp.com”
Commit your changes, and redeploy the Zuul server by running these commands:
$ git add src/main/resources/application.yml
$ git commit -m “eureka”
$ git push heroku master
Finally, open your Eureka client service through the Zuul proxy by running this command:
$ heroku open my-service
From now on, Zuul can proxy each service you registry with the Eureka server simply by adding to your application.yml
. It will wrap the requests in Hystrix commands, to ensure failover, and load-balance with Ribbon. It can also handle many other features such as filters, file uploads, request headers and more.
Further Reading
For more information about Zuul, Ribbon and Hysterix, please see the following documentation from Netflix OSS:
For more information on Spring and its Netflix integration, please see the Spring Cloud documentation.
To learn more about deploying Spring Boot applications on Heroku, see this article on Dev Center, or visit Java on Heroku in Dev Center.