netflixoss season 2 episode 2 - reactive / async

118
Season 2 Episode 2 July 9, 2014

Upload: ruslan-meshenberg

Post on 19-Aug-2014

2.155 views

Category:

Engineering


4 download

DESCRIPTION

NetflixOSS Season 2 Episode 2 Meetup, Reactive/Async theme. Lightning talks by Netflix engineers, as well as guest speakers from Square, Couchbase and Typesafe.

TRANSCRIPT

Page 1: NetflixOSS   season 2 episode 2 - Reactive / Async

Season 2 Episode 2July 9, 2014

Page 2: NetflixOSS   season 2 episode 2 - Reactive / Async

Evening Outline

Lightning Talks:● Reactive / Rx● RxJava● RxNetty● Ribbon 2.0● Karyon 2.0

Guest Speakers● Jake Wharton, Square● Matt Ingenthron, Couchbase● Will Sargent, Typesafe

Page 3: NetflixOSS   season 2 episode 2 - Reactive / Async

Netflix Lightning talks

Page 4: NetflixOSS   season 2 episode 2 - Reactive / Async
Page 5: NetflixOSS   season 2 episode 2 - Reactive / Async
Page 6: NetflixOSS   season 2 episode 2 - Reactive / Async
Page 7: NetflixOSS   season 2 episode 2 - Reactive / Async
Page 8: NetflixOSS   season 2 episode 2 - Reactive / Async
Page 9: NetflixOSS   season 2 episode 2 - Reactive / Async

Composable Functions

Reactively Applied

Page 10: NetflixOSS   season 2 episode 2 - Reactive / Async

Composable Functions

Reactively Applied

Page 11: NetflixOSS   season 2 episode 2 - Reactive / Async

Composable Functions

Reactively Applied

Page 12: NetflixOSS   season 2 episode 2 - Reactive / Async

Clojure Scala

Groovy JRuby

Java 8

(->

(Observable/from ["one" "two" "three"])

(.take 2)

(.subscribe (rx/action [arg] (println arg))))

Observable("one", "two", "three")

.take(2)

.subscribe((arg: String) => {

println(arg)

})

Observable.from("one", "two", "three")

.take(2)

.subscribe(lambda { |arg| puts arg })

Observable.from("one", "two", "three")

.take(2)

.subscribe({arg -> println(arg)})

Observable.from("one", "two", "three")

.take(2)

.subscribe(System.out::println);

Page 13: NetflixOSS   season 2 episode 2 - Reactive / Async

return new UserCommand(userId).observe().flatMap(user -> {

Observable<Map<String, Object>> catalog = new PersonalizedCatalogCommand(user).observe()

.flatMap(catalogList -> {

return catalogList.videos().<Map<String, Object>> flatMap(video -> {

Observable<Bookmark> bookmark = new BookmarkCommand(video).observe();

Observable<Rating> rating = new RatingsCommand(video).observe();

Observable<VideoMetadata> metadata = new VideoMetadataCommand(video).observe();

return Observable.zip(bookmark, rating, metadata, (b, r, m) -> {

return combineVideoData(video, b, r, m);

});

});

});

Observable<Map<String, Object>> social = new SocialCommand(user).observe().map(s -> {

return s.getDataAsMap();

});

return Observable.merge(catalog, social);

}).flatMap(data -> {

return response.writeAndFlush(new ServerSentEvent("", "data", SimpleJson.mapToJson(data)), EdgeServer.SSE_TRANSFORMER);

});

Page 14: NetflixOSS   season 2 episode 2 - Reactive / Async

return new UserCommand(userId).observe().flatMap(user -> {

Observable<Map<String, Object>> catalog = new PersonalizedCatalogCommand(user).observe()

.flatMap(catalogList -> {

return catalogList.videos().<Map<String, Object>> flatMap(video -> {

Observable<Bookmark> bookmark = new BookmarkCommand(video).observe();

Observable<Rating> rating = new RatingsCommand(video).observe();

Observable<VideoMetadata> metadata = new VideoMetadataCommand(video).observe();

return Observable.zip(bookmark, rating, metadata, (b, r, m) -> {

return combineVideoData(video, b, r, m);

});

});

});

Observable<Map<String, Object>> social = new SocialCommand(user).observe().map(s -> {

return s.getDataAsMap();

});

return Observable.merge(catalog, social);

}).flatMap(data -> {

return response.writeAndFlush(new ServerSentEvent("", "data", SimpleJson.mapToJson(data)), EdgeServer.SSE_TRANSFORMER);

});

Page 15: NetflixOSS   season 2 episode 2 - Reactive / Async

