RPC中间件就是把分割的程序通过网络重新构建的中间件。
微服务:就是把一个系统根据业务拆分成独立的小功能进行管理的 软件架构。
中间件:就是中介软件。具体分类,有处理事务的,有传递消息的-MOM中间件,有传递功能的-分布式中间件。
首先,要解决通讯的问题,主要是通过在客户端和服务器之间建立TCP连接,远程调用过程中所有交换的数据都在这个连接里传输,连接可以是按需连接,调用结束后就关闭,也
可以是长连接,多个远程调用共享一个连接。
第二,要解决寻址的问题,也就是说,A服务器上的应用怎么告诉底层的RPC框架,如何连接到B服务器(如主机或IP地址)以及特定的端口号,方法的名称是什么,这样才能完成调用,比如基于WEB服务协议的RPC,就要提供一个endpoint URI,或者是从UDDI服务上查找。如果是RMI调用的话,还需要一个RMI Registry来注册服务的地址。
第三,当A服务器上的应用发起远程过程调用时,方法的参数需要通过底层的网络协议如TCP传递到B服务器,由于网络协议是基于 二进制的,内存中的参数的值要序列化成二进制的形式,也就是序列化(Serialize)或编组(marshal),通过寻址和传输将序列化的二进制发送给B服务器。
第四,B服务器收到请求后,需要对参数进行反序列化(序列化的逆操作),恢复为内存中的表达方式,然后找到对应的方法(寻址的一部分)进行本地调用,然后得到返回值。
第五,返回值还要发送给A服务器上的应用,也要经过序列化的方式发送,服务器A接到后,在反序列化,恢复为内存中的表达方式,交给A服务器上的应用。
远程过程调用 - RPC(remote process call )
consumer----->rpc---->provider
一. 相关概念:
1.本地函数调用: 系统是单体应用时,调用接口可以直接new对象,然后调用方法即可.因为在同一个内 存,即同一个地址空间,所以通过方法栈和参数就可实现。
2.远程过程调用:在分布式系统中,每个模块功能在不同的服务器上,再想调用某个方法,就不行了,因为本地没有那个类.
比如: 想收快递,自己在家时可以自己去接收, 这是本地方法调用; 自己不在家,可以让家中老婆接收,这就好比远程调用. 手机就好比一个代理,代理你发送通讯.进行远程通讯(远程调用).
也许你会说, 可以模仿B/S架构的调用方式,B服务暴露一个restful接口,然后A服务调用这个restful接口间接调用某个方法. 嗯, 这已经很接近RPC了. 不过,这样每次都需要写一串发送http请求的代码,比如:httpClient.sendRequest..之类的, 最好的方式:是像本地调用一样,让使用者感受不到远程调用的过程, 就像这样:
你会说,可以用代理模式呀, 而且最好和spring IOC一起用,通过注入calculator对象,如果扫描到对象加了一个@reference注解,就给他生成一个代理对象.将代理对象放进容器, 代理对象内部就是通过httpClient来实现RPC远程过程调用的.
二. RPC原理
上面这段就是很多RPC框架要解决的问题和解决的原理. 比如dubbo __↑
三 .RPC要解决的问题:
1.分布式系统中,服务之间的调用问题.
2.远程调用时,能像本地调用一样方便,让调用者感知不到远程调用的逻辑
四. RPC实现
实际上,RPC很少用到http协议进行数据传输,毕竟只想传输一下数据,何必动用一个文本传输的应用层协议呢, 直接用二进制传输多好,比如直接用java的socket协议.
不管用何种协议进行数据传输,一个完整的RPC过程,都可以用下面这张图来描述:
以左边的Client端为例,Application就是rpc的调用方,Client Stub就是我们上面说到的代理对象,也就是那个看起来像是Calculator的实现类,其实内部是通过rpc方式来进行远程调用的代理对象,至于Client Run-time Library,则是实现远程调用的工具包,比如jdk的Socket,最后通过底层网络实现实现数据的传输。
这个过程中最重要的就是序列化和反序列化了,因为数据传输的数据包必须是二进制的,你直接丢一个Java对象过去,人家不认识,你必须把Java对象序列化为二进制格式,传给Server端,Server端接收到之后,再反序列化为Java对象。
1.目前拥有RMI,webservice,基于http协议的http Client 等成熟方案,
五. 不同协议实现RPC的区别:
1.基于TCP协议 实现的RPC
由于处于协议栈底层,可更灵活的对协议字段进行定制,减少网络传输字节数,降低网络开销,提高性能,但需要关注底层实现细节,代码量高,由于所定义协议的局限,平台和社区支持性好,难以实现跨平台调用,不同的终端需要开发不同的工具包来进行请求发送和响应解析,工作量大,
2.基于http协议 实现的RPC
可以使用json和xml格式的响应数据,且作为通用格式标准,开源的工具相对成熟,开发简单;
通过代码优化和使用gzip数据压缩,能缩小与tcp传输性能的差距,所以具有很大优势
3.RESTful风格与RPC
1.这两者并不是一个维度的概念,总得来说RPC涉及的维度更广.如果硬要比较,那么可以从RPC风格的url和Restful风格的url上进行比较。
比如你提供一个查询订单的接口,用RPC风格,你可能会这样写:
/queryOrder?orderId=123
用Restful风格可以这样写:Get: /order?orderId=123 甚至更精炼:/order/123
2. RPC是面向过程,Restful是面向资源,并且使用了Http动词。
从这个维度上看,Restful风格的url在表述的精简性、可读性上都要更好。
4.RPC 与 RMI 的区别
严格来说这两者也不是一个维度的。
RMI: 是Java提供的一种访问远程对象的协议,是已经实现好了,可以直接用了。
RPC:只是一种编程模型,并没有规定你具体要怎样实现,你甚至都可以在你的RPC框架里面使用RMI来实现数据的传输,比如Dubbo:Dubbo - rmi协议
六:RPC要考虑的问题
要实现一个RPC不算难,难的是实现一个高性能高可靠的RPC框架。
1. 如果是分布式,一个服务可能有多个实例,在调用时,要如何获取这些实例的地址呢?
2. 这时就需要一个服务注册中心,比如在Dubbo里头,就可以使用Zookeeper作为注册中心,在调用时,从Zookeeper获取服务的实例列表,再从中选择一个进行调用。
3. 选哪个调用好呢?这时候就需要负载均衡了,于是你又得考虑如何实现负载均衡,比如Dubbo就提供了好几种负载均衡策略。
4. 还有,总不能每次调用时都去注册中心查询实例列表吧,这样效率很低,于是又有了缓存,有了缓存,就要考虑缓存更新问题,等等。
5. 客户端不能每次调用完都干等着服务端返回数据吧,于是就要支持异步调用;
6. 服务端的接口被修改了,老的接口还有人在用,怎么办?总不能让他们都改了吧?这就需要版本控制了;
7. 服务端总不能每次接到请求都马上启动一个线程去处理吧?于是就需要线程池;
8. 服务端关闭时,还没处理完的请求怎么办?是直接结束呢,还是等全部请求处理完再关闭呢?
9. 等等........
如此种种,都是一个优秀的RPC框架需要考虑的问题。
---------------------
作者:水河澹澹
来源:CSDN
原文:https://blog.csdn.net/qq_33497137/article/details/81869293
版权声明:本文为博主原创文章,转载请附上博文链接!