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/

Aba82ecdcf1e1534f2c579d124d8cd35?s=128

Alexander Heusingfeld

November 12, 2014
Tweet

Transcript

  1. @goldstift @eigenbrodtm #DV14 #MicroservicesJVM MicroServices on the JVM A practical

    overview Alexander Heusingfeld & Martin Eigenbrodt
  2. @goldstift @eigenbrodtm #DV14 #MicroservicesJVM #MicroServices #buzz • Defined by LOC?

    • UI or not UI? • SOA in new clothes?
  3. @goldstift @eigenbrodtm #DV14 #MicroservicesJVM “Micro” Services?

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

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

  6. @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
  7. @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
  8. @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
  9. @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
  10. @goldstift @eigenbrodtm #DV14 #MicroservicesJVM Our approach

  11. @goldstift @eigenbrodtm #DV14 #MicroservicesJVM Our approach • build around business

    capabilities
  12. @goldstift @eigenbrodtm #DV14 #MicroservicesJVM Our approach • build around business

    capabilities • separate runtime processes
  13. @goldstift @eigenbrodtm #DV14 #MicroservicesJVM Our approach • build around business

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

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

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

    capabilities • separate runtime processes • self-contained • loosely coupled • independent life cycles • decentralised management
  17. @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
  18. @goldstift @eigenbrodtm #DV14 #MicroservicesJVM We’re not talking about…

  19. @goldstift @eigenbrodtm #DV14 #MicroservicesJVM We’re not talking about… • micro

    architecture
  20. @goldstift @eigenbrodtm #DV14 #MicroservicesJVM We’re not talking about… • micro

    architecture • slicing howtos
  21. @goldstift @eigenbrodtm #DV14 #MicroservicesJVM We’re not talking about… • micro

    architecture • slicing howtos • communication protocol
  22. System A System B System C

  23. System A System B Persistence Logic UI System C Logic

    UI Persistence Logic
  24. System A System B Persistence Logic UI System C HTTP

    HTTP Logic UI Persistence Logic
  25. @goldstift @eigenbrodtm #DV14 #MicroservicesJVM Challenges

  26. @goldstift @eigenbrodtm #DV14 #MicroservicesJVM Challenges • distributed configuration

  27. @goldstift @eigenbrodtm #DV14 #MicroservicesJVM Challenges • distributed configuration • service

    registration & discovery
  28. @goldstift @eigenbrodtm #DV14 #MicroservicesJVM Challenges • distributed configuration • service

    registration & discovery • resilience
  29. @goldstift @eigenbrodtm #DV14 #MicroservicesJVM Challenges • distributed configuration • service

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

    registration & discovery • resilience • fast, automated deployment • metrics
  31. @goldstift @eigenbrodtm #DV14 #MicroservicesJVM Frameworks

  32. @goldstift @eigenbrodtm #DV14 #MicroservicesJVM Dropwizard

  33. @goldstift @eigenbrodtm #DV14 #MicroservicesJVM Dropwizard • Glue Code for well

    known libraries • Java
  34. @goldstift @eigenbrodtm #DV14 #MicroservicesJVM Dropwizard libraries

  35. @goldstift @eigenbrodtm #DV14 #MicroservicesJVM Dropwizard libraries • Jetty

  36. @goldstift @eigenbrodtm #DV14 #MicroservicesJVM Dropwizard libraries • Jetty • Jersey

  37. @goldstift @eigenbrodtm #DV14 #MicroservicesJVM Dropwizard libraries • Jetty • Jersey

    • Metrics
  38. @goldstift @eigenbrodtm #DV14 #MicroservicesJVM Dropwizard libraries • Jetty • Jersey

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

  40. @goldstift @eigenbrodtm #DV14 #MicroservicesJVM Spring Boot

  41. @goldstift @eigenbrodtm #DV14 #MicroservicesJVM Spring Boot • convention over configuration

    approach
  42. @goldstift @eigenbrodtm #DV14 #MicroservicesJVM Spring Boot • convention over configuration

    approach • Java, Groovy or Scala
  43. @goldstift @eigenbrodtm #DV14 #MicroservicesJVM Spring Boot • convention over configuration

    approach • Java, Groovy or Scala • self-contained jar or war
  44. @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
  45. @goldstift @eigenbrodtm #DV14 #MicroservicesJVM Spring Cloud

  46. @goldstift @eigenbrodtm #DV14 #MicroservicesJVM Spring Cloud • new umbrella project

    for cloud connectors
  47. @goldstift @eigenbrodtm #DV14 #MicroservicesJVM Spring Cloud • new umbrella project

    for cloud connectors • On top of Spring Boot
  48. @goldstift @eigenbrodtm #DV14 #MicroservicesJVM Spring Cloud • new umbrella project

    for cloud connectors • On top of Spring Boot • config server for distributed configuration
  49. @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
  50. @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
  51. @goldstift @eigenbrodtm #DV14 #MicroservicesJVM Play 2

  52. @goldstift @eigenbrodtm #DV14 #MicroservicesJVM Play 2 • Java or Scala

    • based on Akka • strong async support
  53. @goldstift @eigenbrodtm #DV14 #MicroservicesJVM Routing

  54. @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
  55. @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
  56. @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
  57. @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
  58. @goldstift @eigenbrodtm #DV14 #MicroservicesJVM Configuration

  59. @goldstift @eigenbrodtm #DV14 #MicroservicesJVM Spring Boot @ComponentScan
 @EnableAutoConfiguration
 public class

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

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


    @EnableAutoConfiguration
 public class OrderApp {
 
 public static void main(String[] args) {
 SpringApplication.run(OrderApp.class, args);
 }
 }
  62. @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);
 }
 }
  63. @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);
 }
 }
  64. @goldstift @eigenbrodtm #DV14 #MicroservicesJVM Play - Typesafe Config

  65. @goldstift @eigenbrodtm #DV14 #MicroservicesJVM Play - Typesafe Config • Config

    Library used by akka, play and other
  66. @goldstift @eigenbrodtm #DV14 #MicroservicesJVM Play - Typesafe Config • Config

    Library used by akka, play and other • HOCON - JSON Data Model + syntactic sugar
  67. @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
  68. @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
  69. @goldstift @eigenbrodtm #DV14 #MicroservicesJVM Http Client

  70. @goldstift @eigenbrodtm #DV14 #MicroservicesJVM public Product resolveProduct(String url) { Product

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

    RestTemplate restTemplate = new RestTemplate();
 return restTemplate.getForEntity(url, Product.class);
 } Spring Boot
  72. @goldstift @eigenbrodtm #DV14 #MicroservicesJVM WS.url(apiUrl).get.map { response => response.json.as[List[Bestseller]] }.recover

    { case e => List() } Play
  73. @goldstift @eigenbrodtm #DV14 #MicroservicesJVM Service Discovery

  74. @goldstift @eigenbrodtm #DV14 #MicroservicesJVM Registry Service Client register & heartbeat

    lookup call
  75. @goldstift @eigenbrodtm #DV14 #MicroservicesJVM @ComponentScan
 @EnableAutoConfiguration
 @EnableEurekaServer
 public class EurekaServerApp

    {
 
 public static void main(String[] args) {
 SpringApplication.run(EurekaServerApp.class, args);
 }
 }
  76. @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);
 }
 }
  77. @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);
 }
 }
  78. @goldstift @eigenbrodtm #DV14 #MicroservicesJVM Resilience

  79. @goldstift @eigenbrodtm #DV14 #MicroservicesJVM Resilience • isolate Failure • apply

    graceful degradation • be responsive in case of failure
  80. Request service Request service http://en.wikipedia.org/wiki/Circuit_breaker Request service closed open half-

    open
  81. > Provides Command-oriented Integration of Services > Introduces Circuit Breaker,

    Bulkheads and Isolation > Decouples from Service-dependencies > Provides metrics-facility to protect from failures
  82. @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
  83. @goldstift @eigenbrodtm #DV14 #MicroservicesJVM ResolveProductCommand command = new ResolveProductCommand(client, url);

    Product product = command.execute(); Hystrix & Dropwizard
  84. @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
  85. @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!
  86. @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
  87. @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
  88. @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? :(
  89. @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
  90. @goldstift @eigenbrodtm #DV14 #MicroservicesJVM Deployment

  91. @goldstift @eigenbrodtm #DV14 #MicroservicesJVM Spring Boot - Packaging ./gradlew distZip

    ./gradlew build
  92. @goldstift @eigenbrodtm #DV14 #MicroservicesJVM Spring Boot - Packaging ./gradlew distZip

    ./gradlew build ZIP + shell-script
  93. @goldstift @eigenbrodtm #DV14 #MicroservicesJVM Spring Boot - Packaging ./gradlew distZip

    ./gradlew build ZIP + shell-script executable JAR
  94. @goldstift @eigenbrodtm #DV14 #MicroservicesJVM Play - Packaging sbt dist sbt

    debian:packageBin sbt rpm:packageBin
  95. @goldstift @eigenbrodtm #DV14 #MicroservicesJVM Metrics

  96. @goldstift @eigenbrodtm #DV14 #MicroservicesJVM Dropwizard • “Metrics” Integrated with Dropwizard

    • @Timed on Resources • HTTP Client is already instrumented • JVM Data
  97. @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" }
  98. @goldstift @eigenbrodtm #DV14 #MicroservicesJVM Dropwizard Metrics • Exposed over HTTP

    (as Json) • Exposed as jmx • Others available: stdout, csv, slf4j, ganglia, graphite
  99. @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
  100. @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, ... }
  101. @goldstift @eigenbrodtm #DV14 #MicroservicesJVM Conclusion

  102. @goldstift @eigenbrodtm #DV14 #MicroservicesJVM Take Aways

  103. @goldstift @eigenbrodtm #DV14 #MicroservicesJVM Take Aways • MicroServices aren’t micro!

  104. @goldstift @eigenbrodtm #DV14 #MicroservicesJVM Take Aways • MicroServices aren’t micro!

    • Only “micro” regarding business scope
  105. @goldstift @eigenbrodtm #DV14 #MicroservicesJVM Take Aways • MicroServices aren’t micro!

    • Only “micro” regarding business scope • micro services = distributed systems deep dive
  106. @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
  107. @goldstift @eigenbrodtm #DV14 #MicroservicesJVM Thanks for your attention • Questions?

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