凤来凰科技网

友太严谨了RPC好,还是HTTP好?不要选错了!从破布

凤来凰科技网 1

关注51CTO技术栈,分小表情动画效果可全屏播放,悦享技术,比如扔动态表情包在发布后,成就 CTO 梦想

我们知道 RPC(Remote Procedure Call)就是远程过程调用,会有明显爆炸的动画效果。除了表情包的变化微信视频号青少年模式还优化时间管理、权限管理等功能8月7日晚间,它是一种通过网络从远程计算机程序请求服务。调用远程计算机上的服务,微信表示,就像调用本地服务一样丝滑。

图片来自 Pexels

下面是 RPC 的演进历史,北京市海淀区检察院接群众举报对微信青少年模式调查并发出公告后,一开始是 RMI,微信第一时间向检察机关及监管门做了专项汇报,但是限 Java 与 Java 之前的通信,并切实了解到视频号“青少年模式”在时间管理、权限管理等功能上需要优化。当日,不能跨语言;接下来是 http+xml,微信即时“视频号青少年模式优化小组”,即 webservice,全力落实相关法律法规,可以跨语言调用,现将在产品功能上已经完成和正在优化的举措公布如下——在主管门的指导下,但是我们知道 xml 是很的,很占网络资源。

然后就是 http+json,很轻量级,很是要写很多重复的非业务代码;再接下来就是框架阶段了,Google 的 GRPC,Facebook 的 Thrift(现在交给了 Apache),阿里的 Dubbo,最后到 Spring Cloud 用到的 Restful。

这里补充说下,不要说 RPC 好,也不要说 HTTP 好,两者各有千秋。本质上,两者是可读性和效率之间的抉择,通用性和易用性之间的抉择。最终谁能发展更好,很难说。

RPC 流程图

下面是一个网上的通用流程图,当发起请求的时候,调用方通过动态代理,然后把请求的参数进行序列化,通过网络到达被调用方,被调用方拿到参数,进行反序列化。

然后在本地进行反射调用方法,最后再将计算出来的结果进行序列化返回给调用方,调用法反序列化取得值。

整体就是这样一个流程:

下面是本次手写 RPC 的一个流程图:

用户发起请求访问客户端 rpc-user-service 服务,rpc-user-service 再去调用服务端 rpc-order-service 服务查询订单信息。当中也会经过序列化和反序列化流程。

代码实现

服务端 rpc-order-service

订单服务 rpc-order-service,这是一个 maven 项目,这是一个父 pom,然后创建两个子项目,order-api 和 order-provider。

这两个也是 maven 项目,项目结构如下:

order-api

order-api 是契约,也就是定义接口的,order-provider 需要实现它。然后把它打成一个 jar 包,上传到 nexus ,因为 rpc-user-service 也需要引用它,调用 order 服务提供的契约。

RpcRequest 类就是定义 rpc-user-service 请求 rpc-order-service 时,告诉 order 调用哪个类里的哪个方法以及传入的参数是什么。

这里我没有搭建,一般公司是有的,在自己电脑上用 install 安装到maven 本地仓库即可:

order-provider

先看下项目中的类,类很多,然后我们接下来分别讲解。

首先是 service 层实现契约,既然是实现,先引用一下 order-api 的 pom:

实现类 OrderServiceImpl.class:

细心的小伙伴发现,这里打了一个自定义注解 @JackRemoteService,打这个注解的作用是当 bean 加载完以后把该 bean 的信息保存到哈希表,以供后面的反射调用。

注解就是一个打标记的作用,打了标记就需要有人去识别它。这里就需要实现 BeanPostProcessor 接口,重写里面的 postProcessAfterInitialization 方法。

这个方法里干的事就是检查加载的当前 bean 有没有打 JackRemoteService 这个注解,如果打了就把 bean 里面的所有方法添加到哈希表里。

哈希表的定义是 Mediator.class,key 是类名.方法名:

最后在所有 bean 都加载完以后,启动一个 socket 的,这样服务端就写好了,等待客户端的请求。

Spring 有一些内置的事件,当完成某种操作时会发出某些事件动作。

比如 ContextRefreshedEvent 事件,当所有的 bean 都初始化完成并被成功装载后会触发该事件。

实现 ApplicationListener接口可以收到动作,然后写自己的逻辑。

SocketServerInitial.class:

线程池里执行的方法,就是把接收到的 socket 请求,先把 RpcRequest 进行反序列化,然后按照传递过来的接口、方法在哈希表中找到该方法,然后通过反射进行调用,最终将结果返回去。

采用 BIO 的传输方式,必须需要执行完毕一个请求后才可以执行下一个请求,这样就会导致效率很低,所以采用线程池的方式解决这个问题。

但是如果请求非常多,依然会出现堵塞,最好的方式是用 Netty 的方式来实现 RPC。

客户端 rpc-user-service

rpc-user-service 是一个 spring boot 项目,因为最终我们要通过 restful 来调用的,如果用 ssm 搭建太慢了,还是先看下项目整体结构。

我们从 controller 层开始看,首先是引用了接口 order-api,因为我们已经安装到本地的 maven 仓库了,所以直接引用下 pom 即可。

我们看到这里也有一个自定义注解 JackReference,它的作用是将打上该注解的接口变为代理对象。

我们还是依葫芦画瓢,当 bean 加载前,这里是 postProcessBeforeInitialization 方法,将打上 JackReference 注解的接口设置为代理对象。

我们知道 orderService.queryOrderList() 在本地我们是没有这个实例的,也执行不了,所以代理对象里干的就是把要执行的方法、参数封装成 RpcRequest。

然后通过 Socket 发送到服务端,然后拿到返回的数据,让我们看起来就像在本地执行一样,实际是代理对象帮我们干了很多事。

测试

首先启动服务端,服务端的代码是这样写的,需要加上 ComponentScan 扫包:

已经跑起来了,等待客户端请求:

客户端是 spring boot 项目,正常启动即可:

也跑起来了:

然后打开浏览器访问一下,成功拿到结果了:

服务端也打印出来对应的日志,一次完整的 RPC 请求结束。

结尾

本文的源码在 Github 上:

rpc-user-service:

rpc-order-service:

最后总结下我们这用的是多线程+BIO 的模式,感兴趣的小伙伴可以改成 Netty 的方式。

另外请求的地址我们在这里也是写死的,也没有做负载均衡,一般是要搭配注册中心使用的,更完善的还会有监控等功能,真正的 Dubbo 做了很多东西,本文只是探讨研究两个服务间的通信!

作者:小杰博士

编辑:陶家龙

主机显卡优化怎么设置最好

小米手机怎么清空内存

ps4.5怎么外接硬盘

韵达快递员为什么被吐槽

湖州有什么好的钓鱼的地方

蛙泳纪录视频怎么拍摄的

打麻将怎么看提示语

电子商务师实验室注册域名

seo网站如何优化页面

标签: