gRPC(1)

gRPC - About gRPC and protobuf

Posted by Hebi on December 12, 2022

Learning about gRPC and protobuf

gRPC

RPC (Remote Procedure Call)

  • A form of inter-process communication and a technology for communication between distributed computers
  • Invoking functions/methods on a remote server
  • In the context of HTTP API, it involves putting methods in the URL and arguments in the query string or body
  • RPC APIs use the approach {“id”:1}DELETE/resource/1 instead of the REST approach
  • It can be implemented as RPC-XML and RPC-JSON

Stub

  • A core concept in RPC
  • The server and client use different address spaces, so it is necessary to convert the parameters used in function calls
  • Otherwise, pointers to memory parameters will point to different data
  • A layer that converts objects to messages and vice versa
  • Divided into Client Stub and Server Stub
  • The Client Stub is responsible for converting parameters in function calls and converting results delivered from the server after function execution
  • The server stub is responsible for reverse-converting the parameters delivered by the client and the results of function execution

Microservices

  • The advantage of a monolithic architecture is that it is easy to perform tasks such as logging, performance monitoring, and caching because the unit is one. However, as the scale grows, it becomes difficult to maintain and expand
  • Another important disadvantage of monolithic is that it is limited to a single technology. Adopting a new framework or language may require rewriting the entire system
  • Microservices is an architectural and organizational approach to software development where software is composed of small, independent services that communicate through well-defined APIs
  • It enables easy scaling of applications, accelerates development speed to realize innovation, and shortens the release time of new features

REST API

  • A web architecture that uses the HTTP protocol
  • REST is a client-server relationship where backend data is provided to the client through simple representations like JSON/XML

gRPC

  • A high-performance RPC framework developed by Google that can run in any environment
  • Built on top of HTTP/2, it supports bidirectional communication along with existing request-response
  • Supports various languages
  • By default, it uses protobuf to serialize structured data, offering better performance than text-based formats like JSON
  • Reduces communication costs
  • Rich built-in features (authentication), supports two authentication mechanisms (SSL, Token)
  • A better alternative to REST APIs for microservice architectures
  • gRPC can be considered a great option when it involves idiomatic APIs or multilingual communication with large-scale microservice communication

Components

  • protobuf
  • server
  • client

Advantages

  • Can be built based on various languages
  • Constructs runtime and development environments
  • Enables bidirectional streaming communication based on HTTP/2
  • Lighter and faster communication speed than JSON-based
  • Supports various languages and platforms
  • Enables bidirectional streaming

Disadvantages

  • Cannot directly call gRPC services from a browser (proxy)
  • Requires more code to ensure stability, as it has lower stability compared to REST APIs
  • Increases complexity of the development process, difficult to maintain
  • Unlike REST APIs, messages are delivered in binary, making testing difficult

Structure

  • Application Layer
  • Framework Layer
  • Transport Layer

Channel

  • gRPC sends data using HTTP Streaming based on HTTP/2, and in the case of HTTP/2, it is a mechanism that continuously maintains the connection
  • gRPC usually establishes one connection and calls this connection a channel
  • Opens multiple subchannels for communication
  • Reusing this channel can save communication costs
  • Channels provide an easy interface for users to easily send messages on the surface
  • A channel represents a virtual connection to a single endpoint
  • When a client creates a gRPC channel, it internally connects to the server via HTTP/2
  • RPCs are processed as streams in HTTP/2
  • Messages are processed as frames in HTTP/2
  • The gRPC client has a resolver and LB (load balancer)
  • The resolver periodically resolves the target DNS and communicates with the endpoints
  • If the connection fails, the LB uses the previously used address list to attempt reconnection

  • Keepalive
  • KeepAlive periodically checks the connection status by sending HTTP/2 ping frames
  • It actually serves to keep the connection alive

Stream

  • When a single RPC call is invoked, this call is called a Stream, and when the RPC call starts, the Stream starts and when it ends, the Stream closes

Comparison

  • gRPC-web: Composed only with gRPC
  • REST: Composed by mixing gRPC or using only REST

Workflow

Workflow

  1. Protobufs definitions
  2. Protoc compiler
  3. Generate code
  4. Implement

Protobuf

  • A serialized data structure developed by Google and released as open source
  • Serialization is the act of storing data in the form of a binary stream for file storage or network transmission
  • Supports up to 64M per file
  • It is possible to convert JSON files to the protocol buffer file format, and vice versa, protocol buffer files can also be converted to JSON
  • When communicating with protobuf, if the value is the same as the default value, it is not transmitted during communication
  • Mainly, the Protobuf model is contained in the RequestBody of POST in the Rest server for communication

