51
HIGH PERFORMANCE MICROSERVICES WITH RATPACK AND SPRING BOOT DAN WOODS @DANVELOPER

High Performance Microservices with Ratpack and Spring Boot

Embed Size (px)

Citation preview

HIGH PERFORMANCE MICROSERVICES WITH RATPACK AND SPRING BOOT

DAN WOODS @DANVELOPER

SENIOR SOFTWARE ENGINEER

WORKING ON CLOUD & DEVOPS TOOLING

O'REILLY AUTHOR, 2016

LEARNING RATPACK

SUPPORT YOUR COMMUNITY.

ALL ROYALTIES FOR LEARNING RATPACK GO DIRECTLY TO GR8LADIES

HTTP://GR8LADIES.ORG

ROUGH AGENDA

> Brief overview> Execution model

> Registries> Registries + Spring

> Microservice example> Performance numbers

OVERVIEW

Ratpack is a high throughput, non-blocking, asynchronous, reactive web framework for the JVM

Built on Java 8, has first class support Groovy

Realistically, works great with every JVM language

@Grab('io.ratpack:ratpack-groovy:1.4.0-rc-2')

import static ratpack.groovy.Groovy.ratpack

ratpack { handlers { get { render "Hello World!" } }}

package app;

import ratpack.server.RatpackServer

public class Main { public static void main(String args[]) throws Exception { RatpackServer.start(spec -> spec .handlers(chain -> chain .get(ctx -> ctx.render("Hello World!")) ) ); }}

No opinions about how you build your application

Make common things as easy as possible

Explicit, no convention-over-configuration

First class concerns: performance, developer experience, packaging

EXECUTION MODEL

Asynchronous programming is hard!

Traditionally there is a temporal disconnect between calling an async function and getting its response.

public void asyncDbCall(Long productId, Consumer callback) { Product product = ... async db call + future + wait for future callback.apply(product);}

Bad things happen!final List products = new ArrayList();

Long productId = request.pathTokens.productId;db.asyncDbCall(productId, product -> products.add(product));

Long nextProductId = productId+1;db.asyncDbCall(nextProductId, product -> products.add(product));

response.send(products);

There is no guarantee as to what order async calls will be executed!

final List products = new ArrayList();

String productId = request.pathTokens.productId;db.asyncDbCall(productId, product -> products.add(product)); // call may return first, maybe not!

String nextProductId = productId+1;db.asyncDbCall(nextProductId, product -> products.add(product)); // call may return second, may not!

response.send(products); // what even is the value of `products` here!

Luckily, Ratpack's execution model provides deterministic processing of asynchronous calls

An Execution in Ratpack is the equivalent construct to a continuation

Ratpack Promise type denotes a frame in the continuation (a.k.a "execution segments")

Execution segments are guaranteed to execute in their given order.

RATPACK MAINTAINS A SMALL THREAD POOL FOR ALL ITS PROCESSING

(TYPICALLY 2 * NUM CPU CORES)

While an execution segment is processing, its thread is able to handle other processing and requests

Ratpack ensures the resources given to your application are being efficiently utilized

Ratpack's RxJava integration provides a scheduler that fits Observable into the execution model

Provides an implementation of Reactive Streams, which also fits into the execution model

REGISTRIES

Abstraction over dependency injection

Provides a basic component binding infrastructure

REGISTRIES ARE EVERYWHERE IN

RATPACK

CAN BE BACKED BY ANY COMPONENT-PROVIDING SYSTEMSPRING BOOT AND GUICE NATIVELY SUPPORTED

Can quickly prototype without any DI system public static void main(String[] args) throws Exception { RatpackServer.start(spec -> spec .registryOf(r -> r.add(new MyAsyncDbService())) // bind my service in the registry .handlers(chain -> chain .get(ctx -> { MyAsyncDbService db = ctx.get(MyAsyncDbService.class); // retrieve it later // ... }) ) ); }

Integrate with Spring Boot when you're ready!@SpringBootApplication // Spring Boot!!public class Main {

@Bean public MyAsyncDbService myAsyncDbService() { // bind it as a bean! return new MyAsyncDbService(); }

public static void main(String[] args) { // turn Spring Boot into a Ratpack registry! Registry registry = ratpack.spring.Spring.spring(Main.class);

RatpackServer.start(spec -> spec .registry(registry) .handlers(chain -> chain .get(ctx -> { MyAsyncDbService db = ctx.get(MyAsyncDbService.class); // retrieve your service! // ... }) ) ) }}

Architect your application using all the helpful aspects of Spring Boot, while using Ratpack under the hood for

high throughput, reactive, async, non-blocking processing

MICROSERVICE EXAMPLECODE: HTTPS://GITHUB.COM/DANVELOPER/S1P-HIGH-PERF-MICROSERVICES

PERFORMANCE NUMBERS

A quick tirade about performance testing...

Generalizing performance numbers for all use cases is impossible

The numbers provided should be used as a guide, not the word of law

"YOU SHOULDN'T TEST ON THE

CLOUD!!"

Unrealistic.Modern performance testing needs to be about how much

burst traffic can be sustained, without your service falling over, before you can horizontally scale it.

PERFORMANCE NUMBERSHTTPS://GITHUB.COM/DANVELOPER/S1P-HIGH-PERF-MICROSERVICES/BLOB/MASTER/README.MD

FUTURE POSSIBILITIES

Spring 5 will be all reactive; will be possible to integrate Spring controllers into Ratpack

Provide a scheduler to Project Reactor so that Flex and Mono types can utilize the execution model

Questions?