第三节、rpc通信过程分析 前面两个小节分别对rpc服务端和客户端的建立流程做了详细的分析,也就是说rpc客户端和服务器端已经能够进行正常的通信了(rpc客户端已经通过connect链接上rpc 下面以客户端创建逻辑卷(volume)为例来分析rpc的通信过程,就以下面这个客户端的命令开始: gluster volume create test-volume server3:/exp3 server4 ”, gf_cli3_1_create_volume} 所以真正的提交函数是gf_cli3_1_create_volume函数,继续分析这个函数,主要实现代码如下: ret = cli_cmd_submit , this, gf_cli3_1_create_volume_cbk); 主要代码也只有一行,其余代码就是为了这一行的函数调用做相应参数准备的,这一行的这个函数就是所有客户端命令提交rpc请求服务的实现函数 (rpc);//新建一个rpc调用的id号 conn = &rpc->conn;//从rpc对象中取得链接对象 rpcreq->prog = prog;//赋值
什么是RPC RPC(Remote Procedure Call)是指远程过程调用,是一种进程间通信方式,他是一种技术的思想,而不是规范。 RPC基本原理图 举个例子 A服务器上有段代码 hello(){ String msg = b.hi(new User("Tom")); System.out.println(msg); } 另一台 并将传递的参数对象进行序列化,将内容发送给B服务器的 Server Sub,将序列化的内容反序列化,并调用对应的方法,拿到调用方法产生的返回值,将返回结果序列化传递A服务器,A收到后反序列化并展示调用结果 决定RPC
1.概述 go 源码中带了rpc框架,以相对精简的当时方式实现了rpc功能,目前源码中的rpc官方已经宣布不再添加新功能,并推荐使用grpc. 作为go标准库中rpc框架,还是有很多地方值得借鉴及学习,这里将从源码角度分析go原生rpc框架,以及分享一些在使用过程中遇到的坑. 2.server端 server端主要分为两个步骤,首先进行方法注册 = 3 { if reportErr { log.Println("method", mname, "has wrong number of ins server.sendResponse(sending, req, replyv.Interface(), codec, errmsg) server.freeRequest(req) } 3. ,不过git就有一个基于rpc的功能增强版本,叫rpcx,支持了大部分主流rpc的特性. 6.
3. 什么是 RPC 针对 HTTP 协议进行服务间通信的上述种种不足,RPC 协议诞生了,他是“Implementing Remote Procedure Calls”的缩写。 可以参看官方文档: http://thrift.apache.org/ 主页君下一篇文章将详细介绍了 thrift 的基本使用 本文,我们结合相关的源码,介绍一下 thrift 的工作原理。 DemoService.py 源码分析 # # Autogenerated by Thrift Compiler (0.9.1) # # DO NOT EDIT UNLESS YOU ARE SURE 编码为二进制编码格式数据进行传输 TCompactProtocol — 编码为高效率的、密集的二进制编码格式进行数据传输 TJSONProtocol — 编码为 Json 数据编码协议进行传输 他们的 python 实现源码可以参看 等非固定长度的类型则定义了 readXXXBegin、readXXXEnd 与 writeXXXBegin、writeXXXEnd 系列方法用来在整个结构读写开始和完成的时候进行一些必要的工作,但正如我们上面在源码中看到的
RpcContext 整个RpcContext通过ThreadLocal维持。 public class RpcContext { private static final ThreadLocal<RpcContext> LOCAL = new ThreadLocal<RpcContext>() { @Override protected RpcContext initialValue() { return new RpcContext();
RPC协议假定某些传输协议的存在,如TCP或UDP,为通信程序之间携带信息数据。在OSI网络通信模型中,RPC跨越了传输层和应用层。RPC使得开发包括网络分布式多程序在内的应用程序更加容易。 RPC调用,其内部操作大致有如下十步: 1.调用客户端句柄;执行传送参数 2.调用本地系统内核发送网络消息 3.消息传送到远程主机 4.服务器句柄得到消息并取得参数 5.执行远程过程 HTTP Microsoft RPC-over-HTTP 部署(RPC over HTTP)允许RPC 客户端安全和有效地通过Internet 连接到RPC 服务器程序并执行远程过程调用。 这是在一个名称为RPC-over-HTTP 代理,或简称为RPC 代理的中间件的帮助下完成的。 RPC 代理运行在IIS 计算机上。 通过RPC over HTTP,RPC 客户端不和服务器直接通信,它们使用RPC 代理作为中间件。
所以首先学习了一下hadoop rpc的内部实现,拜读了一下hadoop的源码 准备工作 首先下载hadoop的最新稳定版源码(目前是2.7.3),编译hadoop源码,因为hadoop的底层序列号用的是 如果比较懒的话,其实用maven把相关jar和源码包下载下来也行。 Hadoop的rpc并没有采用现成的rpc框架,如thrift等,而是采用jdk自带的库完全自己写了一套,更加轻量级,更加可控。 用到的主要的技术是java NIO、网络编程、反射和动态代理,如果对这几块不太熟悉的话,建议先找些资料看看相关的东西 #Hadoop rpc实现流程 Hadoop rpc框架位于hadoop源码的hadoop-commn 项目里,就像我们学习任何语言先学习hello world一样,我们先来一个最简单的程序,这个程序是从hadoop源码test目录里找到的,testRPC.java,我们运行其中的main方法。 客户端与服务器通信的一些信息在这个里面 Handler 用于处理接受到rpc请求 Listener 用于监听rpc请求。
RPC协议假定某些传输协议的存在,如TCP或UDP,为通信程序之间携带信息数据。在OSI网络通信模型中,RPC跨越了传输层和应用层。RPC使得开发包括网络分布式程序在内的应用程序更加轻易。 (Hadoop 2.6版本) 二.RPC通信模型 RPC通常采用客户机/服务器模型。 五.Hadoop RPC使用方法 Hadoop RPC对外主要提供两种接口(org.apache.hadoop.ipc.RPC),分别是: //构造一个客户端代理对象(实现某个协议),用于向服务器发送RPC 静态类,构造RPC Server 5.1 定义RPC协议 RPC协议是客户端和服务端之间通信接口,它定义了服务器端对外提供的服务器接口。 * 3.调用connection.sendRpcRequest(call);将Call对象发送给Server * 4.等待Server端处理Call请求,服务端处理完成,通过网络返回服务端处理完成后,
我:朋友圈有个程序猿花了2个月的头发写了一个 RPC 框架示例(代码地址:https://github.com/Snailclimb/guide-rpc-framework),刚刚下载到本地看着看着就【 ---- 项目模块 guide-rpc-framwork 是基于 Netty、Kyro、Zookeeper 实现的 RPC 框架。 rpc-framework-simple RPC 框架核心实现类 项目模块是非常简练的,如果换成是我这种强迫症患者来分的话,还是会增加一个 rpc-framework-parent 模块(虽然 rpc-framework-parent ---- RPC 核心框架 RPC-FRAMEWORK-COMMON 简洁干练的 common 工程,约定了 RPC 错误信息、响应错误码枚举,RPC、序列化的自定义错误,单例工厂类,线程池、zookeeper RPC-FRAMEWORK-SERVICE RPC 框架的核心实现类。保存服务端注册的实例,并提供动态代理的方式用于客户端发送请求(socket、netty 方式)到服务端。
2.2 dubbo=com.alibaba.dubbo.rpc.protocol.dubbo.DubboProtocol 是dubbo默认的protocol,主要用于创建ExchangeServer和 2.3 rmi=com.alibaba.dubbo.rpc.protocol.rmi.RmiProtocol ? 使用的是java的rmi机制进行直连通信。 :webservice协议的实现 thrift=com.alibaba.dubbo.rpc.protocol.thrift.ThriftProtocol:thrift协议 memcached=com.alibaba.dubbo.rpc.protocol.memcached.MemcachedProtocol :memcached协议 redis=com.alibaba.dubbo.rpc.protocol.redis.RedisProtocol:redis协议 rest=com.alibaba.dubbo.rpc.protocol.rest.RestProtocol :rest协议 3. dubbo的序列化 这里顺便提一下dubbo的序列化: ?
上篇文章,有提及 Web Workers RPC 以解决浏览器不阻塞UI的问题,其中 comlink 是一把利器,本文就 comlink 的关键源码进行解析。 Comlink 通过提供 RPC 实现将基于 Worker.postMessage(someObject) 的 API 变成了对开发人员更友好的“类似本地调用”方式。 拆解源码之前,先介绍几个重要的概念:Proxy、Channel Messaging API、Transferable objects 注意:worker 创建完成后,每次通信都是新建 MessageChannel return target(...args) * 10 } }; const proxy1 = new Proxy(sum, handler) console.log(sum(1, 2)) // 3 源码解析 通过 Proxy 对 wrap(worker) 劫持相关操作; 通过 ep(worker/MessageChannel)进行 on message 以及 postMessage 操作;
本篇着重分析Flink的RPC设计,如何封装Actor模型,RPC的创建和调用流程。阅读说明:源码版本:Flink release-1.14.4阅读前提:了解Akka Actor基础知识1). 结合代码,看问题1、2、3,进一步熟悉RPC的创建与交互过程。(重点关注AkkaRpcService、AkkaInvocationHandler、AkkaRpcActor类)3). 3. Dispatcher会连接ResourceManager的Rpc服务 是通过GatewayRetriever来发现ResourceManager的Rpc地址信息3). 3). 什么时候与JM建立连接?
以源代码中muduo/examples/protobuf/rpc/为例,梳理pb rpc+muduo的处理流程。 展示如何在muduo网络库基础上结合protobuf rpc实现一个完整的rpc框架。 muduo-rpc-注册函数.jpg 红色箭头描述了注册函数流程: 红色1-3说明阅读源码时候类的顺序,即从RpcServer的构造函数开始阅读,然后是TcpServer、Acceptor、Channel TcpServer的start开始,start中调用了EventLoop的runInLoop方法 蓝色2:runInLoop中执行Acceptor的listen方法,实现socket的listen操作 蓝色3- 源码,只有一个感觉,没有什么事儿是回调函数不能解决的,如果一层不行,那就再加一层。
第二节、rpc客户端实现原理及代码分析 rpc客户端主要发起一个rpc请求,执行完rpc请求以后就退出rpc,下面分析客户端rpc请求建立的整个过程。 (rpc, cli_rpc_notify, this);//注册rpc请求通知函数 rpc_clnt_start (rpc);//开始rpc 这段代码其实是glusterfs客户端程序启动时建立 rpc请求的初始化过程函数,真正独立开始建立一个rpc请求的过程是从函数rpc_clnt_new开始的,下面就分析这个函数的功能,先看主要代码: rpc = GF_CALLOC (1 ; ret = rpc_clnt_connection_init (rpc, ctx, options, name);//初始化rpc请求连接 rpc = rpc_clnt_ref /初始化为0 if (conn->connected == 0) {//还没有完成链接 tv.tv_sec = 3;
e.printStackTrace(); } transport.close(); } 修改 从maven下载了thrift-0.9.3版本的源码 上述更改需要首先系在thrift源码包: libthrift-0.9.3-sources.jar。修改代码后再本地编译生成jar包,在使用工程导入即可。
ananas是一个基于promise模式和google protobuf的RPC框架,目前由C++11实现,是出于教学目的写的小巧框架。 受作者所托,这两天大概浏览了net部分代码,做个简单总结。 相比Tars RPC代码,ananas更适合初学者学习网络库 1 网络库框架 [网络库框架] 网络库的整体框架非常简洁,如上图所示: 左上角的EventLoop活在主线程中,负责listen、bind, HandleReadEvent方法 7号-8号,当链接成功建立时候,会把链接分配到EventLoopGroup中的一个EventLoop中进行注册 9号 OnNewConnection是回调函数,由用户自己定义,例子可以参考源码 如果我们想在网络库之上制作自己的RPC框架,只需要在外层编写OnNewConnection函数,通过Application类中的Listen方法进行注册即可 3 网络库怎样接收请求和处理结果 [ana-Connection 我们先忽略细节,介绍下主要流程 1号,HandleReadEvent中接收请求,然后调用onMessage函数 2号,onMessage函数也是在外面由用户控制的,怎么解析请求,怎样产生结果,都由用户控制 3号
thrift是一个支持多语言进行RPC的软件库,开发者通过定义数据类型和服务接口,经由thrift的代码生成引擎就可以构建RPC客户端和服务端所需要的代码。它的核心组件如下: Types。 127.0.0.1",9000,1000); //2:传输数据的编码方式 TProtocol protocol=new TBinaryProtocol(transport); //3: TServerSocket(9000); //2:构建server所需要的参数 TServer.Args serverArgs=new TServer.Args(serverSocket); //3: LOG.info("main server start ... "); //6:等待连接到来 server.serve(); 可运行的客户端和服务端案例请戳这里 TBinaryProtocol源码追踪 );") .interpretation("开始往返回Stream中写入数据,表明这是对那个方法的返回值,然后写入返回的结果,最后输入socket"); TBinaryProtocol源码总结
二、Glusterfs的rpc模块实现 第一节、rpc服务器端实现原理及代码分析 1.rpc服务初始化 Rpc服务的初始化工作在函数rpcsvc_init中实现的,实现代码如下: 服务 return svc;//返回初始化后的所有rpc服务的全局描述对象 } 初始化的工作主要就是为描述一个所有rpc服务的全局对象设置一些初始化的值,这些信息一直保存到整个rpc服务结束 svc->notify_count++;//通知函数个数加1 } pthread_mutex_unlock (&svc->rpclock);//释放锁 3. 到此为止整个rpc服务基本上已经建立完成,开始提供rpc服务,不过具体提供哪些程序的服务还需要最后一步,就是在已经建立的rpc服务上注册服务程序(就是提供客户端调用的程序集,每一个程序里面提供多个函数) 一个完整的rpc服务就这样完全建立了。 总结:可以看出整个rpc服务的建立过程还是比较复杂的,下面用一个完整的图来解析整个rpc的建立过程,图如下:
和 Flink 中的 RPC 实现的过程和思考。 关于 RPC 和 RMI 及 Actor Model 具体的差别本文不做展开,主要集中在 Spark 和 Flink 的 RPC 实现来介绍 Actor Model 下的 RPC 实现。 理解了 Spark 和 Flink 为什么要开发自己的 RPC 实现之后,我们再看到 RPC 实现具体的考量点和内容。 Flink 的 RPC 实现 现在我们转过头来看 Flink 的 RPC 实现。总的来说 Flink 的 RPC 实现依然是基于 Akka 的,这一点与 Spark 基于 Netty 开发的一套不同。 RMI 式的类型化 RPC 实现 Flink 中的 RPC 实现主要在 flink-runtime 模块下的 org.apache.flink.runtime.rpc 包中。
RPC架构图如下: 动态代理 主要用来做方法的增强,让你可以在不修改源码的情况下,增强一些方法,在方法执行前后做任何你想做的事情(甚至根本不去执行这个方法),因为在InvocationHandler的 ) { markClosed(e); } finally { IOUtils.closeStream(d); } } Question3: 客户端的源码分析暂时到这,下面我们来分析Server端的源码 ipc.Server源码分析 内部类如下 Call :用于存储客户端发来的请求 Listener : 监听类,用于监听客户端发来的请求,同时 Namenode初始化时一定初始化了RPC的Sever端,那我们去看看Namenode的初始化源码 private void initialize(Configuration conf) throws ipc.RPC类中的getServer()源码如下 public static Server getServer(final Object instance, final String bindAddress