gRPC and Microservice Architecture

Peter Malina github.com/gelidus

CTO @ FlowUp github.com/flowup

Microservice

  • Application
  • Small and flexible
  • Modular
  • Independently deployable (scalable)

Microservice Architecture Pros

  • Divides large teams into smaller focused groups
  • Decreases communication overhead

Microservice Architecture Cons

  • Requires stable APIs
  • Hard integration testing
  • Heavy CD pipeline
  • Service discovery
  • Monitoring
  • Security
  • Separate DBs

RPC

  • Remote Procedure Call
  • Feel's like calling local functions
  • Solves data transportation

Protocol Buffers

  • Binary serialization mechanism for structured data
  • Hard to decode by human eye (schema is needed)
<person>
  <name>John Doe</name>
  <email>jdoe@example.com</email>
</person>

XML

// Schema
message Person {
  string name = 1;
  string email = 2;
}

// Textual representation
person {
  name: "John Doe"
  email: "jdoe@example.com"
}

Protocol Buffers

28 bytes, 100-200ns to parse

69 bytes, 5K-10Kns to parse

Protocol Buffers cont'd

  • Many languages are supported (C++, Java, Go, Python, etc.)
  • Support for extensions (e.g. github.com/gogo/protobuf)
syntax = "proto3";

package mypackage;

import "github.com/gogo/protobuf/gogoproto/gogo.proto";

message Outside {
	string Field1 = 1 [(gogoproto.jsontag) = "myfield"];
	string Field2 = 2 [(gogoproto.moretags) = "xml:\",comment\""];
}

gRPC

  • A high performance, open-source universal RPC framework

gRPC protobuf extension

  • Extends protobuf
  • Generates RPC client stubs
  • Generates RPC server interface
// Calculator is a service that adds two numbers
service Calculator {
  rpc Add (AddRequest) returns (AddReply) {}
}

message AddRequest {
  int32 x = 1;
  int32 y = 2;
}

message AddReply {
  int32 res = 1;
}
type CalculatorServer interface {
	Add(context.Context, *AddRequest) (*AddReply, error)
}

// ... there is far more code ...

~Generates~

Let's implement it!

type calculatorServer struct {}

// Add handles request to add two numbers
func (s *calculatorServer) Add(ctx context.Context, req *AddRequest) (*AddReply, error) {
	return &AddReply{
		Res: req.X + req.Y
	}, nil
}
s := grpc.NewServer()

proto.RegisterCalculatorServer(s, &calculatorServer{})

// Register reflection service on gRPC server.
reflection.Register(s)
if err := s.Serve(lis); err != nil {
	log.Fatalf("failed to serve: %v", err)
}

And start the server

Making calls

  • Create stub
  • Call service methods
// dial grpc connection
conn, _ := grpc.Dial("127.0.0.1:8000")
defer conn.Close()

// create stub
calculator := NewCalculatorClient(conn)

// call remote method
res, err := calculator.Add(context.Background(), &AddRequest{5, 10})
// <AddReply> res.Res == 15

if err != nil {
    // ...
}

gRPC-Gateway

  • https://github.com/grpc-ecosystem/grpc-gateway
  • gRPC to JSON proxy generator

gRPC + GCloud

  • GCloud will do the JSON proxy for you
  • Kubernetes will scale your microservices
  • BigTable, PubSub, Speech APIs

Questions?

Introduction to gRPC

By Peter Malina

Introduction to gRPC

  • 882