return new UserCommand(userId).observe().flatMap(user -> {

Observable<Map<String, Object>> catalog = new PersonalizedCatalogCommand(user).observe()

.flatMap(catalogList -> {

return catalogList.videos().<Map<String, Object>> flatMap(video -> {

Observable<Bookmark> bookmark = new BookmarkCommand(video).observe();

Observable<Rating> rating = new RatingsCommand(video).observe();

Observable<VideoMetadata> metadata = new VideoMetadataCommand(video).observe();

return Observable.zip(bookmark, rating, metadata, (b, r, m) -> {

return combineVideoData(video, b, r, m);

});

});

});

Observable<Map<String, Object>> social = new SocialCommand(user).observe().map(s -> {

return s.getDataAsMap();

});

return Observable.merge(catalog, social);

}).flatMap(data -> {

return response.writeAndFlush(new ServerSentEvent("", "data", SimpleJson.mapToJson(data)), EdgeServer.SSE_TRANSFORMER);

});

Page 16: NetflixOSS   season 2 episode 2 - Reactive / Async

return new UserCommand(userId).observe().flatMap(user -> {

Observable<Map<String, Object>> catalog = new PersonalizedCatalogCommand(user).observe()

.flatMap(catalogList -> {

return catalogList.videos().<Map<String, Object>> flatMap(video -> {

Observable<Bookmark> bookmark = new BookmarkCommand(video).observe();

Observable<Rating> rating = new RatingsCommand(video).observe();

Observable<VideoMetadata> metadata = new VideoMetadataCommand(video).observe();

return Observable.zip(bookmark, rating, metadata, (b, r, m) -> {

return combineVideoData(video, b, r, m);

});

});

});

Observable<Map<String, Object>> social = new SocialCommand(user).observe().map(s -> {

return s.getDataAsMap();

});

return Observable.merge(catalog, social);

}).flatMap(data -> {

return response.writeAndFlush(new ServerSentEvent("", "data", SimpleJson.mapToJson(data)), EdgeServer.SSE_TRANSFORMER);

});

Page 17: NetflixOSS   season 2 episode 2 - Reactive / Async

return new UserCommand(userId).observe().flatMap(user -> {

Observable<Map<String, Object>> catalog = new PersonalizedCatalogCommand(user).observe()

.flatMap(catalogList -> {

return catalogList.videos().<Map<String, Object>> flatMap(video -> {

Observable<Bookmark> bookmark = new BookmarkCommand(video).observe();

Observable<Rating> rating = new RatingsCommand(video).observe();

Observable<VideoMetadata> metadata = new VideoMetadataCommand(video).observe();

return Observable.zip(bookmark, rating, metadata, (b, r, m) -> {

return combineVideoData(video, b, r, m);

});

});

});

Observable<Map<String, Object>> social = new SocialCommand(user).observe().map(s -> {

return s.getDataAsMap();

});

return Observable.merge(catalog, social);

}).flatMap(data -> {

return response.writeAndFlush(new ServerSentEvent("", "data", SimpleJson.mapToJson(data)), EdgeServer.SSE_TRANSFORMER);

});

Page 18: NetflixOSS   season 2 episode 2 - Reactive / Async

return new UserCommand(userId).observe().flatMap(user -> {

Observable<Map<String, Object>> catalog = new PersonalizedCatalogCommand(user).observe()

.flatMap(catalogList -> {

return catalogList.videos().<Map<String, Object>> flatMap(video -> {

Observable<Bookmark> bookmark = new BookmarkCommand(video).observe();

Observable<Rating> rating = new RatingsCommand(video).observe();

Observable<VideoMetadata> metadata = new VideoMetadataCommand(video).observe();

return Observable.zip(bookmark, rating, metadata, (b, r, m) -> {

return combineVideoData(video, b, r, m);

});

});

});

Observable<Map<String, Object>> social = new SocialCommand(user).observe().map(s -> {

return s.getDataAsMap();

});

return Observable.merge(catalog, social);

}).flatMap(data -> {

return response.writeAndFlush(new ServerSentEvent("", "data", SimpleJson.mapToJson(data)), EdgeServer.SSE_TRANSFORMER);

});

Page 19: NetflixOSS   season 2 episode 2 - Reactive / Async

return new UserCommand(userId).observe().flatMap(user -> {

Observable<Map<String, Object>> catalog = new PersonalizedCatalogCommand(user).observe()

.flatMap(catalogList -> {

return catalogList.videos().<Map<String, Object>> flatMap(video -> {

Observable<Bookmark> bookmark = new BookmarkCommand(video).observe();

Observable<Rating> rating = new RatingsCommand(video).observe();

Observable<VideoMetadata> metadata = new VideoMetadataCommand(video).observe();

return Observable.zip(bookmark, rating, metadata, (b, r, m) -> {

return combineVideoData(video, b, r, m);

});

});

});

Observable<Map<String, Object>> social = new SocialCommand(user).observe().map(s -> {

return s.getDataAsMap();

});

return Observable.merge(catalog, social);

}).flatMap(data -> {

return response.writeAndFlush(new ServerSentEvent("", "data", SimpleJson.mapToJson(data)), EdgeServer.SSE_TRANSFORMER);

});

Page 20: NetflixOSS   season 2 episode 2 - Reactive / Async