0. Syntax

1
syntax="proto3";
  • There are proto2 and proto3 in syntax.
  • If this content is not present, proto2 is automatically applied
  • To utilize gRPC, proto3 must be used.

1. Message Types

1
2
3
4
5
6
7
syntax = "proto3";

message SearchRequest {
  string query = 1; // String field
  int32 page_number = 2; // Integer field
  int32 result_per_page = 3;
}
  • int32, int64: Positive and negative
  • uint32, uint64: Unsigned 2-byte integer
  • sint32, sint64: Signed 2-byte integer, more efficient than normal int32
  • fixed32, fixed64: Always more efficient than uint32 when greater than 4 bytes
  • sfixed32, sfixed64: Always more efficient than uint64 when greater than 8 bytes
  • bool
  • string
  • bytes
1
2
3
4
5
**Default values for the above**
numeric: 0
bool: false
string: null
byte: null

2. Message Fields

1
2
3
4
5
6
7
8
message SearchRequest {
  required string query = 1;
  optional int32 page_number = 2;
  repeated int32 result_per_page = 3;
}
/*
In proto3, required and optional are deprecated
*/

3. Field Numbers

1
2
3
4
5
6
7
8
message SearchRequest {
  reserved 3, 9, 5 to 7;
  reserved "leo", "dabin";
}
/*
If a previously used field is removed in the middle and then reused later, it can cause consistency and compatibility issues
Reserve fields in advance
*/
  • Each field has a unique number
  • During encoding, field numbers 1~15 use 1 byte
  • Numbers 16~2047 use 2 bytes
  • Frequently occurring messages are assigned in the range 1~15

4. Service

  • Defines the procedure to be called by the stub object on the client side
1
2
3
service Chat {
  rpc Login(LoginRequest) returns (Token) {}
}
  • Service defines the form of functions that the server will provide to the client through RPC
  • CamelCase is recommended for service names and RPC method names
  • By giving the stream option, bidirectional streaming RPC can be implemented
1
2
3
service User {
  rpc Login(LoginRequest) returns (Token) {}
}
  • If the client sends a single request to the server, the server returns a single response
1
2
3
service User {
  rpc Login(LoginRequest) returns (stream Token) {}
}
  • Server Streaming RPC: If the client sends a single request to the server, the server returns a stream. The stream contains a sequence of messages
  • The client reads the stream until there are no more messages
1
2
3
service User {
  rpc Login(stream LoginRequest) returns (Token) {}
}
  • Client Streaming RPC: The client sends a sequence of messages to the server using the given stream
  • The client writes all the messages and waits for the server to read and give a response
1
2
3
service User {
  rpc Login(stream LoginRequest) returns (stream Token) {}
}
  • Bidirectional Streaming RPC: Both the client and the server send a sequence of messages using a read-write stream
  • The two streams operate independently, and the client and server can read them in order
  • For example, the server can write responses after reading all the client’s messages, or it can alternately read and write messages one by one

Enum

1
2
3
4
5
6
7
8
9
10
enum Corpus {
  CORPUS_UNSPECIFIED = 0;
  CORPUS_UNIVERSAL = 1;
  CORPUS_WEB = 2;
  CORPUS_IMAGES = 3;
  CORPUS_LOCAL = 4;
  CORPUS_NEWS = 5;
  CORPUS_PRODUCTS = 6;
  CORPUS_VIDEO = 7;
}
  • Enums must start with 0

Using Other Message Types

1
2
3
4
5
6
7
message Login {
  User data = 1;
}
message User {
  string id = 1;
  string name = 2;
}
  • Other message types can be used as field types

Nested Types

1
2
3
4
5
6
7
message User_Login {
  message Login {
    string id = 1;
    string password = 2;
  }
  repeated Result results = 1;
}
  • Message types can be nested

Oneof

  • A feature that can be applied to the behavior and save memory when there is a message with many fields and at most one field is set at a time
  • When setting a member of oneof, all other members are automatically cleared
message SampleMessage {
  oneof test_oneof {
    string name = 4;
    SubMessage sub_message = 9;
  }
}

Map Type

1
2
3
message ExampleRequest {
  map<string, string> requests = 1;
}
  • Map can be used as a field type

Package

1
2
3
4
5
6
7
syntax="proto3";

package grpc.sample2;

message ExampleRequest {
  map<string, string> requests = 1;
}
  • A package specifier can optionally be added to the file to avoid name conflicts between proto buf types

Example

Example

  • The back-end server is in Golang
  • Each server