gRPC 调整数据传输大小限制 介绍 安装 快速开始 调整

小知识,大挑战!本文正在参与“ 程序员必备小知识 ”创作活动

本文同时参与 「掘力星计划」 ,赢取创作大礼包,挑战创作激励金

介绍

本文介绍如何通过 rk-boot 调整 gRPC 数据传输大小限制。

grpc 的大小限制存在于接收方,也就是说发送多大的数据没有限制,接收默认大小是 4MB。
例子里使用的是 google.golang.org/grpc v1.38.0 版本。

什么是 gRPC 数据传输大小限制?

gRPC 服务端默认最大数据传输大小为 4MB,有些时候,我们需要传输更大的数据,比如大图片。

请访问如下地址获取完整教程:

安装

1
2
go复制代码go get github.com/rookie-ninja/rk-boot
go get github.com/rookie-ninja/rk-grpc

快速开始

rk-boot 支持通过代码 & YAML 文件的方式调整大小限制。

为了完整演示,我们创建一个 greeter API。

1.创建 protobuf 相关文件

我们使用 buf 命令行来编译 protobuf,需要创建如下几个文件。

文件名 描述
api/v1/greeter.proto protobuf 文件
buf.yaml 告诉 buf 命令行在哪里寻找 protobuf 文件
buf.gen.yaml 告诉 buf 命令行如何编译 protobuf 文件
  • api/v1/greeter.proto
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
protobuf复制代码syntax = "proto3";

package api.v1;

option go_package = "api/v1/greeter";

service Greeter {
rpc Greeter (GreeterRequest) returns (GreeterResponse) {}
}

message GreeterRequest {
bytes msg = 1;
}

message GreeterResponse {}
  • buf.yaml
1
2
3
4
5
yaml复制代码version: v1beta1
name: github.com/rk-dev/rk-demo
build:
roots:
- api
  • buf.gen.yaml
1
2
3
4
5
6
7
8
9
10
11
12
13
yaml复制代码version: v1beta1
plugins:
# protoc-gen-go needs to be installed, generate go files based on proto files
- name: go
out: api/gen
opt:
- paths=source_relative
# protoc-gen-go-grpc needs to be installed, generate grpc go files based on proto files
- name: go-grpc
out: api/gen
opt:
- paths=source_relative
- require_unimplemented_servers=false
  • 编译 protobuf 文件
1
shell复制代码$ buf generate

2.创建 boot.yaml

我们通过 boot.yaml 方式来【取消】大小限制,通过 boot.yaml 我们可以取消限制,但是无法调整限制。

调整限制的话,可以通过代码调整,我们也会在下面介绍。

1
2
3
4
5
6
yaml复制代码---
grpc:
- name: greeter # Name of grpc entry
port: 8080 # Port of grpc entry
enabled: true # Enable grpc entry
noRecvMsgSizeLimit: true

3.创建 server.go

我们实现了 greeter 接口。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
go复制代码// Copyright (c) 2021 rookie-ninja
//
// Use of this source code is governed by an Apache-style
// license that can be found in the LICENSE file.
package main

import (
"context"
"github.com/rookie-ninja/rk-boot"
"github.com/rookie-ninja/rk-demo/api/gen/v1"
"github.com/rookie-ninja/rk-grpc/boot"
"google.golang.org/grpc"
)

// Application entrance.
func main() {
// Create a new boot instance.
boot := rkboot.NewBoot()

// Get grpc entry with name
grpcEntry := boot.GetEntry("greeter").(*rkgrpc.GrpcEntry)
grpcEntry.AddRegFuncGrpc(registerGreeter)

// Bootstrap
boot.Bootstrap(context.Background())

// Wait for shutdown sig
boot.WaitForShutdownSig(context.Background())
}

func registerGreeter(server *grpc.Server) {
greeter.RegisterGreeterServer(server, &GreeterServer{})
}

type GreeterServer struct{}

func (server *GreeterServer) Greeter(ctx context.Context, request *greeter.GreeterRequest) (*greeter.GreeterResponse, error) {
return &greeter.GreeterResponse{}, nil
}

4.创建 client.go

我们试着传输 10MB 的数据。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
go复制代码// Copyright (c) 2021 rookie-ninja
//
// Use of this source code is governed by an Apache-style
// license that can be found in the LICENSE file.
package main

import (
"context"
"github.com/rookie-ninja/rk-demo/api/gen/v1"
"google.golang.org/grpc"
"log"
)

