前言

随着最近关注 cim 项目的人越发增多,导致提的问题以及 Bug 也在增加,在修复问题的过程中难免代码洁癖又上来了。

看着一两年前写的东西总是怀疑这真的是出自自己手里嘛?有些地方实在忍不住了便开始了漫漫重构之路。

前后对比

在开始之前先简单介绍一下 cim 这个项目,下面是它的架构图:

简单来说就是一个 IM 即时通讯系统,主要有以下部分组成:

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

当然服务端、路由都可以水平扩展。


这是一个消息发送的流程图,假设现在部署了两个服务端 A、B 和一个路由服务;其中 ClientAClientB 分别和服务端 A、B 保持了长连接。

ClientAClientB 发送一个 hello world 时,整个的消息流转如图所示:

  1. 先通过 http 将消息发送到 Route 服务。
  2. 路由服务得知 ClientB 是连接在 ServerB 上;于是再通过 http 将消息发送给 ServerB
  3. 最终 ServerB 将消息通过与 ClientB 的长连接通道 push 下去,至此消息发送成功。

这里我截取了 ClientARoute 发起请求的代码:



可以看到这就是利用 okhttp 发起了一个 http 请求,这样虽然能实现功能,但其实并不优雅。

举个例子:假设我们需要对接支付宝的接口,这里发送一个 http 请求自然是没问题;但对于支付宝内部各部门直接互相调用接口时那就不应该再使用原始的 http 请求了。

应该是由服务提供方提供一个 api 包,服务消费者只需要依赖这个包就可以实现接口调用。

当然最终使用的是 http、还是自定义私有协议都可以。

也类似于我们在使用 Dubbo 或者是 SpringCloud 时,通常是直接依赖一个 api 包,便可以像调用一个本地方法一样调用远程服务了,并且完全屏蔽了底层细节,不管是使用的 http 还是 其他私有协议都没关系,对于调用者来说完全不关心。

这么一说是不是有内味了,这不就是 RPC 的官方解释嘛。

对应到这里也是同样的道理,ClientRouteServer 本质上都是一个系统,他们互相的接口调用也应当是走 RPC 才合理。

所以我重构之后的变成这样了:

是不是代码也简洁了许多,就和调用本地方法一样了,而且这样也有几个好处:

  • 完全屏蔽了底层细节,可以更好的实现业务及维护代码。
  • 即便是服务提供方修改了参数,在编译期间就能很快发现,而像之前那样调用是完全不知情的,所以也增加了风险。

绕不开的动态代理

下面来聊聊具体是如何实现的。

其实在上文《动态代理的实际应用》 中也有讲到,原理是类似的。

要想做到对调用者无感知,就得创建一个接口的代理对象;在这个代理对象中实现编码、调用、解码的过程。

对应到此处其实就是创建一个 routeApi 的代理对象,关键就是这段代码:

RouteApi routeApi = new ProxyManager<>(RouteApi.class, routeUrl, okHttpClient).getInstance();

完整源码如下:

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

查看 ProxyInvocation 的源码会发现当我们调用被代理接口的任意一个方法时,都会执行这里的 invoke() 方法。

invoke() 方法自然就实现了上图中提到的:编码、远程调用、解码的过程;相信大家很容易看明白,由于不是本次探讨的重点就不过多介绍了。

总结

其实理解这些就也就很容易看懂 Dubbo 这类 RPC 框架的核心源码了,总体的思路也是类似的,只不过使用的私有协议,所以在编解码时会有所不同。

所以大家要是想自己动手实现一个 RPC 框架,不妨参考这个思路试试,当用自己写的代码跑通一个 RPChelloworld 时的感觉是和自己整合了一个 DubboSpringCloud 这样的第三方框架的感觉是完全不同的。

本文的所有源码:

https://github.com/crossoverJie/cim

你的点赞与分享是对我最大的支持