return new UserCommand(userId).observe().flatMap(user -> {

Observable<Map<String, Object>> catalog = new PersonalizedCatalogCommand(user).observe()

.flatMap(catalogList -> {

return catalogList.videos().<Map<String, Object>> flatMap(video -> {

Observable<Bookmark> bookmark = new BookmarkCommand(video).observe();

Observable<Rating> rating = new RatingsCommand(video).observe();

Observable<VideoMetadata> metadata = new VideoMetadataCommand(video).observe();

return Observable.zip(bookmark, rating, metadata, (b, r, m) -> {

return combineVideoData(video, b, r, m);

});

});

});

Observable<Map<String, Object>> social = new SocialCommand(user).observe().map(s -> {

return s.getDataAsMap();

});

return Observable.merge(catalog, social);

}).flatMap(data -> {

return response.writeAndFlush(new ServerSentEvent("", "data", SimpleJson.mapToJson(data)), EdgeServer.SSE_TRANSFORMER);

});

Page 21: NetflixOSS   season 2 episode 2 - Reactive / Async

+

Page 22: NetflixOSS   season 2 episode 2 - Reactive / Async

1.3.x (current production)1.4 Release Candidate (available now) - support for fully non-blocking1.4.0 Final (coming months)

Page 23: NetflixOSS   season 2 episode 2 - Reactive / Async

0.19.x (current production)0.20 Release Candidates (coming weeks) - the “backpressure” release0.20.0 Final1.0 Release Candidates (Summer 2014) - no more breaking changes1.0.0 Final (Summer/Fall 2014)

Page 24: NetflixOSS   season 2 episode 2 - Reactive / Async

github.com/Netflix/RxJava github.com/ReactiveX/RxJava

Version 1.x to be releasedon Maven Central with groupId io.reactivex.*

Page 25: NetflixOSS   season 2 episode 2 - Reactive / Async

github.com/Netflix/RxJava github.com/ReactiveX/RxJava

github.com/ReactiveX/RxScalagithub.com/ReactiveX/RxGroovygithub.com/ReactiveX/RxClojuregithub.com/ReactiveX/RxKotlingithub.com/ReactiveX/RxJRubygithub.com/ReactiveX/RxAndroidetc ...

Version 1.x to be releasedon Maven Central with groupId io.reactivex.*

Page 26: NetflixOSS   season 2 episode 2 - Reactive / Async

Along the way we started thinking about non-blocking IO ...

Page 27: NetflixOSS   season 2 episode 2 - Reactive / Async

WSPerfLabhttps://github.com/Netflix-Skunkworks/WSPerfLab

Page 28: NetflixOSS   season 2 episode 2 - Reactive / Async

WSPerfLabhttps://github.com/Netflix-Skunkworks/WSPerfLab

Best case latency for response is ~155ms

Page 29: NetflixOSS   season 2 episode 2 - Reactive / Async
Page 30: NetflixOSS   season 2 episode 2 - Reactive / Async

RxNetty Performance

client:wrk -t 4 -c 400

server CPUs~2% idle

NOTE: It is still early days for RxNetty tuning; more to come

Page 31: NetflixOSS   season 2 episode 2 - Reactive / Async

Tuning for an acceptable latency distribution

client: ab

server CPUusage varieswith load

Page 32: NetflixOSS   season 2 episode 2 - Reactive / Async

RxNetty vs TomcatEvent loop model more efficient than thread pools:● Reduces thread CPU overheads● Reduced thread lock contention● Better work scheduling: platform chooses, instead of the

kernel scheduling threads● Warmer CPU caches and memory locality on NUMA:

event worker threads can have better CPU affinity

Page 33: NetflixOSS   season 2 episode 2 - Reactive / Async

RxNetty Micro BenchmarkingServer: AWS c3.xlarge, tuned to reduce perturbationsClient: Multi-threaded (wrk -t 4 -c 100/400), 1 min warmup● Sufficient load to exhaust CPU capacity.Active Benchmarking Methodology:● Tools: sysstat, perf_events, SystemTap, flame graphs, …● USE Method, static performance tuning, etc.● Target analyzed during benchmark confirm target results

and identify (and tune) true limiters.

Page 34: NetflixOSS   season 2 episode 2 - Reactive / Async

Approaching light speed...

Page 35: NetflixOSS   season 2 episode 2 - Reactive / Async

Hello World● All platforms are <100us for Hello World, so their CPU

overheads are already negligible for this workload.○ Consider application compute times of >1ms

● Hence testing “Hello Netflix” as well: a basic Netflix service Hello World with dependency requests.

● Although, Hello World max latency (not pictured) was still much higher for Tomcat...

Page 36: NetflixOSS   season 2 episode 2 - Reactive / Async

Visualizing Tomcat Overheads● Flame graph of

Java CPU timefor Hello Worldbenchmark

● Thread and I/Omanagementoverheads

Page 37: NetflixOSS   season 2 episode 2 - Reactive / Async

Visualizing RxNetty Overheads● Flame graph of Java CPU

time for Hello World● Time in read() and write()

(doing I/O; ie, doing “work”)dominates

● Flame graphs also studiedof kernel and user-time

● Many improvements foundand fixed

Page 38: NetflixOSS   season 2 episode 2 - Reactive / Async

