一不小心实现了RPC

前言

随着最近关注 cim 项目的人越发增多,导致提的问题以及 Bug 也在增加,在修复问题的过程中难免代码洁癖又上来了。
看着一两年前写的东西总是怀疑这真的是出自自己手里嘛?有些地方实在忍不住了便开始了漫漫重构之路。
前后对比
在开始之前先简单介绍一下 cim 这个项目,下面是它的架构图:

简单来说就是一个 IM 即时通讯系统,主要有以下部分组成:
IM-server自然就是服务端了,用于和客户端保持长连接。IM-client客户端,可以简单认为是类似于的 QQ 这样的客户端工具;当然功能肯定没那么丰富,只提供了一些简单消息发送、接收的功能。Route路由服务,主要用于客户端鉴权、消息的转发等;提供一些 http 接口,可以用于查看系统状态、在线人数等功能。
当然服务端、路由都可以水平扩展。

这是一个消息发送的流程图,假设现在部署了两个服务端 A、B 和一个路由服务;其中 ClientA 和 ClientB 分别和服务端 A、B 保持了长连接。
当 ClientA 向 ClientB 发送一个 hello world 时,整个的消息流转如图所示:
- 先通过
http将消息发送到Route服务。 - 路由服务得知
ClientB是连接在ServerB上;于是再通过http将消息发送给ServerB。 - 最终
ServerB将消息通过与ClientB的长连接通道push下去,至此消息发送成功。
这里我截取了 ClientA 向 Route 发起请求的代码:

可以看到这就是利用 okhttp 发起了一个 http 请求,这样虽然能实现功能,但其实并不优雅。
举个例子:假设我们需要对接支付宝的接口,这里发送一个 http 请求自然是没问题;但对于支付宝内部各部门直接互相调用接口时那就不应该再使用原始的 http 请求了。
应该是由服务提供方提供一个 api 包,服务消费者只需要依赖这个包就可以实现接口调用。
当然最终使用的是 http、还是自定义私有协议都可以。
也类似于我们在使用 Dubbo 或者是 SpringCloud 时,通常是直接依赖一个 api 包,便可以像调用一个本地方法一样调用远程服务了,并且完全屏蔽了底层细节,不管是使用的 http 还是 其他私有协议都没关系,对于调用者来说完全不关心。
这么一说是不是有内味了,这不就是 RPC 的官方解释嘛。
对应到这里也是同样的道理,Client 、Route、Server 本质上都是一个系统,他们互相的接口调用也应当是走 RPC 才合理。
所以我重构之后的变成这样了:

是不是代码也简洁了许多,就和调用本地方法一样了,而且这样也有几个好处:
- 完全屏蔽了底层细节,可以更好的实现业务及维护代码。
- 即便是服务提供方修改了参数,在编译期间就能很快发现,而像之前那样调用是完全不知情的,所以也增加了风险。
绕不开的动态代理
下面来聊聊具体是如何实现的。
其实在上文《动态代理的实际应用》 中也有讲到,原理是类似的。
要想做到对调用者无感知,就得创建一个接口的代理对象;在这个代理对象中实现编码、调用、解码的过程。

对应到此处其实就是创建一个 routeApi 的代理对象,关键就是这段代码:
RouteApi routeApi = new ProxyManager<>(RouteApi.class, routeUrl, okHttpClient).getInstance();
完整源码如下:

其中的 getInstance() 函数就是返回了需要被代理的接口对象;而其中的 ProxyInvocation 则是一个实现了 InvocationHandler 接口的类,这套代码就是利用 JDK 实现动态代理的三板斧。

