工作的时候,第一次接触CRPC协议,当时就很懵,啥是CRPC协议,一脸懵逼,于是就到网上去搜,填充知识空缺。

不少解释显得非常官方,我相信大家在各种平台上也都看到过,解释了又好像没解释,都在用一个我们不认识的概念去解释另外一个我们不认识的概念,懂的人不需要看,不懂的人看了还是不懂。

从TCP聊起

作为一个程序员,假设我们需要在A电脑的进程发一段数据到B电脑的进程,我们一般会在代码里使用socket进行编程。这时候,我们可选项一般也就TCP和UDP二选一。TCP可靠,UDP不可靠,只要稍微对可靠性有些要求,普通人一般无脑选TCP就对了。

在定义了socket之后,我们就可以愉快的对这个socket进行操作,比如用bind()绑定IP端口,用connect()发起建连。

之后,我们就可以使用send()发送数据,recv()接收数据。

光这样一个纯裸的TCP连接,就可以做到收发数据了,那是不是就够了?不行,这么用会有问题。

字节流可以理解为一个双向的通道里流淌的数据,这个数据其实就是我们常说的二进制数据,简单来说就是一大堆 01 串。纯裸TCP收发的这些 01 串之间是没有任何边界的,你根本不知道到哪个地方才算一条完整消息。

正因为这个没有任何边界的特点,所以当我们选择使用TCP发送"夏洛"和"特烦恼"的时候,接收端收到的就是"夏洛特烦恼",这时候接收端没发区分你是想要表达"夏洛"+"特烦恼"还是"夏洛特"+"烦恼"

这就是所谓的粘包问题

说这个的目的是为了告诉大家,纯裸TCP是不能直接拿来用的,你需要在这个基础上加入一些自定义的规则,用于区分消息边界

于是我们会把每条要发送的数据都包装一下,比如加入消息头消息头里写清楚一个完整的包长度是多少,根据这个长度可以继续接收数据,截取出来后它们就是我们真正要传输的消息体。(中信银行在18年以前都是使用LR做socket协议的同学深有体会)

这里头提到的消息头,还可以放各种东西,比如消息体是否被压缩过和消息体格式之类的,只要上下游都约定好了,互相都认就可以了,这就是所谓的协议。

每个使用TCP的项目都可能会定义一套类似这样的协议解析标准,他们可能有区别,但原理都类似

于是基于TCP,就衍生了非常多的协议,比如HTTP和RPC

TCP是传输层的协议,而基于TCP造出来的HTTP和各类RPC协议,它们都只是定义了不同消息格式的应用层协议而已。

HTTP协议(Hyper Text Transfer Protocol),又叫做超文本传输协议。我们用的比较多,平时上网在浏览器上敲个网址就能访问网页,这里用到的就是HTTP协议

RPCRemote Procedure Call),又叫做远程过程调用。它本身并不是一个具体的协议,而是一种调用方式

举个例子,我们平时调用一个本地方法就像下面这样。

 res = localFunc(req)

如果现在这不是个本地方法,而是个远端服务器暴露出来的一个方法remoteFunc,如果我们还能像调用本地方法那样去调用它,这样就可以屏蔽掉一些网络细节,用起来更方便,岂不美哉?

res = remoteFunc(req)
 

基于这个思路,大佬们造出了非常多款式的RPC协议,比如比较有名的gRPC(谷歌的),CRPC(中信的)

虽然大部分RPC协议底层使用TCP,但实际上它们不一定非得使用TCP,改用UDP或者HTTP,其实也可以做到类似的功能

既然有HTTP协议,为什么还要有RPC?

其实,TCP70年代出来的协议,而HTTP90年代才开始流行的。而直接使用裸TCP会有问题,可想而知,这中间这么多年有多少自定义的协议,而这里面就有80年代出来的RPC

所以我们该问的不是既然有HTTP协议为什么要有RPC,而是为什么有RPC还要有HTTP协议

那既然有RPC了,为什么还要有HTTP呢?

