HTTP与RPC区别比较分析

一、TCP的特点与问题

一想到TCP,我想大多数人第一时间想到的应该是:面向连接的、可靠的、基于字节流的。

如果我们需要使用TCP协议的话,就需要使用Socket编程

1
2
3
4
5
6
7
8
9
10
11
12
13
public class Client {
public static void main(String[] args) throws IOException {
//1、创建一个Socket对象请求服务端的连接
Socket socket = new Socket("127.0.0.1", 9999);
//2、从Socket对象中获取字节输出流
OutputStream os = socket.getOutputStream();
//3、把字节输出流包装成打印流
PrintStream ps = new PrintStream(os);
ps.println("hello server!");
//4、刷新
ps.flush();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class Server {
public static void main(String[] args) throws Exception {
//1、定义一个ServerSocket对象进行服务端的端口注册
ServerSocket ss = new ServerSocket(9999);
//2、阻塞监听客户端的socket连接请求,当监听到一个连接请求后,执行后续代码
Socket socket = ss.accept();
//3、从socket管道中得到一个字节输入流对象inputStream
InputStream is = socket.getInputStream();
//4、把字节输入流包装成 缓冲字符输入流
BufferedReader br = new BufferedReader(new InputStreamReader(is));
String msg;
//5、按照通信的架构,对方怎么发,这里就要怎么收,服务端按行读取
/*
* 由于bio是同步阻塞式,若接收不到客户端的一行数据,会一直阻塞
* 读到一行数据后,继续循环阻塞等待
* 客户端发完数据后宕机,socket关闭,此时服务端的socket也会跟着关闭,
* 报Connection reset错误
*/

while((msg = br.readLine()) != null){
System.out.println("服务端接收到:"+msg);
}
}
}

上面我们简单演示了一下在Java中是如何基于BIO进行网络编程的,对于使用纯裸TCP存在的问题,我们关注点放在基于字节流上

什么叫基于字节流?

就是当通信双方建立连接后,我们可以形象一点的看作,通信双方之间建立了一个“通信的管道”,想要通信的数据一个一个比特位在通信管道内传输。

如果还不明白的话,我们可以打一个比方:
数据就像河流中的水一样;通信管道就是河道;河流中的水是由小的河流分支汇集而来(小分支就是一个一个用户发送数据);最终河流汇入大海(大海就是数据接收方)。
大海收到河流中的水,但是收到的水并不是一批一批收到,而是不断的收到,这样大海无法确定对方在发送的时候一次发送了多少。所以在接收的时候,就可能一次收的比对方一次发的多,或者少。这就是大名鼎鼎的粘包问题

总之,使用TCP就会有粘包问题,为了解决这个问题,我们就需要在TCP的上层(应用层)再设计一些自定义协议,解决粘包问题,最常见的就是HTTP,HTTP中的某一些字段就可以标识哪些属于同一个报文,这样就可以避免粘包问题。

二、HTTP与RPC

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

1、HTTP协议

HTTP协议【超文本传输协议】,平常我们用浏览器使用的就是HTTP一系列的协议,网上有很多详细的介绍,这里就不去展开了,以下是CSDN社区中的一位博主对HTTP的总结:

HTTP复习(一)
HTTP复习(二)

2、RPC协议

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

调用方法其实跟我们平常在代码中调用自定义方法(或者叫函数)差不多。只不过这个方法是远端服务器暴露出来的接口,我们通过这个接口去使用,就好像我们在调用本地函数一样,就屏蔽了底层网络细节,就方便了很多。需要完成一个任务就调用一个接口。简直不要太爽(回想一些基于TCP的socket通信)

虽然大部分RPC底层使用的是TCP,但是这也不被完全限制。RPC底层可以使用UDP/TCP,甚至是HTTP。

3、有了HTTP,为什么还需要RPC?

其实RPC出现早于HTTP。TCP是上世纪70年代出现,HTTP是90年代才流行。但是TCP的粘包问题确实一直存在,这期间就要用各种各样的自定义应用层协议来解决粘包问题。

一些app,只需要客户端与自家的服务器进行消息传递【C/S架构】,这个时候各家使用各家的RPC协议就可以。

但是随着【B/S架构】发展,浏览器要访问各种服务器,这个使用每家的服务器都必须遵守统一的规则,所以HTTP应用越加广泛。

现在【B/S】【C/S】架构分割越来越不明显了,RPC一般只用于公司内部使用了。

三、HTTP与RPC的区别

1、服务发现

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

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

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

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

2、底层连接形式

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

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

t1

3、传输的内容

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

header:存储的是一些标志信息。可以传字符串也可以传二进制

body:实际传输的内容。一般采用JSON进行序列化

t1

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

对于HTTP/1.1来说,会有头部字段冗余,传输字符串而不是二进制,队头阻塞等等问题。但是HTTP/2进行了很好的改进。所以HTTP/2的性能不一定就比RPC差了。
甚至gRPC底层都是使用的HTTP/2

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

四、结语

本篇文章转载自CSDN社区博主 xiao zhou,原文总结自小林coding

原文连接:https://blog.csdn.net/cdzg_zzk/article/details/127564797

更多细节可以转至原文,也可以浏览小林coding