Announcing out of the box support for gRPC in the Flatbuffers serialization library.

Posted on Thursday, August 17, 2017 by Wouter van Oortmerssen

The recent release of Flatbuffers version 1.7 introduced truly zero-copy support for gRPC out of the box.

Flatbuffers is a serialization library that allows you to access serialized data without first unpacking it or allocating any additional data structures. It was originally designed for games and other resource constrained applications, but is now finding more general use, both by teams within Google and in other companies such as Netflix and Facebook.

Flatbuffers enables maximum throughput by directly using gRPC’s slice buffers with zero-copy for common use cases. An incoming rpc can be processed directly from gRPCs internal buffers, and constructing a new message will write directly to these buffers without intermediate steps.

This is currently, fully supported in the C++ implementation of FlatBuffers, with more languages to come. There is also an implementation in Go, which is not entirely zero copy, but still very low on allocation cost (see below).

Example Usage

Let’s look at an example of how this works.

Use Flatbuffers as an IDL

Start with an .fbs schema (similar to .proto, if you are familiar with protocol buffers) that declares an RPC service:

table HelloReply {
  message:string;
}

table HelloRequest {
  name:string;
}

table ManyHellosRequest {
  name:string;
  num_greetings:int;
}

rpc_service Greeter {
  SayHello(HelloRequest):HelloReply;
  SayManyHellos(ManyHellosRequest):HelloReply (streaming: "server");
}

To generate C++ code from this, run: flatc --cpp --grpc example.fbs, much like in protocol buffers.

Generated Server Implementation

The server implementation is very similar to protocol buffers, except now the request and response messages are of type flatbuffers::grpc::Message<HelloRequest> *. Unlike protocol buffers, where these types represent a tree of C++ objects, here they are merely handles to a flat object in the underlying gRPC slice. You can access the data directly:

auto request = request_msg->GetRoot();
auto name = request->name()->str();

Building a response is equally simple

auto msg_offset = mb_.CreateString("Hello, " + name);
auto hello_offset = CreateHelloReply(mb_, msg_offset);
mb_.Finish(hello_offset);
*response_msg = mb_.ReleaseMessage<HelloReply>();

The client code is the same as that generated by protocol buffers, except for the FlatBuffer access and construction code.

See the full example here. To compile it, you need gRPC. The same repo has a similar example for Go.

Read more about using and building FlatBuffers for your platform on the flatbuffers site.