现在电脑上装的各种联网软件,比如xx管家,xx卫士,它们都作为客户端(client)需要跟服务端(server)建立连接收发消息,此时都会用到应用层协议,在这种client/server (c/s)架构下,它们可以使用自家造的RPC协议,因为它只管连自己公司的服务器就ok了。

但有个软件不同,浏览器(browser),不管是chrome还是IE,它们不仅要能访问自家公司的服务器(server),还需要访问其他公司的网站服务器,因此它们需要有个统一的标准,不然大家没法交流。于是,HTTP就是那个时代用于统一 browser/server (b/s) 的协议。

也就是说在多年以前,HTTP主要用于b/s架构,而RPC更多用于c/s架构。但现在其实已经没分那么清了,b/s和c/s在慢慢融合。很多软件同时支持多端,比如某度云盘,既要支持网页版,还要支持手机端和pc端,如果通信协议都用HTTP的话,那服务器只用同一套就够了。而RPC就开始退居幕后,一般用于公司内部集群里,各个微服务之间的通讯。

那这么说的话,都用HTTP得了,还用什么RPC?

仿佛又回到了开头的样子,那这就要从它们之间的区别开始说起。

HTTP和RPC有什么区别

服务发现

首先要向某个服务器发起请求,你得先建立连接,而建立连接的前提是,你得知道IP地址和端口。这个找到服务对应的IP端口的过程,其实就是服务发现

HTTP中,你知道服务的域名,就可以通过DNS服务去解析得到它背后的IP地址,默认80端口。

RPC的话,就有些区别,一般会有专门的中间服务去保存服务名和IP信息,比如consul或者etcd,甚至是redis。想要访问某个服务,就去这些中间服务去获得IP和端口信息。由于dns也是服务发现的一种,所以也有基于dns去做服务发现的组件,比如CoreDNS

可以看出服务发现这一块,两者是有些区别,但不太能分高低。

底层连接形式

以主流的HTTP1.1协议为例,其默认在建立底层TCP连接之后会一直保持这个连接(keep alive),之后的请求和响应都会复用这条连接。

RPC协议,也跟HTTP类似,也是通过建立TCP长链接进行数据交互,但不同的地方在于,RPC协议一般还会再建个连接池,在请求量大的时候,建立多条连接放在池内,要发数据的时候就从池里取一条连接出来,用完放回去,下次再复用,可以说非常环保。

由于连接池有利于提升网络请求性能,所以不少编程语言的网络库里都会给HTTP加个连接池,比如go就是这么干的。

可以看出这一块两者也没太大区别,所以也不是关键。

传输的内容

基于TCP传输的消息,说到底,无非都是消息头header和消息体body。

header是用于标记一些特殊信息,其中最重要的是消息体长度

body则是放我们真正需要传输的内容,而这些内容只能是二进制01串,毕竟计算机只认识这玩意。所以TCP传字符串和数字都问题不大,因为字符串可以转成编码再变成01串,而数字本身也能直接转为二进制。但结构体呢,我们得想个办法将它也转为二进制01串,这样的方案现在也有很多现成的,比如json,protobuf。

这个将结构体转为二进制数组的过程就叫序列化,反过来将二进制数组复原成结构体的过程叫反序列化

对于主流的HTTP1.1,虽然它现在叫超文本协议,支持音频视频,但HTTP设计初是用于做网页文本展示的,所以它传的内容以字符串为主。header和body都是如此。在body这块,它使用json序列化结构体数据。

我们可以随便截个图直观看下。

可以看到这里面的内容非常多的冗余,显得非常啰嗦。最明显的,像header里的那些信息,其实如果我们约定好头部的第几位是content-type,就不需要每次都真的把"content-type"这个字段都传过来,类似的情况其实在body的json结构里也特别明显。

而RPC,因为它定制化程度更高,可以采用体积更小的protobuf或其他序列化协议去保存结构体数据,同时也不需要像HTTP那样考虑各种浏览器行为,比如302重定向跳转啥的。因此性能也会更好一些,这也是在公司内部微服务中抛弃HTTP,选择使用RPC的最主要原因。

