`
agileai
  • 浏览: 56072 次
  • 性别: Icon_minigender_1
  • 来自: 沈阳
社区版块
存档分类
最新评论

你应该知道的 RPC 原理

RPC 
阅读更多

作者:伯乐在线 - meituanalibaba   网址:http://blog.jobbole.com/92290/ 

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

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

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

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

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

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

 

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

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

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

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

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

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

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

8client 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)参数类型&参数值 

参数类型有很多,比如有boolintlongdoublestringmaplist,甚至如structclass);

以及相应的参数值;

4)超时时间

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

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

1)返回值

2)状态code

3requestID

1.2.2序列化

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

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

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

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

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

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

1.3通信

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

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

1.4消息里为什么要带有requestID 

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

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

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

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

 

 

怎么解决呢?

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

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

3)当线程调用channel.writeAndFlush()发送消息后,紧接着执行callbackget()方法试图获取远程返回的结果。在get()内部,则使用synchronized获取回调对象callback的锁,再先检测是否已经获取到结果,如果没有,然后调用callbackwait()方法,释放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的一个比较粗糙的描述,希望对大家有所帮助,错误之处也请指出修正。

分享到:
评论
1 楼 三片仙人掌 2015-10-28  
动态代理那块有问题吧。RPCProxyClient.getProxy() 这儿传入的参数应该是HelloWorldService的实现类的对象啊

相关推荐

    Python零基础30天速通(小白定制版)(完结)

    宣导片:开启Python进阶之路 30动漫番剧播放量影响因素分析1综合案例 29小红书卖货实力与用户分析1综合案例 28星巴克门店探索|Matplotlib实战 27詹姆斯哈登的制胜宝典1 Panads的使用 26一晚5万的酒店| Numpy的使用 25揭开数据分析的面纱1数据分析"三剑客"概述 24虎牙直播数据告诉你谁最火1案例篇 23我的音乐我做主1数据保存之csv和excel 22电竟| BeautifulSoup解析HTML 21对李焕英的评价1HTML基础 20我的美食我做主1爬虫介绍、requests请 19看我四十二变1内容提取和格式转换 18我的版权我做主1PDF就是这么帅 17婚礼策划师离不开你|亲爱的PPT 16运营部的烦恼1战胜Excel 15Up主的创作之路1 Python与word初次 14你的offer之选|邮件发送 13我的存在只为悦你1 Pillow图片处理 12你喜欢的电竟赛事大全1 Python的文件操作 11哈利波特的魔法棒|模块 10龙珠之赛亚人1面向对象基础 09大吉大利今晚吃鸡1特种兵的战场(项目案

    20240519基本完整

    20240519基本完整

    MATLAB仿真项目-大数据源码-疲劳检测识别,可应用于疲劳驾驶监测,专注度检测等(高分期末大作业).rar

    本项目提供了一个基于MATLAB的疲劳检测识别仿真系统,旨在帮助计算机相关专业的在校学生、老师和企业员工更好地学习和实践大数据与人工智能技术。该项目可应用于疲劳驾驶监测、专注度检测等领域,具有较高的实用价值。 项目源码已经过运行测试,确保OK,可作为课程设计、毕业设计的优质资源。此外,我们还为您提供了一些网络相关资源,以便您在学习过程中进行参考。这些资源将帮助您更好地理解项目的原理和应用。 本项目的源码适用于初学者,即使是编程基础较弱的同学也能快速上手。同时,源码结构清晰,易于理解和修改。您可以在这个基础上进行二次开发,实现更多有趣的功能。 请放心下载使用,我们为您提供了详细的文档说明,以便您更好地了解和使用该项目。希望这个项目能为您提供实质性的帮助,祝您在学习和工作中取得更好的成绩!

    利用协同过滤算法,基于用户历史订单数据,对店铺的用户和商品进行推荐.zip

    协同过滤算法(Collaborative Filtering)是一种经典的推荐算法,其基本原理是“协同大家的反馈、评价和意见,一起对海量的信息进行过滤,从中筛选出用户可能感兴趣的信息”。它主要依赖于用户和物品之间的行为关系进行推荐。 协同过滤算法主要分为两类: 基于物品的协同过滤算法:给用户推荐与他之前喜欢的物品相似的物品。 基于用户的协同过滤算法:给用户推荐与他兴趣相似的用户喜欢的物品。 协同过滤算法的优点包括: 无需事先对商品或用户进行分类或标注,适用于各种类型的数据。 算法简单易懂,容易实现和部署。 推荐结果准确性较高,能够为用户提供个性化的推荐服务。 然而,协同过滤算法也存在一些缺点: 对数据量和数据质量要求较高,需要大量的历史数据和较高的数据质量。 容易受到“冷启动”问题的影响,即对新用户或新商品的推荐效果较差。 存在“同质化”问题,即推荐结果容易出现重复或相似的情况。 协同过滤算法在多个场景中有广泛的应用,如电商推荐系统、社交网络推荐和视频推荐系统等。在这些场景中,协同过滤算法可以根据用户的历史行为数据,推荐与用户兴趣相似的商品、用户或内容,从而提高用户的购买转化率、活跃度和社交体验。 未来,协同过滤算法的发展方向可能是结合其他推荐算法形成混合推荐系统,以充分发挥各算法的优势。

    用C#实现人工智能中的八数码问题,有界面效果,可以得出结果,也可以逐步求解.zip

    用C#实现人工智能中的八数码问题,有界面效果,可以得出结果,也可以逐步求解.zip

    Matlab 太阳能电池 simulink 模型太阳能电池模型连接到巴克 converter.by

    Matlab 太阳能电池 simulink 模型太阳能电池模型连接到巴克 converter.by 不同占空比和 PS 转炉值,我们可以改变输出 voltage.buck 转换器调节来自太阳能电池的电压,因而顺利和调节直流电压在负载的忧伤。通过将许多细胞我们可以使太阳能机舱和增加输出电压电流 (串联或并联).zip

    npy 文件的基本结构和内容

    npy 文件的基本结构和内容

    Learning Python 5th Edition

    Learning Python 5th Edition

    Learning Docker

    Learning Docker

    SwiftUI-加载动画 圆点循环缩放动画

    SwiftUI-加载动画 圆点循环缩放动画

    一种用于非线性模型预测控制的并行优化工具包(NMPC)

    介绍了一种专为非线性模型预测控制(NMPC)设计的并行优化工具包。内容涉及该工具包的功能特点、使用方法以及在解决非线性控制问题中的应用实例。通过对比分析,突出了并行优化在提高NMPC计算效率和实时性方面的重要作用。适合控制工程师、算法研究员和对高性能计算感兴趣的专业人士。使用场景包括复杂系统控制、实时仿真和工业自动化。目标是推广这一工具包的使用,助力非线性控制系统的研究与开发。 关键词标签: 非线性模型预测控制 NMPC 并行优化 工具包 实时控制

    matlab矩阵位移法实现有限元求解.zip

    matlab矩阵位移法实现有限元求解.zip

    Matlab 交互式多模型目标跟踪IMM.zip

    Matlab 交互式多模型目标跟踪IMM.zip

    520节日李珣的爱心代码

    内容概要:本项目是李珣创作的“爱心代码”,旨在通过编程表达浪漫与情感。该项目使用JavaScript编写,生成一个动态的爱心图案,并可以附加个性化的文字祝福。代码逻辑简单清晰,适合在网页上展示和分享。源码提供了完整的代码文件,部署文档详细介绍了代码的使用方法和展示步骤,讲解内容涵盖了代码的实现原理、技术选型理由、设计思路以及使用方法。 适合人群:对JavaScript有基础了解,并希望通过编程表达情感的开发者和编程爱好者。 能学到什么: 1. 掌握JavaScript绘图和动画的实现方法。 2. 学习如何通过代码生成动态图案。 3. 了解简单的前端开发和部署流程。 4. 掌握个性化定制代码的技巧。 阅读建议:本资源旨在帮助学习者通过实践项目掌握JavaScript的绘图和动画实现方法,并了解如何通过编程表达情感。建议在学习过程中结合部署文档进行实践,并深入理解讲解内容中的技术原理和设计思路。同时,鼓励学习者根据实际需求对代码进行拓展和优化,以提升自己的技术水平和创造力。

    python源码毕业设计基于深度学习的水果识别系统源码+文档说明+数据集+模型(期末大作业项目).rar

    本源码提供了一个基于深度学习的水果识别系统,涵盖了Python编程、深度学习、图像识别等多个领域的技术。项目利用神经网络模型对水果图像进行分类,实现了高效的水果识别功能。适合计算机专业的学生、老师和从业人员学习和参考,尤其是对深度学习图像识别感兴趣的朋友。 核心功能包括: 1. 数据集:包含大量水果图片,用于训练和测试模型。 2. 模型训练:采用卷积神经网络(CNN)进行训练,提升模型精度。 3. 图像识别:加载预训练模型,对新图像预测类别。 4. 测试验证:确保模型准确性和实用性。 代码可用于毕业设计、课程设计等,快速构建原型,基于此优化和扩展。 资源丰富,包含详细文档,讲解代码结构和算法;提供数据集和预训练模型,方便测试;代码清晰易懂,结构完整,便于理解深度学习图像识别。 请放心下载,这是经过测试的高质量资源,助你取得课程设计高分!

    Java项目毕业设计-航空订票系统(前台订票+后台票务管理)基于SSM开发+数据库(详细源码)-期末大作业.rar

    本项目为Java项目毕业设计-航空订票系统,基于SSM框架开发,结合前台订票与后台票务管理功能,满足现代航空票务需求。系统采用三层架构,包括表现层、业务逻辑层和数据访问层,确保高效稳定运行。数据库设计考虑数据完整性和安全性,采用MySQL数据库存储关键数据。 经过运行测试,系统性能良好,满足设计要求。界面简洁直观,用户友好;后台管理功能强大,方便管理员管理。系统安全性高,有效防止SQL注入、跨站脚本等攻击。 本资源适合计算机相关专业学生和从业者下载学习。对初学者,可快速掌握SSM框架和航空订票系统开发流程;对有一定基础者,可作为参考,拓宽思路,提升技能。此外,也适用于毕业设计、课程设计、项目立项等场景,展现项目基本框架和功能。 请放心下载使用,相信能助您顺利完成学习和项目任务。期待在您的努力下,系统不断完善,功能更加丰富,为航空事业发展贡献力量。

    web期末大作业-基于html+css+js实现的模仿华为商城静态网页源码+项目说明(附静态网页效果链接).rar

    本学期Web期末大作业,我们为您呈现一个精心制作的静态网页源码项目——基于HTML+CSS+JS实现的仿华为商城。经过严格的运行测试,我们确保该项目在各大主流浏览器中均能完美呈现,无兼容性问题。 这个项目不仅是一个简单的网页复刻,更是一次对前端技术的全面实践。我们采用了HTML5标准编写页面结构,利用CSS3实现丰富的样式与动画效果,同时运用JavaScript进行交互逻辑的编写,使得整个页面动态而生动。 我们深知每位同学的需求不同,因此这个项目的源码设计得非常灵活,易于修改和扩展。无论您是想学习前端技术的基础知识,还是想借鉴实际项目经验,亦或是作为课程设计的素材,这个项目都能满足您的需求。 请放心下载使用,我们承诺提供完善的售后服务和技术支持。遇到任何问题,欢迎随时与我们联系。相信通过这个项目,您一定能获得宝贵的实践经验,为未来的学习和职业生涯打下坚实的基础。

    web期末大作业网页设计期末大作业-大鱼海棠(html+css+js) 项目源码案例.rar

    大鱼海棠网页设计期末大作业项目概述 本项目名为“大鱼海棠”,旨在通过HTML、CSS和JavaScript技术,为学生提供一个具有挑战性的网页设计期末大作业。项目源码经过精心编写与测试,确保运行稳定,无兼容性问题。代码结构清晰,注释详细,便于初学者快速上手,同时也为经验丰富的开发者提供了丰富的参考资料。 大鱼海棠的设计灵感来源于同名动画电影,采用了中国传统元素与现代设计相结合的风格,展现出浓郁的中国风。页面布局合理,色彩搭配和谐,交互效果流畅,用户体验良好。 本资源特别适合计算机相关专业的在校学生、老师以及企业员工下载学习。无论您是初学者还是有一定基础的学员,都能从这个项目中学到宝贵的实践经验。此外,大鱼海棠也适用于毕业设计、课程设计、课程作业以及项目初期立项演示等多种场合。 请放心下载使用,我们承诺提供优质的售后服务和技术支持。祝您学习愉快,取得优异成绩!

    java家庭理财系统(java+applet).zip

    java家庭理财系统(java+applet)java家庭理财系统(java+applet)java家庭理财系统(java+applet)java家庭理财系统(java+applet)java家庭理财系统(java+applet)java家庭理财系统(java+applet)java家庭理财系统(java+applet)java家庭理财系统(java+applet)java家庭理财系统(java+applet)java家庭理财系统(java+applet)java家庭理财系统(java+applet)java家庭理财系统(java+applet)java家庭理财系统(java+applet)java家庭理财系统(java+applet)java家庭理财系统(java+applet)java家庭理财系统(java+applet)java家庭理财系统(java+applet)

    Matlab HP过滤算法可以用于对混沌时间序列分析过滤使用,能够有效去噪,保留时间序列中有效信息.zip

    Matlab HP过滤算法可以用于对混沌时间序列分析过滤使用,能够有效去噪,保留时间序列中有效信息.zip

Global site tag (gtag.js) - Google Analytics