热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

java架构师课程学习心得第4篇仿照Dubbo手写RPC框架

仿照Dubbo手写RPC框架文章目录仿照Dubbo手写RPC框架前言一、RPC是什么?二、完整RPC框架的结构三、RPC框架的核心功能RPC核心三大步骤四、为什么要引

仿照Dubbo手写RPC框架


文章目录

  • 仿照Dubbo手写RPC框架
  • 前言
  • 一、RPC是什么?
  • 二、完整RPC框架的结构
  • 三、RPC框架的核心功能
    • RPC核心三大步骤
  • 四、为什么要引入RPC
  • 五、手写RPC框架的流程和模块说明
    • 1、使用的一些技术点
    • 2、一些模块的说明
    • 3、整体流程图
  • 总结




前言

Dubbo是一款开源的RPC框架,本文通过手写RPC框架的方式来加深对Dubbo的理解




一、RPC是什么?

RPC(Remote Procedure Call)远程过程调用,简单的理解是一个节点请求另一个节点提供的服务。它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的思想。

RPC 是一种技术思想而非一种规范或协议,常见 RPC 技术和框架有:

应用级的服务框架:阿里的 Dubbo/Dubbox、Google gRPC、Spring Boot/Spring Cloud。
远程通信协议:RMI、Socket、SOAP(HTTP XML)、REST(HTTP JSON)。
通信框架:MINA 和 Netty。


二、完整RPC框架的结构

在一个典型 RPC 的使用场景中,包含了服务发现、负载、容错、网络传输、序列化等组件,其中“RPC 协议”就指明了程序如何进行网络传输和序列化。
在这里插入图片描述


三、RPC框架的核心功能

RPC 的核心功能是指实现一个 RPC 最重要的功能模块,就是上图中的”RPC 协议”部分。
RPC的协议有很多,比如最早的CORBA,Java RMI,Web Service的RPC风格,Hessian,Thrift,甚至Rest API。网络传输方式有 HTTP、TCP、Websocket 等
在这里插入图片描述

一个 RPC 的核心功能主要有 5 个部分组成,分别是:客户端、客户端 Stub、网络传输模块、服务端 Stub、服务端等。
在这里插入图片描述
下面分别介绍核心 RPC 框架的重要组成:

客户端(Client):服务调用方。
客户端存根(Client Stub):存放服务端地址信息,将客户端的请求参数数据信息打包成网络消息,再通过网络传输发送给服务端。
服务端存根(Server Stub):接收客户端发送过来的请求消息并进行解包,然后再调用本地服务进行处理。
服务端(Server):服务的真正提供者。
Network Service:底层传输,可以是 TCP 或 HTTP。


RPC核心三大步骤

1、 寻址:客户端是如何知晓服务端具体(ip+port)地址的,比如输入域名会通过DNS服务查询到对应的ip
2、通讯方式:选择tcp/udp,以及具体的上层协议;比如http就是一种基于tcp之上的协议
3、数据序列化:客户端和服务端交互时,对数据使用的序列化方式,比如json,xml等


四、为什么要引入RPC

关于这个问题,首先我们来看看下面的场景:
假如我们的电商系统中需要一个发送短信的服务,调用的是A平台的接口,如果我们把短息服务和电商系统的其他模块都放在一个jar包中,那么当我们需要切换到B平台发送短信时,就需要修改代码,然后再重新部署。如果系统中还有其他类似的服务,那么对于代码管理和运维来说是个很繁重的工作,且这样的系统耦合度会很高。
使用RPC技术带来的好处:
1、使用RPC技术可以使系统降低耦合性,系统拆分成多模块后,各模块之间使用RPC通信,各模块可以独立部署,从而达到解耦的目的
2、RPC底层网络是长链接,不必每次通信都要像http一样去3次握手什么的,减少了网络开销
3、RPC框架一般都有注册中心,有丰富的监控管理、发布、下线接口、动态扩展等,对调用方来说是无感知、统一化的操作。
4、RPC协议的底层传输和序列化都可以自定义,在网络传输过程中是比较安全的。


