查阅了一些资料,站在前人的肩膀上看世界会很美好。
最近一段时间在学习记录Dubbo的一些内容… …
RPC
1.什么是RPC
RPC(Remote Procedure Call),远程过程调用,它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议。RPC协议假定某些传输协议的存在,如TCP或UDP,为通信程序之间携带信息数据。在OSI网络通信模型中,RPC跨越了传输层和应用层。RPC使得开发包括网络分布式多程序在内的应用程序更加容易。
RPC简单理解就是在本地调用远端的程序,但是感觉好像是在调用本地的程序一样。
与PRC远程调用对应的是本地调用:
client stub会对RPC调用的过程进行一些封装,包括代理、传递、序列化等,使得用户使用起来,和调用本地程序一样。
2.如何设计RPC框架
知道RPC是怎么一回事了,现在问你如何设计一个RPC框架,该如何设计?(用户调用是无感的哦!)
2.1服务消费者
- 公用jar包:消费者要面向接口编程,需要知道那些接口可以调用,由公用jar包告知。
- 代理类:消费方的接口调用以后,调用参数封装、传递就由代理类来实现,消费者只需要调用接口就能获取到提供方的数据。
- 注册中心:代理类找到对应的提供方进行方法调用。
- 负载均衡:提供方会进行集群部署,那调用方调用哪个提供方、分担每一个提供方的交互压力,就需要通过某些策略来实现负载均衡。
- 容错机制:对于远程调用,网络并不可靠,就会有重试等操作。
- Filter:过滤器可以做统一处理,比如记录调用次数等。
- 传输协议:提供方和消费方之间的数据交互,需要约定一个传输协议,比如HTTP协议、TCP协议等。
- 序列化格式:本地的数据是立体的,需要序列化之后传输,同时知道序列化协议以后,双方才能成功解析出对方传递的数据。
2.2服务调用者
- 实现对于接口:实现接口,供消费方调用。
- 注册中心:需要向注册中心暴露自己的需要暴露的接口,供消费方调用。
- 序列化协议:知道消费方的序列化协议以后,进行反序列化解析参数。
- 处理线程池:序列化完的请求扔到线程池中等待处理,某个线程执行的时候去找到对应的接口实现调用,之后原路返回结果参数。
2.3其他
注册中心&配置中心&监控运维
- 注册中心提供给消费方和提供方使用,提供方在上面暴露自己的服务,消费方在上面得知自己能调用哪些服务。
- 配置中心将配置集中化处理,动态变更配置的时候会通知订阅者。
- 监控运维就是为了实现 面对众多服务的时候,可以实现精细化的监控和运维,出现问题后可以很快找到问题所在!
当然,上述的这些功能是生产环境级别的了。
总结一下:一个RPC框架需要做的就是约定通信协议、序列化格式,实现容错机制、负载均衡策略,持有监控和运维、注册中心功能!
3.RPC框架
注意:RPC是协议,具体的RPC框架是实现。
现在使用较多的RPC框架有:Dubbo、gRPC、Thift、Spring Cloud等。他们之间使用起来都差不多,这里也不做出具体的对比了,很多文章都描述了他们之间的异同。
Dubbo初始
分布式应用场景有高并发,高可扩展和高性能的要求。还涉及到序列化/反序列化,网络,多线程以及设计模式的问题。幸好 Dubbo 框架将上述知识进行了封装,让程序员能够把注意力放到业务上。
这里推荐一个dubbo入门demo视频讲解:https://www.bilibili.com/video/BV1bX4y1G7SF,当然 其他教程也是🆗的,主要是为了对dubbo有一个了解。
1.Dubbo简介
上面简单的说了一下RPC的东西,现在就从概念到实体——Dubbo。
Dubbo是阿里巴巴2011年开源的基于Java的RPC框架,中间停止了一段时间的更新维护,2017年开始继续维护,2018年和Dubbox合并,2019年由Apach维护。
Dubbo社区主要维护2.6.x和2.7.x,现在使用比较多的也是2.7.x,3.0的话是2021年推出的新版本(云原生)。
它实现了面向接口的代理RPC调用,可以配合zookeeper等组件实现服务注册和发现功能,且拥有负载均衡、容错机制等。
2.Dubbo总体架构
官网的架构图如下:
角色说明如下:
节点 | 角色说明 |
---|---|
Container | 运行的容器 |
Provider | 服务提供方 |
Registry | 注册中心 |
Consumer | 服务消费方 |
Monitor | 监控中心 |
它整体的流程在图中就是一个很好的呈现:
- 容器启动以后,服务者Provider向注册中心Registry注册自己提供的服务;
- 消费者Consumer启动后在注册中心订阅自己所需的服务,然后注册中心将提供者元信息通知给 Consumer,Consumer缓存这部分元信息;
- Consumer 因为已经从注册中心获取提供者的地址,因此可以通过负载均衡选择一个 Provider 直接调用;
- 之后服务提供方元数据变更的话注册中心会把变更推送给服务消费者。
- 服务提供者和消费者都会在内存中记录着调用的次数和时间,然后定时的发送统计数据到监控中心。
请注意:
- 注册中心和监控中心是可选的,可以不要监控中心,可以不要注册中心(得在配置文件中写清楚,两者直连)。
- 提供方、消费方和注册中心之间是长连接,监控中心和其他模块都是短连接。
- 消费方是直接调用提供方,不经过注册中心,注册中心的作用就是告诉消费方该去哪找到提供方。就算注册中心宕机了也不会直接影响到正在运行的提供者和消费者。
3.Dubbo分层架构
总的而言Dubbo分为三层:Business(业务)、RPC层、Remoting。还可分为API和SPI层。
这三个分层使得Dubbo架构层次分明,职责边界清晰,可实现更好的扩展。另外采用微内核设计+SPI扩展,可以自行扩展,做定制开发。
下面看一下每一层的作用:
序号 | 名称 | 作用 |
---|---|---|
1 | Service | 业务层,开发人员开发的业务逻辑(实际上,开发人员开发过程中只需要关注这一层) |
2 | Config | 配置层,主要围绕ServiceConfig和ReferenceConfig,初始化配置信息 |
3 | Proxy | 代理层,服务方和提供方各自生成代理类,做远程调用和返回结果。 |
4 | Registry | 注册层,封装服务注册和发现 |
5 | Cluster | 路由和集群容错层,负责选取具体调用的节点、负责远程调用失败的容错措施 |
6 | Monitor | 监控层,负责监控统计和调用的时间 |
7 | Protocol | 远程调用层,封装RPC调用,以 Invocation , Result 为中心,扩展接口为 Protocol , Invoker , Exporter |
8 | Exchange | 信息交换层,封装请求响应模式,同步转异步,以 Request , Response 为中心 |
9 | Transport | 网络传输层,抽象 mina 和 netty 为统一接口,想用谁用谁 |
10 | Serialize | 序列化层,将数据序列化/反序列化(序列化成二进制流) |
下图是对上图的解释,其中:
左边是Consumer,右边是Provider,绿色的表示接口,蓝色的表示类,在中轴线上的接口或类双方都使用到,蓝色虚线为初始化过程,红色实线为方法调用过程,紫色实线为继承,线上的文字为调用的方法。
4.暴露&调用
建议手动debug一下这个过程,down官方的实例项目。
$ git clone https://github.com/apache/dubbo.git
暴露&调用启动流程图(注意,不要与上面的分层架构图混淆!!!!):
(上面的序号表示启动两个服务后各自模块的执行流程)
首先是图中左上角的服务提供者Provider服务暴露流程
- Provider 启动,通过 Proxy 组件根据具体的协议 Protocol 将需要暴露出去的接口封装成 Invoker(Invoker 是 Dubbo 一个很核心的组件,代表一个可执行体)。
- 然后再通过 Exporter 包装一下,这是为了在注册中心暴露自己套的一层,然后将 Exporter 通过 Registry 注册到注册中心。这就是整体服务暴露过程。
再就是右边的消费者Cosumer调用流程了
- Cosumer启动,从注册中心获取到提供者的元信息,从Proxy代理(代理实现无感调用)。
- Proxy 持有一个 Invoker 对象,调用 invoke 之后需要通过 Cluster 先从 Directory 获取所有可调用的远程服务的 Invoker 列表,如果配置了某些路由规则,比如某个接口只能调用某个节点的那就再过滤一遍 Invoker 列表。
- 剩下的 Invoker 再通过 LoadBalance 做负载均衡选取一个服务方(服务方集群部署)。然后再经过 Filter 做一些统计什么的,再通过 Client 做数据传输,比如用 Netty 来传输。
- 传输需要经过 Codec 接口做协议构造,再序列化。最终发往对应的服务提供者。
- 服务提供者接收到之后也会进行 Codec 协议处理,然后反序列化后将请求扔到线程池处理。某个线程会根据请求找到对应的 Exporter ,而找到 Exporter 其实就是找到了 Invoker,但是还会有一层层 Filter,经过一层层过滤链之后最终调用实现类然后原路返回结果。
调用过程就是如上所示,下面就可以再来看一看Consumer和Provider的依赖关系(清晰很多):
图例说明:
- 小方块中蓝色的表示与业务有交互,绿色的表示只对 Dubbo 内部交互。
- 图中背景方块 Consumer, Provider, Registry, Monitor 代表部署逻辑拓扑节点。
更多框架设计方面的内容,可以参考:https://dubbo.apache.org/zh/docs/v2.7/dev/design/
参考:
- 用户文档 | Apache Dubbo
- https://mp.weixin.qq.com/s/FPbu8rFOHyTGROIV8XJeTA