那是N年前的一天,老王在看一本讲java的技术书(可惜忘了叫啥名字了),突然看到有一章讲RMI的,立马就觉得很好奇。于是乎,就按书上所讲,写了demo程序。当时也就只知道怎么用,却不知道什么原理。直到多年以后,才知道,原来这个RMI和我们今天要聊的RPC几乎是差不多的东西。那他们到底是什么呢?

what:

先来聊聊RMI。这个玩意儿呢,是sun公司为java定义的一套分布式应用接口,全称:Remote Method Invocation。他能让java开发者很轻松的实现分布式服务间数据访问。让这个访问就像是本地的方法访问一样。

那RPC又是一个什么东东呢?他的全称:Remote Procedure Call。为了实现分布式系统内,不同服务之间数据交换而产生的东东。他使得服务间的数据访问就像是函数调用一样简单和方便,方便写服务的人能聚焦到业务本身,而不用太关注网络交互、数据格式组织、跨平台等多个方面的问题。因此,RMI可以看成是RPC的java版。那为了简化,我们接下来就不细聊RMI,而着重聊聊这个RPC。

why:

上面已经提到了一些我们使用RPC的原因,那我们就顺着上面的脉络,具体的聊聊吧~

1、RPC存在的最重要的意义,就在于,他能简化分布式系统内,不同服务间的数据交换,使得这种交换看起来像本地函数调用一样。所以,我们用他最直接的目的:简化跨机器跨进程的服务调用!

2、因为这些东西被封装简化了,所以,他顺带带来的好处就是:代码极大的简化(一会儿我们讲原理的时候就知道了)。

3、另外,一般这种调用的封装还支持多语言、多操作系统,所以,他能帮我们极好的实现跨平台跨语言。比如,我们为了执行的高效率,用c语言写了一个加密算法,做成了一个通用服务。而我们用java或者python来实现了一个http的服务,他们若要调用那个加密算法服务,就可以用RPC轻松实现。所以,有了RPC,我们可以根据不同的应用场景,使用不同的语言,来更方便的实现需求。

4、更高效的数据传输。因为RPC封装了数据交换的协议,所以可以在里面极大的优化数据传输的算法,从而压缩数据传输的量(还记得老王之前讲过一个zigzag算法嘛)。

有了以上的这些好处,当开发分布式系统的时候,作为一个有志向的程序员,有什么理由不使用RPC呢?

how:

好了,有了上述的铺垫,我们终于可以讲如何来实现这一套东西了。

1、简单的模型:

为了讲清楚这个原理,我们先从一个最简单的模型开始,讲讲怎么样实现跨系统的数据交换。

比方说,我们现在有两个系统(可能不在同一台机器上的两个进程),要交换用户信息:一方是逻辑系统(比方叫blog-system),接收用户提交的user_id,这个系统想用user_id获取用户的详细信息,并展示给用户;另一方是用户系统(比方叫user-system),存储了用户所有的数据(比如:name、nickname、email等等),可以提供根据user_id获取用户详细信息的数据。那我们可以怎么做呢?很简单,我们可以有很多做法,最简单的一种:

A、user-system启动一个socket-server,监听某个端口,用json作为传输数据的协议;

B、blog-system则用socket去connect我们的server,并按要求发送一个json数据给server;

C、server收到请求以后,取出json数据中的user_id,从数据库中查出user,并打包成一个json,返回给client;

D、blog-system收到返回的json,包装成对应的格式,展示给用户。


整个过程如上图所示。是不是觉得就是我们在计算机网络里学的那些最基本的东西?

2、变复杂的模型:

从上面的过程,我们其实可以将这个架构做一下拆分:

A、服务端-客户端通讯协议。

在我们之前的实例中,我们用的是tcp-socket来作为这样一个协议:server端建立一个server-socket,用来接收客户端的请求;客户端发起一个socket请求;

其实,我们也可以用Http、Https等协议作为通讯协议,甚至可以自定义应用层协议。

B、数据传输协议。

在上面的例子里,我们用json来封装的数据,在server和client之间进行传递。其实,我们也可以用结构体(c语言的struct)、xml等方式来作为数据传输协议来封装数据。更可以用自己定义的协议来传输。

有了上述两个东西,我们就可以把他们封装到一个函数中,让他们对外看起来就像是一个函数的访问一样,是不是就达到我们想要的效果呢?

3、更完美的模型:

A、IDL(Interface Description Language):接口定义语言。

如果,我们能将远程调用函数的定义,用一种通用的、跨平台的语言来编写,然后,再用编译器生成不同语言的代码(比如:java、c、c++、php等),这样,我们是否就可以轻松的做到跨平台、跨语言的支持了呢?

比如,以下就是facebook开源的rpc框架thrift的idl定义方式:

service TUserService

{

struct.TUser getUser (1: required i32 uid);

}

看起来是不是跟我们平时写的语言代码很相似呢?

有了这个东东,我们就可以用一个编译工具,生成不同语言的代码了。