五、手写RPC框架的流程和模块说明


1、使用的一些技术点

1、本文的RPC框架是用redis做注册中心,基于spring提供远程服务,使用spring注解完成远程服务的注入和调用
2、使用了spring中的bean的后置处理器,来做bean的扩展
3、使用了spi机制,加载配置类
4、使用了netty,完成底层的网络传输
5、使用redis的订阅发布机制,完成服务的注册发现,以及服务的上线和下线通知
6、客户端和服务端都采用了代理机制,来完成服务的调用
7、TrpcBootstrap类是服务调用者和服务提供者的统一入口,TrpcProtocol类是实现rpc协议的统一入口


2、一些模块的说明

类:OrderApplication
1.@EnableTRPC
2.context.star()
3.多线程调用OrderService
1.通过@EnableTRPC开启rpc功能
2.开启spring服务
3.子线程获取OrderServiceImpl对象,发起远程调用

注解:EnableTRPC
@Import()
1.TRPCPostProcessor.class
2.TRPCConfiguration.class
1.通过@import注解,当服务启动时调用TRPCPostProcessor.class
TRPCConfiguration.class,完成一些类的注册
类:TRPCConfiguration
1.BeanDefinitionBuilder
2.environment.getProperty
3.BeanDefinitionRegistry
1.获取配置相关类的构建器
2.将配置文件中的属性,注入到配置类对应的字段中
3.完成配置类对象bean的注册

类:TRPCPostProcessor
1.ServiceConfig
2.ReferenceConfig
3.TrpcBootstrap
1.服务提供者,通过TRpcService注解找到服务的实现类,构建serviceConfig配置,最后由TrpcBootstrap.export()暴露服务
2.服务调用者,通过TRpcReference注解找到执行远程调用的对象变量,通过TrpcBootstrap.getReferenceBean(referenceConfig)获取服务代理对象,并注入到变量中

类:TrpcBootstrap
1.export()
2.getReferenceBean()
1.服务提供者
1.1 ProxyFactory.getInvoker()获取服务实现类的代理对象
1.2 serviceConfig.getProtocolConfigs()获取具体协议,构建协议的URI
1.3 protocol.export(exportUri, invoker)暴露协议
1.4 RegistryService通过spi加载,然后注册协议到redis

2.服务调用者
2.1 new ClusterInvoker()获取服务提供者实例集群
2.2 ProxyFactory.getProxy(clusterInvoker, new Class[]{referenceConfig.getService()})获取实例集群的代理
2.3代理调用invoke方法时,会采用负载均衡策略选择实例聚群中的一个实例进行远程调用

类:ClusterInvoker
1.构造函数
2.invoke()
2.1 loadbalance
1.在构造函数中获取ReferenceConfig中的注册中心uri
2.通过RegistryService和uri,初始化注册中心,并订阅相关服务,最后通过notify回调,更新本地服务列表
3.当notiy回调通知有新的服务uri时,会通过protocol.refer(uri)创建一个新的invoker服务代理,并添加到本地服务列表中

类:ProxyFactory
1 getProxy()
1.1 new InvokerInvocationHandler(invoker)
2.getInvoker()
2.1 new Invoker()
1.服务提供者
1.1 getInvoker(Object proxy, Class type), 返回new Invoker()匿名代理类
2.1 参数proxy是具体提供服务的实现类,匿名代理类中的invoke(RpcInvocation rpcInvocation)方法就会通过反射调用服务实现类的方法

2.服务调用者
2.1 getProxy(Invoker invoker), 方法返回InvokerInvocationHandler代理对象
2.2 该代理对象执行本地方法,有需要远程调用的方法时,就构建RpcInvocation对象
2.3 最后InvokerInvocationHandler(invoker)对象会调用真正服务实现类的invoker来执行服务,既这里多了一层代理

