一次RPC学习

image.png

最近写自己项目的时候,发现到现在都没什么好用的跨语言RPC。本来打算写一个新的无IDL的RPC。但是最终放弃了。

协议性能跨语言IDL序列化
dubboTCP,HTTP高,跨语言需要走HTTP2(支持HTTP1)跨语言需要IDL跨语言主力支持triple
thrift可组合TCP,HTTP高,但同一个连接同时只能一个请求需要中间语言定义函数和数据模型thrift
grpcprotobuf+HTTP2能够并行多请求,但是底层受限于HTTP2性能需要中间语言定义函数和数据模型protobuf
TARSTCP,UDP(不可靠)requestId实现TCP多路复用需要中间语言定义函数和数据模型TARS 自有二进制编码
ZeroC IceTCP,UDP(不可靠)requestId实现TCP多路复用,通用RPC元数据稍多需要中间语言定义函数和数据模型Ice Encoding
ConnectRPCHTTPHTTP2需要中间语言定义函数和数据模型protobuf

IDL上限注定是较高的。但相对来说麻烦。要学习IDL的语言语法,然后让这个IDL在双方生成对应的函数和数据模型。如果发生改变还要在双方同步修改后的IDL。

我这里打算实现类似http+json的体验。啥都不用管,直接调用完事。序列化使用fory(Apache的跨语言序列化反序列化库)。

问题来了,如何保证跨语言的统一呢。比如A定义了u32,但是java只有i32 。这个问题其实已经被fory解决了。这里只是阐述fory的解决方案。

但是我们发现json+http这个被使用最多的“RPC”模式其实也没有解决这个问题。讲个笑话,json对json的支持不好。json的没有u64,因此

{ "id": 9007199254740993} 能被python,java,php,rust,go正常解析为整数。但是js就有问题。

因此i32传u32,底层是二进制表示不同,结果自然是不同的。但是一方如果定义的是u32,一方定义的是u64。在没有溢出的情况下,数据则不会产生任何问题。理论上双方只要定义了相同的数据结构,就不会出现问题。

优势:fory的序列化性能数倍于protobuf,加上TCP的高性能。遇到python,js等低效率语言,用rust做底层的TCP reactor的多路复用。应该能在无IDL的情况下,性能超越主流以上除了TARS(面对TARS至少能打平)所有RPC。可以将IDL作为一个可扩展选项。双方定义的时候就像定义HTTP接口一样自然。给方法注册一个路径。等待对方请求。

这个项目最终被放弃:原因如下,http是网络世界的一等公民,兼容性最好,nginx,envoy等天然支持各种负载均衡算法。json的最重要的是人类可读性和性能之间权衡的最优解。因此写一个类似的RPC作用有限。无IDL不能成为一个核心卖点,这不只是一个工程上的取舍。更是跨团队的协作规范。并且有IDL的情况下,性能能达到更高的上限是一定的。TARS,zeroC ICE都会将网络核心逻辑交给C++实现,因此,重复造轮子是没有意义的。不能作为绝对性优势。

本身的想法是该RPC框架可以随时转换成HTTP调用(因为以HTTP风格来注册的接口)。但是get请求,和HTTP的各种路径参数反而成了一个问题。

最终,该想法被废弃。但是仍然是一次有趣的学习经历。

Last modification:August 31, 2026
如果觉得我的文章对你有用,请随意赞赏