building distributed systems with netflix oss and spring cloud

84
Building Distributed Systems with Netflix OSS and Spring Cloud © 2015 Matt Stine 1

Upload: matt-stine

Post on 14-Jul-2015

2.733 views

Category:

Software


4 download

TRANSCRIPT

Page 1: Building Distributed Systems with Netflix OSS and Spring Cloud

Building Distributed Systems with

Netflix OSSandSpring Cloud© 2015 Matt Stine 1

Page 2: Building Distributed Systems with Netflix OSS and Spring Cloud

MeMatt Stine (@mstine)Senior Product ManagerPivotalhttp://[email protected]

© 2015 Matt Stine 2

Page 3: Building Distributed Systems with Netflix OSS and Spring Cloud

There Seems to Be Some Hype...

© 2015 Matt Stine 3

Page 4: Building Distributed Systems with Netflix OSS and Spring Cloud

Define: Microservice“Loosely coupled service oriented architecture with bounded contexts...”Adrian Cockcroft

© 2015 Matt Stine 4

Page 5: Building Distributed Systems with Netflix OSS and Spring Cloud

Spring BootA Microframework for Microservices

© 2015 Matt Stine 5

Page 6: Building Distributed Systems with Netflix OSS and Spring Cloud

It Can Get Pretty Small...@RestControllerclass ThisWillActuallyRun { @RequestMapping("/") String home() { "Hello World!" }}

© 2015 Matt Stine 6

Page 7: Building Distributed Systems with Netflix OSS and Spring Cloud

DEMO© 2015 Matt Stine 7

Page 8: Building Distributed Systems with Netflix OSS and Spring Cloud

With Spring Data REST!@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

Page 9: Building Distributed Systems with Netflix OSS and Spring Cloud

With Spring Data REST!@RepositoryRestResource(collectionResourceRel = "cities", path = "cities")public interface CityRepository extends PagingAndSortingRepository<City, Long> {}

© 2015 Matt Stine 9

Page 10: Building Distributed Systems with Netflix OSS and Spring Cloud

With Spring Data REST!@SpringBootApplication@EnableJpaRepositories@Import(RepositoryRestMvcConfiguration.class)public class Application {

public static void main(String[] args) { SpringApplication.run(Application.class, args); }}

© 2015 Matt Stine 10

Page 11: Building Distributed Systems with Netflix OSS and Spring Cloud

