43
Async servers and clients in Rest.li 1

Async servers and clients in Rest.li

Embed Size (px)

Citation preview

Async servers and clients in

Rest.li

1

(Please read the speaker notes)

2

What is this Rest.li thing

you speak about?

“Rest.li is an open source REST framework for building robust,

scalable RESTful architectures using type-safe bindings and

asynchronous, non-blocking I/O.”

3

The Stack

Rest.li Data and REST API

D2 Dynamic Discovery and load balancing

R2 Network communication

4

What do you by mean

by async?

5

What do you mean by

async (I/O)?

6

Request 1

Request 2

Blocked on I/O

Tim

e

Sync Async

Free CPU

Rest.li is async and non-blocking

under the hood!

7

Rest.li

D2

R2

8

How is R2 async and

non-blocking?

• Netty based async client

• Jetty based server – configuration change (link) needed to run

the server in async mode

Rest.li

D2

R2

9

How is D2 async and

non-blocking?

• All communication with ZooKeeper uses the asynchronous

APIs

• ZooKeeper pushes data to clients in case of updates

Rest.li

D2

R2

10

How is Rest.li async

and non-blocking?

• Does not handle I/O

• I/O is taken care of by R2

• R2 is async and non-blocking!

• Uses ParSeq when interacting with and delegating to

application code.

Rest.li

D2

R2

11

Async Rest.li Servers

12

Async Server

Implementations

• The Rest.li framework is async and non-blocking under the

hood.

• As a result of this, if you do any blocking work in your method

implementation it can negatively impact your application

throughput as threads are held up by your application which

are needed by Rest.li. (if you are using Rest.li in async

mode)

13

Async Server

Implementations -

Options

1. Callback based

2. ParSeq based

14

Async Server – Callback

@RestMethod.Get

public void get(final Long id, @CallbackParam final Callback<Greeting> callback) {

String path = "/data/" + id;

_zkClient.getData(path, false, new DataCallback() {

public void processResult(int i, String s, Object o, byte[] b, Stat st) {

if (b.length == 0) {

callback.onError(new RestLiServiceException(HttpStatus.S_404_NOT_FOUND));

}

else {

callback.onSuccess(buildGreeting(b));

}

}

}, null);

} 15

Async Server –

Callback Signature

@RestMethod.Get

public void get(final Long id, @CallbackParam final Callback<Greeting> callback)

com.linkedin.common.Callback

16

Async Server – Filling

out the callback

_zkClient.getData(path, false, new DataCallback() {

public void processResult(int i, String s, Object o, byte[] b, Stat st) {

if (b.length == 0) {

callback.onError(new RestLiServiceException(HttpStatus.S_404_NOT_FOUND));

}

else {

callback.onSuccess(buildGreeting(b));

}

}

}, null);17

Async Server – Callback

@RestMethod.Get

public void get(final Long id, @CallbackParam final Callback<Greeting> callback) {

String path = "/data/" + id;

_zkClient.getData(path, false, new DataCallback() {

public void processResult(int i, String s, Object o, byte[] b, Stat st) {

if (b.length == 0) {

callback.onError(new RestLiServiceException(HttpStatus.S_404_NOT_FOUND));

}

else {

callback.onSuccess(buildGreeting(b));

}

}

}, null);

} 18

Async server - ParSeq

19

Key ParSeq Concepts

• Promise Fully async Java Future + listener mechanism.

• Task Basic unit of work that is similar to Java Callable.

Task<T>

• Engine runs Tasks.

• Context Used by a Task to run sub-Tasks.

• Composition par and seq

(link)

20

Async Server – ParSeq

@RestMethod.Get

public Task<Greeting> get(final Long id) {

final Task<FileData> fileDataTask = buildFileDataTask();

final Task<Greeting> mainTask = Tasks.callable("main", new Callable<Greeting>() {

@Override

public Greeting call() throws Exception {

FileData fileData = fileDataTask.get();

return buildGreetingFromFileData(id, fileData);

}

});

return Tasks.seq(fileDataTask, mainTask);

}

21

Async Server – ParSeq

signature

@RestMethod.Get

public Task<Greeting> get(final Long id)

22

Async Server – ParSeq body

final Task<FileData> fileDataTask = buildFileDataTask();

23

Async Server – ParSeq body

final Task<Greeting> mainTask = Tasks.callable("main", new Callable<Greeting>() {

@Override

public Greeting call() throws Exception {

FileData fileData = fileDataTask.get();

return buildGreetingFromFileData(id, fileData);

}

});

24

Async Server –

assembling the Tasks

return Tasks.seq(fileDataTask, mainTask);

25

fileDataTask mainTask

Async Server – ParSeq