Blog post forthcoming… Keywords:● Oracle JDK 1.8.0 (others tried); Xmx & Xms; different

GCs and settings, eg -XX:+UseConcMarkSweepGC● Apache-tomcat 7.0.54: tested BIO, NIO, APR;

maxThreads=150 or 512; maxQueueSize=up to 400; acceptCount=up to 100; disabled access log, ...

● Node.js 0.6.12 with clustering (faster than 0.10/0.11)● vert.x 2.1 with -instances 4● Java profilers: Google lightweight java profiler; JFR; …● perf_events; SystemTap; flame graphs, ...

Page 39: NetflixOSS   season 2 episode 2 - Reactive / Async

RxNetty & Karyon 2.0

@NiteshKant

Page 40: NetflixOSS   season 2 episode 2 - Reactive / Async

Netflix IPC Stack (1.0)Apache

HTTP Client

Eureka (Service Registry)

Server (Karyon)

Apache

Tomcat

Client

Hystrix

EVCache

Ribbon

Load Balancing

Eureka Integration

Metrics (Servo)

Bootstrapping (Governator)

Metrics (Servo)

Admin ConsoleHTTP

Eureka Integration

Registration

Fetch Registry

A Blocking Architecture

Page 41: NetflixOSS   season 2 episode 2 - Reactive / Async

Netflix IPC Stack (2.0)Client (Ribbon 2.0)

Eureka (Service Registry)

Server (Karyon)

Ribbon Transport

Load Balancing

Eureka Integration

Metrics (Servo)

Bootstrapping (Governator)

Metrics (Servo)

Admin Console

HTTP

Eureka Integration

Registration

Fetch Registry

Ribbon

Hystrix

EVCache

RxNetty

RxNetty

UDP

TCPWebSockets

SSE

A Completely Reactive

Architecture

Page 42: NetflixOSS   season 2 episode 2 - Reactive / Async

“We want an extremely performant IPC library”

Heard this before?

Page 43: NetflixOSS   season 2 episode 2 - Reactive / Async

Reinventing The Wheel?

Image Courtesy: Oxford Creativity

Finagle

Vert.x

Ratpack

Tons of

Netty based

Frameworks?

Page 44: NetflixOSS   season 2 episode 2 - Reactive / Async

On the lookout …..

● Low level control.○ Traffic Shaping. (Zuul)○ Backpressure.

● Netflix “fit”○ Reactive programming model.○ Netflix Components (Eureka, Archaius, Governator, etc.)

Page 45: NetflixOSS   season 2 episode 2 - Reactive / Async

RxNetty

Reactive Extensions To Netty

Nucleus of Netflix’s IPC stack

Powering Ribbon 2.0 & Karyon 2.0

https://github.com/Netflix/RxNetty

Page 46: NetflixOSS   season 2 episode 2 - Reactive / Async

Example (Server Sent Events)RxNetty.createHttpServer(8887, (request, response) -> { return Observable.interval(1, TimeUnit.SECONDS) .flatMap(interval -> { return response.writeAndFlush(new ServerSentEvent(...)); }); }, PipelineConfigurators.<ByteBuf>sseServerConfigurator()).start();

Server

Client

RxNetty.<ByteBuf, ServerSentEvent>createHttpClient("127.0.0.1", 8887, PipelineConfigurators.sseClientConfigurator()) .submit(HttpClientRequest.<ByteBuf>createGet("/")) .flatMap(response -> response.getContent()) .toBlocking().forEach(event -> System.out.println(event))

Page 47: NetflixOSS   season 2 episode 2 - Reactive / Async

data: interval: 0

data: interval: 1

data: interval: 2

data: interval: 3

Output …...

data: interval: 4

data: interval: 5

Page 48: NetflixOSS   season 2 episode 2 - Reactive / Async

Example (Stream Aggregation)

RxNetty.createHttpServer(8887, (request, response) -> { return Observable.interval(1, TimeUnit.SECONDS) .flatMap(interval -> { return response.writeAndFlush(new ServerSentEvent(...)); }); }, PipelineConfigurators.<ByteBuf>sseServerConfigurator()).start();{ } *3

Page 49: NetflixOSS   season 2 episode 2 - Reactive / Async

Example (Stream Aggregation)

Observable.merge(RxNetty.<ByteBuf, ServerSentEvent>createHttpClient("127.0.0.1", 8887...),

RxNetty.<ByteBuf, ServerSentEvent>createHttpClient("127.0.0.1", 8888...),

RxNetty.<ByteBuf, ServerSentEvent>createHttpClient("127.0.0.1", 8889...))).toBlocking().forEach(event -> System.out.println(event))

RxNetty.createHttpServer(8887, ...).start(); RxNetty.createHttpServer(8888, ...).start(); RxNetty.createHttpServer(8889, ...).start();

Page 50: NetflixOSS   season 2 episode 2 - Reactive / Async

data: interval (8887): 0

data: interval (8888): 0

data: interval (8887): 1

data: interval (8887): 2

Output …...

data: interval (8889): 0

