迅速的说清楚rpc原理
第一个问题是服务提供者进程如果被kill -9暴力杀死,不能主动调用srem命令怎么办?
这个时候服务列表中多了一个黑地址指向了不存在的服务而消费者完全不知道,这个时候服务中介就成了黑中介了。那该怎么办呢?
我们引入服务保活和检查机制,并更换数据结构。服务提供者需要每隔5秒左右向服务中介汇报存活,服务中介将服务地址和汇报时间记录在zset数据结构的value和score中。服务中介需要每隔10秒左右检查zset数据结构,踢掉汇报时间严重落后的服务地址项。这样就可以准实时地保证服务列表中服务地址的有效性。
第二个问题是服务列表变动时如何通知消费者。有两种解决方案。
第一种是轮询,消费者需要每隔几秒查询服务列表是否有改变。如果服务很多,服务列表很大,消费者很多,redis会有一定压力。所以这时候可以引入服务列表的版本号机制,给每个服务提供一个key/value设置服务的版本号,就是在服务列表发生变动时,递增这个版本号。消费者只需要轮询这个版本号的变动即可知道服务列表是否发生了变化。因为服务列表比较稳定,仅在网络严重抖动的情况下才会频繁发生变动,所以redis几乎没有压力。
第二种是采用pubsub。这种方式及时性要明显好于轮询。缺点是每个pubsub都会占用消费者一个线程和一个额外的redis连接。为了减少对线程和连接的浪费,我们使用单个pubsub广播全局版本号的变动。所谓全局版本号就是任意服务列表发生了变动,这个版本号都会递增。接收到版本变动的消费者再去检查各自的依赖服务列表的版本号是否发生了变动。这种全局版本号也可以用于第一种轮询方案。
- 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这些步骤都封装起来,让用户对这些细节透明。
怎么封装通信细节才能让用户像以本地调用方式调用远程服务呢?对java来说就是使用代理!java代理有两种方式:1) jdk 动态代理;2)字节码生成。尽管字节码生成方式实现的代理更为强大和高效,但代码不易维护,大部分公司实现RPC框架时还是选择动态代理方式。
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()唤醒前面处于等待状态的线程。
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都会通知服务消费方服务提供者地址列表已经发生改变,从而进行更新。
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等。
https://www.cnblogs.com/panxuejun/p/6094790.html
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等。
迅速的说清楚rpc原理的更多相关文章
- 你应该知道的RPC原理
你应该知道的RPC原理 在学校期间大家都写过不少程序,比如写个hello world服务类,然后本地调用下,如下所示.这些程序的特点是服务消费方和服务提供方是本地调用关系. 而一旦踏入公司尤其是大型互 ...
- RPC原理解析
1.RPC原理解析 1.1 什么是RPC RPC(Remote Procedure Call Protocol) --远程过程调用协议,它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络 ...
- 简述RPC原理实现
前言 架构的改变,往往是因为业务规模的扩张. 随着业务规模的扩张,为了满足业务对技术的要求,技术架构需要从单体应用架构升级到分布式服务架构,来降低公司的技术成本,更好的适应业务的发展. 分布式服务 ...
- RPC 原理
转载地址:你应该知道的 RPC 原理 在校期间大家都写过不少程序,比如写个hello world服务类,然后本地调用下,如下所示.这些程序的特点是服务消费方和服务提供方是本地调用关系. 而一旦踏入公司 ...
- 一文搞懂RPC原理
RPC原理解析 什么是RPC RPC(Remote Procedure Call Protocol)--远程过程调用协议,它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议.R ...
- 你应该知道的 RPC 原理
作者:伯乐在线 - meituanalibaba 网址:http://blog.jobbole.com/92290/ 在校期间大家都写过不少程序,比如写个hello world服务类,然后本地调用 ...
- 基于RPC原理的dubbo
在校期间大家都写过不少程序,比如写个hello world服务类,然后本地调用下,如下所示.这些程序的特点是服务消费方和服务提供方是本地调用关系. 而一旦踏入公司尤其是大型互联网公司就会发现,公司的系 ...
- RPC 原理的前生今世
(如果感觉有帮助,请帮忙点推荐,添加关注,谢谢!你的支持是我不断更新文章的动力.本博客会逐步推出一系列的关于大型网站架构.分布式应用.设计模式.架构模式等方面的系列文章) 在校期间大家都写过不少程序, ...
- 五分钟快速掌握RPC原理及实现
随着公司规模的不断扩大,以及业务量的激增,单体应用逐步演化为服务/微服务的架构模式, 服务之间的调用大多采用rpc的方式调用,或者消息队列的方式进行解耦.几乎每个大厂都会创建自己的rpc框架,或者基于 ...
- RPC原理及实现
一.什么是RPC RPC 的全称是 Remote Procedure Call 是一种进程间通信方式.它允许程序调用另一个地址空间(通常是共享网络的另一台机器上)的过程或函数,而不用程序员显式编码这个 ...
随机推荐
- puthon文件头
#!/usr/bin/u/ubv/a python # -*- coding:utf-8 -*-
- .NET并行计算和并发:Task
任务不是线程. 任务运行的时候需要使用线程,任务并没有取代线程.
- Fescar: Fast & Easy Commit And Rollback
Fescar is an easy-to-use, high-performance, java based, open source distributed transaction solution ...
- ASP.NET项目答辩系统课件使用中的问题记录
使用软件:VS2008 模块一:登录模块 1-08 问题:显示属性“background”不是元素"td"的有效属性 解决:style="background-image ...
- python基础3、4---流程控制、运算符
1.for循环 和while循环 for 临时变量 in 待遍历的数据: 循环体 (循环体这里一般加break,结束循环,执行else代码) else: 循环不满足条件执行的代码 while 表达式 ...
- JS判断
/***************************************************************** 表单校验工具类 (linjq) ***************** ...
- Docker 部署应用过程记录
Kibana直接部署到centos中,老是没有任何征兆退出,今天将他移动到docker中部署,以下是部署的过程,做个记录防止忘记 1.安装Docker # yum install docker 2.启 ...
- idea 里自动下载私服jar一直不能下载下来
idea 里自动下载私服jar一直不能下载下来,只生成了.lastUpdated文件,检查了setting.xml文件.网络,私服,均无问题,在idea中打开Terminal窗口,在所要更新的pom. ...
- 3.14 unittest之skip
3.14 unittest之skip 前言当测试用例写完后,有些模块有改动时候,会影响到部分用例的执行,这个时候我们希望暂时跳过这些用例.或者前面某个功能运行失败了,后面的几个用例是依赖于这个功能的用 ...
- sparksql错误报No such file or director
今天在非hadoop用户使用sparksql处理insert overwrite table a select b left join c这个句型遇到以下的错误. Error: org.apache. ...