Spring Boot and Spring Cloud are relatively newer additions to the Spring portfolio. Boot makes it faster to spin up your project with less configuration (and an opinionated programming model). Spring Cloud brings in techniques and tools to efficiently standup distributed applications. In a previous blog I had noted my ramblings on API/Microservices style. If you take that path and have more than a handful of API’s then you will need some of the capabilities of what Spring Boot and Spring Cloud offer.
In this post we will deploy one UI app and two RESTful API’s (3 independently deployable components). We will then stand up a service registry/discovery tool using Netflix Eureka (or the Spring Cloud wrapper). We will also use Hystrix to provide for reliable inter-service invocations. Please read up on Hystrix here (its a great read). The github code I point to here is still a work in progress. There are things I got working and things I did not; but the code does work in case anyone wants to refer. What I did not get working yet is the Hystrix metrics on the dashboard. But the core Hystrix works…for example you can kill the 2nd service and see how the other service detects the service failure and falls back to the configured fall back method.
The application is a simple todo note taker. Put in a note and a date when you want to get that done by. There are two components…
- notetaker-ui. An AngularJS+Bootstrap app (single page app). Let’s you list existing notes, delete one and add a new one. This was initially generated using Yo generator, but later modified by hand. https://github.com/thomasma/notetaker-ui
- The RESTful API backend.
- notetaker-service API that supports the notes CRUD operations. https://github.com/thomasma/quote-service
- quote-service API that invokes a remote service to get a random Chuck Norris joke. https://github.com/thomasma/notetaker-services. Notetaker RESTful end point invokes the quote-service to get a random quote before returning response the calling client (in this case the AngularJS code).
To get this app running…( it is a bit involved )
Run a copy of the Eureka server project and run that to stand up a local instance. With this you have your service registry setup. You can alternatively use consul if you so choose. Consul looks promising but I have not tried it yet.
1 2 3 4 |
git clone https://github.com/thomasma/eureka-service-registry mvn clean spring-boot:run http://localhost:8761 (eureka web client) http://localhost:8761/eureka/apps (XML response from Eureka) |
Start a local MongoDB database for persistence.
Run hystrix-dashboard (you need to start this but as of today Dec 7th for some reason I am not able to get metrics flowing into the dashboard)
1 2 3 |
git clone https://github.com/spring-cloud-samples/hystrix-dashboard.git mvn clean spring-boot:run From your browser go to http://localhost:7979/hystrix |
Run the two RESTful API apps (notetaker-services and quote-service). Since I have added Actuator to the mix we get (for free) health related metrics for each of the service endpoints.
1 2 3 |
mvn clean spring-boot:run http://localhost:7070/health (or /metrics) to view quote-service actuator metrics http://localhost:8080/health (or /metrics) to view notetaker-service metrics |
Run UI app (notetaker-ui)
1 |
grunt serve |
Web Proxy Server (notetaker-ui). We will run a nodejs proxy server so that the browser invokes a single endpoint for both UI and backend code. Proxy server then routes the call based on the incoming URL path.
1 |
node server.js |
Once you get the various components running, go to Eureka web client and you should see the two API services registered. This is step#1 to validate your setup.
Now visit the proxy url at http://localhost:9090 . Look at the notetaker-ui/server.js code to see the web proxy routing. You should see something like this on the web page.
See the Chuck Norris joke above. I can confirm that that came from the remote site http://api.icndb.com/jokes/random?firstName=Chuck&lastName=Doe
Now to test if the Hystrix fallback works lets manually kill the quote-service. Remember the notetaker-service RESTful API to get all notes also invokes the quote-service. So killing the quote-service should force our Hystrix fallback method to be invoked.
Here is the Eureka dashboard where you can see the quote-service is down.
And the response to the browser now contains the fallback quote.
The invocation from notetaker-service to the quote-service is done via a Hystrix proxy (see NoteServiceEndpoint.all() which invokes QuoteRetriever.getRandomQuote(). The latter is annotated with the @HystrixCommand annotation. See code below for QuoteRetriever.java.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
package com.aver.notetaker.services.notes; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import com.aver.notetaker.domain.Quote; import com.aver.notetaker.domain.Value; import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand; @Component public class QuoteRetriever { private final static Logger LOGGER = LoggerFactory .getLogger(QuoteRetriever.class); @Autowired private QuoteClient quoteClient; @HystrixCommand(fallbackMethod = "fallbackQuoteService") public Quote getRandomQuote() { Quote quote = quoteClient.getQuote(); LOGGER.info(quote.toString()); return quoteClient.getQuote(); } private Quote fallbackQuoteService() { Quote q = new Quote(); q.setType("success"); Value v = new Value(); v.setId(1l); v.setJoke("Chuck Norris cannot be found but he is behind you so don't look back!"); q.setValue(v); return q; } } |
Hystrix collects invocation metrics which can be seen on the Hystrix-dashboard at http://localhost:7979/hystrix/monitor?stream=http%3A%2F%2Flocalhost%3A8080%2Fhystrix.stream
As you can see doing all of this is quite involved. For a production deployment with many 100s o of service instances this approach while possible can be cumbersome. This is where using something like Pivotal CloudFoundry with its Spring Cloud support is an absolute must do.
The above is standalone Hystrix Dashboard view of the notetaker-service’s view of the world. If you have multiple Hystrix enabled invocations, we will need a combined dashboard using NetflixOSS Turbine which can aggregate metrics from multiple services (with RabbitMQ behind the scenes). Will update that into another blog once I get that to work.
Great work Mathew.. keep going.