data: interval (8888): 1

Page 51: NetflixOSS   season 2 episode 2 - Reactive / Async

Karyon 2.0

● Adds Netflix constructs (governator, eureka, archaius, etc.) on RxNetty.

● Provides extensions (servlet, jersey, etc.) to RxNetty.

● More palatable to application developers.

Page 52: NetflixOSS   season 2 episode 2 - Reactive / Async

Example @ArchaiusBootstrap

@KaryonBootstrap(name = "hello-netflix-oss")

@Modules(include = {HelloNossApp.KaryonJerseyModuleImpl.class, KaryonWebAdminModule.class, KaryonEurekaModule.class})

public final class HelloNossApp {

public static class KaryonJerseyModuleImpl extends KaryonJerseyModule {

protected void configure() {

super.configure();

bind(AuthenticationService.class).to(AuthenticationServiceImpl.class);

}

public int serverPort() { return 8888; }

public int shutdownPort() { return 8899; }

public void configureInterceptors(GovernatorHttpInterceptorSupport<ByteBuf, ByteBuf> interceptorSupport) {

interceptorSupport.forUri("/hello").interceptIn(AuthInterceptor.class);

}

}

}

Page 53: NetflixOSS   season 2 episode 2 - Reactive / Async

Ribbon 2Allen Wang

Page 54: NetflixOSS   season 2 episode 2 - Reactive / Async

● Tendency to become “fat” with boilerplate code

● Hystrix integration● Go “async”● “Declare” a client, rather than “write” a client

Ribbon 2.0 - Motivation

Page 55: NetflixOSS   season 2 episode 2 - Reactive / Async

Ribbon 2.0: Let’s tie ‘em up

Page 56: NetflixOSS   season 2 episode 2 - Reactive / Async

Ribbon 2.0 - New “ribbon” module● Template support for building HTTP request● Rx style non-blocking and blocking APIs● Hystrix built-in for fault tolerance ● Pluggable cache access with EVCache

implementation● Annotation based client creation as an

alternative

Page 57: NetflixOSS   season 2 episode 2 - Reactive / Async

Ribbon 2.0 - Annotation Examplepublic interface MovieService {

RibbonRequest<Recommendations> recommendationsByUserId(@Var("userId") String userId);

}

@TemplateName(“recommendations”)

@Http(method = HttpMethod.GET, uriTemplate="/users/{userId}/recommendations")

@Hystrix(fallbackHandler = RecommendationFallbackHandler.class)

@EvCache(name = "movie-rec", appName = "movieService", cacheKeyTemplate = "{userId}")

MovieService movieService = Ribbon.from(MovieService.class);

Observable<Recommendations> result =

movieService.recommendationsByUserId(“user1”)

.toObservable();

Page 58: NetflixOSS   season 2 episode 2 - Reactive / Async

Ribbon 2: Template ExampleHttpResourceGroup movieService = Ribbon.createHttpResourceGroup("movieService");HttpRequestTemplate<ByteBuf> template1 = movieService.newRequestTemplate("recommendationsByUserId", ByteBuf.class) .withMethod("GET") .withUriTemplate("/users/{userId}/recommendations") .withFallbackProvider(new RecommendationServiceFallbackHandler());

RibbonRequest<ByteBuf> request = template1.requestBuilder() .withRequestProperty("userId", “user1”).build();Observable<ByteBuf> result = request.toObservable(); // non blockingByteBuf result = request.execute(); // blocking

Page 59: NetflixOSS   season 2 episode 2 - Reactive / Async

Ribbon 2.0 - Other New Features

● Ribbon’s async module - “ribbon-transport”○ HTTP, TCP and UDP clients on top of RxNetty with

load balancing capability● New load balancing features

○ Command pattern load balancing APIs implemented with Rx for easy integration for third party client

○ Shuffle sharding server list for fault isolation

Page 60: NetflixOSS   season 2 episode 2 - Reactive / Async

Reactive outside Netflix

Page 61: NetflixOSS   season 2 episode 2 - Reactive / Async

RetrofitJake Wharton

Page 62: NetflixOSS   season 2 episode 2 - Reactive / Async

Retrofit

Example: GitHub API List Contributors

GET /repos/:owner/:repo/contributors

Page 63: NetflixOSS   season 2 episode 2 - Reactive / Async

Retrofit

GET /repos/:owner/:repo/contributors

interface GitHub { List<Contributor> contributors( String owner, String repo);}

class Contributor { String login; long contributions;}

Page 64: NetflixOSS   season 2 episode 2 - Reactive / Async

Retrofit

GET /repos/:owner/:repo/contributors

interface GitHub { @GET("/repos/{owner}/{repo}/contributors") List<Contributor> contributors( String owner, String repo);}

Page 65: NetflixOSS   season 2 episode 2 - Reactive / Async

Retrofit

GET /repos/:owner/:repo/contributors

interface GitHub { @GET("/repos/{owner}/{repo}/contributors") List<Contributor> contributors( @Path("owner") String owner, @Path("repo") String repo);}