当然上面说的HTTP,其实特指的是现在主流使用的HTTP1.1HTTP2在前者的基础上做了很多改进,所以性能可能比很多RPC协议还要好,甚至连gRPC底层都直接用的HTTP2

那么问题又来了。

为什么既然有了HTTP2,还要有RPC协议?

这个是由于HTTP2是2015年出来的。那时候很多公司内部的RPC协议都已经跑了好些年了,基于历史原因,一般也没必要去换了。

总结

  • 纯裸TCP是能收发数据,但它是个无边界的数据流,上层需要定义消息格式用于定义消息边界。于是就有了各种协议,HTTP和各类RPC协议就是在TCP之上定义的应用层协议。

  • RPC本质上不算是协议,而是一种调用方式,而像gRPC和thrift这样的具体实现,才是协议,它们是实现了RPC调用的协议。目的是希望程序员能像调用本地方法那样去调用远端的服务方法。同时RPC有很多种实现方式,不一定非得基于TCP协议

  • 从发展历史来说,HTTP主要用于b/s架构,而RPC更多用于c/s架构。但现在其实已经没分那么清了,b/s和c/s在慢慢融合。很多软件同时支持多端,所以对外一般用HTTP协议,而内部集群的微服务之间则采用RPC协议进行通讯。

  • RPC其实比HTTP出现的要早,且比目前主流的HTTP1.1性能要更好,所以大部分公司内部都还在使用RPC。

  • HTTP2.0HTTP1.1的基础上做了优化,性能可能比很多RPC协议都要好,但由于是这几年才出来的,所以也不太可能取代掉RPC。