类:TrpcProtocol
1.export()
2.refer()
2.1 transporter.connect()
2.2 TrpcClientInvoker
1.服务提供者
1.1 getInvoker(Object proxy, Class type),获取序列化对象,编解码器对象,服务端Handler对象
1.2 通过spi加载网络协议的实现类transporter,通过transporter.export()导出服务

2.服务调用者
2.1 refer(URI consumerUri),获取序列化对象,编解码器对象,客户端Handler对象
2.2 通过spi加载网络协议的实现类transporter,通过transporter.connect()获取客户端连接
2.3 new TrpcClientInvoker(connect, serialization)返回客户端连接代理,既ClusterInvoker中的服务代理

类:TrpcClientInvoker
1.implements Invoker
2.invoke(RpcInvocation rpcInvocation)
2.1 client.getChannel().send(requestBody)
2.2 future=TrpcClientHandler.waitResult()
2.3 return (Response) future.get()
1.实现了Invoker接口
2.invoke(RpcInvocation rpcInvocation)
2.1方法中通过client中的trpcChannel来完成远程服务调用,既把相关数据发送到netty服务端
2.2 通过TrpcClientHandler异步获取服务端返回的响应,并通过id唯一标识
2.3 将获取到的响应返回

类:RedisRegistry
1.构造函数
2.void register(URI uri)
3.void subscribe(String service, NotifyListener notifyListener)
1.init()
1.1 通过心跳机制,定时刷新redis中服务uri的过期时间
1.2 开启子线程,new JedisPubSub()定义收到订阅消息时的回调处理方式,并通过NotifyListener完成回调通知
1.3 通过__keyspace@0__:trpc-*"和psubscribe进行模式订阅
2.register(URI uri),在redis中set 服务的uri
3. subscribe(),通过 keys()命令,模糊匹配的方式获取到想要调用的远程服务的uri列表

类:Netty4Transporter
1.Client connect()
2.Server start()
1.通过netty服务端程序,开启网络服务
2.通过netty客户端程序,建立长连接

接口:LoadBalance()
1.Invoker select(Map invokerMap)
1.两个实现类RandomLoadBalance和RoundRobin
2.通过select方法,采用对应的策略返回ClusterInvoker中的一个代理对象

类:TrpcClientHandler
1.CompletableFuture waitResult()
2.onReceive()
1.登记,创建返回一个future, 每个发起远程调用的线程有一个单独的future
2.接收远程服务执行结果,删除future
类:TrpcServerHandler
1.onReceive()
2.getInvoker()
1.获取远程服务实现类SmsServiceImpl的代理,并执行远程方法
2.获取远程方法执行结果,并包装成response返回给客户端

类:RpcInvocation
1.将netty发送数据的请求体进行包装
2.long incrementAndGet()
通过自旋方式获取自增id

类:RoundRobin
1.Invoker select()
2.int incrementAndGet()

类:SmsApplication
1.@EnableTRPC
2.context.star()

类:SmsServiceImpl
1.@TRpcService
2.Object send()服务实现类

类:OrderServiceImpl
1.@TRpcReference(loadbalance = “RoundRobin”)
2.smsService.send()远程调用

接口:SmsService
1.Object send(String phone, String content)

接口:OrderService
1.void create(String orderContent);

接口:Invoker
1.invoke(RpcInvocation rpcInvocation)

接口:Handler
1.onReceive()
2.onWrite()


3、整体流程图

在这里插入图片描述


总结

这个手写RPC框架,花了我两个星期的时间,真是不容易呀!欢迎各位技术大牛前来指点江山,交流评论。你的支持就是对我最大的鼓励!谢谢!