Page 66: NetflixOSS   season 2 episode 2 - Reactive / Async

RetrofitRestAdapter restAdapter = new RestAdapter.Builder() .setEndpoint("https://api.github.com/") .build();

GitHub gitHub = restAdapter.create(GitHub.class);

List<Contributor> contributors = gitHub.contributors("netflix", "rxjava");

Page 67: NetflixOSS   season 2 episode 2 - Reactive / Async

RetrofitList<Contributor> contributors = gitHub.contributors("netflix", "rxjava");

for (Contributor c : contributors) { println(c.login + '\t' + c.contributions);}

1483 benjchristensen225 zsxwing167 samuelgruetter146 jmhofer137 akarnokd105 DavidMGross102 AppliedDuality...

Page 68: NetflixOSS   season 2 episode 2 - Reactive / Async

RetrofitRestAdapter restAdapter = new RestAdapter.Builder() .setEndpoint("https://drive.google.com/api/") .setConverter(new ProtoConverter()) .build();

Page 69: NetflixOSS   season 2 episode 2 - Reactive / Async

Retrofitinterface GitHub { @GET("/repos/{owner}/{repo}/contributors") List<Contributor> contributors( @Path("owner") String owner, @Path("repo") String repo);}

Page 70: NetflixOSS   season 2 episode 2 - Reactive / Async

Retrofitinterface GitHub { @GET("/repos/{owner}/{repo}/contributors?anon=true") List<Contributor> contributors( @Path("owner") String owner, @Path("repo") String repo);}

Page 71: NetflixOSS   season 2 episode 2 - Reactive / Async

Retrofitinterface GitHub { @GET("/repos/{owner}/{repo}/contributors") List<Contributor> contributors( @Path("owner") String owner, @Path("repo") String repo, @Query("anon") boolean includeAnonymous);}

Page 72: NetflixOSS   season 2 episode 2 - Reactive / Async

Retrofitinterface GitHub { @POST("/repos/{owner}/{repo}/hooks") Response createHook( @Path("owner") String owner, @Path("repo") String repo, @Body Hook hook);}

class Hook { String name; Map<String, Object> config; List<String> events; boolean active;}

Page 73: NetflixOSS   season 2 episode 2 - Reactive / Async

RetrofitRestAdapter restAdapter = new RestAdapter.Builder() .setEndpoint("https://drive.google.com/api/") .setConverter(new ProtoConverter()) .setClient(new OkClient()) .build();

Page 74: NetflixOSS   season 2 episode 2 - Reactive / Async

RetrofitOkHttpClient client = new OkHttpClient();client.setProtocols(Arrays.asList(HTTP_2));

RestAdapter restAdapter = new RestAdapter.Builder() .setEndpoint("https://drive.google.com/api/") .setConverter(new ProtoConverter()) .setClient(new OkClient(client)) .build();

Page 75: NetflixOSS   season 2 episode 2 - Reactive / Async

Retrofit● Form URL encoding● Response streaming● Request interceptors● Dynamic headers● Android

● Multipart● Logging● Mock RestAdapter● Asynchronous invoke● AppEngine

...and more!

Page 76: NetflixOSS   season 2 episode 2 - Reactive / Async

Retrofit + RxJavainterface GitHub { @GET("/repos/{owner}/{repo}/contributors") List<Contributor> contributors( @Path("owner") String owner, @Path("repo") String repo);}

Page 77: NetflixOSS   season 2 episode 2 - Reactive / Async

Retrofit + RxJavainterface GitHub { @GET("/repos/{owner}/{repo}/contributors") Observable<List<Contributor>> contributors( @Path("owner") String owner, @Path("repo") String repo);}

Page 78: NetflixOSS   season 2 episode 2 - Reactive / Async

Retrofit + RxJavagitHub.contributors("netflix", "rxjava") .lift(flattenList()) .forEach(c -> println(c.login + '\t' + c.contributions));

1483 benjchristensen225 zsxwing167 samuelgruetter146 jmhofer137 akarnokd105 DavidMGross102 AppliedDuality...

Page 79: NetflixOSS   season 2 episode 2 - Reactive / Async

Retrofit + RxJavainterface GitHub { @GET("/repos/{owner}/{repo}/contributors") Observable<List<Contributor>> contributors( @Path("owner") String owner, @Path("repo") String repo);

@GET("/users/{user}") Observable<User> user( @Path("user") String user);}

Page 80: NetflixOSS   season 2 episode 2 - Reactive / Async

Retrofit + RxJavagitHub.contributors("netflix", "rxjava") .lift(flattenList()) .flatMap(c -> gitHub.user(c.login)) .forEach(user -> println(user.name));

Ben ChristensenShixiong ZhunullJoachim HofernullDavid Grossnull...

Page 81: NetflixOSS   season 2 episode 2 - Reactive / Async

Retrofit + RxJavagitHub.contributors("netflix", "rxjava") .lift(flattenList()) .flatMap(c -> gitHub.user(c.login)) .filter(user -> user.name != null) .forEach(user -> println(user.name));

