Efficient
Service Communication
with gRPC
Petra Bierleutgeb
@pbvie
Efficient,
Maintainable and Pleasant
Service Communication
with gRPC
Petra Bierleutgeb
@pbvie
Why
Do we even need another approach?
HTTP/JSON: The good parts
- time-proven
- easy, low learning-curve
- well supported
- good tooling, cURL-friendly
- platform-indepedent
- human-readable
Example: Twitter API
HTTP/JSON: Not so great parts
- working with HTTP/JSON based APIs is cumbersome => wrappers
- APIs often not really RESTful or forced to be
- need to manually write boilerplate-code*
- bad support for documentation*
- bad support for versioning
- error-prone: no type-safety, misspelled field names
- inefficient format, (gzip) compression is CPU-intensive
- drawbacks of HTTP1.1
* without additional tools like Swagger and friends
Meet gRPC
- open-source Remote Procedur Call framework
- services and exchanged message described using Protocol Buffers
- type-safety
- interface (server-side) and stub (client-side) code generation
- HTTP/2 for transport
-
cross-platform, 9 officially supported platforms
- C/C++, C#, Go, Java, Ruby, Node, Dart, PHP, Python
- additional community supported platforms
Isn't RPC an Anti-Pattern?
- RPC has been around for some time
- CORBA
- RMI
- WSDL/SOAP,...
- gRPC shares some ideas but differs in important parts
How is gRPC different?
-
support requirements of distributed systems - don't hide them
- asynchronous, non-blocking, streaming, flow-control, interceptors
-
prefer simplicity over complexity
- IDL with just-enough features instead of complicated (and verbose) XML schemas
-
message-based instead of distributed objects
- no shared/mutable state, communicate only via messages, loose-coupling
-
cross-platform, open-source and based on standards
- instead of proprietary tools
Another kind of RPC
manual RPC
over
HTTP/JSON?
operations:
follow
unfollow
retweet
like
...
wrappers/stubs
+
=
What about Kafka?
- also message-based
- supports streaming
- fully de-coupled and asynchronous
- persistent
- messages are sent to topics not recipients
- involves three parties
- publisher
- broker
- subscriber
- pub/sub not RPC
Where does gRPC fit in?
- gRPC and Kafka share some features but cover (very) different use cases => gRPC is usually no alternative to Kafka
- many RESTful services are actually manual RPC over HTTP/JSON
=> gRPC can be a very good alternative to HTTP/JSON
gRPC in a Nutshell
Principles and Design
gRPC: a short history
- successor to Google's internal framework Stubby
- re-worked and open-sourced in 2015
- Version 1.0 (first stable) released on August 23, 2016
- now at version 1.10
- project joined CNCF (Cloud Native Computing Foundation) on March 1, 2017
- wide adoption in modern network infrastructure tools like Linkerd, Envoy and NGINX
- active Gitter channel and mailing list, bi-weekly online community meetings, proposals discussed on GitHub
Fundamental Principles
- free & open
- services not objects, messages not references
- cross-platform and easy to implement for new platforms
- payload agnostic - while protocol buffers are the default it should be possible to use other formats such as Thrift, JSON, XML,...
- first-class support for streaming
- support blocking and non-blocking clients
- pluggable architecture for security, health checks, metrics, etc.
(g)RPC development flow
- define services using IDL (protocol buffer definitions)
- server-side
- generate service interfaces
- implement service interfaces
- run server
- client-side
- generate stubs
- create channel
- invoke methods on stubs
Protocol Buffers: gRPC's IDL
- a.k.a. Protobuf and Proto
- completely independent of gRPC
- gRPC uses Proto 3 syntax
- used to describe services and exchanged messages
- very compact, binary serialization format
- requires schema for serialization and deserialization
Protobuf Definitions
- scalar value types like String, Integer, Boolean, Byte, etc...
- all fields are optional* and have default values
- custom message types
- enums
- repeated values
- oneof
- fields identified via tag numbers
* good explanation: https://stackoverflow.com/a/31814967
Protobuf message definitions
message User {
uint64 id = 1;
string email = 2;
Address address = 3;
repeated Interest interests = 4;
}
message Address {
message City {
string zipCode = 1;
string name = 2;
}
uint64 id = 1;
City city = 2;
string street = 3;
}
// ...
tag numbers
Anatomy of a gRPC service
service MyExampleService {
rpc MyExampleMethod(MyRequestMessage) returns (stream MyResponseMessage) {}
}
service name
method name
request param
response
streaming
gRPC communication styles
- unary request/response
- client-side streaming
- server-side streaming
- bi-directional streaming
gRPC communication styles
/*
* Example service showing all available gRPC communication styles.
*/
service ExampleService {
rpc Unary(MyReqMsg) returns (MyRespMsg) {}
rpc ClientStreaming(stream MyReqMsg) returns (MyRespMsg) {}
rpc ServerStreaming(MyReqMsg) return (stream MyRespMsg) {}
rpc ServerStreaming(stream MyReqMsg) return (stream MyRespMsg) {}
}
gRPC service definition
syntax = "proto3";
package io.ontherocks.echo.protocol;
/*
* Simple echo service - example of unary and streaming responses.
*/
service Echo {
rpc Echo (EchoRequest) returns (EchoResponse) {}
rpc EchoStream (EchoRequest) returns (stream EchoResponse) {}
}
message EchoRequest {
string message = 1;
}
message EchoResponse {
string message = 1;
}
Demo
How to try out your service
gRPC error handling
- HTTP status code 200 (unless deployment is broken)
- standardized gRPC status codes for all platforms
- gRPC uses header `grpc-status` to indicate error
- additional header `grpc-message` to provide error description
Middleware/Interceptors
- intercept requests and responses
- implement non-functional, cross-cutting requirements such as
- logging
- metrics
- authentication
- tracing
gRPC Benefits
Technical and non-technical wins
Protocol Buffers
Protobuf...compared to JSON
- message size: always smaller but the exact answer is "it depends"
- size of the message
- compression (gzip)
- redundancy of fields
- it's not only about size
- JSON compression is slower and more CPU-intensive
- important factor on mobile phones (battery) and IoT devices (limited resources)
Protocol Buffers
-
protocol first: great for discussion
(also with non-dev team members) - type-safety
- ...and no more misspelled field names
- generate boiler-plate code
- polyglot, cross-platform
- versioning (more on that up next)
Versioning
&
Protocol Evolution
Protocol Evolution
- APIs evolve over time
- tag numbers are important - never re-use them
- operations that maintain compatibility
- adding/removing fields
- renaming fields
- in some cases: changing data type of field
-
How?
- ignore additional unknown fields
- use default value for missing fields
- identify fields not by name but by tag number
Protocol Evolution - Example
service Evolver {
rpc Sample(Req) returns (Resp) {}
}
message SomeRequest {
string old_name = 1;
int32 counter = 2;
}
service Evolver {
rpc Sample(Req) returns (Req) {}
}
message SomeRequest {
string new_name = 1;
boolean toggle = 3;
}
SomeRequest(
new_name = "abc",
toggle = true // ignored
)
SomeRequest(
old_name = "abc", // through tag no.
counter = 0 // default
)
SomeRequest(
old_name = "abc",
counter = 7 // ignored
)
SomeRequest(
new_name = "abc", // through tag no.
toggle = false // default
)
new message to old service
old message to new service
Versioning - Approaches
-
opinionated - but seems to work well for teams
- package generated source code as versioned libs
- use semantic versioning
-
service "owns" protocol definitions
(avoid one-proto-repo-to-rule-them-all) - one repo for common message types is fine though
- great use case for interceptors:
automatically add version as request/response metadata
HTTP/2
HTTP/2 Goodies
-
connection multiplexing
- using one connection for multiple calls
- no head-of-line blocking (drawback of HTTP1.1 pipelining)
-
header compression
- reduce header size
- don't resend redundant headers
good intro to HTTP/2: https://developers.google.com/web/fundamentals/performance/http2/
HTTP/2 Goodies - continued
-
flow-control and bi-directional streaming
- back-pressure to avoid "flooding" slower clients
- fits nicely into the reactive streams model
- already good integration with reactive libs like RxJava and Akka Streams
good intro to HTTP/2: https://developers.google.com/web/fundamentals/performance/http2/
Transport Independence
Transport Independence
- transport is not hard-wired in gRPC
- stubs and services are agnostic to underlying transport
- e.g. grpc-java
- Netty => default
- OkHttp => devices with limited resources (mobile, IoT)
- InProcess => great for testing
Backward Compatibility
supporting (legacy) clients via HTTP/JSON
Defining the mapping
- mapping is defined in protocol definition
- makes use of custom options
service Echo {
rpc Echo (EchoRequest) returns (EchoResponse) {}
}
message EchoRequest {
string message = 1;
}
message EchoResponse {
string message = 1;
}
service Echo {
rpc Echo (EchoRequest) returns (EchoResponse) {
option (google.api.http) = {
get: "/example/echo"
};
}
}
message EchoRequest {
string message = 1;
}
message EchoResponse {
string message = 1;
}
GET /example/echo?message=HelloBerlin
Available Tooling
- with Envoy: gRPC-JSON transcoder
- grpc-gateway (Go)
- convenient option but
- doesn't cover full gRPC feature set due to HTTP1.1 limitations
- works best with unary communication
Summing it up
aka
"final slides before beer/food"
gRPC - takeaways
- "Next-gen HTTP/JSON" with batteries-included
- protocol-first approach
- HTTP/2 based transport
- cross-platform
- supports 4 different styles of communication
- interceptors for cross-cutting concerns
Wait!
What does the 'g' actually stand for?
So far...
- 1.0 'g' stands for 'gRPC'
- 1.1 'g' stands for 'good'
- 1.2 'g' stands for 'green'
- 1.3 'g' stands for 'gentle'
- 1.4 'g' stands for 'gregarious'
- 1.6 'g' stands for 'garcia'
- 1.7 'g' stands for 'gambit'
- 1.8 'g' stands for 'generous'
- 1.9 'g' stands for 'glossy'
- 1.10 'g' stands for 'glamorous'
- 1.11 'g' stands for 'gorgeous'
...to be
continued
Thank you!
Questions?
Efficient service communication with gRPC
By Petra Bierleutgeb
Efficient service communication with gRPC
- 2,770