一、概述
Dubbo是一款高性能、轻量级的开源 Java RPC 框架,它提供了三大核心能力:面向接口的远程方法调用,智能容错和负载均衡,以及服务自动注册和发现。
首先需要回答一个问题:为什么需要远程调用RPC?
为了解决高并发的问题,引入了微服务的架构,即将整体业务拆封层多个微服务,单个微服务能独立运行,那服务与服务间的调用如何保障呢?这就需要通过远程调用RPC来实现。
在将应用改造成异构、微服务的架构下,就需要再不同服务间进行数据通信,甚至在不同语言编写的服务间进行通信,所以就需要像dubbo这样的RPC框架。
dubbo不但实现RPC远程通信基本的功能外,还集成了许多服务治理的功能,比如负载均衡和流控策略、容错策略等。
二、特性
dubbo的特性既包括RPC的基础能力,也有自身的特色,包括更高效的通信机制、更丰富的服务治理能力等。
- 远程调用的能力:这是RPC的基本能力,在分布式架构中,服务间存在远程调用;在异构应用中,不同编程语言的服务存在调用,目前dubbo 3.x能够支持Java和Golang等语言;
- 高效和丰富的远程通信机制:dubbo支持丰富的通信协议,一般都是基于TCP协议进行开发的,相对与HTTP协议,他有更好的性能,并且能够做更多自定义的开发,包括自定义通信协议格式或流控重试策略等;
- 服务注册和服务发现:可以通过服务注册中心来集中式管理服务,服务提供者将服务注册到注册中心,服务消费者从注册中心获取服务列表,同时能通过监控中心来监控服务使用情况;
- 负载均衡和容错处理:dubbo在调用服务存在多实例的时候,有丰富的负载均衡策略;在存在调用失败的时候,也有完善的流控策略和容错策略。
三、原理
1.RPC原理
首先需要搞清楚常见RPC框架必须的组件,常见RPC需要实现的组件有:
- 序列化和反序列化:进行远程通信的数据需要进行序列化后才进行传输,他们的序列号方式一般有二进制编码和文本编码格式,二进制的编码包括protobuf格式,文本编码格式中最常见的是json格式;
- 网络通信:服务消费者和服务提供者进行数据通信的协议,一般有Netty和或者JDK原生的NIO等协议;
- 动态代理:一般通过动态代理的方式实现,比如最简单通过JDK原生的动态代理实现;
2.架构设计
dubbo的官方架构图:
节点 | 角色说明 |
---|---|
Provider | 暴露服务的服务提供方 |
Consumer | 调用远程服务的服务消费方 |
Registry | 服务注册与发现的注册中心 |
Monitor | 统计服务的调用次数和调用时间的监控中心 |
Container | 服务运行容器 |
dubbo的整体架构也是生产者/消费者模式,只是在此基础上新增了注册中心和监控中心的角色。整个流程如下:
- 服务提供者启动服务,会将服务信息注册到注册中心去;
- 服务消费者启动服务,会订阅注册中心的服务列表,服务有更新,则同步更新本地的服务列表;
- 当服务消费者需要调用远程的服务提供者时,就会从服务列表中获取远程的服务信息,通过远程通信的方式调用对端服务,对端的服务实例通过动态代理的方式生成服务实例,再返回响应;
- 这样的一次远程服务调用会记录在监控中心中;
分布式系统中随着服务的增多,服务间的访问愈发负载,所以需要一个中心化的注册中心来管理服务,Dubbo就有这样的特性,拥有一个中心化的服务注册中心,服务提供方将服务注册到注册中心,服务消费方从注册中心获取服务信息,再进行远程调用;每次进行远程调用都会记录在监控中心中。
3.重要组件
Dubbo中服务端最核心的对象有四个:
- ApplicationConfig:配置当前应用信息
- ProtocolConfig:配置提供服务的协议信息
- RegistryConfig:配置注册相关信息
- ServiceConfig:配置暴露的服务信息
Dubbo客户端中核心的对象有两个:
- ApplicationConfig:配置当前应用信息
- ReferenceConfig:配置引用的服务信息
4.负载均衡
dubbo实现的是客户端负载均衡,消费者拉取了服务提供方列表,通过负载均衡算法进行负载。
负载均衡模式 | 说明 | 使用方法 |
Random LoadBalance | 随机 按权重设置随机概率 | xxx:负载均衡方法 |
RoundRobin LoadBalance | 轮询 按公约后的权重设置轮询比率。 | |
LeastActive LoadBalance | 最少活跃调用数 相同活跃数的随机,活跃数指调用前后计数差。 | |
ConsistentHash LoadBalance | 一致性 Hash 相同参数的请求总是发到同一提供者。 当某一台提供者挂时,原本发往该提供者的请求,基于虚拟节点,平摊到其它提供者,不会引起剧烈变动。 |
5.容错机制
dubbo 也是支持集群容错的,同时也有很多可选的方案,其中,默认的方案是 failover
,也就是重试机制。
集群模式 | 说明 | 使用方法 |
Failover Cluster | 失败自动切换,当出现失败,重试其它服务器。通常用于读操作,但重试会带来更长延迟。可通过 retries="2" 来设置重试次数(不含第一次)。 | cluster="xxx" xxx:集群模式名称 ,例如cluster="failover" |
Failfast Cluster | 快速失败,只发起一次调用,失败立即报错。通常用于非幂等性的写操作,比如新增记录。 | |
Failsafe Cluster | 失败安全,出现异常时,直接忽略。 | |
Failback Cluster | 失败自动恢复,后台记录失败请求,定时重发。通常用于消息通知操作。 | |
Forking Cluster | 并行调用多个服务器,只要一个成功即返回。通常用于实时性要求较高的读操作,但需要浪费更多服务资源。可通过 forks="2" 来设置最大并行数。 | |
Broadcast Cluster | 广播调用所有提供者,逐个调用,任意一台报错则报错。通常用于通知所有提供者更新缓存或日志等本地资源信息。 |
四、总结
1.dubbo和spring cloud的比较
核心区别是在网络通信协议选择方面,Spring Cloud的服务调用是选择基于HTTP的网络通信模式,而Dubbo选择的是自定义的基于TCP模式的网络通信模式,相对来说,后者定制化程度更高,性能更好。
2.dubbo和gRPC的比较
dubbo和gRPC都是非常优秀的RPC框架,他们的区别在于:
- gRPC支持更多语言的服务调用,目前dubbo在后端领域主要还是支持Java生态;
- Dubbo具有更丰富的服务治理能力,包括负载均衡和流控等策略,都是gRPC欠缺的;
- 针对序列化的方案,目前gRPC只支持protobuf,dubbo支持更丰富的序列号方案;
参考文献
Dubbo两小时快速上手教程(直接代码、Spring、SpringBoot):https://juejin.cn/post/6949558189733969951#heading-6 (介绍了3中dubbo的使用方式)
Dubbo 一篇文章就够了:从入门到实战:https://segmentfault.com/a/1190000019896723 (重点关注负载均衡和容错机制)
RPC框架的组成:https://blog.csdn.net/hdughy/article/details/119995403 (解释了RPC的通用架构)