Ben ChristensenShixiong ZhuJoachim HoferDavid GrossMatthias KäpplerJustin RyanMairbek Khadikov...

Page 82: NetflixOSS   season 2 episode 2 - Reactive / Async

Retrofit + RxJavainterface GitHub { @GET("/repos/{owner}/{repo}/contributors") Observable<List<Contributor>> contributors( @Path("owner") String owner, @Path("repo") String repo);

@GET("/users/{user}/starred") Observable<List<Repo>> starred( @Path("user") String user);}

Page 83: NetflixOSS   season 2 episode 2 - Reactive / Async

Retrofit + RxJavagitHub.contributors("netflix", "rxjava") .lift(flattenList()) .flatMap(c -> gitHub.starred(c.login)) .lift(flattenList()) .groupBy(r -> r.full_name) .flatMap(g -> g.count().map(c -> c + "\t" + g.getKey())) .toSortedList((a, b) -> b.compareTo(a)) .lift(flattenList()) .take(8) .forEach(Main::println);

Page 84: NetflixOSS   season 2 episode 2 - Reactive / Async

Retrofit + RxJava

7 Netflix/RxJava2 twitter/finagle2 scala/scala2 mbostock/d32 kpelykh/docker-java2 Netflix/zuul2 Netflix/feign2 Netflix/archaius

Page 85: NetflixOSS   season 2 episode 2 - Reactive / Async

Retrofit + RxJavagitHub.contributors("square", "retrofit") .lift(flattenList()) .flatMap(c -> gitHub.starred(c.login)) .lift(flattenList()) .groupBy(r -> r.full_name) .flatMap(g -> g.count().map(c -> c + "\t" + g.getKey())) .toSortedList((a, b) -> b.compareTo(a)) .lift(flattenList()) .take(8) .forEach(Main::println);

Page 86: NetflixOSS   season 2 episode 2 - Reactive / Async

gitHub.contributors("square", "retrofit") .lift(flattenList()) .flatMap(c -> gitHub.starred(c.login)) .lift(flattenList()) .filter(r -> !r.full_name.startsWith("square/")) .groupBy(r -> r.full_name) .flatMap(g -> g.count().map(c -> c + "\t" + g.getKey())) .toSortedList((a, b) -> b.compareTo(a)) .lift(flattenList()) .take(8) .forEach(Main::println);

Retrofit + RxJava

Page 87: NetflixOSS   season 2 episode 2 - Reactive / Async

Retrofit + RxJava

4 frankiesardo/auto-parcel4 Comcast/FreeFlow3 xxv/android-lifecycle3 robolectric/robolectric3 inmite/android-butterknife-zelezny3 google/auto3 facebook/rebound3 etsy/AndroidStaggeredGrid3 Netflix/RxJava

Page 88: NetflixOSS   season 2 episode 2 - Reactive / Async

Retrofitsquare.github.io/retrofit

Page 89: NetflixOSS   season 2 episode 2 - Reactive / Async

CouchbaseMatt Ingenthron

Page 90: NetflixOSS   season 2 episode 2 - Reactive / Async

Couchbase is...

Document-oriented (JSON) database ...Low latency & high throughput …Highly available and scalable ...

Page 91: NetflixOSS   season 2 episode 2 - Reactive / Async

Motivations with Couchbase Java

➢ Simplify ...➢ Even *more* performance➢ Build for the JVM, not for the Java language

○ Have Scala, JRuby already being worked on

Page 92: NetflixOSS   season 2 episode 2 - Reactive / Async

History of Concurrency

Core Java component, spymemcached, has used Futures since 2006 or so.➢ Always been ahead of most other database

like clients, however…➢ Difficult for developers to code against

○ Dumb benchmarks turn into FAQs

Page 93: NetflixOSS   season 2 episode 2 - Reactive / Async

while (true) { client.set("foo", "bar") };

Page 94: NetflixOSS   season 2 episode 2 - Reactive / Async

while (true) { client.set("foo", "bar") };

Signature: public OperationFuture<java.lang.Boolean> set(java.lang.String key, java.lang.Object value);

Page 95: NetflixOSS   season 2 episode 2 - Reactive / Async

while (true) { client.set("foo", "bar").get() };

Page 96: NetflixOSS   season 2 episode 2 - Reactive / Async

What we’re Building On

➢ A set of new components○ RxJava (both internal and public interface)○ Netty (internal only)○ LMAX Disruptor

Page 97: NetflixOSS   season 2 episode 2 - Reactive / Async

RxJava for Couchbase

➢ Will be part of the client’s public API○ Helps us support Java 8, but is also backward

compatible■ Generally get a great Java 8 experience for free!

➢ Also using RxJava extensively internally○ Breaking the project into core and language façade

helps build toward Scala and others

Page 98: NetflixOSS   season 2 episode 2 - Reactive / Async

Getting Referenced Elements client.asyncGet("posts::1").addListener(future -> { if (future.isDone() && !future.isCancelled()) { String content = (String) future.get(); List<String> ids = comments_ids_from_json(content);

int i = 0; for (String id : ids) { if (i++ == 5) { break; } client.asyncGet(id).addListener(future1 -> { if (future1.isDone() && !future1.isCancelled()) { System.out.println(future1.get()); } }); } } });

