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

news2024/11/17 21:54:29

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

从TCP聊起

作为一个程序员,假设我们需要在A电脑的进程发一段数据到B电脑的进程,我们一般会在代码里使用socket进行编程。

这时候,我们可选项一般也就TCP和UDP二选一。TCP可靠,UDP不可靠。除非是马总这种神级程序员(早期QQ大量使用UDP),否则,只要稍微对可靠性有些要求,普通人一般无脑选TCP就对了。

类似下面这样。

fd = socket(AF_INET,SOCK_STREAM,0);

其中SOCK_STREAM,是指使用字节流传输数据,说白了就是TCP协议

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

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

光这样一个纯裸的TCP连接,就可以做到收发数据了,那是不是就够了?

不行,这么用会有问题。

使用纯裸TCP会有什么问题

八股文常背,TCP是有三个特点,面向连接可靠、基于字节流

这三个特点真的概括的非常精辟,这个八股文我们没白背。

每个特点展开都能聊一篇文章,而今天我们需要关注的是基于字节流这一点。

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

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

这就是所谓的粘包问题

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

于是我们会把每条要发送的数据都包装一下,比如加入消息头消息头里写清楚一个完整的包长度是多少,根据这个长度可以继续接收数据,截取出来后它们就是我们真正要传输的消息体

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

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

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

HTTP和RPC

我们回过头来看网络的分层图。

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

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

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

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

 res = localFunc(req)

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

 res = remoteFunc(req)

基于这个思路,大佬们造出了非常多款式的RPC协议,比如比较有名的gRPCthrift

值得注意的是,虽然大部分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有什么区别

我们来看看RPC和HTTP区别比较明显的几个点。

服务发现

首先要向某个服务器发起请求,你得先建立连接,而建立连接的前提是,你得知道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原理

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。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/350021.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

第六章 - 数据过滤where(where与and和or的组合用法)

第六章 - 数据过滤&#xff08;where的用法&#xff09;基本用法where的条件限制符等于号不等号! 或者<>小于<大于>小于等于<大于等于>between 的用法空值和非空值组合条件 and组合条件 orand 和 or 的计算次序in 和 not in基本用法 在查询语句中&#xff0…

JAVA面试八股文一(并发与线程)

并发的三大特性原子性&#xff1a;cpu在执行过程不可以暂停然后再调度&#xff0c;不可以中断&#xff0c;要不全部执行完&#xff0c;要不全部不执行。可见性&#xff1a;当多个线程访问同一个变量时&#xff0c;一个线程改变了这个变量的值&#xff0c;其他线程能够立即看到修…

PDF加密如何批量解除?快来了解下这个方法

在现代办公环境中&#xff0c;PDF文档的使用非常普遍。然而&#xff0c;由于一些安全需求&#xff0c;有时候PDF文档会被加密&#xff0c;使得只有授权人员可以查看或修改它。但是&#xff0c;如果您需要对许多加密PDF文档进行操作&#xff0c;逐个解密这些文档可能非常费时费力…

一文了解JAVA中同步、异步、阻塞和非阻塞

&#x1f3c6;今日学习目标&#xff1a; &#x1f340;JAVA中同步、异步、阻塞和非阻塞 ✅创作者&#xff1a;林在闪闪发光 ⏰预计时间&#xff1a;30分钟 &#x1f389;个人主页&#xff1a;林在闪闪发光的个人主页 &#x1f341;林在闪闪发光的个人社区&#xff0c;欢迎你的加…

阿里云服务器入门使用流程 新手学习教程

一、阿里云根据个人需要选合适的云服务器&#xff0c;选好cpu、内存、带宽&#xff0c;地域&#xff0c;这四个是主要的。其他可以默认选择。 二、登陆控制台 输入账号密码&#xff0c;进去看到服务界面&#xff0c;新手可能不容易看懂。点击左侧菜单&#xff0c;点击云服务器…

ASE12N65SE-ASEMI高压MOS管ASE12N65SE

编辑-Z ASE12N65SE在ITO-220AB封装里的静态漏极源导通电阻&#xff08;RDS(ON)&#xff09;为0.68Ω&#xff0c;是一款N沟道高压MOS管。ASE12N65SE的最大脉冲正向电流ISM为48A&#xff0c;零栅极电压漏极电流(IDSS)为10uA&#xff0c;其工作时耐温度范围为-55~150摄氏度。ASE…

Web IDE优势在哪?详解Web版数据库管理工具SQL Studio

Web IDE优势在哪&#xff1f;详解Web版数据库管理工具SQL Studio 去年年末&#xff0c;GitPod在A轮融资中获得2500万美元&#xff0c;用来兑现云端开发环境&#xff08;Cloud Development Environments&#xff09;的承诺。 一周后&#xff0c;GitHub就宣布CodeSpaces将面向所…

【Python入门第十天】Python 布尔

