grpc能传大文件,但默认配置下必崩——rpc error: code = resourceexhausted desc = grpc: received message larger than max 是最常见报错,根源是默认4mb消息限制和proto字段设计陷阱;必须用stream关键字正确定义流式rpc、显式调大收发缓冲、分块读写、避免proto实例复用及中间件静默断连。

直接说结论:gRPC能传大文件,但默认配置下必崩——rpc error: code = ResourceExhausted desc = grpc: received message larger than max 是最常见报错,根源是默认 4MB 消息限制和 proto 字段设计陷阱。
proto 里怎么定义流式消息才不 OOM
别用 repeated bytes data 或单个超大 bytes 字段。gRPC 序列化器会试图一次性分配整块内存,100MB 文件直接触发 OOM。
- 必须拆成带元信息的 chunk:定义
chunk_id(int64)、offset(int64)、data(bytes,单次 ≤1MB)、checksum(uint32可选) - 双向流场景用
rpc Sync(stream FileChunk) returns (stream SyncAck),不是rpc Upload(stream bytes) -
stream关键字位置不能错:写在请求侧就是客户端流,写在响应侧才是服务端流,写两边才是双向流
客户端发文件时怎么避免卡死或内存暴涨
常见错误是 os.ReadFile() 读全量再塞进 stream.Send(),协程瞬间吃光内存。
- 用
io.Copy分块读写:每次make([]byte, 1024*1024),读一块发一块 - 别用
for range stream.Recv()接收响应——某次卡住就永久挂起;改用select+stream.RecvMsg(&msg)+ 超时控制 - 确保
*grpc.ClientConn复用,别每次调用都grpc.Dial()新建连接 - 主动发心跳:每 5 个 chunk 发一次空
data+is_heartbeat: true,防 NAT/Envoy 断连
服务端收文件时必须调哪些参数和检查点
默认配置下,服务端收到第 4MB 数据就会断连,错误信息里明写着 4194304。
- 启动时显式调大限制:
grpc.MaxRecvMsgSize(64 * 1024 * 1024)和grpc.MaxSendMsgSize(64 * 1024 * 1024) - 接收逻辑别复用同一个
*pb.FileChunk实例:proto 内部 buffer 会被覆盖,导致客户端收到乱码 - 写文件用
os.WriteAt(data, offset)直接落盘,别拼接内存再写 - 每次收到 chunk 后校验
checksum,失败立即返回status.Error(codes.Aborted, "checksum mismatch") - 务必检查
stream.Context().Err(),遇到context.DeadlineExceeded或context.Canceled要清理临时文件
真正麻烦的从来不是“能不能传”,而是中间件(比如 Envoy)、NAT、防火墙对长连接的静默回收,以及 proto 定义和 Go 实现之间那几处看似微小、实则致命的细节偏差。