Page 99: NetflixOSS   season 2 episode 2 - Reactive / Async

Getting Referenced Elements Rx Way

bucket .get("posts::1") .map(document -> document.content().getArray("comments")) .flatMap(comments -> Observable.from(comments.toList())) .take(5) .filter(o -> o instanceof String) .flatMap(o -> bucket.get((String) o)) .subscribe(doc -> System.out.println(doc.content()));

Page 100: NetflixOSS   season 2 episode 2 - Reactive / Async

Beauty of Error Handling return super.registerBucket(name, password).flatMap(new Func1<Boolean, Observable<BucketStreamingResponse>>() { @Override public Observable<BucketStreamingResponse> call(Boolean aBoolean) { return cluster().send(new BucketStreamingRequest(TERSE_PATH, name, password)); } }).onErrorResumeNext(new Func1<Throwable, Observable<BucketStreamingResponse>>() { @Override public Observable<BucketStreamingResponse> call(Throwable throwable) { return cluster().send(new BucketStreamingRequest(VERBOSE_PATH, name, password)); } })

Page 101: NetflixOSS   season 2 episode 2 - Reactive / Async

CouchbaseReact to our Dev Preview 2!

Michael Nitschinger’s blog:http://blog.couchbase.com/couchbase-java-sdk-200-developer-preview-2

Page 102: NetflixOSS   season 2 episode 2 - Reactive / Async

Five Minutes of FuturesWill Sargent, Typesafe

Page 103: NetflixOSS   season 2 episode 2 - Reactive / Async

Reactive Interface In Theory

Looks like: ● Responsive?● Scalable?● Resilient?● Event-Driven?

Page 104: NetflixOSS   season 2 episode 2 - Reactive / Async

Reactive Interface in Practice

Really looks like this:

trait FooService { def find(fooId:FooID) : Future[Option[Foo]]}

Page 105: NetflixOSS   season 2 episode 2 - Reactive / Async

Plain English

“Non-blocking” / “Async” means either Future[T] or Actor model

Page 106: NetflixOSS   season 2 episode 2 - Reactive / Async

Choices

To Akka, or Not to Akka?

Page 107: NetflixOSS   season 2 episode 2 - Reactive / Async

Akka with Futures

Akka to Future:val myFuture = actorRef ? messageFuture to Akka:futureStuff pipeTo actorRef

Page 108: NetflixOSS   season 2 episode 2 - Reactive / Async

Assuming a Services based API

val fooFuture = fooService.get(1)val barFuture = barService.get(2)val quuxFuture = quuxService.get(3)

...Simple, right?

Page 109: NetflixOSS   season 2 episode 2 - Reactive / Async

Not so fast

val fooFuture = fooService.get(1)val barFuture = barService.get(foo.barId)val quuxFuture = quuxService.get(bar.quuxId)

...wat.

Page 110: NetflixOSS   season 2 episode 2 - Reactive / Async

FLATMAP THAT

fooService.get(1).map { maybeFoo => maybeFoo.flatMap { foo => val barFuture = barService.get(foo.barId) // do the same for bar & quux }}

Page 111: NetflixOSS   season 2 episode 2 - Reactive / Async

For comprehensions!

for { maybeFoo <- fooService.get(1)} yield { for { // Option / Future does not compose foo <- maybeFoo } yield ...}

Page 112: NetflixOSS   season 2 episode 2 - Reactive / Async

Scala Async!

async { val maybeFoo = await(fooService.get(1)) maybeFoo.flatMap { foo => val bar = await(barService.get(2)) }}

Page 113: NetflixOSS   season 2 episode 2 - Reactive / Async

Scala Async Sadness

COMPILE ERROR.

“await must not be used inside a closure nested within an async block” == no flatMap of that.

Page 114: NetflixOSS   season 2 episode 2 - Reactive / Async

Monads don’t compose

But before reaching for readers/transformers:● Use small methods● Short circuit● Use loan patterns

Page 115: NetflixOSS   season 2 episode 2 - Reactive / Async

Use Small Methods

def foo2bar(ff:Future[Foo]) : Future[Bar]

Page 116: NetflixOSS   season 2 episode 2 - Reactive / Async

Short Circuit

implicit def flatten[A](fofoa: Future[Option[Future[Option[A]]]]): Future[Option[A]] = fofoa.flatMap(_.getOrElse(Future.successful(None)))

Page 117: NetflixOSS   season 2 episode 2 - Reactive / Async

Loan Pattern def getFuture[T](futureOptionBlock: Future[Option[T]])(foundBlock: (T => Future[Result])): Future[Result] = { futureOptionBlock.flatMap { case Some(found) => foundBlock(found) case None => Future.successful(NotFound) } }

Page 118: NetflixOSS   season 2 episode 2 - Reactive / Async

What’s next?

Demos, food and drinks!

August 20th - NetflixOSS and Cloud Security