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
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 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 – 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
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 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 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
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
Top Related