查看 ProxyInvocation 的源码会发现当我们调用被代理接口的任意一个方法时,都会执行这里的 invoke() 方法。
而 invoke() 方法自然就实现了上图中提到的:编码、远程调用、解码的过程;相信大家很容易看明白,由于不是本次探讨的重点就不过多介绍了。
总结
其实理解这些就也就很容易看懂 Dubbo 这类 RPC 框架的核心源码了,总体的思路也是类似的,只不过使用的私有协议,所以在编解码时会有所不同。
所以大家要是想自己动手实现一个 RPC 框架,不妨参考这个思路试试,当用自己写的代码跑通一个 RPC 的 helloworld 时的感觉是和自己整合了一个 Dubbo、SpringCloud 这样的第三方框架的感觉是完全不同的。
本文的所有源码:
https://github.com/crossoverJie/cim
你的点赞与分享是对我最大的支持
一不小心实现了RPC的更多相关文章
- RabbitMQ 实现RPC
实现RPC 首先要弄明白,RPC是个什么东西. (RPC) Remote Procedure Call Protocol 远程过程调用协议 在一个大型的公司,系统由大大小小的服务构成,不同的团队维护不 ...
- 基于RabbitMQ的Rpc框架
参考文档:https://www.cnblogs.com/ericli-ericli/p/5917018.html 参考文档:RabbitMQ 实现RPC MQ的使用场景大概包括解耦,提高峰值处理能力 ...
- 从RPC开始(一)
这是一篇关于纯C++RPC框架的文章.所以,我们先看看,我们有什么? 1.一个什么都能干的C++.(前提是,你什么都干了) 2.原始的Socket接口,还是C API.还得自己去二次封装... 3.C ...
- RPC 使用中的一些注意点
最近线上碰到一点小问题,分析其原因发现是出在对 RPC 使用上的一些细节掌握不够清晰导致.很多时候我们做业务开发会把 RPC 当作黑盒机制来使用,但若不对黑盒的工作原理有个基本掌握,也容易犯一些误用的 ...
- 谈谈如何使用Netty开发实现高性能的RPC服务器
RPC(Remote Procedure Call Protocol)远程过程调用协议,它是一种通过网络,从远程计算机程序上请求服务,而不必了解底层网络技术的协议.说的再直白一点,就是客户端在不必知道 ...
- 游戏编程系列[1]--游戏编程中RPC协议的使用[3]--体验
运行环境,客户端一般编译为.Net 3.5 Unity兼容,服务端因为用了一些库,所以一般为4.0 或往上.同一份代码,建立拥有2个项目.客户端引用: WindNet.Client服务端引用: OpL ...
- python通过protobuf实现rpc
由于项目组现在用的rpc是基于google protobuf rpc协议实现的,所以花了点时间了解下protobuf rpc.rpc对于做分布式系统的人来说肯定不陌生,对于rpc不了解的童鞋可以自行g ...
- spider RPC入门指南
本部分将介绍使用spider RPC开发分布式应用的客户端和服务端. spider RPC中间件基于J2SE 8开发,因此需要确保服务器上安装了JDK 8及以上版本,不依赖于任何额外需要独立安装和配置 ...
- Netty实现高性能RPC服务器优化篇之消息序列化
在本人写的前一篇文章中,谈及有关如何利用Netty开发实现,高性能RPC服务器的一些设计思路.设计原理,以及具体的实现方案(具体参见:谈谈如何使用Netty开发实现高性能的RPC服务器).在文章的最后 ...
随机推荐
- 使用Dism命令对Win7镜像进行操作
在操作前,我们需要下载Win7部署工具AIK和Win7原版镜像 ★镜像迅雷链接 ed2k://|file|cn_windows_7_ultimate_with_sp1_x64_dvd_u_677408 ...
- STL之sstream的用法
STL之sstream的用法 说在前面: 库定义了三种类:istringstream.ostringstream和stringstream,分别用来进行流的输入.输出和输入输出操作.另外,每个类都有一 ...
- D. Little Artem and Dance(带环模拟 + 规律)
D. Little Artem and Dance Little Artem is fond of dancing. Most of all dances Artem likes rueda - Cu ...
- centos8系统下docker安装jenkins
前提是已经安装好docker 1.下载jenkins(最新版本) docker pull jenkins/jenkins 2.创建用于存放jenkins的文件夹 mkdir /home/var/jen ...
- 使用css动画实现领积分效果
最近项目中要做一个领积分的效果,根据老板的描述,这个效果类似于支付宝蚂蚁森林里的领取能量.整体效果是就是在树周围飘着几个积分元素,上下滑动,类似星星闪烁,点击领取后,沿着树中心的位置滑动并消失,树上的 ...
- Mysql数据库下载
链接:https://pan.baidu.com/s/1ZwkY_Twsil7acvtCJ4ljgQ 提取码:t5ih
- 微信小程序项目总结
最近公司做的项目,我主要负责小程序前端页面也API数据请求页面渲染工作,因为对微信小程序的不熟悉,在做的过程中不免做了很多弯路.现在总结如下: 首先遇到的问题就是"微信小程序尺寸单位&quo ...
- 如果你的 pip 命令不能用,你可以这样解决
文章更新于:2020-04-05 注:如果想了解 pip 参数的使用参见:pip 命令参数以及如何配置国内镜像源 如何解决 pip 不能用的问题 一.你可能会遇到的问题 1.检查你敲命令的位置 2.如 ...
- 初始WebApi(1)
如果你要问我WebApi是干嘛,我只能说它是的给数据.哈哈哈哈哈,这几天也才刚刚了解了解关于WebApi的知识,今天就来谈谈吧. 1.创建WebApi项目 第一步:选择ASP.NET Web应用程序 ...
- jvm入门及理解(四)——运行时数据区(堆+方法区)
一.堆 定义: Heap,通过new关键字创建的对象,都存放在堆内存中. 特点 线程共享,堆中的对象都存在线程安全的问题 垃圾回收,垃圾回收机制重点区域. jvm内存的划分: JVM内存划分为堆内存和 ...