gRPC vs REST: let the battle begin!
JavaDay, November 4, 2017
Alex Borysov, Software Engineer @ Google
Mykyta Protsenko, Software Engineer @ Roku
Who are we?
Mykyta Protsenko
Software Engineer @ Roku
• passionate about all things scalable
• 18+ years in software engineering
• Author of Henka
REST vs gRPC
Alex Borysov
Software Engineer @ Google
• large scale systems developer
• 11+ years in software engineering
• Active gRPC user
REST vs gRPC
@aiborisov
@mykyta_p
@aiborisov
@mykyta_p
@aiborisov
@mykyta_p
JSON over HTTP
@aiborisov
@mykyta_p
I am getting frustrated by the number of people calling any
HTTP-based interface a REST API.
Roy Fielding
http://roy.gbiv.com/untangled/2008/rest-apis-must-be-hypertext-driven
@aiborisov
@mykyta_p
@aiborisov
@mykyta_p
@aiborisov
@mykyta_p
RESTful API
GET /user/15
{
“name”: “John Doe”,
“email”:“john.doe@gmail.com”,
...
}
non-RESTful API
GET /last_search?page=2
{
“products”: [...]
...
}
@aiborisov
@mykyta_p
What is gRPC?
gRPC stands for gRPC Remote Procedure Calls.
A high performance, general purpose, feature-rich
RPC framework.
Part of Cloud Native Computing Foundation cncf.io
HTTP/2 and mobile first.
Open sourced version of Stubby RPC used in Google.
@aiborisov
@mykyta_p
RPC?! But...
AMF?
RMI?
CORBA?
@aiborisov
@mykyta_p
gRPC is not RMI
Maitainability
Ease of use
Performance
Scalability
L
e
s
s
o
n
s
Years of using Stubby
@aiborisov
@mykyta_p
What is gRPC?
Abstractions and best practices on how to design
RPCs.
Default implementation(s) from Google.
Extension points to plug custom implementations and
modifications.
Supports 10+ programming languages.
@aiborisov
@mykyta_p
gRPC Interoperability
Java
Service
Python
Service
GoLang
Service
C++
Service
gRPC
Service
gRPC
Stub
gRPC
Stub
gRPC
Stub
gRPC
Stub
gRPC
Service
gRPC
Service
gRPC
Service
gRPC
Stub
@aiborisov
@mykyta_p
Apples to Oranges?
@aiborisov
@mykyta_p
Microservices?
@aiborisov
@mykyta_p
Microservices?
How to draw an owl?
@aiborisov
@mykyta_p
Microservices?
How to draw an owl?
How to build microservices?
@aiborisov
@mykyta_p
Microservices?
How to draw an owl?
How to build microservices?
Draw some circles.
@aiborisov
@mykyta_p
Microservices?
How to draw an owl?
How to build microservices?
Draw some circles.
Take XYZ framework.
@aiborisov
@mykyta_p
Microservices?
How to draw an owl?
How to build microservices?
Draw the REST of the owlDraw some circles.
Take XYZ framework.
@aiborisov
@mykyta_p
Microservices?
How to draw an owl?
How to build microservices?
Draw the REST of the owl
Write your microservices!
Draw some circles.
Take XYZ framework.
@aiborisov
@mykyta_p
Microservices
@aiborisov
@mykyta_p
Microservices
@aiborisov
@mykyta_p
Microservices
@aiborisov
@mykyta_p
Microservices
@aiborisov
@mykyta_p
Remote Calls
@aiborisov
@mykyta_p
Call Flow
@aiborisov
@mykyta_p
Service Discovery?
?
?
?
?
?
?
@aiborisov
@mykyta_p
Multiple Instances
#1
#N
#2
. . .
@aiborisov
@mykyta_p
Multiple Instances
#1
#N
#2
?
?
?
. . .
@aiborisov
@mykyta_p
Call Flow
@aiborisov
@mykyta_p
Call Flow
@aiborisov
@mykyta_p
Call Flow
@aiborisov
@mykyta_p
Call Flow
@aiborisov
@mykyta_p
Call Flow
@aiborisov
@mykyta_p
Slow Services?
@aiborisov
@mykyta_p
Failure Scenarios
@aiborisov
@mykyta_p
A distributed system is one in which the failure of a
computer you didn't even know existed can render your own
computer unusable.
Leslie Lamport, 1987
https://www.microsoft.com/en-us/research/wp-content/uploads/2016/12/Distribution.pdf
@aiborisov
@mykyta_p
Fault Tolerance
@aiborisov
@mykyta_p
Microservices?! But...
Performance Hit?
Service Discovery?
Load Balancing?
Fault Tolerance?
Monitoring?
Testing?
@aiborisov
@mykyta_p
Microservices?! But...
Performance Hit?
Service Discovery?
Load Balancing?
Fault Tolerance?
Monitoring?
Testing?
@aiborisov
@mykyta_p
Sample Problem
Client
@aiborisov
@mykyta_p
Sample Problem: Aggregator
Src
#2
Src
#1
Aggr
...
Src
#X
Client
@aiborisov
@mykyta_p
Heterogeneous Data Format
Src
#2
Src
#1
Aggr
...
Src
#X
<XML>...<XML>
{JSON}
Binary 110011
[ Unified Format ]
Client
@aiborisov
@mykyta_p
REST: It’s All About Resources
@aiborisov
@mykyta_p
REST: Call Hierarchy
Controller
Service
Data Source A
. . .
Data Source N
RestTemplate
RestTemplate
RestTemplate
@aiborisov
@mykyta_p
REST: Data Source
JSON
URL: http://zrada.com/content/11
{
"id": 11,
"content": "EJB 2.1",
"next_uri": "/content/12"
}
XML
URL: http://peremoga.com/content/22
<ContentResponse>
<id>22</id>
<content>JavaDay is live!</content>
</ContentResponse>
@aiborisov
@mykyta_p
REST: Data Source
...
ResponseEntity<Content> contentEntity = restTemplate.getForEntity(
url + "{content_id}"
Content.class,
ImmutableMap.of("content_id", contentId));
...
@aiborisov
@mykyta_p
REST: Service
public class AggregatingService {
public AggregatedContent fetch(int id) {
...
return new AggregatedContent(...);
}
}
public class AggregatedContent {
private final Integer id; // 115
private final String type; // ZRADA
private final String content; // Политики украли у детей...
private final Integer nextId; // 116
@aiborisov
@mykyta_p
REST: Service
public class AggregatingService {
public AggregatedContent fetch(int id) {
...
return new AggregatedContent(...);
}
}
public class AggregatedContent {
private Integer id;
private String type;
private String content;
private Integer nextId;
@aiborisov
@mykyta_p
REST: Service
public class AggregatingService {
public AggregatedContent fetch(int id) {
...
return new AggregatedContent(...);
}
}
public class AggregatedContent {
private Integer id; // 115
private String type; // ZRADA
private String content; // EJB 2.1
private Integer nextId; // 116
@aiborisov
@mykyta_p
REST: Service
public class AggregatingService {
public AggregatedContent fetch(int id) {
...
return new AggregatedContent(...);
}
}
public class AggregatedContent {
private Integer id; // 115
private String type; // ZRADA
private String content; // EJB 2.1
private Integer nextId; // 116
@aiborisov
@mykyta_p
REST: Controller
@GetMapping(
value = "/content/{id}",
produces = "application/json")
public AggregatedContent aggregated(@PathVariable("id") int id) {
return aggregatingService.fetch(id);
}
@aiborisov
@mykyta_p
REST: It’s All About Resources
@GetMapping(
value = "/content/{id}",
produces = "application/json")
public AggregatedContent aggregated(@PathVariable("id") int id) {
return aggregatingService.fetch(id);
}
@aiborisov
@mykyta_p
REST: It’s simple
http://localhost:8080/content/115
{
"id": 115,
"content_type": "PEREMOGA",
"content": "JavaDay 2017 is live",
"next_uri": "/content/116"
}
@aiborisov
@mykyta_p
REST: Service Discovery
@aiborisov
@mykyta_p
k8s/zrada.yaml
...
kind: Service
metadata:
name: rest-zrada-content-service
k8s/aggregator.yaml
...
env:
- name: datasource_a_url
value: "http://rest-zrada-content-service:8080"
REST: Service Discovery
@aiborisov
@mykyta_p
k8s/zrada.yaml
...
kind: Service
metadata:
name: rest-zrada-content-service
k8s/aggregator.yaml
...
env:
- name: datasource_a_url
value: "http://rest-zrada-content-service:8080"
REST: Service Discovery
@aiborisov
@mykyta_p
Controllers and POJOs, oh my!
public class AggregatedContent {
@JsonProperty("id")
private Integer id;
@JsonProperty("type")
private String type;
@JsonProperty("content")
private String content;
@JsonProperty("next_uri")
private String nextUri;
...
}
{
"id": 115,
"content_type": "ZRADA",
"content": "EJB 2.1",
"next_uri": "/content/116"
}
@aiborisov
@mykyta_p
gRPC: It’s All About APIs
@aiborisov
@mykyta_p
Sample Problem: Aggregator
Src
#2
Src
#1
Aggr
...
Src
#X
Client
@aiborisov
@mykyta_p
Service Definition (aggregator.proto)
@aiborisov
@mykyta_p
Service Definition (aggregator.proto)
syntax = "proto3";
service AggregationService {
rpc Get(AggregationRequest)
returns (AggregationResponse);
}
@aiborisov
@mykyta_p
Service Definition (aggregator.proto)
syntax = "proto3";
service AggregationService {
rpc Get(AggregationRequest)
returns (AggregationResponse);
}
message AggregationRequest {
int32 item_id = 1;
}
message AggregationResponse {
int32 id = 1;
ResponseType type = 2;
string content = 3;
int32 next_item_id = 4;
}
enum ResponseType {
UNDEFINED = 0;
PEREMOGA = 1;
ZRADA = 2;
}
@aiborisov
@mykyta_p
Service Definition
aggregator.proto
@aiborisov
@mykyta_p
Service Definition
aggregator.proto
gRPC Runtime
@aiborisov
@mykyta_p
Service Definition
aggregator.proto
AggregationServiceImplBase.java AggregationRequest.java
AggregationResponse.java
AggregationServiceStub.java
AggregationServiceFutureStub.java
AggregationServiceBlockingStub.java
Service Implementation Request and response Client libraries
gRPC Java runtime
@aiborisov
@mykyta_p
Implement gRPC Service
public class AggregationService extends AggregationServiceImplBase {
@Override
public void get(AggregationRequest request,
StreamObserver<AggregationResponse> responseObserver) {
}
}
@aiborisov
@mykyta_p
Implement gRPC Service
public class AggregationService extends AggregationServiceImplBase {
@Override
public void get(AggregationRequest request,
StreamObserver<AggregationResponse> responseObserver) {
}
}
Implement gRPC Service
public class AggregationService extends AggregationServiceImplBase {
@Override
public void get(AggregationRequest request,
StreamObserver<AggregationResponse> responseObserver) {
}
}
@aiborisov
@mykyta_p
Thread #X
Thread ...
Thread #7
Thread #6
Thread #5
Thread #4
Blocking API (aka Thread-per-Request)?
Thread #3
Thread #2
Thread #1
Thread pool
of size X
@aiborisov
@mykyta_p
Thread #X
Thread ...
Thread #7
Thread #6
Thread #5
Thread #4
Blocking API (aka Thread-per-Request)?
Thread #3
Thread #2
Thread #1
Thread pool
of size X
1
@aiborisov
@mykyta_p
Thread #X
Thread ...
Thread #7
Thread #6
Thread #5
Thread #4
Blocking API (aka Thread-per-Request)?
Thread #3
Thread #2
Thread #1
Thread pool
of size X
1
2
@aiborisov
@mykyta_p
Thread #X
Thread ...
Thread #7
Thread #6
Thread #5
Thread #4
Blocking API (aka Thread-per-Request)?
Thread #3
Thread #2
Thread #1
Thread pool
of size X
1
2
3
@aiborisov
@mykyta_p
Thread #X
Thread ...
Thread #7
Thread #6
Thread #5
Thread #4
Thread #3
Thread #2
Blocking API (aka Thread-per-Request)?
Thread #1
Thread pool
of size X
1
2
3
X
. . .
@aiborisov
@mykyta_p
Thread #X
Thread ...
Thread #7
Thread #6
Thread #5
Thread #4
Thread #3
Thread #2
Blocking API (aka Thread-per-Request)?
Thread #1
Thread pool
of size X
1
2
3
X
. . .
X + 1
@aiborisov
@mykyta_p
Thread #X
Thread ...
Thread #7
Thread #6
Thread #5
Thread #4
Thread #3
Thread #2
Blocking API (aka Thread-per-Request)?
Thread #1
Thread pool
of size X
1
2
3
X
. . .
X + 1
@aiborisov
@mykyta_p
Implement gRPC Service
public class AggregationService extends AggregationServiceImplBase {
@Override
public void get(AggregationRequest request,
StreamObserver<AggregationResponse> responseObserver) {
}
}
@aiborisov
@mykyta_p
Implement gRPC Service
public class AggregationService extends AggregationServiceImplBase {
@Override
public void get(AggregationRequest request,
public interface StreamObserver<AggregationResponse> responseObserver){{
void onNext(AggregationResponse response);
void onCompleted();
void onError(Throwable error);
}
}
}
@aiborisov
@mykyta_p
Non-Blocking API
1
2
3
. . .
X + Y
X
. . .
@aiborisov
@mykyta_p
Non-Blocking API (aka Hollywood Principle)
1
2
3
. . .
X + Y
X
. . .
WillCallYouLater!
@aiborisov
@mykyta_p
Non-Blocking API (aka Hollywood Principle)
1
2
3
. . .
X + Y
X
. . .
WillCallYouLater!
onNext(1)
@aiborisov
@mykyta_p
Non-Blocking API (aka Hollywood Principle)
1
2
3
. . .
X + Y
X
. . .
WillCallYouLater!
onNext(3)
@aiborisov
@mykyta_p
Non-Blocking API (aka Hollywood Principle)
1
2
3
. . .
X + Y
X
. . .
WillCallYouLater!
onNext(X)
@aiborisov
@mykyta_p
Implement gRPC Service
public class AggregationService extends AggregationServiceImplBase {
@Override
public void get(AggregationRequest request,
StreamObserver<AggregationResponse> responseObserver) {
AggregationResponse response = AggregationResponse
.newBuilder()
.setId(request.getItemId())
.setContent("JavaDay 2017 is happening right now!")
.setType(ResponseType.PEREMOGA)
.build();
responseObserver.onNext(response);
responseObserver.onCompleted();
}
}
@aiborisov
@mykyta_p
Implement gRPC Service
public class AggregationService extends AggregationServiceImplBase {
@Override
public void get(AggregationRequest request,
StreamObserver<AggregationResponse> responseObserver) {
AggregationResponse response = AggregationResponse
.newBuilder()
.setId(request.getItemId())
.setContent("JavaDay 2017 is happening right now!")
.setType(ResponseType.PEREMOGA)
.build();
responseObserver.onNext(response);
responseObserver.onCompleted();
}
}
@aiborisov
@mykyta_p
Service Definition (aggregator.proto)
syntax = "proto3";
service AggregationService {
rpc Get(AggregationRequest)
returns (AggregationResponse);
}
message AggregationRequest {
int32 item_id = 1;
}
message AggregationResponse {
int32 id = 1;
ResponseType type = 2;
string content = 3;
int32 next_item_id = 4;
}
enum ResponseType {
UNDEFINED = 0;
PEREMOGA = 1;
ZRADA = 2;
}
@aiborisov
@mykyta_p
Service Definition (aggregator.proto)
syntax = "proto3";
service AggregationService {
rpc Get(AggregationRequest)
returns (AggregationResponse);
}
message AggregationRequest {
}
message AggregationResponse {
int32 id = 1;
ResponseType type = 2;
string content = 3;
}
enum ResponseType {
UNDEFINED = 0;
PEREMOGA = 1;
ZRADA = 2;
}
@aiborisov
@mykyta_p
Service Definition (aggregator.proto)
syntax = "proto3";
service AggregationService {
rpc Get(AggregationRequest)
returns (AggregationResponse);
}
message AggregationRequest {
}
message AggregationResponse {
int32 id = 1;
ResponseType type = 2;
string content = 3;
}
enum ResponseType {
UNDEFINED = 0;
PEREMOGA = 1;
ZRADA = 2;
}
@aiborisov
@mykyta_p
Service Definition (aggregator.proto)
syntax = "proto3";
service AggregationService {
rpc Get(AggregationRequest)
returns (stream AggregationResponse);
}
message AggregationRequest {
}
message AggregationResponse {
int32 id = 1;
ResponseType type = 2;
string content = 3;
}
enum ResponseType {
UNDEFINED = 0;
PEREMOGA = 1;
ZRADA = 2;
}
@aiborisov
@mykyta_p
Service Definition (aggregator.proto)
syntax = "proto3";
service AggregationService {
rpc Subscribe(AggregationRequest)
returns (stream AggregationResponse);
}
message AggregationRequest {
}
message AggregationResponse {
int32 id = 1;
ResponseType type = 2;
string content = 3;
}
enum ResponseType {
UNDEFINED = 0;
PEREMOGA = 1;
ZRADA = 2;
}
@aiborisov
@mykyta_p
Service Definition (aggregator.proto)
syntax = "proto3";
service AggregationService {
rpc Subscribe(AggregationRequest)
returns (stream AggregationResponse);
}
message AggregationRequest {
}
message AggregationResponse {
int32 id = 1;
ResponseType type = 2;
string content = 3;
}
enum ResponseType {
UNDEFINED = 0;
PEREMOGA = 1;
ZRADA = 2;
}
@aiborisov
@mykyta_p
Sample Problem: Aggregator
Src
#2
Src
#1
Aggr
...
Src
#X
Client
aggregator.proto
@aiborisov
@mykyta_p
Sample Problem: Content
Src
#2
Src
#1
Aggr
...
Src
#X
Client
aggregator.proto
content.proto
@aiborisov
@mykyta_p
content.proto
syntax = "proto3";
service ContentService {
rpc Subscribe(ContentRequest)
returns (stream ContentResponse);
}
message ContentRequest {
}
message ContentResponse {
int32 id = 1;
string content = 2;
}
@aiborisov
@mykyta_p
Streaming gRPC Service
public class AggregationService extends AggregationServiceImplBase {
private final Collection<ContentServiceStub> contentStubs;
public AggregationService(Collection<ContentServiceStub> contentStubs) {
this.contentStubs = contentStubs;
}
...
@aiborisov
@mykyta_p
Streaming gRPC Service
public class AggregationService extends AggregationServiceImplBase {
@Override
public void subscribe(AggregationRequest request,StreamObserver<AggregationResponse> responseObserver) {
contentStubs.forEach(stub -> { stub.subscribe(ContentRequest.getDefaultInstance(),
new StreamObserver<ContentResponse>() {
@Override
public void onNext(ContentResponse response) {
...
}
@Override
public void onError(Throwable error) {
responseObserver.onError(error);
}
@Override
public void onCompleted() {}
});
});
}
@aiborisov
@mykyta_p
Streaming gRPC Service
public class AggregationService extends AggregationServiceImplBase {
@Override
public void subscribe(AggregationRequest request,StreamObserver<AggregationResponse> responseObserver) {
contentStubs.forEach(stub -> { stub.subscribe(ContentRequest.getDefaultInstance(),
new StreamObserver<ContentResponse>() {
@Override
public void onNext(ContentResponse response) {
...
}
@Override
public void onError(Throwable error) {
responseObserver.onError(error);
}
@Override
public void onCompleted() {}
});
});
}
@aiborisov
@mykyta_p
Streaming gRPC Service
public class AggregationService extends AggregationServiceImplBase {
@Override
public void subscribe(AggregationRequest request,StreamObserver<AggregationResponse> responseObserver) {
contentStubs.forEach(stub -> { stub.subscribe(ContentRequest.getDefaultInstance(),
new StreamObserver<ContentResponse>() {
@Override
public void onNext(ContentResponse response) {
...
}
@Override
public void onError(Throwable error) {
responseObserver.onError(error);
}
@Override
public void onCompleted() {}
});
});
}
@aiborisov
@mykyta_p
Streaming gRPC Service
public class AggregationService extends AggregationServiceImplBase {
@Override
public void subscribe(AggregationRequest request,StreamObserver<AggregationResponse> responseObserver) {
contentStubs.forEach(stub -> { stub.subscribe(ContentRequest.getDefaultInstance(),
new StreamObserver<ContentResponse>() {
@Override
public void onNext(ContentResponse response) {
...
}
@Override
public void onError(Throwable error) {
responseObserver.onError(error);
}
@Override
public void onCompleted() {}
});
});
}
@aiborisov
@mykyta_p
Streaming gRPC Service
public class AggregationService extends AggregationServiceImplBase {
@Override
public void subscribe(AggregationRequest request,StreamObserver<AggregationResponse> responseObserver) {
contentStubs.forEach(stub -> { stub.subscribe(ContentRequest.getDefaultInstance(),
new StreamObserver<ContentResponse>() {
@Override
public void onNext(ContentResponse response) {
ResponseType type = typeForStub(stub);
int aggregationId = aggregationId(response.getId(), type);
AggregationResponse aggrResponse =
AggregationResponse.newBuilder()
.setContent(response.getContent()).setId(aggregationId).
.setType(type).build();
responseObserver.onNext(aggrResponse);
}
});
});
}
@aiborisov
@mykyta_p
Streaming gRPC Service
public class AggregationService extends AggregationServiceImplBase {
@Override
public void subscribe(AggregationRequest request,StreamObserver<AggregationResponse> responseObserver) {
contentStubs.forEach(stub -> { stub.subscribe(ContentRequest.getDefaultInstance(),
new StreamObserver<ContentResponse>() {
@Override
public void onNext(ContentResponse response) {
ResponseType type = typeForStub(stub);
int aggregationId = aggregationId(response.getId(), type);
AggregationResponse aggrResponse =
AggregationResponse.newBuilder()
.setContent(response.getContent()).setId(aggregationId).
.setType(type).build();
responseObserver.onNext(aggrResponse);
}
});
});
}
@aiborisov
@mykyta_p
Streaming gRPC Service
Src
#2
Src
#1
Aggr
...
Src
#X
Client
@aiborisov
@mykyta_p
Streaming gRPC Service
Src
#2
Src
#1
Aggr
...
Src
#X
Client Subscribe()
@aiborisov
@mykyta_p
Streaming gRPC Service
Src
#2
Src
#1
Aggr
...
Src
#X
Client Subscribe()
Subscribe()
Subscribe()
Subscribe()
@aiborisov
@mykyta_p
Streaming gRPC Service
Src
#2
Src
#1
Aggr
...
Src
#X
Client
onNext()
@aiborisov
@mykyta_p
Streaming gRPC Service
Src
#2
Src
#1
Aggr
...
Src
#X
Client
onNext()
onNext()
@aiborisov
@mykyta_p
Streaming gRPC Service
Src
#2
Src
#1
Aggr
...
Src
#X
Client
onNext()
@aiborisov
@mykyta_p
Streaming gRPC Service
Src
#2
Src
#1
Aggr
...
Src
#X
Client onNext()
onNext()
@aiborisov
@mykyta_p
Start gRPC Server
ContentServiceStub peremogaClient = ...
ContentServiceStub zradaClient = ...
Server grpcServer = NettyServerBuilder.forPort(8080)
.addService(new AggregationService(asList(peremogaClient, zradaClient)))
.build().start();
@aiborisov
@mykyta_p
Start gRPC Server
ContentServiceStub peremogaClient = ...
ContentServiceStub zradaClient = ...
Server grpcServer = NettyServerBuilder.forPort(8080)
.addService(new AggregationService(asList(peremogaClient, zradaClient)))
.build().start();
@aiborisov
@mykyta_p
Create gRPC Client
String host = System.getenv("peremoga_host");
int post = Integer.valueOf(System.getenv("peremoga_port"));
ManagedChannel peremogaChannel = NettyChannelBuilder.forAddress(host, port).build();
@aiborisov
@mykyta_p
Create gRPC Client
String host = System.getenv("peremoga_host");
int post = Integer.valueOf(System.getenv("peremoga_port"));
ManagedChannel peremogaChannel = NettyChannelBuilder.forAddress(host, port).build();
ContentServiceStub peremogaClient = ContentServiceGrpc.newStub(peremogaChannel);
@aiborisov
@mykyta_p
Create gRPC Client
String host = System.getenv("peremoga_host");
int port = Integer.valueOf(System.getenv("peremoga_port"));
ManagedChannel peremogaChannel = NettyChannelBuilder.forAddress(host, port).build();
ContentServiceStub peremogaClient = ContentServiceGrpc.newStub(peremogaChannel);
ContentServiceBlockingStub peremogaBlockingClient =
ContentServiceGrpc.newBlockingStub(peremogaChannel);
ContentServiceFutureStub peremogaFutureClient =
ContentServiceGrpc.newFutureStub(peremogaChannel);
@aiborisov
@mykyta_p
Service Discovery & Load Balancing
String host = System.getenv("peremoga_host");
int post = Integer.valueOf(System.getenv("peremoga_port"));
ManagedChannel peremogaChannel = NettyChannelBuilder.forAddress(host, port).build();
@aiborisov
@mykyta_p
Service Discovery & Load Balancing
ManagedChannel peremogaChannel = NettyChannelBuilder.forAddress(host, port).build();
@aiborisov
@mykyta_p
Service Discovery & Load Balancing
ManagedChannel peremogaChannel = NettyChannelBuilder.forTarget("peremoga")
.build();
@aiborisov
@mykyta_p
Service Discovery & Load Balancing
ManagedChannel peremogaChannel = NettyChannelBuilder.forTarget("peremoga")
.nameResolverFactory(new DnsNameResolverProvider())
.loadBalancerFactory(RoundRobinLoadBalancerFactory.getInstance())
.build();
@aiborisov
@mykyta_p
Service Discovery & Load Balancing
ManagedChannel peremogaChannel = NettyChannelBuilder.forTarget("peremoga")
.nameResolverFactory(new MyCustomNameResolverProviderFactory())
.loadBalancerFactory(new MyMoonPhaseLoadBalancerFactory())
.build();
@aiborisov
@mykyta_p
Netty
ManagedChannel peremogaChannel = NettyChannelBuilder.forTarget("peremoga")
.nameResolverFactory(new MyCustomNameResolverProvider())
.loadBalancerFactory(new MyMoonPhaseLoadBalancerFactory())
.build();
@aiborisov
@mykyta_p
Netty + HTTP/2 + Protobuf
@aiborisov
@mykyta_p
Netty + HTTP/2 + Protobuf = Performance
http://www.grpc.io/docs/guides/benchmarking.html
@aiborisov
@mykyta_p
8 core VMs, streaming throughput
Netty + HTTP/2 + Protobuf = Performance
http://www.grpc.io/docs/guides/benchmarking.html
@aiborisov
@mykyta_p
32 core VMs, streaming throughput
Client Latency
...
900 ms!
@aiborisov
@mykyta_p
Caching
CDN
9 ms
...
@aiborisov
@mykyta_p
pay 24/7
Classic Cloud
VM
VM
LB
...
VM
pay as you go
@aiborisov
@mykyta_p
Serverless
pay as you go
Func
Funcinput
...
Func
input
...
input
@aiborisov
@mykyta_p
All about resources
IDL optional
Synchronous by default
Unary
Perfect fit for serverless
All about APIs
IDL centric
Asynchronous by nature
Streaming or Unary
Performance first
REST gRPC
@aiborisov
@mykyta_p
Sample Problem
Src
#2
Src
#1
...
Src
#X
Client Aggr
@aiborisov
@mykyta_p
Sample Problem: Voting
Src
#2
Src
#1
...
Src
#X
Client
Voting
Aggr
@aiborisov
@mykyta_p
Sample Problem: Voting
Src
#2
Src
#1
...
Src
#X
Client
Voting
Aggr
@aiborisov
@mykyta_p
Sample Problem: Voting
Src
#2
Src
#1
...
Src
#X
Client
Voting
Aggr
@aiborisov
@mykyta_p
Sample Problem: Voting & Leaderboard
Src
#2
Src
#1
...
Src
#X
Client
Voting
Aggr
L-board
@aiborisov
@mykyta_p
Sample Problem: Voting & Leaderboard
Src
#2
Src
#1
...
Src
#X
Client
Voting
Aggr
L-board
@aiborisov
@mykyta_p
Sample Problem: Voting & Leaderboard
Src
#2
Src
#1
...
Src
#X
Gateway
Voting
Aggr
L-board
@aiborisov
@mykyta_p
Sample Problem
Src
#2
Src
#1
...
Src
#X
Gateway
VotingL-board
Aggr
@aiborisov
@mykyta_p
Failing Leaderboard
Src
#2
Src
#1
...
Src
#X
Gateway
Voting
Aggr
@aiborisov
@mykyta_p
Cascading Failure
Src
#2
Src
#1
...
Src
#X
Gateway
Voting
Aggr
@aiborisov
@mykyta_p
Cascading Failure
Src
#2
Src
#1
...
Src
#X
Gateway
Voting
Aggr
@aiborisov
@mykyta_p
Cascading Failure
Src
#2
Src
#1
...
Src
#X
Gateway
Voting
Aggr
@aiborisov
@mykyta_p
Circuit Breaker
Src
#2
Src
#1
...
Src
#X
Gateway
VotingL-board
Aggr
@aiborisov
@mykyta_p
Circuit Breaker
Src
#2
Src
#1
...
Src
#X
Gateway
VotingL-board
Aggr
@aiborisov
@mykyta_p
Circuit Breaker
Src
#2
Src
#1
...
Src
#X
Gateway
VotingL-board
Aggr
@aiborisov
@mykyta_p
Circuit Breaker
Src
#2
Src
#1
...
Src
#X
Gateway
VotingL-board
Aggr
@aiborisov
@mykyta_p
Circuit Breaker
Src
#2
Src
#1
...
Src
#X
Gateway
VotingL-board
Aggr
@aiborisov
@mykyta_p
Circuit Breaker
Src
#2
Src
#1
...
Src
#X
Gateway
VotingL-board
Aggr
@aiborisov
@mykyta_p
Slow Services
Src
#2
Src
#1
...
Src
#X
Gateway
VotingL-board
Aggr
@aiborisov
@mykyta_p
Timeouts?
Src
#2
Src
#1
...
Src
#X
Gateway
VotingL-board
Aggr
200 ms
2 sec
@aiborisov
@mykyta_p
Large Timeouts
Gateway Voting L-Board
1,000 ms
timeout
1,000 ms
timeout
200 ms
client timeout
@aiborisov
@mykyta_p
Large Timeouts
Gateway Voting L-Board
1,000 ms
timeout
1,000 ms
timeout
200 ms
client timeout
50 ms
@aiborisov
@mykyta_p
Large Timeouts
Gateway Voting L-Board
1,000 ms
timeout
1,000 ms
timeout
200 ms
client timeout
50 ms
400 ms
@aiborisov
@mykyta_p
Large Timeouts
Gateway Voting L-Board
1,000 ms
timeout
1,000 ms
timeout
200 ms
client timeout
50 ms
400 ms
@aiborisov
@mykyta_p
Large Timeouts
Gateway Voting L-Board
1,000 ms
timeout
1,000 ms
timeout
200 ms
client timeout
50 ms
400 ms
300 ms
@aiborisov
@mykyta_p
Short Timeouts
Gateway Voting L-Board
100 ms
timeout
100 ms
timeout
@aiborisov
@mykyta_p
Short Timeouts
Gateway Voting L-Board
100 ms
timeout
100 ms
timeout
2,000 ms
client timeout
@aiborisov
@mykyta_p
Short Timeouts
Gateway Voting L-Board
100 ms
timeout
100 ms
timeout
2,000 ms
client timeout
50 ms
@aiborisov
@mykyta_p
Short Timeouts
Gateway Voting L-Board
100 ms
timeout
100 ms
timeout
2,000 ms
client timeout
50 ms
400 ms
@aiborisov
@mykyta_p
Short Timeouts
Gateway Voting L-Board
100 ms
timeout
100 ms
timeout
2,000 ms
client timeout
50 ms
400 ms
@aiborisov
@mykyta_p
Short Timeouts
Gateway Voting L-Board
100 ms
timeout
100 ms
timeout
2,000 ms
client timeout
50 ms
400 ms
@aiborisov
@mykyta_p
gRPC Deadline Propagation
Gateway Voting L-Board
200 ms
client timeout
@aiborisov
@mykyta_p
gRPC Deadline Propagation
Gateway Voting L-Board
200 ms
client timeout
50 ms
@aiborisov
@mykyta_p
gRPC Deadline Propagation
Gateway Voting L-Board
200 - 50 ms
timeout
200 ms
client timeout
50 ms
@aiborisov
@mykyta_p
gRPC Deadline Propagation
Gateway Voting L-Board
200 - 50 ms
timeout
200 ms
client timeout
50 ms
400 ms
@aiborisov
@mykyta_p
gRPC Deadline Propagation
Gateway Voting L-Board
200 - 50 - 400 ms
timeout
200 - 50 ms
timeout
200 ms
client timeout
50 ms
400 ms
@aiborisov
@mykyta_p
gRPC Deadline Propagation (Short)
Gateway Voting L-Board
200 - 50 - 400 ms
timeout
200 - 50 ms
timeout
200 ms
client timeout
50 ms
400 ms
@aiborisov
@mykyta_p
gRPC Deadline Propagation (Large)
Gateway Voting L-Board
2,000 - 50 - 400 ms
timeout
2,000 - 50 ms
timeout
2,000 ms
client timeout
50 ms
400 ms
300 ms
@aiborisov
@mykyta_p
Investigation
Src
#2
Src
#1
...
Src
#X
Gateway
VotingL-board
Aggr
@aiborisov
@mykyta_p
Gateway
VotingL-board
Aggr
Investigation
Src
#2
Src
#1
...
Src
#X
@aiborisov
@mykyta_p
VotingL-board
Aggr
Investigation
Src
#2
Src
#1
...
Src
#X
Gateway
@aiborisov
@mykyta_p
L-board
Aggr
Investigation
Src
#2
Src
#1
...
Src
#X
Gateway
Voting
@aiborisov
@mykyta_p
L-board
Aggr
Investigation
Src
#2
Src
#1
...
Src
#X
Gateway
Voting
@aiborisov
@mykyta_p
Aggr
L-board
Investigation
Src
#2
Src
#1
...
Src
#X
Gateway
Voting
@aiborisov
@mykyta_p
Aggr
L-board
Investigation
Src
#2
Src
#1
...
Src
#X
Gateway
Voting
@aiborisov
@mykyta_p
Zipkin: Traces and Latency
@aiborisov
@mykyta_p
Zipkin and gRPC
https://github.com/openzipkin/brave/tree/master/instrumentation/grpc
URLConnectionSender sender = ...
GrpcTracing grpcTracing = GrpcTracing.create(Tracing.newBuilder()
.sampler(ALWAYS_SAMPLE).spanReporter(AsyncReporter.create(sender)).build());
@aiborisov
@mykyta_p
Zipkin and gRPC
https://github.com/openzipkin/brave/tree/master/instrumentation/grpc
URLConnectionSender sender = ...
GrpcTracing grpcTracing = GrpcTracing.create(Tracing.newBuilder()
.sampler(ALWAYS_SAMPLE).spanReporter(AsyncReporter.create(sender)).build());
ManagedChannel peremogaChannel = NettyChannelBuilder.forAddress(peremogaHost, peremogaPort)
.intercept(grpcTracing.newClientInterceptor())
.build();
Server grpcServer = NettyServerBuilder.forPort(8080)
.addService(new AggregationService(asList(peremogaClient, zradaClient)))
.intercept(grpcTracing.newServerInterceptor())
.build().start();
@aiborisov
@mykyta_p
Zipkin and gRPC
https://github.com/openzipkin/brave/tree/master/instrumentation/grpc
URLConnectionSender sender = ...
GrpcTracing grpcTracing = GrpcTracing.create(Tracing.newBuilder()
.sampler(ALWAYS_SAMPLE).spanReporter(AsyncReporter.create(sender)).build());
ManagedChannel peremogaChannel = NettyChannelBuilder.forAddress(peremogaHost, peremogaPort)
.intercept(grpcTracing.newClientInterceptor())
.build();
Server grpcServer = NettyServerBuilder.forPort(8080)
.addService(new AggregationService(asList(peremogaClient, zradaClient)))
.intercept(grpcTracing.newServerInterceptor())
.build().start();
@aiborisov
@mykyta_p
Zipkin and REST
build.gradle:
dependencies {
compile 'org.springframework.cloud:spring-cloud-sleuth-zipkin'
compile 'org.springframework.cloud:spring-cloud-starter-sleuth'
...
application.properties:
spring.zipkin.baseUrl=http://zipkin:9411/
# sample 100%
spring.sleuth.sampler.percentage=1.0
...
@aiborisov
@mykyta_p
Zipkin : REST and gRPC
@aiborisov
@mykyta_p
http://GrpcVsRest.com
#zrada
or
#peremoga
@aiborisov
@mykyta_p
Explore More?
Demo: https://github.com/grpcvsrest
@aiborisov
@mykyta_p
Explore More?
Demo: https://github.com/grpcvsrest
http://grpc.io
https://github.com/grpc
http://www.grpc.io/docs/quickstart/java.html
gRPC Google group: grpc-io@googlegroups.com
REST: http://google.com/search?q=rest
gRPC
or
REST?
@aiborisov
@mykyta_p
Demo UI is written by
Yevgen Golubenko
Software Engineer @ Anomali
• Twitter: @HalloGene_
• github.com/HalloGene
• linkedin.com/in/yevgen-golubenko
@aiborisov
@mykyta_p
REST gRPC
@aiborisov
@mykyta_p
All about resources
Synchronous and unary
Simplicity first
External fault-tolerance
Production ready
All about APIs
Async and streaming
Performance first
Built-in fault-tolerance
Production ready
REST gRPC
@aiborisov
@mykyta_p
All about resources
Synchronous and unary
Simplicity first
External fault-tolerance
Production ready
All about APIs
Async and streaming
Performance first
Built-in fault-tolerance
Production ready
REST gRPC
Be pragmatic,
start with your problem!
@aiborisov
@mykyta_p
Questions?
@aiborisov
@mykyta_p

gRPC vs REST: let the battle begin!