一不小心实现了RPC的更多相关文章

  1. RabbitMQ 实现RPC

    实现RPC 首先要弄明白,RPC是个什么东西. (RPC) Remote Procedure Call Protocol 远程过程调用协议 在一个大型的公司,系统由大大小小的服务构成,不同的团队维护不 ...

  2. 基于RabbitMQ的Rpc框架

    参考文档:https://www.cnblogs.com/ericli-ericli/p/5917018.html 参考文档:RabbitMQ 实现RPC MQ的使用场景大概包括解耦,提高峰值处理能力 ...

  3. 从RPC开始(一)

    这是一篇关于纯C++RPC框架的文章.所以,我们先看看,我们有什么? 1.一个什么都能干的C++.(前提是,你什么都干了) 2.原始的Socket接口,还是C API.还得自己去二次封装... 3.C ...

  4. RPC 使用中的一些注意点

    最近线上碰到一点小问题,分析其原因发现是出在对 RPC 使用上的一些细节掌握不够清晰导致.很多时候我们做业务开发会把 RPC 当作黑盒机制来使用,但若不对黑盒的工作原理有个基本掌握,也容易犯一些误用的 ...

  5. 谈谈如何使用Netty开发实现高性能的RPC服务器

    RPC(Remote Procedure Call Protocol)远程过程调用协议,它是一种通过网络,从远程计算机程序上请求服务,而不必了解底层网络技术的协议.说的再直白一点,就是客户端在不必知道 ...

  6. 游戏编程系列[1]--游戏编程中RPC协议的使用[3]--体验

    运行环境,客户端一般编译为.Net 3.5 Unity兼容,服务端因为用了一些库,所以一般为4.0 或往上.同一份代码,建立拥有2个项目.客户端引用: WindNet.Client服务端引用: OpL ...

  7. python通过protobuf实现rpc

    由于项目组现在用的rpc是基于google protobuf rpc协议实现的,所以花了点时间了解下protobuf rpc.rpc对于做分布式系统的人来说肯定不陌生,对于rpc不了解的童鞋可以自行g ...

  8. spider RPC入门指南

    本部分将介绍使用spider RPC开发分布式应用的客户端和服务端. spider RPC中间件基于J2SE 8开发,因此需要确保服务器上安装了JDK 8及以上版本,不依赖于任何额外需要独立安装和配置 ...

  9. Netty实现高性能RPC服务器优化篇之消息序列化

    在本人写的前一篇文章中,谈及有关如何利用Netty开发实现,高性能RPC服务器的一些设计思路.设计原理,以及具体的实现方案(具体参见:谈谈如何使用Netty开发实现高性能的RPC服务器).在文章的最后 ...

随机推荐

  1. c++中的多态机制

    目录 1  背景介绍 2  多态介绍 2-1  什么是多态 2-2  多态的分类 2-3  动态多态成立的条件 2-4  静态联编和动态联编 2-5  动态多态的实现原理    2-6   虚析构函数 ...

  2. C#接口多继承方法重名问题

    最近实现一个功能需要继承两个接口,然而父类接口有这重名的方法,且方法实现一致.两个父接口均被多个子接口继承,并在类实例中实现.起初,我是通过new重名方法来实现我的功能调用.后被指正,在网上看了一个工 ...

  3. 《带你装B,带你飞》pytest成魔之路4 - fixture 之大解剖

    1. 简介 fixture是pytest的一个闪光点,pytest要精通怎么能不学习fixture呢?跟着我一起深入学习fixture吧.其实unittest和nose都支持fixture,但是pyt ...

  4. Java面试金典

    1,将构造函数声明为私有的作用 构造函数私有化,保证类以外的地方不能直接实例化该类,这种情况下,要创建这个类的实例,只能提供一个公共静态方法,像工厂方法模式,由于构造函数私有化,不能被继承. 2,在t ...

  5. J. Justifying the Conjecture(规律——整数拆分)

    题目链接 五校友谊赛终于开始了,话不多说A题吧. 从前从前有一个正整数n,你需要找到一个素数x和一个合数y使x+y=n成立,这样就可以双剑合并了. 素数是一个大于1的自然数,它的因数只有1与它自己本身 ...

  6. 为什么要学习Oracle技术?

    为什么要学习Oracle技术? 众所周知,Oracle占据着企业数据库领域超过48.1%的市场份额,成为高端企业数据库软件的绝对领导者.随着时间的推移,企业数据库的规模不断扩大,富有经验的资深Orac ...

  7. PTA数据结构与算法题目集(中文) 7-15

    PTA数据结构与算法题目集(中文)  7-15 7-15 QQ帐户的申请与登陆 (25 分)   实现QQ新帐户申请和老帐户登陆的简化版功能.最大挑战是:据说现在的QQ号码已经有10位数了. 输入格式 ...

  8. MySQl 和 Redis

    MySQL MySQL 是关系型数据库,开放源码软件,主要使用持久化存储设备(像磁盘)数据存放在磁盘中,功能强大. 因为磁盘访问速度远远慢于内存,所以访问速度慢 Redis 是非关系型,高性能的key ...

  9. 原理解密 → Spring AOP 实现动态数据源(读写分离),底层原理是什么

    开心一刻 女孩睡醒玩手机,收到男孩发来一条信息:我要去跟我喜欢的人表白了! 女孩的心猛的一痛,回了条信息:去吧,祝你好运! 男孩回了句:但是我没有勇气说不来,怕被打! 女孩:没事的,我相信你!此时女孩 ...

  10. pyecharts数据可视化模块

    目录 安装 柱状图-Bar 饼图-Pie 箱体图-Boxplot 折线图-Line 雷达图-Rader 散点图-scatter 我们都知道python上的一款可视化工具matplotlib,而前些阵子 ...