为什么RPC通常基于tcp而不是 websocket或者http2,处理粘包,拆包,压缩,长度等问题?

内容分享7小时前发布
1 4 0

记住我这句话,对于追求极致性能的基础设施来说,那些所谓的方便,全是累赘。

我很理解你的想法,TCP 还要自己处理粘包拆包,多麻烦啊,WebSocket 和 HTTP/2 都帮你切好帧了,直接拿来用不香吗?

一、 真有那么麻烦吗?

你觉得处理粘包、拆包、计算长度很麻烦,是由于你站在应用层开发的视角。但在 RPC 框架开发者眼里,这就是10 行代码的事儿。

粘包拆包完全不难啊,定一个协议头 Header,里面放一个 Length 字段。读的时候先读头,拿到长度,再读 Body。Netty 里一个
LengthFieldBasedFrameDecoder 就搞定了。

压缩也不难,拿到 Body 的字节数组,调用一下 Snappy 或 Gzip 压缩,完事。

为了省下这几十行通用的底层代码,去引入 WebSocket 或 HTTP 2 有点得不偿失吧!

二、 WebSocket 烦琐

WebSocket 主要是为浏览器设计的,它的许多机制在服务器内部RPC通信场景下,显得许多余。

Web 环境本身不安全,为了安全浏览器发出的 WebSocket 帧是要进行掩码处理的。服务端收到消息后,又会消耗 CPU 去做一次异或运算解密,才能拿到数据。

那都在内网微服务调用里,大家都是自己人,你防谁呢? 这不纯纯浪费算力嘛。

而且 WebSocket 握手流程也繁琐,建连接前先发一个 HTTP 升级协议的请求,服务器响应 101,才能升级Upgrade。

RPC 的核心设计要求就是快,没有比直接 TCP 三次握手直连效率更快的了。WebSocket 应用主要是解决穿透防火墙和浏览器兼容上,并不太擅长高性能传输。

三、 HTTP2 冗余

gRPC 底层选择 HTTP/2,应该是看中了它的标准化和生态,毕竟谁都认识HTTP。但如果要追求极致吞吐的场景,相比之下 HTTP/2 还是显得冗余。

你发一个HTTP请求,Header 还得带上 method, path 这些伪头。但要弄一个私有 TCP 协议,我就定义一个字节 Magic Number,一个字节 Type,一个 RequestID,剩下的全是数据,没有一个字节是多余的。

四、 可操作性

RPC 框架要对网络层有强的可控性,列如我要准确控制连接的生老病死,心跳检测 KeepAlive 就要自己实现,由于 TCP 层的 KeepAlive 太慢太呆了。

还有缓冲区管理,Netty + TCP 可以做到零拷贝,直接把网卡的 Buffer 指针指来指去,不需要把数据在用户态内存里拷来拷去。如果中间隔了一层 HTTP/2 或 WebSocket 的库,你很难深入到底层去做这种优化。

服务器内部通信场景,WebSocket 给浏览器设计的,有一些没用的安全机制,HTTP 又不够精简,TCP + 私有协议用一点点开发成本换高性能,实则很划算

© 版权声明

相关文章

4 条评论

  • 头像
    田拾叁 读者

    写的不错的,重点还是性能与流量治理

    无记录
    回复
  • 头像
    Szh____ 读者

    关键是rpc大部分都是微服务,在调用,根本不会在乎Http这一点点消耗呀,你要做流服务,那你用TCP

    无记录
    回复
  • 头像
    天边 读者

    rpc不在乎http损耗?如果美团淘宝这种内部那么多微服务调用http浪费大了去了。。小公司无所谓,都不用上这种框架,走内部http调用完事

    无记录
    回复
  • 头像
    林升扬 读者

    tcp也不是最好的,三次握手导致效率低下,而流式处理也不适合这种一来一回的调用。更好的是基于udp的定制协议,…那不就是QUIC么?

    无记录
    回复