前言
本章节将介绍 gRPC 的流式,分为三种类型:
Server-side streaming RPC:服务器端流式 RPC
Client-side streaming RPC:客户端流式 RPC
Bidirectional streaming RPC:双向流式 RPC
流
任何技术,因为有痛点,所以才有了存在的必要性。如果您想要了解 gRPC 的流式调用,请继续
图
gRPC Streaming 是基于 HTTP/2 的,后续章节再进行详细讲解
为什么不用 Simple RPC
流式为什么要存在呢,是 Simple RPC 有什么问题吗?通过模拟业务场景,可得知在使用 Simple RPC 时,有如下问题:
数据包过大造成的瞬时压力
接收数据包时,需要所有数据包都接受成功且正确后,才能够回调响应,进行业务处理(无法客户端边发送,服务端边处理)
为什么用 Streaming RPC
大规模数据包
实时场景
模拟场景
每天早上 6 点,都有一批百万级别的数据集要同从 A 同步到 B,在同步的时候,会做一系列操作(归档、数据分析、画像、日志等)。这一次性涉及的数据量确实大
在同步完成后,也有人马上会去查阅数据,为了新的一天筹备。也符合实时性。
两者相较下,这个场景下更适合使用 Streaming RPC
gRPC
在讲解具体的 gRPC 流式代码时,会着重在第一节讲解,因为三种模式其实是不同的组合。希望你能够注重理解,举一反三,其实都是一样的知识点 👍
目录结构
$ tree go-grpc-example
go-grpc-example
├── client
│ ├── simple_client
│ │ └── client.go
│ └── stream_client
│ └── client.go
├── proto
│ ├── search.proto
│ └── stream.proto
└── server
├── simple_server
│ └── server.go
└── stream_server
└── server.go
增加 streamserver、streamclient 存放服务端和客户端文件,proto/stream.proto 用于编写 IDL
IDL
在 proto 文件夹下的 stream.proto 文件中,写入如下内容:
syntax = "proto3";
package proto;
service StreamService {
rpc List(StreamRequest) returns (stream StreamResponse) {};
rpc Record(stream StreamRequest) returns (StreamResponse) {};
rpc Route(stream StreamRequest) returns (stream StreamResponse) {};
}
message StreamPoint {
string name = 1;
int32 value = 2;
}
message StreamRequest {
StreamPoint pt = 1;
}
message StreamResponse {
StreamPoint pt = 1;
}
注意关键字 stream,声明其为一个流方法。这里共涉及三个方法,对应关系为
List:服务器端流式 RPC
Record:客户端流式 RPC
Route:双向流式 RPC
基础模板 + 空定义
Server
package main
import (
"log"
"net"
"google.golang.org/grpc"
pb "github.com/EDDYCJY/go-grpc-example/proto"
)
type StreamService struct{}
const (
PORT = "9002"
)
func main() {
server := grpc.NewServer()
pb.RegisterStreamServiceServer(server, &StreamService{})
lis, err := net.Listen("tcp", ":"+PORT)
if err != nil {
log.Fatalf("net.Listen err: %v", err)
}
server.Serve(lis)
}
func (s *StreamService) List(r *pb.StreamReque