精华内容
下载资源
问答
  • RPC 原理

    2019-05-17 00:57:00
    RPC 原理 原文:RPC 原理转载地址:你应该知道的 RPC 原理 在校期间大家都写过不少程序,比如写个hello world服务类,然后本地调用下,如下所示。这些程序的特点是服务消费方和服务提供方是本地调用...
    原文:RPC 原理

    转载地址:你应该知道的 RPC 原理

    在校期间大家都写过不少程序,比如写个hello world服务类,然后本地调用下,如下所示。这些程序的特点是服务消费方和服务提供方是本地调用关系。

    而一旦踏入公司尤其是大型互联网公司就会发现,公司的系统都由成千上万大大小小的服务组成,各服务部署在不同的机器上,由不同的团队负责。这时就会遇到两个问题:1)要搭建一个新服务,免不了需要依赖他人的服务,而现在他人的服务都在远端,怎么调用?2)其它团队要使用我们的服务,我们的服务该怎么发布以便他人调用?下文我们将对这两个问题展开探讨。

     

     

     

    1 如何调用他人的远程服务?

    由于各服务部署在不同机器,服务间的调用免不了网络通信过程,服务消费方每调用一个服务都要写一坨网络通信相关的代码,不仅复杂而且极易出错。

    如果有一种方式能让我们像调用本地服务一样调用远程服务,而让调用者对网络通信这些细节透明,那么将大大提高生产力,比如服务消费方在执行helloWorldService.sayHello(“test”)时,实质上调用的是远端的服务。这种方式其实就是RPC(Remote Procedure Call Protocol),在各大互联网公司中被广泛使用,如阿里巴巴的hsf、dubbo(开源)、Facebook的thrift(开源)、Google grpc(开源)、Twitter的finagle等。

    要让网络通信细节对使用者透明,我们自然需要对通信细节进行封装,我们先看下一个RPC调用的流程:

    • 1)服务消费方(client)调用以本地调用方式调用服务;
    • 2)client stub接收到调用后负责将方法、参数等组装成能够进行网络传输的消息体;
    • 3)client stub找到服务地址,并将消息发送到服务端;
    • 4)server stub收到消息后进行解码;
    • 5)server stub根据解码结果调用本地的服务;
    • 6)本地服务执行并将结果返回给server stub;
    • 7)server stub将返回结果打包成消息并发送至消费方;
    • 8)client stub接收到消息,并进行解码;
    • 9)服务消费方得到最终结果。

    RPC的目标就是要2~8这些步骤都封装起来,让用户对这些细节透明。

    1.1 怎么做到透明化远程服务调用?

    怎么封装通信细节才能让用户像以本地调用方式调用远程服务呢?对java来说就是使用代理!java代理有两种方式:1) jdk 动态代理;2)字节码生成。尽管字节码生成方式实现的代理更为强大和高效,但代码不易维护,大部分公司实现RPC框架时还是选择动态代理方式。

    下面简单介绍下动态代理怎么实现我们的需求。我们需要实现RPCProxyClient代理类,代理类的invoke方法中封装了与远端服务通信的细节,消费方首先从RPCProxyClient获得服务提供方的接口,当执行helloWorldService.sayHello(“test”)方法时就会调用invoke方法。

     

     

    1.2  怎么对消息进行编码和解码?

    1.2.1 确定消息数据结构

    上节讲了invoke里需要封装通信细节,而通信的第一步就是要确定客户端和服务端相互通信的消息结构。客户端的请求消息结构一般需要包括以下内容:

    1)接口名称

    在我们的例子里接口名是“HelloWorldService”,如果不传,服务端就不知道调用哪个接口了;

    2)方法名

    一个接口内可能有很多方法,如果不传方法名服务端也就不知道调用哪个方法;

    3)参数类型&参数值

    参数类型有很多,比如有bool、int、long、double、string、map、list,甚至如struct(class);

    以及相应的参数值;

    4)超时时间

    5)requestID,标识唯一请求id,在下面一节会详细描述requestID的用处。

    同理服务端返回的消息结构一般包括以下内容。

    1)返回值

    2)状态code

    3)requestID

    1.2.2 序列化

    一旦确定了消息的数据结构后,下一步就是要考虑序列化与反序列化了。

    什么是序列化?序列化就是将数据结构或对象转换成二进制串的过程,也就是编码的过程。

    什么是反序列化?将在序列化过程中所生成的二进制串转换成数据结构或者对象的过程。

    为什么需要序列化?转换为二进制串后才好进行网络传输嘛!为什么需要反序列化?将二进制转换为对象才好进行后续处理!

    现如今序列化的方案越来越多,每种序列化方案都有优点和缺点,它们在设计之初有自己独特的应用场景,那到底选择哪种呢?从RPC的角度上看,主要看三点:1)通用性,比如是否能支持Map等复杂的数据结构;2)性能,包括时间复杂度和空间复杂度,由于RPC框架将会被公司几乎所有服务使用,如果序列化上能节约一点时间,对整个公司的收益都将非常可观,同理如果序列化上能节约一点内存,网络带宽也能省下不少;3)可扩展性,对互联网公司而言,业务变化快,如果序列化协议具有良好的可扩展性,支持自动增加新的业务字段,删除老的字段,而不影响老的服务,这将大大提供系统的健壮性。

    目前国内各大互联网公司广泛使用hessian、protobuf、thrift、avro等成熟的序列化解决方案来搭建RPC框架,这些都是久经考验的解决方案。

    1.3  通信

    消息数据结构被序列化为二进制串后,下一步就要进行网络通信了。目前有两种IO通信模型:1)BIO;2)NIO。一般RPC框架需要支持这两种IO模型,原理可参考:《一个故事讲清楚 NIO》

    如何实现RPC的IO通信框架?1)使用java nio方式自研,这种方式较为复杂,而且很有可能出现隐藏bug,见过一些互联网公司使用这种方式;2)基于mina,mina在早几年比较火热,不过这些年版本更新缓慢;3)基于netty,现在很多RPC框架都直接基于netty这一IO通信框架,比如阿里巴巴的HSF、dubbo,Twitter的finagle等。

    1.4  消息里为什么要带有requestID?

    如果使用netty的话,一般会用channel.writeAndFlush()方法来发送消息二进制串,这个方法调用后对于整个远程调用(从发出请求到接收到结果)来说是一个异步的,即对于当前线程来说,将请求发送出来后,线程就可以往后执行了,至于服务端的结果,是服务端处理完成后,再以消息的形式发送给客户端的。于是这里出现以下两个问题:

    1)怎么让当前线程“暂停”,等结果回来后,再向后执行?

    2)如果有多个线程同时进行远程方法调用,这时建立在client server之间的socket连接上会有很多双方发送的消息传递,前后顺序也可能是随机的,server处理完结果后,将结果消息发送给client,client收到很多消息,怎么知道哪个消息结果是原先哪个线程调用的?

    如下图所示,线程A和线程B同时向client socket发送请求requestA和requestB,socket先后将requestB和requestA发送至server,而server可能将responseA先返回,尽管requestA请求到达时间更晚。我们需要一种机制保证responseA丢给ThreadA,responseB丢给ThreadB。

    怎么解决呢?

    1)client线程每次通过socket调用一次远程接口前,生成一个唯一的ID,即requestID(requestID必需保证在一个Socket连接里面是唯一的),一般常常使用AtomicLong从0开始累计数字生成唯一ID;

    2)将处理结果的回调对象callback,存放到全局ConcurrentHashMap里面put(requestID, callback);

    3)当线程调用channel.writeAndFlush()发送消息后,紧接着执行callback的get()方法试图获取远程返回的结果。在get()内部,则使用synchronized获取回调对象callback的锁,再先检测是否已经获取到结果,如果没有,然后调用callback的wait()方法,释放callback上的锁,让当前线程处于等待状态。

    4)服务端接收到请求并处理后,将response结果(此结果中包含了前面的requestID)发送给客户端,客户端socket连接上专门监听消息的线程收到消息,分析结果,取到requestID,再从前面的ConcurrentHashMap里面get(requestID),从而找到callback对象,再用synchronized获取callback上的锁,将方法调用结果设置到callback对象里,再调用callback.notifyAll()唤醒前面处于等待状态的线程。

     

     

    2 如何发布自己的服务?

    如何让别人使用我们的服务呢?有同学说很简单嘛,告诉使用者服务的IP以及端口就可以了啊。确实是这样,这里问题的关键在于是自动告知还是人肉告知。

    人肉告知的方式:如果你发现你的服务一台机器不够,要再添加一台,这个时候就要告诉调用者我现在有两个ip了,你们要轮询调用来实现负载均衡;调用者咬咬牙改了,结果某天一台机器挂了,调用者发现服务有一半不可用,他又只能手动修改代码来删除挂掉那台机器的ip。现实生产环境当然不会使用人肉方式。

    有没有一种方法能实现自动告知,即机器的增添、剔除对调用方透明,调用者不再需要写死服务提供方地址?当然可以,现如今zookeeper被广泛用于实现服务自动注册与发现功能!

    简单来讲,zookeeper可以充当一个服务注册表(Service Registry),让多个服务提供者形成一个集群,让服务消费者通过服务注册表获取具体的服务访问地址(ip+端口)去访问具体的服务提供者。如下图所示:

    具体来说,zookeeper就是个分布式文件系统,每当一个服务提供者部署后都要将自己的服务注册到zookeeper的某一路径上: /{service}/{version}/{ip:port}, 比如我们的HelloWorldService部署到两台机器,那么zookeeper上就会创建两条目录:分别为/HelloWorldService/1.0.0/100.19.20.01:16888  /HelloWorldService/1.0.0/100.19.20.02:16888。

    zookeeper提供了“心跳检测”功能,它会定时向各个服务提供者发送一个请求(实际上建立的是一个 socket 长连接),如果长期没有响应,服务中心就认为该服务提供者已经“挂了”,并将其剔除,比如100.19.20.02这台机器如果宕机了,那么zookeeper上的路径就会只剩/HelloWorldService/1.0.0/100.19.20.01:16888。

    服务消费者会去监听相应路径(/HelloWorldService/1.0.0),一旦路径上的数据有任务变化(增加或减少),zookeeper都会通知服务消费方服务提供者地址列表已经发生改变,从而进行更新。

    更为重要的是zookeeper 与生俱来的容错容灾能力(比如leader选举),可以确保服务注册表的高可用性。

    3 小结

    RPC几乎是每一个从学校进入互联网公司的同学都要首先学习的框架,之前面试过一个在大型互联网公司工作过两年的同学,对RPC还是停留在使用层面,这是不应该的。本文也仅是对RPC的一个比较粗糙的描述,希望对大家有所帮助,错误之处也请指出修正。

    4 一些开源的RPC框架

    https://github.com/alibaba/dubbo

    http://thrift.apache.org/?cm_mc_uid=87762817217214314008006&cm_mc_sid_50200000=1444181090

    posted on 2019-05-17 00:57 NET未来之路 阅读(...) 评论(...) 编辑 收藏

    转载于:https://www.cnblogs.com/lonelyxmas/p/10879051.html

    展开全文
  • rpc原理

    2019-01-23 18:54:00
    rpc原理 rpc 什么是 RPC RPC 是远程过程调用(Remote Procedure Call)的缩写形式,Birrell 和 Nelson 在 1984 发表于 ACM Transactions on Computer Systems 的论文《Implementing remote procedure ...

    rpc原理

     

    rpc

    • 什么是 RPC
      • RPC 是远程过程调用(Remote Procedure Call)的缩写形式,Birrell 和 Nelson 在 1984 发表于 ACM Transactions on Computer Systems 的论文《Implementing remote procedure calls》对 RPC 做了经典的诠释。RPC 是指计算机 A 上的进程,调用另外一台计算机 B 上的进程,其中 A 上的调用进程被挂起,而 B 上的被调用进程开始执行,当值返回给 A 时,A 进程继续执行。调用方可以通过使用参数将信息传送给被调用方,而后可以通过传回的结果得到信息。而这一过程,对于开发人员来说是透明的。
      • 20160630-rpc.pnguploading.4e448015.gif转存失败重新上传取消enter image description here
      • enter image description here
      • enter image description here
      • 远程过程调用采用客户机/服务器(C/S)模式。请求程序就是一个客户机,而服务提供程序就是一台服务器。和常规或本地过程调用一样,远程过程调用是同步操作,在远程过程结果返回之前,需要暂时中止请求程序。使用相同地址空间的低权进程或低权线程允许同时运行多个远程过程调用。
    • RPC 的基本操作
      • 当消息到达服务器时,服务器上的操作系统将它传递给服务器存根(server stub)。服务器存根是客户存根在服务器端的等价物,也是一段代码,用来将通过网络输入的请求转换为本地过程调用。服务器存根一般先调用 receive ,然后被阻塞,等待消息输入。收到消息后,服务器将参数由消息中提取出来,然后以常规方式调用服务器上的相应过程(如图3所示)。从服务器角度看,过程好像是由客户直接调用的一样:参数和返回地址都位于堆栈中,一切都很正常。服务器执行所要求的操作,随后将得到的结果以常规的方式返回给调用方。以 read 为例,服务器将用数据填充 read 中第二个参数指向的缓冲区,该缓存区是属于服务器存根内部的。
      • 调用完后,服务器存根要将控制权教会给客户发出调用的过程,它将结果(缓冲区)打包成消息,随后调用 send 将结果返回给客户。事后,服务器存根一般会再次调用 receive,等待下一个输入的请求。
      • 客户机器接收到消息后,客户操作系统发现该消息属于某个客户进程(实际上该进程是客户存根,只是操作系统无法区分二者)。操作系统将消息复制到相应的缓存区中,随后解除对客户进程的阻塞。客户存根检查该消息,将结果提取出来并复制给调用者,而后以通常的方式返回。当调用者在 read 调用进行完毕后重新获得控制权时,它所知道的唯一事就是已经得到了所需的数据。它不指导操作是在本地操作系统进行,还是远程完成。
      • 整个方法,客户方可以简单地忽略不关心的内容。客户所涉及的操作只是执行普通的(本地)过程调用来访问远程服务,它并不需要直接调用 send 和 receive 。消息传递的所有细节都隐藏在双方的库过程中,就像传统库隐藏了执行实际系统调用的细节一样。
      • 概况来说,远程过程调用包含如下步骤:

        客户过程以正常的方式调用客户存根;
        客户存根生成一个消息,然后调用本地操作系统;
        客户端操作系统将消息发送给远程操作系统;
        远程操作系统将消息交给服务器存根;
        服务器存根调将参数提取出来,而后调用服务器;
        服务器执行要求的操作,操作完成后将结果返回给服务器存根;
        服务器存根将结果打包成一个消息,而后调用本地操作系统;
        服务器操作系统将含有结果的消息发送给客户端操作系统;
        客户端操作系统将消息交给客户存根;
        客户存根将结果从消息中提取出来,返回给调用它的客户存根。

    • 实现远程过程调用如何传递参数
      • 20160630-rpc-compute.pnguploading.4e448015.gif转存失败重新上传取消enter image description here
      • 将参数放入消息中,并在消息中添加要调用的过程的名称或者编码。
        消息到达服务器后,服务器存根堆该消息进行分析,以判明需要调用哪个过程,随后执行相应的调用。
        服务器运行完毕后,服务器存根将服务器得到的结果打包成消息送回客户存根,客户存根将结果从消息中提取出来,把结果值返回给客户端。

    • 常见的RPC框架

      dubbo
      阿里巴巴公司开源的一个Java高性能优秀的服务框架,使得应用可通过高性能的 RPC 实现服务的输出和输入功能,可以和 Spring框架无缝集成
      motan
      新浪微博开源的一个Java 框架。它诞生的比较晚,起于2013年,2016年5月开源。Motan 在微博平台中已经广泛应用,每天为数百个服务完成近千亿次的调用。
      rpcx
      Go语言生态圈的Dubbo, 比Dubbo更轻量,实现了Dubbo的许多特性,借助于Go语言优秀的并发特性和简洁语法,可以使用较少的代码实现分布式的RPC服务。
      gRPC
      Google开发的高性能、通用的开源RPC框架,主要面向移动应用开发并基于HTTP/2协议标准而设计,基于ProtoBuf(Protocol Buffers)序列化协议开发,且支持众多开发语言。本身它不是分布式的,所以要实现上面的框架的功能需要进一步的开发。
      thrift
      Apache的一个跨语言的高性能的服务框架

    • RPC与MQ
      • 异步MQ,同步RPC
      • 关注下游执行执行结果,用RPC;
      • 不关注下游执行结果,用MQ,不用RPC;
    • RPC和Http:
      • RPC并没有规定数据传输格式,这个格式可以任意指定,不同的RPC协议,数据格式不一定相同。
      • Http中还定义了资源定位的路径,RPC中并不需要
      • RPC需要满足像调用本地服务一样调用远程服务,也就是对调用过程在API层面进行封装。Http协议没有这样的要求,因此请求、响应等细节需要我们自己去实现。
      • 论复杂度,RPC框架肯定是高于简单的HTTP接口的。但毋庸置疑,HTTP接口由于受限于HTTP协议,需要带HTTP请求头, 导致传输起来效率或者说安全性不如RPC。(RPC 本身是一种框架,而http 是应用层的协议 )
      • RPC是一种技术的概念名词。 HTTP是一种协议,RPC可以通过HTTP来实现,也可以通过Socket自己实现一套协议来实现。所以楼主可以换一个问法,为何RPC还有除HTTP 之外的实现法,有何必要。毕竟除了HTTP实现外,私有协议不具备通用性。那么我想唯一的答案就在于HTTP不能满足其业务场景的地方,所以这个就要具体 案例具体分析了。
      • http接口是在接口不多、系统与系统交互较少的情况下,解决信息孤岛初期常使用的一种通信手段;优点就是简单、直接、开发方便。利用现成的http协议 进行传输。但是如果是一个大型的网站,内部子系统较多、接口非常多的情况下,RPC框架的好处就显示出来了,首先就是长链接,不必每次通信都要像http 一样去3次握手什么的,减少了网络开销;其次就是RPC框架一般都有注册中心,有丰富的监控管理;发布、下线接口、动态扩展等,对调用方来说是无感知、统 一化的操作。第三个来说就是安全性。最后就是最近流行的服务化架构、服务化治理,RPC框架是一个强力的支撑。
     
     
     
     
     
     
     
    posted @ 2019-01-23 18:54 节奏型男-全栈 阅读(...) 评论(...) 编辑 收藏
    展开全文
  • RPC原理

    2020-07-19 11:45:21
    RPC原理及实现 一、什么是RPC RPC 的全称是 Remote Procedure Call 是一种进程间通信方式。它允许程序调用另一个地址空间(通常是共享网络的另一台机器上)的过程或函数,而不用程序员显式编码这个远程调用的细节。...

    RPC原理及实现
    一、什么是RPC

    RPC 的全称是 Remote Procedure Call 是一种进程间通信方式。它允许程序调用另一个地址空间(通常是共享网络的另一台机器上)的过程或函数,而不用程序员显式编码这个远程调用的细节。即无论是调用本地接口/服务的还是远程的接口/服务,本质上编写的调用代码基本相同。

    比如两台服务器A,B,一个应用部署在A服务器上,想要调用B服务器上应用提供的函数或者方法,由于不在一个内存空间,不能直接调用,这时候需要通过就可以应用RPC框架的实现来解决。

    RPC 会隐藏底层的通讯细节(不需要直接处理Socket通讯或Http通讯)

    RPC 是一个请求响应模型。客户端发起请求,服务器返回响应(类似于Http的工作方式)

    RPC 在使用形式上像调用本地函数(或方法)一样去调用远程的函数(或方法)。

    二、常见RPC框架

    几种比较典型的RPC的实现和调用框架。

    (1)RMI实现,利用java.rmi包实现,基于Java远程方法协议(Java Remote Method Protocol)

    和java的原生序列化。

    (2)Hessian,是一个轻量级的remoting onhttp工具,使用简单的方法提供了RMI的功能。 基于HTTP协议,采用二进制编解码。

    (3)THRIFT是一种可伸缩的跨语言服务的软件框架。thrift允许你定义一个描述文件,描述数据类型和服务接口。依据该文件,编译器方便地生成RPC客户端和服务器通信代码。

    二、RPC框架实现原理

    在RPC框架中主要有三个角色:Provider、Consumer和Registry。如下图所示:

    在这里插入图片描述

    RPC框架面试总结-RPC原理及实现

    节点角色说明:

    • Server: 暴露服务的服务提供方。

    • Client: 调用远程服务的服务消费方。

    • Registry: 服务注册与发现的注册中心。

    三、RPC调用流程

    RPC基本流程图:
    在这里插入图片描述

    RPC框架面试总结-RPC原理及实现

    一次完整的RPC调用流程(同步调用,异步另说)如下:

    1)服务消费方(client)调用以本地调用方式调用服务;

    2)client stub接收到调用后负责将方法、参数等组装成能够进行网络传输的消息体;

    3)client stub找到服务地址,并将消息发送到服务端;

    4)server stub收到消息后进行解码;

    5)server stub根据解码结果调用本地的服务;

    6)本地服务执行并将结果返回给server stub;

    7)server stub将返回结果打包成消息并发送至消费方;

    8)client stub接收到消息,并进行解码;

    9)服务消费方得到最终结果。

    RPC框架的目标就是要2~8这些步骤都封装起来,让用户对这些细节透明。

    四、服务注册&发现

    RPC框架面试总结-RPC原理及实现
    服务提供者启动后主动向注册中心注册机器ip、port以及提供的服务列表;

    服务消费者启动时向注册中心获取服务提供方地址列表,可实现软负载均衡和Failover;

    五、使用到的技术

    1、动态代理

    生成 client stub和server stub需要用到 Java 动态代理技术 ,我们可以使用JDK原生的动态代理机制,可以使用一些开源字节码工具框架 如:CgLib、Javassist等。

    2、序列化

    为了能在网络上传输和接收 Java对象,我们需要对它进行 序列化和反序列化操作。

    • 序列化:将Java对象转换成byte[]的过程,也就是编码的过程;

    • 反序列化:将byte[]转换成Java对象的过程;

    可以使用Java原生的序列化机制,但是效率非常低,推荐使用一些开源的、成熟的序列化技术,例如:protobuf、Thrift、hessian、Kryo、Msgpack

    关于序列化工具性能比较可以参考:jvm-serializers

    3、NIO

    当前很多RPC框架都直接基于netty这一IO通信框架,比如阿里巴巴的HSF、dubbo,Hadoop Avro,推荐使用Netty 作为底层通信框架。

    4、服务注册中心

    可选技术:

    • Redis 、Zookeeper、Consul、Etcd
    展开全文
  • Rpc 原理

    2020-12-25 01:05:14
    rpc

    Rpc是什么?

    Rpc(remote procedure call)即远程过程调用,为解决不同服务间相互调用的方法的复杂处理,让服务间调用如本地方法一般简单。

    为什么需要Rpc框架?

    因为服务架构的演变从最初的单机服务到如今的分布式,微服务,因为功能拆分的为服务之间需要一定程度的通信沟通,而传统服务间使用api请求存在各种问题,如负载,调用失败处理,异常处理,请求管理等,所以rpc框架就是为了解决这种问题。

    RPC框架原理:

    在RPC框架中主要有三个角色:Provider、Consumer和Registry。如下图所示:

     

    图片发自简书App

    节点角色说明:

    * Server: 暴露服务的服务提供方。

    * Client: 调用远程服务的服务消费方。

    * Registry: 服务注册与发现的注册中心。

    Rpc基本流程:

    rpc机构组件拆分图:

    1. client 以调用本地方法的方式调用服务方法

    2. 使用rpcProxy代理 让 rpcInvoket调用 通过 rpcProtocol 对 参数组成的消息题进行加密传输给server

    3.server 的RpcAcceptor用于接收client rpcConnedor(维持与服务的RpcChannel)传输的消息题,然后使用同样的RpcProtocol 进行解码

    4 Server将解码结果 交给RpcProcessor处理调用过程,然后再委托给RpcInvokel处理参数返回结果

    5 server 将结果加密传输给client 解密

    rpc就是为了解决流程中的步骤,让用户无感知的装填如本地调用的方式调用远程服务方法。为了微服务,分布式应用更稳定,高效的开发运行。

     

    成熟的Rpc框架:

    1.dubbo框架

    2.springCloud

    3.gRpc

    展开全文

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 5,863
精华内容 2,345
关键字:

rpc原理