Advertisement
Advertisement

More Related Content

Similar to Building Distributed Systems with Netflix OSS and Spring Cloud(20)

Advertisement

Recently uploaded(20)

Advertisement

Building Distributed Systems with Netflix OSS and Spring Cloud

  1. Building Distributed Systemswith Netflix OSS and Spring Cloud© 2015 Matt Stine 1
  2. Me Matt Stine (@mstine) Senior Product Manager Pivotal http://www.mattstine.com matt.stine@gmail.com © 2015 Matt Stine 2
  3. There Seemsto Be Some Hype... © 2015 Matt Stine 3
  4. Define: Microservice “Loosely coupled service oriented architecture with bounded contexts...” Adrian Cockcroft © 2015 Matt Stine 4
  5. Spring BootAMicroframework for Microservices © 2015 Matt Stine 5
  6. ItCan GetPrettySmall... @RestController class ThisWillActuallyRun { @RequestMapping("/") String home() { "Hello World!" } } © 2015 Matt Stine 6
  7. DEMO© 2015 Matt Stine 7
  8. With Spring DataREST! @Entity @Table(name = "city") public class City implements Serializable { @Id @GeneratedValue private Long id; @Column(nullable = false) private String name; @Column(nullable = false) private String county; //... } © 2015 Matt Stine 8
  9. With Spring DataREST! @RepositoryRestResource(collectionResourceRel = "cities", path = "cities") public interface CityRepository extends PagingAndSortingRepository<City, Long> {} © 2015 Matt Stine 9
  10. With Spring DataREST! @SpringBootApplication @EnableJpaRepositories @Import(RepositoryRestMvcConfiguration.class) public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } } © 2015 Matt Stine 10
  11. With Spring DataREST! { "_links" : { "next" : { "href" : "http://localhost:8080/cities?page=1&size=20" }, "self" : { "href" : "http://localhost:8080/cities{?page,size,sort}", "templated" : true } }, "_embedded" : { "cities" : [ { "name" : "HOLTSVILLE", "county" : "SUFFOLK", "stateCode" : "NY", "postalCode" : "00501", "latitude" : "+40.922326", "longitude" : "-072.637078", © 2015 Matt Stine 11
  12. DEMO© 2015 Matt Stine 12
  13. WritingaSingle Service is Nice...© 2015 Matt Stine 13
  14. ButNo Microservice isan Island © 2015 Matt Stine 14
  15. Challenges ofDistributed Systems » Configuration Management » Service Registration & Discovery » Routing & Load Balancing » Fault Tolerance (Circuit Breakers!) » Monitoring » Concurrent API Aggregation & Transformation © 2015 Matt Stine 15
  16. © 2015 Matt Stine 16
  17. Spring CloudDistributed System Patterns FTW! © 2015 Matt Stine 17
  18. Configuration Management © 2015 Matt Stine 18
  19. Spring Environment » Properties » Profiles © 2015 Matt Stine 19
  20. app.groovy @RestController class BasicConfig { @Value('${greeting}') String greeting @RequestMapping("/") String home() { "${greeting} World!" } } © 2015 Matt Stine 20
  21. application.yml greeting: Hello © 2015 Matt Stine 21
  22. DEMO© 2015 Matt Stine 22
  23. BootPriority 1.Command Line Args 2.JNDI 3.Java System Properties 4.OS Environment Variables 5.Properties Files 6.@PropertySource 7.Defaults © 2015 Matt Stine 23
  24. DEMO© 2015 Matt Stine 24
  25. Profiles © 2015 Matt Stine 25
  26. application.yml greeting: Hello --- spring: profiles: spanish greeting: Hola © 2015 Matt Stine 26
  27. DEMO© 2015 Matt Stine 27
  28. Distributed? © 2015 Matt Stine 28
  29. Config Server!© 2015 Matt Stine 29
  30. Config Server app.groovy @Grab("org.springframework.cloud:spring-cloud-starter-bus-amqp:1.0.0.RC1") @Configuration @EnableAutoConfiguration @EnableConfigServer class ConfigServer { } © 2015 Matt Stine 30
  31. Config Server application.yml server: port: 8888 spring: cloud: config: server: git: uri: https://github.com/mstine/config-repo.git © 2015 Matt Stine 31
  32. https://github.com/ mstine/config-repo/ blob/master/demo.yml greeting: Bonjour © 2015 Matt Stine 32
  33. Config Clientapp.groovy @Grab("org.springframework.cloud:spring-cloud-starter-bus-amqp:1.0.0.RC1") @RestController class BasicConfig { @Autowired Greeter greeter @RequestMapping("/") String home() { "${greeter.greeting} World!" } } @Component @RefreshScope class Greeter { @Value('${greeting}') String greeting } © 2015 Matt Stine 33
  34. Config Clientbootstrap.yml spring: application: name: demo © 2015 Matt Stine 34
  35. DEMO© 2015 Matt Stine 35
  36. Cloud Bus!© 2015 Matt Stine 36
  37. curl -X POST http://localhost:8888/bus/refresh © 2015 Matt Stine 37
  38. DEMO© 2015 Matt Stine 38
  39. Service Registration & Discovery© 2015 Matt Stine 39
  40. Eureka © 2015 Matt Stine 40
  41. Producer Consumer © 2015 Matt Stine 41
  42. EurekaService Registry @GrabExclude("ch.qos.logback:logback-classic") @EnableEurekaServer class Eureka { } © 2015 Matt Stine 42
  43. Producer @EnableDiscoveryClient @RestController public class Application { int counter = 0 @RequestMapping("/") String produce() { "{"value": ${counter++}}" } } © 2015 Matt Stine 43
  44. Consumer @EnableDiscoveryClient @RestController public class Application { @Autowired DiscoveryClient discoveryClient @RequestMapping("/") String consume() { InstanceInfo instance = discoveryClient.getNextServerFromEureka("PRODUCER", false) RestTemplate restTemplate = new RestTemplate() ProducerResponse response = restTemplate.getForObject(instance.homePageUrl, ProducerResponse.class) "{"value": ${response.value}" } } public class ProducerResponse { Integer value } © 2015 Matt Stine 44
  45. DEMO© 2015 Matt Stine 45
  46. Routing & Load Balancing © 2015 Matt Stine 46
  47. Ribbon © 2015 Matt Stine 47
  48. Consumerwith Load Balancer @Autowired LoadBalancerClient loadBalancer @RequestMapping("/") String consume() { ServiceInstance instance = loadBalancer.choose("producer") URI producerUri = URI.create("http://${instance.host}:${instance.port}"); RestTemplate restTemplate = new RestTemplate() ProducerResponse response = restTemplate.getForObject(producerUri, ProducerResponse.class) "{"value": ${response.value}" } © 2015 Matt Stine 48
  49. DEMO© 2015 Matt Stine 49
  50. Consumerwith Ribbon-enabled RestTemplate @Autowired RestTemplate restTemplate @RequestMapping("/") String consume() { ProducerResponse response = restTemplate.getForObject("http://producer", ProducerResponse.class) "{"value": ${response.value}" } © 2015 Matt Stine 50
  51. DEMO© 2015 Matt Stine 51
  52. Feign Client @FeignClient("producer") public interface ProducerClient { @RequestMapping(method = RequestMethod.GET, value = "/") ProducerResponse getValue(); } © 2015 Matt Stine 52
  53. Consumerwith Feign Client @SpringBootApplication @FeignClientScan @EnableDiscoveryClient @RestController public class Application { @Autowired ProducerClient client; @RequestMapping("/") String consume() { ProducerResponse response = client.getValue(); return "{"value": " + response.getValue() + "}"; } public static void main(String[] args) { SpringApplication.run(Application.class, args); } } © 2015 Matt Stine 53
  54. Demo© 2015 Matt Stine 54
  55. FaultTolerance© 2015 Matt Stine 55
  56. Hystrix © 2015 Matt Stine 56
  57. CircuitBreaker © 2015 Matt Stine 57
  58. Consumer app.groovy @EnableDiscoveryClient @EnableCircuitBreaker @RestController public class Application { @Autowired ProducerClient client @RequestMapping("/") String consume() { ProducerResponse response = client.getProducerResponse() "{"value": ${response.value}" } } © 2015 Matt Stine 58
  59. Producer Client @Component public class ProducerClient { @Autowired RestTemplate restTemplate @HystrixCommand(fallbackMethod = "getProducerFallback") ProducerResponse getProducerResponse() { restTemplate.getForObject("http://producer", ProducerResponse.class) } ProducerResponse getProducerFallback() { new ProducerResponse(value: 42) } } © 2015 Matt Stine 59
  60. Demo© 2015 Matt Stine 60
  61. Monitoring © 2015 Matt Stine 61
  62. DEMOhttp://localhost:8082/ © 2015 Matt Stine 62
  63. Hystrix Dashboard© 2015 Matt Stine 63
  64. Hystrix Dashboard © 2015 Matt Stine 64
  65. Hystrix Dashboard @Grab("org.springframework.cloud:spring-cloud-starter-hystrix-dashboard:1.0.0.RC1") import org.springframework.cloud.netflix.hystrix.dashboard.EnableHystrixDashboard @EnableHystrixDashboard class HystrixDashboard { } © 2015 Matt Stine 65
  66. Demo© 2015 Matt Stine 66
  67. Concurrent API Aggregation & Transformation© 2015 Matt Stine 67
  68. RxJava© 2015 Matt Stine 68
  69. Movie Catalog Service @RequestMapping(value = "/catalog/movies/{mlId}", method = RequestMethod.GET) public Movie movie(@PathVariable String mlId) { return movieRepository.findByMlId(mlId); } © 2015 Matt Stine 69
  70. Movie Catalog Service { id: 1001, title: "GoldenEye (1995)", mlId: "2", genres: [ { id: 1001, mlId: "1", name: "Action" }, { id: 1002, mlId: "2", name: "Adventure" }, { id: 1016, mlId: "16", name: "Thriller" } ] } © 2015 Matt Stine 70
  71. Movie ReviewService @RequestMapping(value = "/reviews/reviews/{mlId}", method = RequestMethod.GET) public Iterable<Review> reviews(@PathVariable String mlId) { return reviewRepository.findByMlId(mlId); } © 2015 Matt Stine 71
  72. Movie ReviewService [ { id: "54b85cbe004e0464177e90e4", mlId: "2", userName: "mstine", title: "GoldenEye (1995)", review: "Pretty good...", rating: 3 }, { id: "54b85cbe004e0464177e90e5", mlId: "2", userName: "starbuxman", title: "GoldenEye (1995)", review: "BOND BOND BOND!", rating: 5 }, { id: "54b85cbf004e0464177e90e8", mlId: "2", userName: "littleidea", title: "GoldenEye (1995)", review: "Good show!", rating: 4 } ] © 2015 Matt Stine 72
  73. Movie Recommendations Service public interface MovieRepository extends GraphRepository<Movie> { Movie findByMlId(String mlId); @Query("MATCH (movie:Movie) WHERE movie.mlId = {0} MATCH movie<-[:LIKES]-slm-[:LIKES]->recommendations " + "RETURN distinct recommendations") Iterable<Movie> moviesLikedByPeopleWhoLiked(String mlId); } © 2015 Matt Stine 73
  74. Movie Recommendations Service @RequestMapping(value = "/recommendations/forMovie/{mlId}", method = RequestMethod.GET) public Iterable<Movie> recommendedMoviesForMovie(@PathVariable String mlId) { return movieRepository.moviesLikedByPeopleWhoLiked(mlId); } © 2015 Matt Stine 74
  75. Movie Recommendations Service @RequestMapping(value = "/recommendations/forMovie/{mlId}", method = RequestMethod.GET) public Iterable<Movie> recommendedMoviesForMovie(@PathVariable String mlId) { return movieRepository.moviesLikedByPeopleWhoLiked(mlId); } © 2015 Matt Stine 75
  76. Movie Recommendations Service [ { id: 6, mlId: "1", title: "Toy Story (1995)" }, { id: 1, mlId: "4", title: "Get Shorty (1995)" }, { id: 2, mlId: "5", title: "Copycat (1995)" }, { id: 0, mlId: "3", title: "Four Rooms (1995)" } ] © 2015 Matt Stine 76
  77. API Gateway© 2015 Matt Stine 77
  78. Catalog Integration Service @Service public class CatalogIntegrationService { @Autowired RestTemplate restTemplate; @HystrixCommand(fallbackMethod = "stubMovie") public Observable<Movie> getMovie(final String mlId) { return new ObservableResult<Movie>() { @Override public Movie invoke() { return restTemplate.getForObject("http://catalog-service/catalog/movies/{mlId}", Movie.class, mlId); } }; } private Movie stubMovie(final String mlId) { Movie stub = new Movie(); stub.setMlId(mlId); stub.setTitle("Interesting...the wrong title. Sssshhhh!"); return stub; } } © 2015 Matt Stine 78
  79. Reviews Integration Service @Service public class ReviewsIntegrationService { @Autowired RestTemplate restTemplate; @HystrixCommand(fallbackMethod = "stubReviews") public Observable<List<Review>> reviewsFor(String mlId) { return new ObservableResult<List<Review>>() { @Override public List<Review> invoke() { ParameterizedTypeReference<List<Review>> responseType = new ParameterizedTypeReference<List<Review>>() { }; return restTemplate.exchange("http://reviews-service/reviews/reviews/{mlId}", HttpMethod.GET, null, responseType, mlId).getBody(); } }; } private List<Review> stubReviews(String mlId) { Review review = new Review(); review.setMlId(mlId); review.setRating(4); review.setTitle("Interesting...the wrong title. Sssshhhh!"); review.setReview("Awesome sauce!"); review.setUserName("joeblow"); return Arrays.asList(review); } } © 2015 Matt Stine 79
  80. Recommendations Integration Service @Service public class RecommendationsIntegrationService { @Autowired RestTemplate restTemplate; @HystrixCommand(fallbackMethod = "stubRecommendations") public Observable<List<Movie>> getRecommendations(final String mlId) { return new ObservableResult<List<Movie>>() { @Override public List<Movie> invoke() { ParameterizedTypeReference<List<Movie>> responseType = new ParameterizedTypeReference<List<Movie>>() { }; return restTemplate.exchange("http://recommendations-service/recommendations/forMovie/{mlId}", HttpMethod.GET, null, responseType, mlId).getBody(); } }; } private List<Movie> stubRecommendations(final String mlId) { Movie one = new Movie(); one.setMlId("25"); one.setMlId("A movie which doesn't exist"); Movie two = new Movie(); two.setMlId("26"); two.setMlId("A movie about nothing"); return Arrays.asList(one, two); } } © 2015 Matt Stine 80
  81. ConcurrentlyAggregateand Transform @RequestMapping("/movie/{mlId}") public DeferredResult<MovieDetails> movieDetails(@PathVariable String mlId) { Observable<MovieDetails> details = Observable.zip( catalogIntegrationService.getMovie(mlId), reviewsIntegrationService.reviewsFor(mlId), recommendationsIntegrationService.getRecommendations(mlId), (movie, reviews, recommendations) -> { MovieDetails movieDetails = new MovieDetails(); movieDetails.setMlId(movie.getMlId()); movieDetails.setTitle(movie.getTitle()); movieDetails.setReviews(reviews); movieDetails.setRecommendations(recommendations); return movieDetails; } ); return toDeferredResult(details); } © 2015 Matt Stine 81
  82. Demo© 2015 Matt Stine 82
  83. Thanks! Matt Stine (@mstine) » Spring Cloud: http://cloud.spring.io » This Presentation: https://github.com/mstine/ nfjs_2015/tree/master/ DistributedSystemsWithSpringCloud » SpringBox-Cloud: https://github.com/mstine/ microservices-lab/tree/master/springbox-cloud © 2015 Matt Stine 83
  84. Image Credits » http://i.imgur.com/atz81.jpg » http://theroomermill.net/wp-content/uploads/ 2014/06/island-house.jpg » Circuit Breaker: Nygard, Michael. Release It! © 2015 Matt Stine 84
Advertisement