func main() {
opts := []grpc.DialOption{
grpc.WithInsecure(),
grpc.WithBlock(),
}

// 1: Create grpc client
conn, client := createGreeterClient(opts...)
defer conn.Close()

kb := 1024
mb := 1024*kb

// 2: Call server with 10mb size of data
if _, err := client.Greeter(context.Background(), &greeter.GreeterRequest{Msg: make([]byte, 10*mb, 10*mb)}); err != nil {
panic(err)
}
}

func createGreeterClient(opts ...grpc.DialOption) (*grpc.ClientConn, greeter.GreeterClient) {
// 1: Set up a connection to the server.
conn, err := grpc.DialContext(context.Background(), "localhost:8080", opts...)
if err != nil {
log.Fatalf("Failed to connect: %v", err)
}

// 2: Create grpc client
client := greeter.NewGreeterClient(conn)

return conn, client
}

5.文件夹结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
go复制代码.
├── api
│ ├── gen
│ │ └── v1
│ │ ├── greeter.pb.go
│ │ └── greeter_grpc.pb.go
│ └── v1
│ └── greeter.proto
├── boot.yaml
├── buf.gen.yaml
├── buf.yaml
├── client.go
├── go.mod
├── go.sum
└── server.go

6.验证

不会出现任何错误。

1
2
go复制代码$ go run server.go
$ go run client.go

因为服务端默认只允许接收 4MB 大小的数据,如果我们在 boot.yaml 里把 noRecvMsgSizeLimit 设置成 false,会得到如下错误。

1
ini复制代码rpc error: code = ResourceExhausted desc = grpc: received message larger than max (10485765 vs. 4194304)

调整【服务端】传输数据大小

上次的例子中,我们使用 noRecvMsgSizeLimit 选项取消了 gRPC 服务端的大小限制,这次,我们试着调整大小。
还是使用上面的 protobuf 文件。

1.修改 boot.yaml

这次我们把 noRecvMsgSizeLimit 设置成 false。

1
2
3
4
5
6
yaml复制代码---
grpc:
- name: greeter # Name of grpc entry
port: 8080 # Port of grpc entry
enabled: true # Enable grpc entry
noRecvMsgSizeLimit: false

2.修改 server.go

我们通过 AddServerOptions() 函数设置服务端接收最大值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
go复制代码// Copyright (c) 2021 rookie-ninja
//
// Use of this source code is governed by an Apache-style
// license that can be found in the LICENSE file.
package main

import (
"context"
"github.com/rookie-ninja/rk-boot"
"github.com/rookie-ninja/rk-demo/api/gen/v1"
"github.com/rookie-ninja/rk-grpc/boot"
"google.golang.org/grpc"
)

// Application entrance.
func main() {
// Create a new boot instance.
boot := rkboot.NewBoot()

// Get grpc entry with name
grpcEntry := boot.GetEntry("greeter").(*rkgrpc.GrpcEntry)
grpcEntry.AddRegFuncGrpc(registerGreeter)

// *************************************** //
// *** Set server receive size to 20MB ***
// *************************************** //
kb := 1024
mb := 1024*kb
grpcEntry.AddServerOptions(grpc.MaxRecvMsgSize(20*mb))

// Bootstrap
boot.Bootstrap(context.Background())

// Wait for shutdown sig
boot.WaitForShutdownSig(context.Background())
}

func registerGreeter(server *grpc.Server) {
greeter.RegisterGreeterServer(server, &GreeterServer{})
}

type GreeterServer struct{}

func (server *GreeterServer) Greeter(ctx context.Context, request *greeter.GreeterRequest) (*greeter.GreeterResponse, error) {
return &greeter.GreeterResponse{}, nil
}

3.验证

不会出现任何错误。

1
2
go复制代码$ go run server.go
$ go run client.go

如果我们发送的数据大于 20mb,会出现如下错误。

1
ini复制代码rpc error: code = ResourceExhausted desc = grpc: received message larger than max (31457285 vs. 20971520)

调整【客户端】传输数据大小

如果服务端返回的数据大于 4MB,我们需要在客户端调整大小。

1
2
3
4
5
6
7
8
go复制代码kb := 1024
mb := 1024*kb

opts := []grpc.DialOption{
grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(20*mb)),
grpc.WithInsecure(),
grpc.WithBlock(),
}

本文转载自: 掘金

开发者博客 – 和开发相关的 这里全都有

0%