Build microserviceBuild microservice
with gRPC in Golangwith gRPC in Golang
David Chou
We are UmboWe are Umbo
Computer VisionComputer Vision
We buildWe build
autonomous videoautonomous video
security systemsecurity system
CyberlinkCyberlink
TrendMicroTrendMicro
Umbo CVUmbo CV
Google I/O ExtendGoogle I/O Extend
Golang TaipeiGolang Taipei
  
A high performance, open source, general purpose
standards-based, feature-rich RPC framework.
O(10^10) RPCs per second at Google
gRPC: MotivationgRPC: Motivation
Google has its internal RPC called Stubby
All applications and systems built using RPCs
Over 10^10 RPCs per second
Tightly couple with internal infrastructure
Not suitable for open source community
gRPC: StatusgRPC: Status
A high performance, universal RPC framework
Google open sourced it in Feb 2015
Being 1.0 in Aug 2016
Latest version: v1.3.2
Already been adpoted in
CoreOS, Netflix, Square, Cisco, Juniper
gRPC: FeaturesgRPC: Features
Bi-directional streaming over HTTP/2
Support multi-language, multi-platform
Simple service definition framework
Bi-directional streaming over HTTP/2Bi-directional streaming over HTTP/2
Single TCP connection for each client-server pair
Support bi-directional streaming
Support multi-language,Support multi-language,
multi-platformmulti-platform
Use protoc as the code generator
Native implementations in C/C++, Java, and Go
C stack wrapped by C#, Node, ObjC, Python, Ruby, PHP
Platforms supported: Linux, MacOS, Windows, Android, iOS
Currently, no browser side support. #8682
gRPC gateway
gRPC-web
Simple service definition frameworkSimple service definition framework
Use Protocol Buffer IDL
Service definition
Generate server and client stub code
Message definition
Binary format
Much better performace than json
syntax = "proto3";
package pb;
message EchoMessage {
string msg = 1;
}
service EchoService {
rpc Echo(EchoMessage) returns (EchoMessage);
}
Protobuf IDL: EchoServiceProtobuf IDL: EchoService
BenchmarkToJSON_1000_Director-2 500 2512808 ns/op 560427 B/op 9682 allocs/op
BenchmarkToPB_1000_Director-2 2000 1338410 ns/op 196743 B/op 3052 allocs/op
BenchmarkToJSONUnmarshal_1000_Director-4 1000 1279297 ns/op 403746 B/op 5144 allocs/op
BenchmarkToPBUnmarshal_1000_Director-4 3000 489585 ns/op 202256 B/op 5522 allocs/op
Json vs Protobuf performanceJson vs Protobuf performance
Ref: Dgraph: JSON vs. Binary clients
Marshalling: 2x faster, 65% less memory
Unmarshalling: 2.6x faster, 50% less memory
Example: DemoServiceExample: DemoService
gRPC Service DefinitiongRPC Service Definition
message Demo {
string value = 1;
}
service DemoService {
rpc SimpleRPC(Demo) returns (Demo);
rpc ServerStream(Demo) returns (stream Demo);
rpc ClientStream(stream Demo) returns (Demo);
rpc Bidirectional(stream Demo) returns (stream Demo);
}
gRPC Service DefinitiongRPC Service Definition
gRPC supprots 4 kinds of service methods
Unary RPC
Server streaming RPC
Client streaming RPC
Bidirectional RPC
Generate client and server codeGenerate client and server code
Run protoc to generate client/server interfaces
$ protoc --go_out=plugins=grpc:. demo.proto
protoc will generate demo.pb.go
Install relevant tools
demo.pb.godemo.pb.go
type Demo struct {
Value string `protobuf:"bytes,1,opt,name=value" json:"value,omitempty"`
}
// Client API for DemoService service
type DemoServiceClient interface {
SimpleRPC(ctx context.Context, in *Demo, opts ...grpc.CallOption) (*Demo, error)
ServerStream(ctx context.Context, in *Demo, opts ...grpc.CallOption) (DemoService_ServerStreamClient,
ClientStream(ctx context.Context, opts ...grpc.CallOption) (DemoService_ClientStreamClient, error)
Bidirectional(ctx context.Context, opts ...grpc.CallOption) (DemoService_BidirectionalClient, error)
}
// Implementation of DemoService client
type demoServiceClient struct {
cc *grpc.ClientConn
}
func NewDemoServiceClient(cc *grpc.ClientConn) DemoServiceClient {
...
}
// Server API for DemoService service
type DemoServiceServer interface {
SimpleRPC(context.Context, *Demo) (*Demo, error)
ServerStream(*Demo, DemoService_ServerStreamServer) error
ClientStream(DemoService_ClientStreamServer) error
Bidirectional(DemoService_BidirectionalServer) error
}
Go ServerGo Server
type server struct{}
func (this *server) SimpleRPC(c context.Context, msg *Demo) (*Demo, error) {
msg.Value = "Hello" + msg.Value
return msg, nil
}
func (this *server) ServerStream(msg *Demo, stream DemoService_ServerStreamServer) error {
for i := 0; i < 10; i++ {
err := stream.Send(&Demo{value: "Hello"})
if err != nil {
fmt.Printf("err: %sn", err.Error())
}
time.Sleep(100 * time.Millisecond)
}
return nil
}
func main() {
lis, err := net.Listen("tcp", "localhost:12345")
if err != nil {
log.Fatalf("Failed to listen: %v", err)
}
grpcServer := grpc.NewServer()
RegisterDemoServiceServer(grpcServer, &server{})
grpcServer.Serve(lis)
}
Go Client: SimpleRPCGo Client: SimpleRPC
func main() {
grpcAddr := "localhost:12345"
conn, err := grpc.Dial(grpcAddr)
if err != nil {
log.Fatalf("Dial(%s) = %v", grpcAddr, err)
}
defer conn.Close()
client := NewDemoServiceClient(conn)
msg := &Demo{value: "World"}
reply, err := client.SimpleRPC(context.Background(), msg)
if err != nil {
log.Fatalf("SimpleRPC(%#v) failed with %v", msg, err)
}
println("received message " + reply.Value)
}
Go Client: ServerStreamGo Client: ServerStream
func main() {
grpcAddr := "localhost:12345"
conn, err := grpc.Dial(grpcAddr)
if err != nil {
log.Fatalf("Dial(%s) = %v", grpcAddr, err)
}
defer conn.Close()
client := NewDemoServiceClient(conn)
stream, err := client.ServerStream(context.TODO(), &Demo{
Value: "Hello",
})
for {
msg, err := stream.Recv()
if err == io.EOF {
break
}
fmt.Printf("%+vn", msg)
}
}
Let's go deeperLet's go deeper
gRPC build-in authenticationgRPC build-in authentication
Two types of Credentials objects
Channel credentials
Call credentials
Channel credentialsChannel credentials
Credentials are attached to a Channel
Ex: SSL credentials
tls := credentials.NewClientTLSFromCert(nil, "")
conn, err := grpc.Dial(serverAddr, grpc.WithTransportCredentials(tls))
creds, err := credentials.NewServerTLSFromFile(certFile, keyFile)
server := grpc.NewServer(grpc.Creds(creds))
server.Serve()
TLS on server side
TLS on client side
Call credentialsCall credentials
Credentials are attached to each RPC call
Token based authentication, ex: OAuth, JWT
func unaryInterceptor(ctx context.Context, req interface{}
if err := authorize(ctx); err != nil {
return err
}
return handler(ctx, req)
}
func authorize(ctx context.Context) error {
if md, ok := metadata.FromContext(ctx); ok {
if checkJWT(md["jwt"][0]) {
return nil
}
return AccessDeniedErr
}
return EmptyMetadataErr
}
grpc.NewServer(grpc.UnaryInterceptor(unaryInterceptor))
TLS on server side
type JWTCreds struct {
Token string
}
func (c *JWTCreds) GetRequestMetadata(context.Context, ..
return map[string]string{
"jwt": c.Token,
}, nil
}
grpc.Dial(target, grpc.WithPerRPCCredentials(&JWTCreds{
Token: "test-jwt-token",
}))
TLS on client side
Ref: grpc-go #106
gRPC load balancegRPC load balance
Approaches to Load Balancing
Server-side LB
Client-side LB
Load Balancing in gRPCLoad Balancing in gRPC
#gRPC load balancing proposal
Any Question?Any Question?

Build microservice with gRPC in golang

  • 1.
    Build microserviceBuild microservice withgRPC in Golangwith gRPC in Golang David Chou
  • 2.
    We are UmboWeare Umbo Computer VisionComputer Vision We buildWe build autonomous videoautonomous video security systemsecurity system
  • 3.
    CyberlinkCyberlink TrendMicroTrendMicro Umbo CVUmbo CV GoogleI/O ExtendGoogle I/O Extend Golang TaipeiGolang Taipei   
  • 4.
    A high performance,open source, general purpose standards-based, feature-rich RPC framework.
  • 5.
    O(10^10) RPCs persecond at Google
  • 6.
    gRPC: MotivationgRPC: Motivation Googlehas its internal RPC called Stubby All applications and systems built using RPCs Over 10^10 RPCs per second Tightly couple with internal infrastructure Not suitable for open source community
  • 7.
    gRPC: StatusgRPC: Status Ahigh performance, universal RPC framework Google open sourced it in Feb 2015 Being 1.0 in Aug 2016 Latest version: v1.3.2 Already been adpoted in CoreOS, Netflix, Square, Cisco, Juniper
  • 8.
    gRPC: FeaturesgRPC: Features Bi-directionalstreaming over HTTP/2 Support multi-language, multi-platform Simple service definition framework
  • 9.
    Bi-directional streaming overHTTP/2Bi-directional streaming over HTTP/2 Single TCP connection for each client-server pair Support bi-directional streaming
  • 10.
    Support multi-language,Support multi-language, multi-platformmulti-platform Useprotoc as the code generator Native implementations in C/C++, Java, and Go C stack wrapped by C#, Node, ObjC, Python, Ruby, PHP Platforms supported: Linux, MacOS, Windows, Android, iOS Currently, no browser side support. #8682 gRPC gateway gRPC-web
  • 11.
    Simple service definitionframeworkSimple service definition framework Use Protocol Buffer IDL Service definition Generate server and client stub code Message definition Binary format Much better performace than json
  • 12.
    syntax = "proto3"; packagepb; message EchoMessage { string msg = 1; } service EchoService { rpc Echo(EchoMessage) returns (EchoMessage); } Protobuf IDL: EchoServiceProtobuf IDL: EchoService
  • 13.
    BenchmarkToJSON_1000_Director-2 500 2512808ns/op 560427 B/op 9682 allocs/op BenchmarkToPB_1000_Director-2 2000 1338410 ns/op 196743 B/op 3052 allocs/op BenchmarkToJSONUnmarshal_1000_Director-4 1000 1279297 ns/op 403746 B/op 5144 allocs/op BenchmarkToPBUnmarshal_1000_Director-4 3000 489585 ns/op 202256 B/op 5522 allocs/op Json vs Protobuf performanceJson vs Protobuf performance Ref: Dgraph: JSON vs. Binary clients Marshalling: 2x faster, 65% less memory Unmarshalling: 2.6x faster, 50% less memory
  • 15.
  • 16.
    gRPC Service DefinitiongRPCService Definition message Demo { string value = 1; } service DemoService { rpc SimpleRPC(Demo) returns (Demo); rpc ServerStream(Demo) returns (stream Demo); rpc ClientStream(stream Demo) returns (Demo); rpc Bidirectional(stream Demo) returns (stream Demo); }
  • 17.
    gRPC Service DefinitiongRPCService Definition gRPC supprots 4 kinds of service methods Unary RPC Server streaming RPC Client streaming RPC Bidirectional RPC
  • 18.
    Generate client andserver codeGenerate client and server code Run protoc to generate client/server interfaces $ protoc --go_out=plugins=grpc:. demo.proto protoc will generate demo.pb.go Install relevant tools
  • 19.
    demo.pb.godemo.pb.go type Demo struct{ Value string `protobuf:"bytes,1,opt,name=value" json:"value,omitempty"` } // Client API for DemoService service type DemoServiceClient interface { SimpleRPC(ctx context.Context, in *Demo, opts ...grpc.CallOption) (*Demo, error) ServerStream(ctx context.Context, in *Demo, opts ...grpc.CallOption) (DemoService_ServerStreamClient, ClientStream(ctx context.Context, opts ...grpc.CallOption) (DemoService_ClientStreamClient, error) Bidirectional(ctx context.Context, opts ...grpc.CallOption) (DemoService_BidirectionalClient, error) } // Implementation of DemoService client type demoServiceClient struct { cc *grpc.ClientConn } func NewDemoServiceClient(cc *grpc.ClientConn) DemoServiceClient { ... } // Server API for DemoService service type DemoServiceServer interface { SimpleRPC(context.Context, *Demo) (*Demo, error) ServerStream(*Demo, DemoService_ServerStreamServer) error ClientStream(DemoService_ClientStreamServer) error Bidirectional(DemoService_BidirectionalServer) error }
  • 20.
    Go ServerGo Server typeserver struct{} func (this *server) SimpleRPC(c context.Context, msg *Demo) (*Demo, error) { msg.Value = "Hello" + msg.Value return msg, nil } func (this *server) ServerStream(msg *Demo, stream DemoService_ServerStreamServer) error { for i := 0; i < 10; i++ { err := stream.Send(&Demo{value: "Hello"}) if err != nil { fmt.Printf("err: %sn", err.Error()) } time.Sleep(100 * time.Millisecond) } return nil } func main() { lis, err := net.Listen("tcp", "localhost:12345") if err != nil { log.Fatalf("Failed to listen: %v", err) } grpcServer := grpc.NewServer() RegisterDemoServiceServer(grpcServer, &server{}) grpcServer.Serve(lis) }
  • 21.
    Go Client: SimpleRPCGoClient: SimpleRPC func main() { grpcAddr := "localhost:12345" conn, err := grpc.Dial(grpcAddr) if err != nil { log.Fatalf("Dial(%s) = %v", grpcAddr, err) } defer conn.Close() client := NewDemoServiceClient(conn) msg := &Demo{value: "World"} reply, err := client.SimpleRPC(context.Background(), msg) if err != nil { log.Fatalf("SimpleRPC(%#v) failed with %v", msg, err) } println("received message " + reply.Value) }
  • 22.
    Go Client: ServerStreamGoClient: ServerStream func main() { grpcAddr := "localhost:12345" conn, err := grpc.Dial(grpcAddr) if err != nil { log.Fatalf("Dial(%s) = %v", grpcAddr, err) } defer conn.Close() client := NewDemoServiceClient(conn) stream, err := client.ServerStream(context.TODO(), &Demo{ Value: "Hello", }) for { msg, err := stream.Recv() if err == io.EOF { break } fmt.Printf("%+vn", msg) } }
  • 23.
  • 24.
    gRPC build-in authenticationgRPCbuild-in authentication Two types of Credentials objects Channel credentials Call credentials
  • 25.
    Channel credentialsChannel credentials Credentialsare attached to a Channel Ex: SSL credentials tls := credentials.NewClientTLSFromCert(nil, "") conn, err := grpc.Dial(serverAddr, grpc.WithTransportCredentials(tls)) creds, err := credentials.NewServerTLSFromFile(certFile, keyFile) server := grpc.NewServer(grpc.Creds(creds)) server.Serve() TLS on server side TLS on client side
  • 26.
    Call credentialsCall credentials Credentialsare attached to each RPC call Token based authentication, ex: OAuth, JWT
  • 27.
    func unaryInterceptor(ctx context.Context,req interface{} if err := authorize(ctx); err != nil { return err } return handler(ctx, req) } func authorize(ctx context.Context) error { if md, ok := metadata.FromContext(ctx); ok { if checkJWT(md["jwt"][0]) { return nil } return AccessDeniedErr } return EmptyMetadataErr } grpc.NewServer(grpc.UnaryInterceptor(unaryInterceptor)) TLS on server side type JWTCreds struct { Token string } func (c *JWTCreds) GetRequestMetadata(context.Context, .. return map[string]string{ "jwt": c.Token, }, nil } grpc.Dial(target, grpc.WithPerRPCCredentials(&JWTCreds{ Token: "test-jwt-token", })) TLS on client side Ref: grpc-go #106
  • 28.
    gRPC load balancegRPCload balance Approaches to Load Balancing Server-side LB Client-side LB
  • 31.
    Load Balancing ingRPCLoad Balancing in gRPC #gRPC load balancing proposal
  • 32.