liangdas / mqant

mqant是一款基于Golang语言的简洁,高效,高性能的分布式微服务框架

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

protobuf中带有二进制数组使用rpc会改变二进制数组cap

huangbwww opened this issue · comments

如题,使用这套rpc进行通信是,请求参数使用protobuf,如果含有protobuf的bytes类型,可能导致rpc_server接收到的二进制数组cap发生改变,进而导致解析报错。

我最近也用到了protobuf的bytes类型,貌似么有发现问题,是必现吗?是否有示例参考一下

嗯 我把我大概使用场景贴给你看看
我的proto

message UpdatePlayerDataReq {
  uint64 account_id = 1;
  string nickname = 2;
  bytes data = 3;
}

rpc调用方

err = mqrpc.Proto(rsp, func() (reply interface{}, err interface{}) {
	return proxy.cli.Call(context.TODO(), “db_proxy”, "updateplayerdata", mqrpc.Param(req))
})

rpc接收方
注册
m.GetServer().RegisterGO("updateplayerdata", ser.UpdatePlayerData)

UpdatePlayerData接口

func (dm *DBProxyModule) UpdatePlayerData(req *pb.UpdatePlayerDataReq) (*pb.Empty, error) {
	return &pb.Empty{}, nil
}

这是我第一个使用bytes在rpc间进行传输的协议,一开始我的data数据是一个protobuf的二进制又经过了snappy压缩,出现的问题是发送时的请求参数encode的protobuf二进制的cap要比接收方收到的大,二进制数据时对的,所以proto解码req这个请求参数时报了一个无效二进制的报错。

然后我就尝试去掉了data的snppy过程,直接把一个数据通过protobuf进行encode然后放进了data进行传输,这次通讯时完成了但是接收方的req里的数据都是nil,表现像是拿一个nil进行了decode

然后我把二进制搞了下base64字符串,再尝试就没有出现问题。

时间问题我当时尝试成功就先用base64进行传输了,二进制的问题断点看了一点,只看到了第一次的cap问题,等有时间我再尝试看看

我又排查了一下,上面说的我漏掉了中间的string,编辑补充上了
同样是这个proto

message UpdatePlayerDataReq {
  uint64 account_id = 1;
  string nickname = 2;
  bytes data = 3;
}

接收方都是用proto
发送方使用ArgType: ProtocolMarshal会有这个问题
如果proto中是uint64+string+bytes的组合,bytes如果是snappy压缩的那就会报错,如果不压缩会解析不出数据,但是我如果去掉中间的string,只发一个uint64+bytes,就都可以用了,对比了bytes内容发现除了cap都一模一样,但是在别的场景下测试发现cap的差别其实不会影响decode

发送方使用ArgType: []byte不会有个问题

具体问题还是没有排查到

我知道为啥了,和我的名字叫data有关系,ProtocolMarshal接口内的func叫做GetData(),这样我生成的proto的data字段会带有GetData(),这个结构就会被识别为ProtocolMarshal,然后底层2Bytes或者2Args的时候会判定进ProtocolMarshal,通过接口的GetData来获取二进制,这样就把二进制给损坏了。
应该就是这个原因,前面没有再仔细地进更里面的接口去看原因,今天有时间就往更深调试了下流程,熟悉了下底层流程后就比较快调试到问题所在。大佬可以看看能不能加个注释提醒一下,不要不小心实现了ProtocolMarshal接口,踩到小坑-……