推荐阅读
  • php怎么做rpc通信(RPC通信)
    导读:很多朋友问到关于php怎么做rpc通信的相关问题,本文编程笔记就来为大家做个详细解答,供大家参考,希望对大家有所帮助!一起来看看吧!本文目录一览: ... [详细]
  • 本文为转载,原连接:https:www.zhihu.comquestion40822826简单说一下吧做要解释这些要从netconf说起。netconf ... [详细]
  • 本文介绍了RPC框架Thrift的安装环境变量配置与第一个实例,讲解了RPC的概念以及如何解决跨语言、c++客户端、web服务端、远程调用等需求。Thrift开发方便上手快,性能和稳定性也不错,适合初学者学习和使用。 ... [详细]
  • 计算机存储系统的层次结构及其优势
    本文介绍了计算机存储系统的层次结构,包括高速缓存、主存储器和辅助存储器三个层次。通过分层存储数据可以提高程序的执行效率。计算机存储系统的层次结构将各种不同存储容量、存取速度和价格的存储器有机组合成整体,形成可寻址存储空间比主存储器空间大得多的存储整体。由于辅助存储器容量大、价格低,使得整体存储系统的平均价格降低。同时,高速缓存的存取速度可以和CPU的工作速度相匹配,进一步提高程序执行效率。 ... [详细]
  • 利用Visual Basic开发SAP接口程序初探的方法与原理
    本文介绍了利用Visual Basic开发SAP接口程序的方法与原理,以及SAP R/3系统的特点和二次开发平台ABAP的使用。通过程序接口自动读取SAP R/3的数据表或视图,在外部进行处理和利用水晶报表等工具生成符合中国人习惯的报表样式。具体介绍了RFC调用的原理和模型,并强调本文主要不讨论SAP R/3函数的开发,而是针对使用SAP的公司的非ABAP开发人员提供了初步的接口程序开发指导。 ... [详细]
  • SOA架构理解理解SOA架构,了解ESB概念,明白SOA与微服务的区别和联系,了解SOA与热门技术的结合与应用。1、面向服务的架构SOASOA(ServiceOrien ... [详细]
  • Java开发面试问题,2021网易Java高级面试题及答案,实战案例
    前言大厂面试真题向来都是各大求职者的最佳练兵场,而今天小编带来的便是“HUAWEI”面经!这是一次真实的面试经历,虽然不是我自己亲身经历 ... [详细]
  • 阿里首席架构师科普RPC框架
    RPC概念及分类RPC全称为RemoteProcedureCall,翻译过来为“远程过程调用”。目前,主流的平台中都支持各种远程调用技术,以满足分布式系统架构中不同的系统之间的远程 ... [详细]
  • SpringBoot使用Netty实现远程调用的示例
    这篇文章主要介绍了SpringBoot使用Netty实现远程调用的示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着 ... [详细]
  • 在这分布式系统架构盛行的时代,很多互联网大佬公司开源出自己的分布式RPC系统框架,例如:阿里的dubbo,谷歌的gRPC,apache的Thrift。而在我们公司一直都在推荐使用d ... [详细]
  • 本文介绍了Redis的基础数据结构string的应用场景,并以面试的形式进行问答讲解,帮助读者更好地理解和应用Redis。同时,描述了一位面试者的心理状态和面试官的行为。 ... [详细]
  • Netty(三)
    开发十年,就只剩下这套架构体系了!>>>  熟悉TCP编程的读者可能都会知道,无论是服务端 ... [详细]
  • Windows网络编程(一):创建链接文章目录Windows网络编程(一):创建链接一、使用前的 ... [详细]
  • Nettty指南(1):Netty简介
    一、Netty介绍与应用场景1.1Netty的介绍Netty是由JBOSS提供的一个Java开源框架,现为Github上的独立项目。Netty是一个异步的、基于事 ... [详细]
  • 杂谈,微服务API Gateway
    让我们想象一下你正在建立一个使用微服务模式的网上商店,你所用的产品详细信息页面。你需要开发多个版本的产品详情界面:l由服务器端Web应用程序生成的HTM ... [详细]
author-avatar
good7758
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有