responseB 丢给 ThreadB
标签:
Netty RPC 实现观点
RPC,即 Remote Procedure Call(长途过程挪用),挪用长途计算机上的处事,就像挪用本地处事一样。RPC 可以很好的解耦系统,如 WebService 就是一种基于 Http 协议的 RPC。这个 RPC 整体框架
如下:
关键技术
处事颁布与订阅:处事端使用 Zookeeper 注册处事地点,客户端从 Zookeeper 获取可用的处事地点。
通信:使用 Netty 作为通信框架。
Spring:使用 Spring 配置处事,加载 Bean,扫描注解。
动态代办代理:客户端使用代办代理模式透明化处事挪用。
动静编解码:使用 Protostuff 序列化和反序列化动静。
核心流程
处事消费方(client)挪用以本地挪用方法挪用处事;
client stub 接收到挪用后卖力将要领、参数等组装成能够进行网络传输的动静体;
client stub 找随处事地点,并将动静发送随处事端;
server stub 收到动静后进行解码;
server stub 按照解码功效挪用本地的处事;
本地处事执行并将功效返回给 server stub;
server stub 将返回功效打包成动静并发送至消费方;
client stub 接收到动静,并进行解码;
处事消费方得到最终功效。
RPC 的方针就是要 2~8 这些法式都封装起来,让用户对这些细节透明。JAVA 一般使用动态代办代理方法实现长途挪用。
动静编解码
息数据布局(接口名称+要领名+参数类型和参数值+超不时间+ requestID)
客户真个请求动静布局一般需要包孕以下内容:
接口名称:在我们的例子里接口名是“HelloWorldService”,如果不传,处事端就不知道挪用哪个接口了;
要领名:一个接口内可能有很多要领,如果不传要领名处事端也就不知道挪用哪个要领;
参数类型和参数值:参数类型有很多,好比有 bool、int、long、double、string、map、list,甚至如 struct(class);以及相应的参数值;
超不时间:
requestID,标识独一请求 id,不才面一节会详细描述 requestID 的用处。
处事端返回的动静 : 一般包孕以下内容。返回值+状态 code+requestID
序列化
目前互联网公司广泛使用 Protobuf、Thrift、Avro 等成熟的序列化解决方案来搭建 RPC 框架,这些都是久经考验的解决方案。
通讯过程
核心问题(线程暂停、动静乱序)
如果使用 netty 的话,一般会用 channel.writeAndFlush()要领来发送动静二进制串,这个要领挪用后对付整个长途挪用(从发出请求到接收到功效)来说是一个异步的,即对付当前线程来说,将请求发送出来后,线程就可以往后执行了,至于处事真个功效,是处事端措置惩罚惩罚完成后,再以动静的形式发送给客户真个。于是这里呈现以下两个问题:
怎么让当前线程“暂停”,等功效回来后,再向后执行?
如果有多个线程同时进行长途要领挪用,这时成立在 client server 之间的 socket 连接上会有很多双方发送的动静通报,前后挨次也可能是随机的,server 措置惩罚惩罚完功效后,将功效动静发送给 client,client 收到很多动静,怎么知道哪个动静功效是原先哪个线程挪用的?如下图所示,线程 A 和线程 B 同时向 client socket 发送请求 requestA 和 requestB,socket 先后将 requestB 和 requestA 发送至 server,而 server 可能将 responseB 先返回,尽管 requestB 请求达到时间更晚。我们需要一种机制保证 responseA 丢给****ThreadA,responseB 丢给 ThreadB。
通讯流程
requestID 生成-AtomicLong
client 线程每次通过 socket 挪用一次长途接口前,生成一个独一的 ID,即 requestID(requestID 必须保证在一个 Socket 连接里面是独一的),一般每每使用 AtomicLong从 0 开始累计数字生成独一 ID;存放回调东西 callback 到全局 ConcurrentHashMap
将 处 理 结 果 的 回 调 对 象 callback , 存 放 到 全 局 ConcurrentHashMap 里 面put(requestID, callback);synchronized 获取回调东西 callback 的锁并自旋 wait
当线程挪用 channel.writeAndFlush()发送动静后,紧接着执行 callback 的 get()要领试图获取长途返回的功效。在 get()内部,则使用 synchronized 获取回调东西 callback 的锁,再先检测是否已经获取到功效,如果没有,然后挪用 callback 的 wait()要领,释放callback 上的锁,让当前线程处于期待状态。监听动静的线程收到动静,找到 callback 上的锁并唤醒
温馨提示: 本文由Jm博客推荐,转载请保留链接: https://www.jmwww.net/file/web/32610.html