布尔表示两值之一&#xff1a;True 或 False。 布尔值 在编程中&#xff0c;通常需要知道表达式是 True 还是 False。 可以计算 Python 中的任何表达式&#xff0c;并获得两个答案之一&#xff0c;即 True 或 False。 比较两个值时&#xff0c;将对表达式求值&#xff0c;P…

如何做出好看的Excel可视化图表?

可视化死磕excel是不行的&#xff0c;作为数据分析行业的偷懒大户&#xff0c;分享一些我在可视化工具上的使用心得&#xff0c;总结了三大类&#xff1a;快速出图类、专业图表类、高端大屏类。个人经验&#xff0c;大家按需采纳&#xff1a; 一、快速出图类 如果你只是因为偶…

如何重新安装安卓手机系统

下载并安装您设备的驱动程序和ADB工具。如果您已经拥有了它们&#xff0c;请跳过此步骤。没有就百度下载。 打开终端或命令提示符&#xff0c;并将其设置为包含ADB二进制文件的目录。 启动设备并将其连接到计算机上。 在终端或命令提示符中运行以下命令以确认设备是否连接成…

vue脚手架项目的详解

文章目录Vue CLI简介安装vue-cli创建项目启动项目打包项目项目结构对Vue不同构建版本的解释完整的版本信息术语运行时 编译器 vs. 只包含运行时开发环境 vs. 生产环境模式单文件组件为什么需要单文件组件什么是单文件组件<template><script><style>自动名称…

Python常见类型转换合集

近期在工作中常常接触到各种转换&#xff0c;如字符串转byte&#xff0c;byte转字符串&#xff0c;还有byte数组转成报文能接纳的格式&#xff08;bin格式的十六进制&#xff09;。故有必要系统的总结一下Python中常见的类型转换。 一&#xff1a;常见类型的概念 类型举例说明…

【企业档案管理】制药企业电子档案解决方案

某制药股份有限公司于2010年在深交所中小板上市&#xff0c;公司以生产中药制剂为主&#xff0c;化学药为辅&#xff0c;拥有药品批准文号155个&#xff0c;其中73个列入国家医保目录&#xff0c;57个列入国家基本药物目录。现有员工1300人&#xff0c;公司注册资金5.032亿元&a…

从零实现Web服务器(三):日志优化,压力测试,实战接收HTTP请求,实战响应HTTP请求

文章目录一、日志系统的运行流程1.1 异步日志和同步日志的不同点1.2 缓冲区的实现二、基于Webbench的压力测试三、HTTP请求报文解析http报文处理流程epoll相关代码服务器接收http请求四、HTTP请求报文响应一、日志系统的运行流程 步骤: 单例模式&#xff08;局部静态变量懒汉…

手把手带你读java源码之JAVA-stream数据结构和初始化源码详解(万字长文详解)

手把手带你读java源码之JAVA-stream数据结构和初始化源码详解(万字长文详解) stream stream是java8新增的非常重要的一个特性。并且非常的常用。它实现了函数式编程。具体函数式编程的概念已经很久了&#xff0c;比如js中的箭头函数。java中也通过stream做出了支持。想深入理…

云原生安全检测器 Narrows(CNSI)的部署和使用

近日&#xff0c; 云原生安全检测器 Narrows&#xff08;Cloud Native Security Inspector&#xff0c;简称CNSI&#xff09;发布了0.2.0版本。 &#xff08;https://github.com/vmware-tanzu/cloud-native-security-inspector&#xff09; 此项目旨在对K8s集群中的工作负载进…

分布式文件管理系统(MinIO)

1.去中心化&#xff0c;每个点是对等的关系&#xff0c;通过Ngix对负载做均衡工作。 好处&#xff1a; 能够避免单点故障&#xff0c;将多块硬盘组成一个对象存储服务。 2. 使用纠删编码技术来保护数据&#xff0c;是一种回复丢失和损坏的数据的数学算法&#xff0c;他将数据分…

小红书用户画像 | 小红书数据平台

小红书的用户画像是小红书品牌营销的必备技能&#xff0c;也是小红书推广种草的一个重要前提。通过对小红书用户画像进行分析&#xff0c;对品牌进行精准营销&#xff0c;实现更高的流量转化。 2022小红书粉丝人群画像 千瓜数据在2022年发布的千瓜活跃用户画像趋势报告中分析了…

Hive---安装教程

Hive安装教程 Hive属于Hadoop生态圈&#xff0c;所以Hive必须运行在Hadoop上 文章目录Hive安装教程上传安装包解压并且更名修改 /etc/profile创建hive-site.xml将mysql的jar包放入Hive库中开启刷新配置文件hadoop开启mysql初始化启动hive上传安装包 将安装包上传到/opt/insta…

一文搞懂Docker容器里进程的 pid 是如何申请出来的?

如果大家有过在容器中执行 ps 命令的经验&#xff0c;都会知道在容器中的进程的 pid 一般是比较小的。例如下面我的这个例子。 # ps -ef PID USER TIME COMMAND1 root 0:00 ./demo-ie13 root 0:00 /bin/bash21 root 0:00 ps -ef 不知道大家是否和我一样…