Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Microservices on the JVM - a practical overview

Microservices on the JVM - a practical overview

Slides for @eigenbrodtm's and my session at Devoxx 2014
https://www.innoq.com/en/talks/2014/11/microservices-on-the-jvm-devoxx-2014/

Alexander Heusingfeld

November 12, 2014
Tweet

More Decks by Alexander Heusingfeld

Other Decks in Technology

Transcript

  1. @goldstift @eigenbrodtm #DV14 #MicroservicesJVM “Micro” Services? Monolith A A A

    A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A C A A B D Y K
  2. @goldstift @eigenbrodtm #DV14 #MicroservicesJVM “Micro” Services? Monolith A A A

    A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A C A A B D Y K
  3. @goldstift @eigenbrodtm #DV14 #MicroservicesJVM “Micro” Services? Monolith System A System

    B System C System D A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A C A A B D Y K
  4. @goldstift @eigenbrodtm #DV14 #MicroservicesJVM “Micro” Services? Monolith System A System

    B System C System D A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A C A A B D Y K
  5. @goldstift @eigenbrodtm #DV14 #MicroservicesJVM Our approach • build around business

    capabilities • separate runtime processes • self-contained
  6. @goldstift @eigenbrodtm #DV14 #MicroservicesJVM Our approach • build around business

    capabilities • separate runtime processes • self-contained • loosely coupled
  7. @goldstift @eigenbrodtm #DV14 #MicroservicesJVM Our approach • build around business

    capabilities • separate runtime processes • self-contained • loosely coupled • independent life cycles
  8. @goldstift @eigenbrodtm #DV14 #MicroservicesJVM Our approach • build around business

    capabilities • separate runtime processes • self-contained • loosely coupled • independent life cycles • decentralised management
  9. @goldstift @eigenbrodtm #DV14 #MicroservicesJVM Our approach • build around business

    capabilities • separate runtime processes • self-contained • loosely coupled • independent life cycles • decentralised management Self-Contained System
  10. @goldstift @eigenbrodtm #DV14 #MicroservicesJVM We’re not talking about… • micro

    architecture • slicing howtos • communication protocol
  11. @goldstift @eigenbrodtm #DV14 #MicroservicesJVM Challenges • distributed configuration • service

    registration & discovery • resilience • fast, automated deployment
  12. @goldstift @eigenbrodtm #DV14 #MicroservicesJVM Challenges • distributed configuration • service

    registration & discovery • resilience • fast, automated deployment • metrics
  13. @goldstift @eigenbrodtm #DV14 #MicroservicesJVM Dropwizard libraries • Jetty • Jersey

    • Metrics • Jackson • Guava • Logback • Hibernate Validator • Apache Http Client • JDBI • Liquibase • Freemarker & Mustache • Joda
  14. @goldstift @eigenbrodtm #DV14 #MicroservicesJVM Spring Boot • convention over configuration

    approach • Java, Groovy or Scala • self-contained jar or war
  15. @goldstift @eigenbrodtm #DV14 #MicroservicesJVM Spring Boot • convention over configuration

    approach • Java, Groovy or Scala • self-contained jar or war • tackles dependency-hell via pre-packaging
  16. @goldstift @eigenbrodtm #DV14 #MicroservicesJVM Spring Cloud • new umbrella project

    for cloud connectors • On top of Spring Boot • config server for distributed configuration
  17. @goldstift @eigenbrodtm #DV14 #MicroservicesJVM Spring Cloud • new umbrella project

    for cloud connectors • On top of Spring Boot • config server for distributed configuration • Eureka annotations for service-discovery
  18. @goldstift @eigenbrodtm #DV14 #MicroservicesJVM Spring Cloud • new umbrella project

    for cloud connectors • On top of Spring Boot • config server for distributed configuration • Eureka annotations for service-discovery • Hystrix annotations for resilience enhancements
  19. @goldstift @eigenbrodtm #DV14 #MicroservicesJVM @Path ("/cart") public class ShoppingCartResource {

    @GET @Path("{id}") @Timed @Produces(MediaType.TEXT_HTML) public ShoppingCartView shoppingCart(@PathParam("id") String cartId, @Context UriInfo uriInfo) { ImmutableList<String> urls = dao.findItemsForCartId(cartId); ImmutableList<Product> products = catalog.resolveProducts(urls); return new ShoppingCartView(products, uriInfo.getAbsolutePath().toString() ); } ... } Dropwizard
  20. @goldstift @eigenbrodtm #DV14 #MicroservicesJVM @Controller
 @RequestMapping(value = ORDERS_RESOURCE)
 public class

    OrderController {
 
 private @Autowired CounterService counterService;
 
 @RequestMapping(method = RequestMethod.POST)
 public String checkoutCart(@RequestParam(value = "products") List<String> productUris) {
 counterService.increment("checkouts.withproducts." + productUris.size());
 
 // save products as an order 
 return "redirect:" ORDERS_RESOURCE + order.getId(); // like “/order/123”
 }
 } Spring Boot
  21. @goldstift @eigenbrodtm #DV14 #MicroservicesJVM # Routes # List of all

    books GET / controllers.BooksController.books # A specific Book GET /books/:id controllers.BooksController.book(id:String) Play
  22. @goldstift @eigenbrodtm #DV14 #MicroservicesJVM object BooksController extends Controller { def

    books = Action.async { implicit request => val bestsellerFuture = Bestseller.getBestseller val booksFuture = Books.books for { bestseller <- bestsellerFuture books <- booksFuture } yield { Ok(views.html.books(books.values.toList, bestseller)) } } ... } Play
  23. @goldstift @eigenbrodtm #DV14 #MicroservicesJVM Spring Boot @ComponentScan
 @EnableAutoConfiguration
 public class

    OrderApp {
 
 public static void main(String[] args) {
 SpringApplication.run(OrderApp.class, args);
 }
 }
  24. @goldstift @eigenbrodtm #DV14 #MicroservicesJVM Spring Boot @ComponentScan
 @EnableAutoConfiguration
 public class

    OrderApp {
 
 public static void main(String[] args) {
 SpringApplication.run(OrderApp.class, args);
 }
 }
  25. @goldstift @eigenbrodtm #DV14 #MicroservicesJVM Spring Boot • opinionated preset @ComponentScan


    @EnableAutoConfiguration
 public class OrderApp {
 
 public static void main(String[] args) {
 SpringApplication.run(OrderApp.class, args);
 }
 }
  26. @goldstift @eigenbrodtm #DV14 #MicroservicesJVM Spring Boot • opinionated preset •

    HTTP resource “/env” shows all properties @ComponentScan
 @EnableAutoConfiguration
 public class OrderApp {
 
 public static void main(String[] args) {
 SpringApplication.run(OrderApp.class, args);
 }
 }
  27. @goldstift @eigenbrodtm #DV14 #MicroservicesJVM Spring Boot • opinionated preset •

    HTTP resource “/env” shows all properties • overwrite via application.properties or CLI parameter @ComponentScan
 @EnableAutoConfiguration
 public class OrderApp {
 
 public static void main(String[] args) {
 SpringApplication.run(OrderApp.class, args);
 }
 }
  28. @goldstift @eigenbrodtm #DV14 #MicroservicesJVM Play - Typesafe Config • Config

    Library used by akka, play and other • HOCON - JSON Data Model + syntactic sugar
  29. @goldstift @eigenbrodtm #DV14 #MicroservicesJVM Play - Typesafe Config • Config

    Library used by akka, play and other • HOCON - JSON Data Model + syntactic sugar • override via system property
  30. @goldstift @eigenbrodtm #DV14 #MicroservicesJVM Play - Typesafe Config • Config

    Library used by akka, play and other • HOCON - JSON Data Model + syntactic sugar • override via system property • rich merge and include possibilities
  31. @goldstift @eigenbrodtm #DV14 #MicroservicesJVM public Product resolveProduct(String url) { Product

    product = client.resource(url) .accept(MediaType.APPLICATION_JSON).get(Product.class); return product; } Dropwizard
  32. @goldstift @eigenbrodtm #DV14 #MicroservicesJVM public Product resolveProduct(String url) { final

    RestTemplate restTemplate = new RestTemplate();
 return restTemplate.getForEntity(url, Product.class);
 } Spring Boot
  33. @goldstift @eigenbrodtm #DV14 #MicroservicesJVM @ComponentScan
 @EnableAutoConfiguration
 @EnableEurekaServer
 public class EurekaServerApp

    {
 
 public static void main(String[] args) {
 SpringApplication.run(EurekaServerApp.class, args);
 }
 }
  34. @goldstift @eigenbrodtm #DV14 #MicroservicesJVM @ComponentScan
 @EnableAutoConfiguration
 @EnableEurekaServer
 public class EurekaServerApp

    {
 
 public static void main(String[] args) {
 SpringApplication.run(EurekaServerApp.class, args);
 }
 } @ComponentScan
 @EnableAutoConfiguration
 @EnableEurekaClient
 public class OrdersApp {
 
 public static void main(String[] args) {
 SpringApplication.run(OrdersApp.class, args);
 }
 }
  35. @goldstift @eigenbrodtm #DV14 #MicroservicesJVM @ComponentScan
 @EnableAutoConfiguration
 @EnableEurekaServer
 public class EurekaServerApp

    {
 
 public static void main(String[] args) {
 SpringApplication.run(EurekaServerApp.class, args);
 }
 } @ComponentScan
 @EnableAutoConfiguration
 @EnableEurekaClient
 public class OrdersApp {
 
 public static void main(String[] args) {
 SpringApplication.run(OrdersApp.class, args);
 }
 }
  36. @goldstift @eigenbrodtm #DV14 #MicroservicesJVM Resilience • isolate Failure • apply

    graceful degradation • be responsive in case of failure
  37. > Provides Command-oriented Integration of Services > Introduces Circuit Breaker,

    Bulkheads and Isolation > Decouples from Service-dependencies > Provides metrics-facility to protect from failures
  38. @goldstift @eigenbrodtm #DV14 #MicroservicesJVM public class CommandInDropwizard extends TenacityCommand<Product> {

    @Override protected Product run() throws Exception { Product product = client.resource(url) .accept(MediaType.APPLICATION_JSON).get(Product.class); return product; } protected Product getFallback() { return FALLBACK_PRODUCT } } Hystrix & Dropwizard
  39. @goldstift @eigenbrodtm #DV14 #MicroservicesJVM @HystrixCommand(fallbackMethod = “fallbackProduct") private Pair<String, ResponseEntity<Product>>

    resolveProduct(String productUri) {
 final RestTemplate restTemplate = new RestTemplate();
 return new Pair(productUri, restTemplate.getForEntity(productUri, Product.class));
 } private Pair<String, ResponseEntity<Product>> fallbackProduct(String productUri) {
 final Product product = new Product(productUri, null, BigDecimal.ZERO);
 final ResponseEntity<Product> response = new ResponseEntity<Product>(product, PARTIAL_CONTENT);
 return new Pair(productUri, response);
 } Spring Cloud Hystrix
  40. @goldstift @eigenbrodtm #DV14 #MicroservicesJVM @HystrixCommand(fallbackMethod = “fallbackProduct") private Pair<String, ResponseEntity<Product>>

    resolveProduct(String productUri) {
 final RestTemplate restTemplate = new RestTemplate();
 return new Pair(productUri, restTemplate.getForEntity(productUri, Product.class));
 } private Pair<String, ResponseEntity<Product>> fallbackProduct(String productUri) {
 final Product product = new Product(productUri, null, BigDecimal.ZERO);
 final ResponseEntity<Product> response = new ResponseEntity<Product>(product, PARTIAL_CONTENT);
 return new Pair(productUri, response);
 } Spring Cloud Hystrix wrapped in command -> async!
  41. @goldstift @eigenbrodtm #DV14 #MicroservicesJVM @HystrixCommand(fallbackMethod = “fallbackProduct") private Pair<String, ResponseEntity<Product>>

    resolveProduct(String productUri) {
 final RestTemplate restTemplate = new RestTemplate();
 return new Pair(productUri, restTemplate.getForEntity(productUri, Product.class));
 } private Pair<String, ResponseEntity<Product>> fallbackProduct(String productUri) {
 final Product product = new Product(productUri, null, BigDecimal.ZERO);
 final ResponseEntity<Product> response = new ResponseEntity<Product>(product, PARTIAL_CONTENT);
 return new Pair(productUri, response);
 } Spring Cloud Hystrix
  42. @goldstift @eigenbrodtm #DV14 #MicroservicesJVM @HystrixCommand(fallbackMethod = “fallbackProduct") private Pair<String, ResponseEntity<Product>>

    resolveProduct(String productUri) {
 final RestTemplate restTemplate = new RestTemplate();
 return new Pair(productUri, restTemplate.getForEntity(productUri, Product.class));
 } private Pair<String, ResponseEntity<Product>> fallbackProduct(String productUri) {
 final Product product = new Product(productUri, null, BigDecimal.ZERO);
 final ResponseEntity<Product> response = new ResponseEntity<Product>(product, PARTIAL_CONTENT);
 return new Pair(productUri, response);
 } Spring Cloud Hystrix
  43. @goldstift @eigenbrodtm #DV14 #MicroservicesJVM @HystrixCommand(fallbackMethod = “fallbackProduct") private Pair<String, ResponseEntity<Product>>

    resolveProduct(String productUri) {
 final RestTemplate restTemplate = new RestTemplate();
 return new Pair(productUri, restTemplate.getForEntity(productUri, Product.class));
 } private Pair<String, ResponseEntity<Product>> fallbackProduct(String productUri) {
 final Product product = new Product(productUri, null, BigDecimal.ZERO);
 final ResponseEntity<Product> response = new ResponseEntity<Product>(product, PARTIAL_CONTENT);
 return new Pair(productUri, response);
 } Spring Cloud Hystrix method reference? :(
  44. @goldstift @eigenbrodtm #DV14 #MicroservicesJVM val apiUrl = "..." val breaker

    = CircuitBreaker(Akka.system().scheduler, maxFailures = 5, callTimeout = 2.seconds, resetTimeout = 1.minute) def getBestseller : Future[List[Bestseller]] = { breaker.withCircuitBreaker( WS.url(apiUrl).get.map { response => response.json.as[List[Bestseller]] }).recover { case e => List() } } Play - Circuit Breaker
  45. @goldstift @eigenbrodtm #DV14 #MicroservicesJVM Dropwizard • “Metrics” Integrated with Dropwizard

    • @Timed on Resources • HTTP Client is already instrumented • JVM Data
  46. @goldstift @eigenbrodtm #DV14 #MicroservicesJVM "cart.resources.ShoppingCartResource.shoppingCart": { "count": 22, "max": 0.136162,

    "mean": 0.01208109090909091, "min": 0.00093, "p50": 0.008174500000000001, "p75": 0.011782250000000001, "p95": 0.11783499999999976, "p98": 0.136162, "p99": 0.136162, "p999": 0.136162, "stddev": 0.02813530239821426, "m15_rate": 1.8524577712890011, "m1_rate": 0.18057796798879996, "m5_rate": 1.315746847992022, "mean_rate": 0.133050618509084, "duration_units": "seconds", "rate_units": "calls/second" } "org.apache.http.client.HttpClient.cart.get-requests": { "count": 11, "max": 0.062107, "mean": 0.013355909090909092, "min": 0.005750000000000001, "p50": 0.009454, "p75": 0.010427, "p95": 0.062107, "p98": 0.062107, "p99": 0.062107, "p999": 0.062107, "stddev": 0.016285873488729705, "m15_rate": 0, "m1_rate": 0, "m5_rate": 0, "mean_rate": 2.9714422786532126, "duration_units": "seconds", "rate_units": "calls/second" }
  47. @goldstift @eigenbrodtm #DV14 #MicroservicesJVM Dropwizard Metrics • Exposed over HTTP

    (as Json) • Exposed as jmx • Others available: stdout, csv, slf4j, ganglia, graphite
  48. @goldstift @eigenbrodtm #DV14 #MicroservicesJVM Spring Boot Metrics • Prepackaged Spring

    Boot starter module • enables HTTP resources for metrics • configurable via application.properties http://docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference/htmlsingle/#production-ready
  49. @goldstift @eigenbrodtm #DV14 #MicroservicesJVM Using a counter metric in your

    Java code… …will display it in the /metrics JSON counterService.increment("checkouts.withproducts." + productUris.size()); GET /metrics HTTP/1.1 { "counter.checkouts.withproducts.3": 4, ... }
  50. @goldstift @eigenbrodtm #DV14 #MicroservicesJVM Take Aways • MicroServices aren’t micro!

    • Only “micro” regarding business scope • micro services = distributed systems deep dive
  51. @goldstift @eigenbrodtm #DV14 #MicroservicesJVM Take Aways • MicroServices aren’t micro!

    • Only “micro” regarding business scope • micro services = distributed systems deep dive • no framework is a silver bullet
  52. @goldstift @eigenbrodtm #DV14 #MicroservicesJVM Thanks for your attention • Questions?

    Martin Eigenbrodt, @eigenbrodtm Alexander Heusingfeld, @goldstift https://www.innoq.com/en/timeline/