B、高承载能力的server模型。

当我们要启动一个server的时候,最简单的就是按我们之前的那种方式,启动一个server-socket。但是这个模型太简单,以至于只要轻轻的给一些压力,服务就可能崩塌。因此,我们需要一个高承载能力的server模型。

现在在linux平台上,大家基本都使用epoll模型。这个是非阻塞的事件驱动模型,能够根据请求事件来触动业务逻辑。所以具有很强的负载能力。现在主流的服务器,比如:nginx、mina、netty等等,都基本采用这种底层模型。

有了这个server做基础,我们才能保证服务的压力能抗的住,才能使得rpc具有相对稳定的调用。

C、简单准确的通讯协议。

这个协议就跟我们tcp、http协议一样,能够描述整个包有多大,哪个地方是协议头、哪个地方是数据包、哪个地方是结束符等等。这个协议越简单越好,使得我们传输的数据量越小。

比如上图就是tcp协议,他定义了数据的大小、数据的校验、序列号等,就是为了保证数据能准确传输到对端。我们也可以仿照这样的协议,来定制我们的协议,比如我们协议包含:版本号、数据包的大小、数据包的校验、数据包等这样的数据。

D、高压缩比 && 快速序列化与反序列化的数据协议。

这个就是我们的数据包的定义。我们可以用文本的json、xml作为数据协议,当然也可以用结构体、java序列化对象等二进制协议作为数据协议。更可以我们定义自己的数据协议。但是这个协议要尽量的小:以保证我们每次传输的数据量尽可能的少;也要保证序列化和反序列化尽量的快:以保证我们的调用时间尽可能的短。

所以,在thrift中,定义TBinaryProtocol、TCompactProtocol等这样的二进制压缩协议,来保证我们的数据传输的速度、打包和解包的速度。

好了,讲了这么多空虚的概念。我们就来看看现有的这些rpc工具是怎么做的吧。

google的protobuf:

这个是一个非常牛逼的rpc工具。不过他只提供了IDL和数据协议。就是只管生成不同语言的实现代码、将一个对象打包成二进制的数据;数据到达对端,他负责解包。然而具体怎么样提供服务、怎么样传输数据,他并不负责。

如果我们要使用这个东东,就需要再弄一个server来接收服务,还要弄一个传输协议来传递数据。常见的,在java下,大家喜欢用netty+protobuf来实现RPC的功能。四要素:

IDL:protobuf

Server: netty

传输协议:TCP

数据协议:protobuf

facebook的thrift:

这个相比于protobuf,提供了server和传输协议的支持。比如,java的实现代码中,就有TThreadPoolServer、TThreadedSelectorServer等多个server模型,便于我们根据业务规模选择不同的模型。

同时,他还提供了TSocket、TSaslTransport、THttpClient等多种传输协议,来实现数据的传输功能。

所以,他集成RPC的四个要素,用起来更简单方便一些。

其他的,诸如以前的CORBA、RMI、Web-Service等等,都是类似的原理。所以,听起来高大上的RPC,实际上都是我们常规的技术,然后进行了组合和封装,让使用者更方便易用(也可以在面试的时候去吓唬人,哈哈哈~)。

好了,关于RPC理论的技术,大体就讲这么多。如果大家想深入的去了解,建议去阅读thrift源代码,很不错的实践代码。老王之前也总结过thrift的代码架构,后面找时间整理出来,分享给大家。

最新文章

  1. mybatis map常用数据类型
  2. bzoj 3262 陌上花开
  3. ArcGIS图层和要素的过滤显示
  4. SQL SA密码丢失
  5. BZOJ3733 : [Pa2013]Iloczyn
  6. POJ 3335 Rotating Scoreboard(多边形的核)
  7. JSChart
  8. JQuery源码分析(四)
  9. Linux Bash Shell学习笔记
  10. php魔法常量
  11. Floodlight Controller 路线原则
  12. linux上安装mono发布.net网站步骤
  13. ARM处理器工作模式
  14. linux libpcap的性能问题,请大家注意绕行。
  15. linux 云计算Openstack搭建
  16. 4.3dotnet watch run「深入浅出ASP.NET Core系列」
  17. BZOJ2658 ZJOI2012 小蓝的好友(treap)
  18. 在linux中安装selenium+chrome
  19. linux获取当前系统的时间
  20. Vue.js学习笔记之修饰符详解

热门文章

  1. Android动画例子。
  2. 升级Xcode8、iOS10问题记录
  3. iOS团队风格的统一
  4. iOS开发 解决UITapGestureRecognizer手势与UITableView的点击事件的冲突
  5. CSS3-04 样式 3
  6. 转载文章-----Rational Rose2007(v7.0)下载地址、安装及激活详解教程(图)
  7. IE6、IE7兼容querySelectorAll和querySelector方法-最终版本
  8. jQuery中多个元素的Hover事件
  9. 关于ActionBar
  10. Git安装与配置