第一个问题是服务提供者进程如果被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原理的更多相关文章

  1. 你应该知道的RPC原理

    你应该知道的RPC原理 在学校期间大家都写过不少程序,比如写个hello world服务类,然后本地调用下,如下所示.这些程序的特点是服务消费方和服务提供方是本地调用关系. 而一旦踏入公司尤其是大型互 ...

  2. RPC原理解析

    1.RPC原理解析 1.1 什么是RPC RPC(Remote Procedure Call Protocol) --远程过程调用协议,它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络 ...

  3. 简述RPC原理实现

      前言 架构的改变,往往是因为业务规模的扩张. 随着业务规模的扩张,为了满足业务对技术的要求,技术架构需要从单体应用架构升级到分布式服务架构,来降低公司的技术成本,更好的适应业务的发展. 分布式服务 ...

  4. RPC 原理

    转载地址:你应该知道的 RPC 原理 在校期间大家都写过不少程序,比如写个hello world服务类,然后本地调用下,如下所示.这些程序的特点是服务消费方和服务提供方是本地调用关系. 而一旦踏入公司 ...

  5. 一文搞懂RPC原理

    RPC原理解析 什么是RPC RPC(Remote Procedure Call Protocol)--远程过程调用协议,它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议.R ...

  6. 你应该知道的 RPC 原理

    作者:伯乐在线 - meituanalibaba   网址:http://blog.jobbole.com/92290/ 在校期间大家都写过不少程序,比如写个hello world服务类,然后本地调用 ...

  7. 基于RPC原理的dubbo

    在校期间大家都写过不少程序,比如写个hello world服务类,然后本地调用下,如下所示.这些程序的特点是服务消费方和服务提供方是本地调用关系. 而一旦踏入公司尤其是大型互联网公司就会发现,公司的系 ...

  8. RPC 原理的前生今世

    (如果感觉有帮助,请帮忙点推荐,添加关注,谢谢!你的支持是我不断更新文章的动力.本博客会逐步推出一系列的关于大型网站架构.分布式应用.设计模式.架构模式等方面的系列文章) 在校期间大家都写过不少程序, ...

  9. 五分钟快速掌握RPC原理及实现

    随着公司规模的不断扩大,以及业务量的激增,单体应用逐步演化为服务/微服务的架构模式, 服务之间的调用大多采用rpc的方式调用,或者消息队列的方式进行解耦.几乎每个大厂都会创建自己的rpc框架,或者基于 ...

  10. RPC原理及实现

    一.什么是RPC RPC 的全称是 Remote Procedure Call 是一种进程间通信方式.它允许程序调用另一个地址空间(通常是共享网络的另一台机器上)的过程或函数,而不用程序员显式编码这个 ...

随机推荐

  1. 集合List的排序

    自从出现了泛型和LINQ,对于集合的排序变得更简单了. //倒序 list.OrderByDescending(p=> p.a).ThenByDescending(p => p.b); / ...

  2. openstack常用命令-neutron篇

    列出当前租户所有的网络 neutron net-list 列出所有租户的所有网络(需要管理员权限) neutron net-list --all-tenants 创建一个网络(vlan/flat) n ...

  3. String与StringBuilder 区别

    string 是不可变字符串.一旦创建不可修改,使用Insert.Remove.PadLeft.Replace.Splict等,返回都是新的字符串对象. StringBuilder 是可变字符串,大多 ...

  4. 【转载】 “强化学习之父”萨顿:预测学习马上要火,AI将帮我们理解人类意识

    原文地址: https://yq.aliyun.com/articles/400366 本文来自AI新媒体量子位(QbitAI)     ------------------------------- ...

  5. 2018 CCPC网络赛 hdu6444 Neko's loop

    题目描述: Neko has a loop of size n.The loop has a happy value ai on the i−th(0≤i≤n−1) grid. Neko likes ...

  6. C#中扩展方法的使用

    MSDN中这样定义扩展方法:扩展方法使你能够向现有类型“添加”方法,而无需创建新的派生类型.重新编译或以其他方式修改原始类型. 扩展方法是一种特殊的静态方法,但可以像扩展类型上的实例方法一样进行调用. ...

  7. 浏览器h5新建文件 保存到本地(相当于浏览器写文件)

    function doSave(value, type, name) {         var blob;         if (typeof window.Blob == "funct ...

  8. 当进行服务端渲染的时间,某些npm包可能会调用document,window这些对象而导致报错

    1.在didmount里面使用require引入 require.ensure([], (require) => { this.setState({ picker: require('./Pic ...

  9. windows10环境下VMware14中Ubuntu16.04解决如何上网问题

    进入控制面板,网络和Internet,网络连接 点击以太网,查看详细信息 点击属性 --> 共享,允许其他网络-->选择VMnet1 点开虚拟机编辑选项 ,选择 VMNET1 仅主机,其他 ...

  10. 2018-2019-2 20165313《网络对抗技术》Exp1 缓冲区溢出实验

    实践涉及指令 NOP:NOP指令即"空指令".执行到NOP指令时,CPU什么也不做,仅仅当做一个指令执行过去并继续执行NOP后面的一条指令.(机器码:90) JNE:条件转移指令, ...