什么是RPC协议的更多相关文章

  1. 游戏编程系列[1]--游戏编程中RPC协议的使用

    RPC(Remote Procedure Call Protocol)--远程过程调用协议,它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议.RPC协议假定某些传输协议的存在 ...

  2. 传入的表格格式数据流(TDS)远程过程调用(RPC)协议流不正确。此 RPC 请求中提供了过多的参数。最多应为 2100

    出现这个问题的背景是,判断一批激活码在系统中是否已经存在,很傻的一个作法是,把这一批激活码,以in(in (‘ddd‘,‘aaa‘))的形式来处理,导致问题的出现. 后来,查找资料,http://bb ...

  3. Hessian 二进制RPC协议框架

    Hessian是一个由Caucho Technology开发的轻量级二进制RPC协议. 和其他Web服务的实现框架不同的是,Hessian是一个使用二进制轻量级的Web服务协议的框架,免除了许多附加的 ...

  4. 初识RPC协议

    什么是rpc框架 先回答第一个问题:什么是RPC框架? 如果用一句话概括RPC就是:远程调用框架(Remote Procedure Call) 那什么是远程调用? 通常我们调用一个php中的方法,比如 ...

  5. 转:传入的表格格式数据流(TDS)远程过程调用(RPC)协议流不正确 .

    近期在做淘宝客的项目,大家都知道,淘宝的商品详细描述字符长度很大,所以就导致了今天出现了一个问题 VS的报错是这样子的  ” 传入的表格格式数据流(TDS)远程过程调用(RPC)协议流不正确“ 还说某 ...

  6. SQLServer 2000 Driver for JDBC][SQLServer]传入的表格格式数据流(TDS)远程过程调用(RPC)协议流不正确解决方法

    问题:[SQLServer 2000 Driver for JDBC][SQLServer]传入的表格格式数据流(TDS)远程过程调用(RPC)协议流不正确.参数 1 (""): ...

  7. 网络协议 22 - RPC 协议(下)- 二进制类 RPC 协议

        前面我们认识了两个常用文本类的 RPC 协议,对于陌生人之间的沟通,用 NBA.CBA 这样的缩略语,会使得协议约定非常不方便.     在讲 CDN 和 DNS 的时候,我们讲过接入层的设计 ...

  8. 网络协议 20 - RPC 协议(上)- 基于XML的SOAP协议

    [前五篇]系列文章传送门: 网络协议 15 - P2P 协议:小种子大学问 网络协议 16 - DNS 协议:网络世界的地址簿 网络协议 17 - HTTPDNS:私人定制的 DNS 服务 网络协议 ...

  9. 网络协议 19 - RPC协议综述:远在天边近在眼前

    [前五篇]系列文章传送门: 网络协议 14 - 流媒体协议:要说爱你不容易 网络协议 15 - P2P 协议:小种子大学问 网络协议 16 - DNS 协议:网络世界的地址簿 网络协议 17 - HT ...

  10. SQL :“传入的表格格式数据流(TDS)远程过程调用(RPC)协议流不正确” 错误

    其中在DAL层调用存储过程来插入数据的参数 SqlParameter[] parameters = {                                            new S ...

随机推荐

  1. 从零玩转系列之微信支付实战PC端项目构建+页面基础搭建 | 技术创作特训营第一期

    一.前言 欢迎来到本期的博客!在这篇文章中,我们将带您深入了解前端开发领域中的一个热门话题: 如何使用 Vue 3 和 Vite 构建前端项目.随着现代 Web 应用程序的需求不断演进, 选择适当的工 ...

  2. 1.0 Python 标准输入与输出

    python 是一种高级.面向对象.通用的编程语言,由Guido van Rossum发明,于1991年首次发布.python 的设计哲学强调代码的可读性和简洁性,同时也非常适合于大型项目的开发.py ...

  3. Airtest的iOS实用接口介绍

    1. 前言 前段时间Airtest更新了1.3.0.1版本,里面涉及非常多的iOS功能新增和改动,今天想详细跟大家聊一下里面的iOS设备接口. PS:本文示例均使用本地连接的iOS设备,Airtest ...

  4. Django模板(请用Django2.0版本完成)

    1. 在learn目录下新建一个templates文件夹,里面新建一个home.html (1) 很简单的,就直接右键learn,新建文件夹,完成后,继续右键templates,创建文档,后缀名为ht ...

  5. 《小白WEB安全入门》02. 开发篇

    @ 目录 初识HTML潜在漏洞 初识CSS潜在漏洞 初识JS潜在漏洞 初识后端潜在漏洞 后端能做什么 后端种类 后端框架 潜在漏洞 本系列文章只叙述一些超级基础理论知识,极少有实践部分 本文涉及到的语 ...

  6. 给DataTable添加额外字段

    //dt为DataTable dt.Columns.Add("字段名");//创建字段 //给新增字段赋值 foreach(DataRow item in dt.Rows) { i ...

  7. Unity 性能优化Shader分析处理函数:ShaderUtil.GetShaderGlobalKeywords用法

    Unity 性能优化Shader分析处理函数:ShaderUtil.GetShaderGlobalKeywords用法 点击封面跳转下载页面 简介 Unity 性能优化Shader分析处理函数:Sha ...

  8. SQL Server关于AlwaysOn的理解-读写分离的误区(一)

    前言 很多人认为AlwaysOn在同步提交模式下数据是实时同步的,也就是说在主副本写入数据后可以在辅助副本立即查询到.因此期望实现一个彻底的读写分离策略,即所有的写语句在主副本上,所有的只读语句分离到 ...

  9. 「co-examination - A」

    破壁,组合意义法: 五种颜色 \(\star,a,b,c,d\). 对于 l.h.s. 钦定 \(k\),在 \(3n+k\) 个球中选出 \(2n\) 个球染色,在靠左的 \(n\) 个球中选 \( ...

  10. 2023 ICPC 网络赛 II

    开场顺着读了 AC 不会,B 是 KDT 优化建图板子,让 zsy 确认了一下并制止他现在做.把 D 转化转化成了经典问题·,当时以为是网络流,所以 zsy 签完 M 就上去写了,写一半发现假了,问了 ...