With Spring Data REST!{ "_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

Page 12: Building Distributed Systems with Netflix OSS and Spring Cloud

DEMO© 2015 Matt Stine 12

Page 13: Building Distributed Systems with Netflix OSS and Spring Cloud

Writing a Single Service is

Nice...© 2015 Matt Stine 13

Page 14: Building Distributed Systems with Netflix OSS and Spring Cloud

But No Microservice

is an Island© 2015 Matt Stine 14

Page 15: Building Distributed Systems with Netflix OSS and Spring Cloud

Challenges of Distributed Systems» Configuration Management

» Service Registration & Discovery

» Routing & Load Balancing

» Fault Tolerance (Circuit Breakers!)

» Monitoring

» Concurrent API Aggregation & Transformation

© 2015 Matt Stine 15

Page 16: Building Distributed Systems with Netflix OSS and Spring Cloud

© 2015 Matt Stine 16

Page 17: Building Distributed Systems with Netflix OSS and Spring Cloud

Spring CloudDistributed System Patterns FTW!

© 2015 Matt Stine 17

Page 18: Building Distributed Systems with Netflix OSS and Spring Cloud

ConfigurationManagement© 2015 Matt Stine 18

Page 19: Building Distributed Systems with Netflix OSS and Spring Cloud

Spring Environment» Properties

» Profiles

© 2015 Matt Stine 19

Page 20: Building Distributed Systems with Netflix OSS and Spring Cloud

app.groovy@RestControllerclass BasicConfig {

@Value('${greeting}') String greeting

@RequestMapping("/") String home() { "${greeting} World!" }}

© 2015 Matt Stine 20

Page 21: Building Distributed Systems with Netflix OSS and Spring Cloud

application.ymlgreeting: Hello

© 2015 Matt Stine 21

Page 22: Building Distributed Systems with Netflix OSS and Spring Cloud

DEMO© 2015 Matt Stine 22

Page 23: Building Distributed Systems with Netflix OSS and Spring Cloud

Boot Priority1.Command Line Args

2.JNDI

3.Java System Properties

4.OS Environment Variables

5.Properties Files

6.@PropertySource

7.Defaults

© 2015 Matt Stine 23

Page 24: Building Distributed Systems with Netflix OSS and Spring Cloud

DEMO© 2015 Matt Stine 24

Page 25: Building Distributed Systems with Netflix OSS and Spring Cloud

Profiles© 2015 Matt Stine 25

Page 26: Building Distributed Systems with Netflix OSS and Spring Cloud

application.ymlgreeting: Hello

---

spring: profiles: spanishgreeting: Hola

© 2015 Matt Stine 26

Page 27: Building Distributed Systems with Netflix OSS and Spring Cloud

DEMO© 2015 Matt Stine 27

Page 28: Building Distributed Systems with Netflix OSS and Spring Cloud

Distributed?

© 2015 Matt Stine 28

Page 29: Building Distributed Systems with Netflix OSS and Spring Cloud

ConfigServer!

© 2015 Matt Stine 29

Page 30: Building Distributed Systems with Netflix OSS and Spring Cloud

Config Server app.groovy@Grab("org.springframework.cloud:spring-cloud-starter-bus-amqp:1.0.0.RC1")@Configuration@EnableAutoConfiguration@EnableConfigServerclass ConfigServer {}

© 2015 Matt Stine 30

Page 31: Building Distributed Systems with Netflix OSS and Spring Cloud

Config Server application.ymlserver: port: 8888

spring: cloud: config: server: git: uri: https://github.com/mstine/config-repo.git

© 2015 Matt Stine 31

Page 32: Building Distributed Systems with Netflix OSS and Spring Cloud

https://github.com/mstine/config-repo/blob/master/demo.ymlgreeting: Bonjour

© 2015 Matt Stine 32

Page 33: Building Distributed Systems with Netflix OSS and Spring Cloud

Config Client app.groovy@Grab("org.springframework.cloud:spring-cloud-starter-bus-amqp:1.0.0.RC1")@RestControllerclass BasicConfig {

@Autowired Greeter greeter

@RequestMapping("/") String home() { "${greeter.greeting} World!" }}

@Component@RefreshScopeclass Greeter {

@Value('${greeting}') String greeting

}

© 2015 Matt Stine 33

Page 34: Building Distributed Systems with Netflix OSS and Spring Cloud

Config Client bootstrap.ymlspring: application: name: demo

© 2015 Matt Stine 34

Page 35: Building Distributed Systems with Netflix OSS and Spring Cloud

DEMO© 2015 Matt Stine 35

Page 36: Building Distributed Systems with Netflix OSS and Spring Cloud

Cloud

Bus!© 2015 Matt Stine 36

Page 37: Building Distributed Systems with Netflix OSS and Spring Cloud

curl -X POST http://localhost:8888/bus/refresh

© 2015 Matt Stine 37

Page 38: Building Distributed Systems with Netflix OSS and Spring Cloud

DEMO© 2015 Matt Stine 38

Page 39: Building Distributed Systems with Netflix OSS and Spring Cloud

ServiceRegistration &

Discovery© 2015 Matt Stine 39

Page 40: Building Distributed Systems with Netflix OSS and Spring Cloud

Eureka© 2015 Matt Stine 40

Page 41: Building Distributed Systems with Netflix OSS and Spring Cloud

ProducerConsumer© 2015 Matt Stine 41

Page 42: Building Distributed Systems with Netflix OSS and Spring Cloud

Eureka Service Registry@GrabExclude("ch.qos.logback:logback-classic")@EnableEurekaServerclass Eureka {}

© 2015 Matt Stine 42

Page 43: Building Distributed Systems with Netflix OSS and Spring Cloud

Producer@EnableDiscoveryClient@RestControllerpublic class Application {

int counter = 0

@RequestMapping("/") String produce() { "{\"value\": ${counter++}}" }}

© 2015 Matt Stine 43

Page 44: Building Distributed Systems with Netflix OSS and Spring Cloud

Consumer@EnableDiscoveryClient@RestControllerpublic 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

Page 45: Building Distributed Systems with Netflix OSS and Spring Cloud

DEMO© 2015 Matt Stine 45

Page 46: Building Distributed Systems with Netflix OSS and Spring Cloud

Routing &Load Balancing© 2015 Matt Stine 46

Page 47: Building Distributed Systems with Netflix OSS and Spring Cloud

Ribbon© 2015 Matt Stine 47

Page 48: Building Distributed Systems with Netflix OSS and Spring Cloud

Consumer with Load Balancer@AutowiredLoadBalancerClient 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

Page 49: Building Distributed Systems with Netflix OSS and Spring Cloud

DEMO© 2015 Matt Stine 49

Page 50: Building Distributed Systems with Netflix OSS and Spring Cloud

Consumer with Ribbon-enabled RestTemplate@AutowiredRestTemplate restTemplate

@RequestMapping("/")String consume() { ProducerResponse response = restTemplate.getForObject("http://producer", ProducerResponse.class)

"{\"value\": ${response.value}"}

© 2015 Matt Stine 50

Page 51: Building Distributed Systems with Netflix OSS and Spring Cloud

DEMO© 2015 Matt Stine 51

Page 52: Building Distributed Systems with Netflix OSS and Spring Cloud

Feign Client@FeignClient("producer")public interface ProducerClient {

@RequestMapping(method = RequestMethod.GET, value = "/") ProducerResponse getValue();}

© 2015 Matt Stine 52

Page 53: Building Distributed Systems with Netflix OSS and Spring Cloud

Consumer with Feign Client@SpringBootApplication@FeignClientScan@EnableDiscoveryClient@RestControllerpublic 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

Page 54: Building Distributed Systems with Netflix OSS and Spring Cloud

Demo© 2015 Matt Stine 54

Page 55: Building Distributed Systems with Netflix OSS and Spring Cloud

FaultTolerance© 2015 Matt Stine 55

Page 56: Building Distributed Systems with Netflix OSS and Spring Cloud

Hystrix© 2015 Matt Stine 56

Page 57: Building Distributed Systems with Netflix OSS and Spring Cloud

Circuit Breaker

© 2015 Matt Stine 57

Page 58: Building Distributed Systems with Netflix OSS and Spring Cloud

Consumer app.groovy@EnableDiscoveryClient@EnableCircuitBreaker@RestControllerpublic class Application {

@Autowired ProducerClient client

@RequestMapping("/") String consume() { ProducerResponse response = client.getProducerResponse()

"{\"value\": ${response.value}" }

}

© 2015 Matt Stine 58

Page 59: Building Distributed Systems with Netflix OSS and Spring Cloud

Producer Client@Componentpublic 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

Page 60: Building Distributed Systems with Netflix OSS and Spring Cloud

Demo© 2015 Matt Stine 60

Page 61: Building Distributed Systems with Netflix OSS and Spring Cloud

Monitoring© 2015 Matt Stine 61

Page 62: Building Distributed Systems with Netflix OSS and Spring Cloud

DEMOhttp://localhost:8082/

© 2015 Matt Stine 62

Page 63: Building Distributed Systems with Netflix OSS and Spring Cloud

HystrixDashboard© 2015 Matt Stine 63

Page 64: Building Distributed Systems with Netflix OSS and Spring Cloud

Hystrix Dashboard

© 2015 Matt Stine 64

Page 65: Building Distributed Systems with Netflix OSS and Spring Cloud

Hystrix Dashboard@Grab("org.springframework.cloud:spring-cloud-starter-hystrix-dashboard:1.0.0.RC1")

import org.springframework.cloud.netflix.hystrix.dashboard.EnableHystrixDashboard

@EnableHystrixDashboardclass HystrixDashboard {}

© 2015 Matt Stine 65

Page 66: Building Distributed Systems with Netflix OSS and Spring Cloud

Demo© 2015 Matt Stine 66

Page 67: Building Distributed Systems with Netflix OSS and Spring Cloud

ConcurrentAPIAggregation &Transformation© 2015 Matt Stine 67

Page 68: Building Distributed Systems with Netflix OSS and Spring Cloud

RxJava© 2015 Matt Stine 68

Page 69: Building Distributed Systems with Netflix OSS and Spring Cloud

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

Page 70: Building Distributed Systems with Netflix OSS and Spring Cloud

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

Page 71: Building Distributed Systems with Netflix OSS and Spring Cloud

Movie Review Service@RequestMapping(value = "/reviews/reviews/{mlId}", method = RequestMethod.GET)public Iterable<Review> reviews(@PathVariable String mlId) { return reviewRepository.findByMlId(mlId);}

© 2015 Matt Stine 71

Page 72: Building Distributed Systems with Netflix OSS and Spring Cloud

Movie Review Service[{ 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

Page 73: Building Distributed Systems with Netflix OSS and Spring Cloud

Movie Recommendations Servicepublic 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

Page 74: Building Distributed Systems with Netflix OSS and Spring Cloud

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

Page 75: Building Distributed Systems with Netflix OSS and Spring Cloud

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

Page 76: Building Distributed Systems with Netflix OSS and Spring Cloud

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

Page 77: Building Distributed Systems with Netflix OSS and Spring Cloud

APIGateway© 2015 Matt Stine 77

Page 78: Building Distributed Systems with Netflix OSS and Spring Cloud

Catalog Integration Service@Servicepublic 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

Page 79: Building Distributed Systems with Netflix OSS and Spring Cloud

Reviews Integration Service@Servicepublic 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

Page 80: Building Distributed Systems with Netflix OSS and Spring Cloud

Recommendations Integration Service@Servicepublic 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

Page 81: Building Distributed Systems with Netflix OSS and Spring Cloud

Concurrently Aggregate and 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

Page 82: Building Distributed Systems with Netflix OSS and Spring Cloud

Demo© 2015 Matt Stine 82

Page 83: Building Distributed Systems with Netflix OSS and Spring Cloud

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

Page 84: Building Distributed Systems with Netflix OSS and Spring Cloud

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