@RestMethod.Get

public Task<Greeting> get(final Long id) {

final Task<FileData> fileDataTask = buildFileDataTask();

final Task<Greeting> mainTask = Tasks.callable("main", new Callable<Greeting>() {

@Override

public Greeting call() throws Exception {

FileData fileData = fileDataTask.get();

return buildGreetingFromFileData(id, fileData);

}

});

return Tasks.seq(fileDataTask, mainTask);

}

26

Async Server – ParSeq

• Can use this approach to build complex call graphs and

return the final Task. (more on this later).

• Can use ParSeq tracing

• No callback hell!

27

Async Rest.li Clients

28

Async Rest.li requests

• RestClient is async and non-blocking under the hood – it

uses ParSeq and Netty.

• Applications can still block the thread if they block on the

results of the Rest.li call!

Response response = _restClient.sendRequest(BUILDER.get().id(1L).build()).get();Fortune fortune = response.getEntity();

Blocking on the result of a Future

29

Async Rest.li requests

Two Options:

1. Callback based API

2. Use a ParSeqRestClient – This is a wrapper around a

RestClient that returns ParSeq Tasks and Promises.

30

Async Rest.li requests

– Callbacks

Callback<Response<Greeting>> cb = new Callback() {

void onSuccess(Response<Greeting> response) {

// do something with the returned Greeting

}

void onError(Throwable e) {

// whoops

}

}

Request<Greeting> getRequest = BUILDERS.get().id(1L).build();

_restClient.sendRequest(getRequest, new RequestContext(), cb);

31

Async Rest.li requests – defining

a Callback

Callback<Response<Greeting>> callback = new Callback() {

void onSuccess(Response<Greeting> response) {

// do something with the returned Greeting

}

void onError(Throwable e) {

// whoops

}

}

32

Async Rest.li requests – sending

the request

Request<Greeting> getRequest = BUILDERS.get().id(1L).build();

_restClient.sendRequest(getRequest, new RequestContext(), callback);

33

Async Rest.li requests – using

ParSeq

• Callback based API is good for simple use cases (one or two

requests and you are done.)

• But it is hard to express more complicated call flows using the

CallbackAPI

Callback ParSeq

34

Async Rest.li requests – using

ParSeq

a1 a2 a3

b1 b2

c1

35

Async Rest.li requests – using

ParSeq

Task<Response<?>> a1ResponseTask =

_parseqRestClient.createTask(a1Request);

Task<Response<?>> a2ResponseTask =

_parseqRestClient.createTask(a2Request);

Task<Response<?>> a3ResponseTask =

_parseqRestClient.createTask(a3Request); a1 a2 a3

b1 b2

c1

36

Async Rest.li requests – using

ParSeq

Task<Response<?>> b1ResponseTask = Tasks.callable("", new Callable<Task<Response<?>>() {

@Override

public Task<Response<?>> call() throws Exception {

Response<?> a1Response = a1ResponseTask.get();

// Similarly, access the results from a2 and a3 as well

// use this to build request b1Request

return _parseqRestClient.createTask(b1Request)

}

});

Task<Response<?>> b2ResponseTask = _parseqRestClient.createTask(b2Request);

a1 a2 a3

b1 b2

c1

37

Async Rest.li requests – using

ParSeq

Task<Response<?>> c1ResponseTask = Tasks.callable("", new Callable<Task<Response<?>>() {

@Override

public Task<Response<?>> call() throws Exception {

Response<?> b1Response =

b1ResponseTask.get();

Response<?> b2Response =

b2ResponseTask.get();

// use b1Response and b2Response for

// c1Request

return _parseqRestClient.createTask(c1Request)

}

});

a1 a2 a3

b1 b2

c1

38

Async Rest.li requests – using

ParSeq

_engine.run(Tasks.seq(

Tasks.par(a1ResponseTask, a2ResponseTask, a3ResponseTask), Tasks.par(b1ResponseTask, b2ResponseTask),c1ResponseTask));

a1 a2 a3

b1 b2

c1

39

Conclusion

• Rest.li is async and non-blocking under the hood

• You can use Callbacks and ParSeq Tasks and Promises to

write async Rest.li clients and servers

40

Links and references

• Rest.li user guide https://github.com/linkedin/rest.li/wiki/Rest.li-

User-Guide

• Asynchronous servers and clients in Rest.li

https://github.com/linkedin/rest.li/wiki/Asynchronous-Servers-

and-Clients-in-Rest.li

• ParSeq https://github.com/linkedin/parseq

41

Me.

https://www.linkedin.com/in/parikhkaran

https://github.com/karanparikh

http://karanparikh.com/

42

Thanks!

43