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

  1. define services using IDL (protocol buffer definitions)
  • server-side
    1. generate service interfaces
    2. implement service interfaces
    3. run server
  • client-side
    1. generate stubs
    2. create channel
    3. 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

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

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

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