最近在研究Dubbo和SpringCloud,网上查了查资料学习,这里记录一下
https://github.com/apache/dubbo
阿里巴巴在2011年开源了Dubbo框架,虽然在2013年停止更新,但在2017年9月又重启维护并发布了新版本。目前已有很多的公 司将自己的业务建立在Dubbo之上,同时阿里云也推出了企业级分布式应用服务EDAS,为Dubbo提供应用托管。
Dubbo采用Zookeeper作为注册中心,RPC作为服务调用方式,致力于提供高性能和透明化的RPC远程服务调用方案。它与Spring无缝集成,基于服务提供方(服务端)与服务调用方(客户端)角色构建简单模型,其优点是使用方便、学习成本低。
组件角色 | 说明 |
---|---|
Provider | 暴露服务的服务提供方 |
Consumer | 调用远程服务的服务消费方 |
Registry | 服务注册与发现的注册中心 |
Monitor | 统计服务的调用次调和调用时间的监控中心 |
Container | 服务运行容器 |
- 服务容器Container负责启动,加载,运行服务提供者。
- 服务提供者Provider在启动时,向注册中心注册自己提供的服务。
- 服务消费者Consumer在启动时,向注册中心订阅自己所需的服务。
- 注册中心Registry返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推送变更数据给消费者。
- 服务消费者Consumer,从提供者地址列表中,基于软负载均衡算法,选一台提供者进行调用,如果调用失败,再选另一台调用。
- 服务消费者Consumer和提供者Provider,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心Monitor。
上面介绍给出的都是抽象层面的组件关系,可以说是纵向的以服务模型的组件分析,其实Dubbo最大的特点是按照分层的方式来架构,使用这种方式可以使各个层之间解耦合(或者最大限度地松耦合)。所以,我们横向以分层的方式来看下Dubbo的架构,如图所示:
Dubbo框架设计一共划分了10个层,而最上面的Service层是留给实际想要使用Dubbo开发分布式服务的开发者实现业务逻辑的接口层。图中左边淡蓝背景的为服务消费方使用的接口,右边淡绿色背景的为服务提供方使用的接口, 位于中轴线上的为双方都用到的接口。
下面,结合Dubbo官方文档,我们分别理解一下框架分层架构中,各个层次的设计要点:
从上图可以看出,Dubbo对于服务提供方和服务消费方,从框架的10层中分别提供了各自需要关心和扩展的接口,构建整个服务生态系统(服务提供方和服务消费方本身就是一个以服务为中心的)。
根据官方提供的,对于上述各层之间关系的描述,如下所示:
- 在RPC中,Protocol是核心层,也就是只要有Protocol + Invoker + Exporter就可以完成非透明的RPC调用,然后在Invoker的主过程上Filter拦截点。
- 图中的Consumer和Provider是抽象概念,只是想让看图者更直观的了解哪些类分属于客户端与服务器端,不用Client和Server的原因是Dubbo在很多场景下都使用Provider、Consumer、Registry、Monitor划分逻辑拓普节点,保持统一概念。
- 而Cluster是外围概念,所以Cluster的目的是将多个Invoker伪装成一个Invoker,这样其它人只要关注Protocol层Invoker即可,加上Cluster或者去掉Cluster对其它层都不会造成影响,因为只有一个提供者时,是不需要Cluster的。
- Proxy层封装了所有接口的透明化代理,而在其它层都以Invoker为中心,只有到了暴露给用户使用时,才用Proxy将Invoker转成接口,或将接口实现转成Invoker,也就是去掉Proxy层RPC是可以Run的,只是不那么透明,不那么看起来像调本地服务一样调远程服务。
- 而Remoting实现是Dubbo协议的实现,如果你选择RMI协议,整个Remoting都不会用上,Remoting内部再划为Transport传输层和Exchange信息交换层,Transport层只负责单向消息传输,是对Mina、Netty、Grizzly的抽象,它也可以扩展UDP传输,而Exchange层是在传输层之上封装了Request-Response语义。
- Registry和Monitor实际上不算一层,而是一个独立的节点,只是为了全局概览,用层的方式画在一起。
Spring Cloud基于Spring Boot实现,使用HTTP的RESTful风格API作为调用方式。它所包含的多个子项目共同构建了微服务架构体系。
SpringBoot专注于快速开发单个微服务。
SpringCloud是关注全局的微服务协调框架,它将SpringBoot开发的单个微服务整合管理,并为微服务之间提供,配置管理、服务发现、断路器、路由网关等集成服务,SpringCloud依赖SpringBoot。
服务调用方式是 Dubbo 和 Spring Cloud 重要不同点,熟悉RPC/HTTP/REST概念,有助对比 Dubbo 和SpringCloud。
RPC 是远端过程调用,其调用协议通常包含传输协议和编码协议。RPC调用是面向服务的封装,针对服务的可用性和效率等都做了优化。
http是超文本传输协议,RPC 也可以用http作为传输协议,但一般是用 tcp作为传输协议。
Dubbo 采用单一长连接和NIO异步通讯(保持连接/轮询处理),使用自定义报文的TCP协议,并且序列化使用定制Hessian2框架,适合于小数据量大并发的服务调用,以及服务消费者机器数远大于服务提供者机器数的情况,但不适用于传输大数据的服务调用。
Spring Cloud 直接使用 HTTP 协议,在性能上弱于Dubbo。
这里通常指ZooKeeper(Dubbo注册中心)和Eureka(Cloud注册中心)的对比。
分布式领域著名的CAP理论(C:数据一致性,A:服务可用性,P:分区故障的容错性),Zookeeper保证的是CP,但对于服务发现而言,可用性比数据一致性更加重要,AP胜过CP,而 Eureka 设计则遵循 AP 原则。
可能说起来Dubbo,很多人都不陌生,这毕竟是一款从2012年就开始开源的Java RPC框架,中间由于各种各样的原因停止更新4年半的时间,中间只发过一个小版本修了一个小bug,甚至大家都以为这个项目已经死掉了,竟然又在2017年9月份恢复了更新,不可谓不神奇。
网络上很多人都拿Dubbo和Spring Cloud做对比,可能在大家的心目中,这两个框架是可以画上等号的吧,后来在网络上有一个非常流行的表格,比较详细的对比了 Spring Cloud 和 Dubbo ,表格如下:
Dubbo | SpringCloud | |
---|---|---|
服务注册中心 | Zookeeper | Spring Cloud Netfix Eureka |
服务调用方式 | RPC | REST API |
服务监控 | Dubbo-monitor | Spring Boot Admin |
熔断器 | 不完善 | Spring Cloud Netflix Hystrix |
服务网关 | 无 | Spring Cloud Netflix Zuul |
分布式配置 | 无 | Spring Cloud Config |
服务跟踪 | 无 | Spring Cloud Sleuth |
数据流 | 无 | Spring Cloud Stream |
批量任务 | 无 | Spring Cloud Task |
信息总线 | 无 | Spring Cloud Bus |
Dubbo 专注 RPC 和服务治理,Spring Cloud 则是一个微服务架构生态。
以上列举了一些核心部件,当然这里需要申明一点,Dubbo对于上表中总结为“无”的组件不代表不能实现,而只是Dubbo框架自身不提供,需要另外整合以实现对应的功能,这样看起来确实Dubbo更像是Spring Cloud的一个子集。
Dubbo 在国内拥有着巨大的用户群,大家希望在使用 Dubbo 的同时享受 Spring Cloud 的生态,出现各种各样的整合方案,但是因为服务中心的不同,各种整合方案并不是那么自然,直到 Spring Cloud Alibaba 这个项目出现,由官方提供了 Nacos 服务注册 中心后,才将这个问题完美的解决。并且提供了 Dubbo 和 Spring Cloud 整合的方案,命名为: Dubbo Spring Cloud 。
Spring Cloud拥有很多的项目模块,包含了微服务系统的方方面面。Dubbo是一个非常优秀的服务治理和服务调用框架,但缺少很多功能模块,例如网关、链路追踪等。在项目模块上,Spring Cloud占据着更大的优势。
Spring Cloud的更新速度非常块,Camden.SR5版本发布于2017年2月6日,Camden.SR6版本发布于2017年3月10日,Dalston版本发布于2017年4月12日,基本每个月会发一次版本的迭代。从GitHub的代码仓库来看,Spring Cloud几乎每天都有更新。阿里巴巴于2011年10月开源了Dubbo,开源后的Dubbo发展迅速,大概每2~3个月有一次版本更新。然而,从在2013年3月开始,Dubbo暂停了版本更新,并只在2014年10月发布了一个小版本,修复了一个bug,之后长期处于版本停止更新的状态。直到2017年9月,阿里巴巴中间件部门重新组建了Dubbo团队,把Dubbo列为重点开源项目,并在2017年9~11月期间,一直保持每月一次版本更新的频率。
从学习成本上考虑,Dubbo的版本趋于稳定,文档完善,可以即学即用,没有太大难度。Spring Cloud 基于Spring Boot开发,需要开发者先学会Spring Boot。另外,Spring Cloud版本迭代快,需要快速跟进学习。Spring Cloud文档大多是英文的,要求学习者有一定的英文阅读能力。此外,Spring Cloud文档很多,不容易快速找到相应的文档。
从开发风格上来讲,Dubbo 更倾向于Spring Xml的配置方式,Dubbo官方也推荐这种方式。Spring Cloud基于Spring Boot,Spring Boot采用的是基于注解和JavaBean配置方式的敏捷开发。从开发速度上讲,Spring Cloud具有更高的开发和部署速度。
最后,Spring Cloud 的通信方式大多数是基于HTTP Restful风格的,服务与服务之间完全无关、无耦合。由于采用的是HTTP Rest,因此服务无关乎语言和平台,只需要提供相应API接口,就可以相互调用。Dubbo 的通信方式基于远程调用,对接口、平台和语言有强依赖性。如果需要实现跨平台调用服务,需要写额外的中间件,这也是Dubbo存在的原因。
Dubbo和Spring Cloud拥有各自的优缺点。Dubbo更易上手,并且广泛使用于阿里巴巴的各大站点,经历了“双11”期间高并发、大流量的检验,Dubbo框架非常成熟和稳定。Spring Cloud服务框架严格遵守Martin Fowler 提出的微服务规范,社区异常活跃,它很可能成为微服务架构的标准。
Dubbo Spring Cloud 构建在原生的 Spring Cloud 之上,其服务治理方面的能力可认为是 Spring Cloud Plus, 不仅完全覆盖 Spring Cloud 原生特性,而且提供更为稳定和成熟的实现,特性比对如下表所示:
功能组件 | Spring Cloud | Dubbo Spring Cloud |
---|---|---|
分布式配置(Distributed configuration) | Git、Zookeeper、Consul、JDBC | Spring Cloud 分布式配置 + Dubbo 配置中心 |
服务注册与发现(Service registration and discovery) | Eureka、Zookeeper、Consul | Spring Cloud 原生注册中心 + Dubbo 原生注册中心 |
负载均衡(Load balancing) | Ribbon(随机、轮询等算法) | Dubbo 内建实现(随机、轮询等算法 + 权重等特性) |
服务熔断(Circuit Breakers) | Spring Cloud Hystrix | Spring Cloud Hystrix + Alibaba Sentinel 等 |
服务调用(Service-to-service calls) | Open Feign、RestTemplate | Spring Cloud 服务调用 + Dubbo @Reference |
链路跟踪(Tracing) | Spring Cloud Sleuth + Zipkin | Zipkin、opentracing 等 |
以上对比表格摘自Dubbo Spring Cloud官方文档。
而且Dubbo Spring Cloud 基于 Dubbo Spring Boot 2.7.1 和 Spring Cloud 2.x 开发,无论开发人员是 Dubbo 用户还是 Spring Cloud 用户, 都能轻松地驾驭,并以接近“零”成本的代价使应用向上迁移。Dubbo Spring Cloud 致力于简化云原生开发成本,以达成提高研发效能以及提升应用性能等目的。
在Spring Cloud构建的微服务系统中,大多数的开发者使用都是官方提供的Feign组件来进行内部服务通信,这种声明式的HTTP客户端使用起来非常的简洁、方便、优雅,但是有一点,在使用Feign消费服务的时候,相比较Dubbo这种RPC框架而言,性能堪忧。
虽说在微服务架构中,会讲按照业务划分的微服务独立部署,并且运行在各自的进程中。微服务之间的通信更加倾向于使用HTTP这种简答的通信机制,大多数情况都会使用REST API。这种通信方式非常的简洁高效,并且和开发平台、语言无关,但是通常情况下,HTTP并不会开启KeepAlive功能,即当前连接为短连接,短连接的缺点是每次请求都需要建立TCP连接,这使得其效率变的相当低下。
对外部提供REST API服务是一件非常好的事情,但是如果内部调用也是使用HTTP调用方式,就会显得显得性能低下,Spring Cloud默认使用的Feign组件进行内部服务调用就是使用的HTTP协议进行调用,这时,我们如果内部服务使用RPC调用,对外使用REST API,将会是一个非常不错的选择,恰巧,Dubbo Spring Cloud给了我们这种选择的实现方式。
本小结将会以一个简单的入门案例,介绍一下在使用Nacos作为服务中心,使用Dubbo来实现服务提供方和服务消费方的案例。
Nacos的安装、部署配置和使用已经在前面的章节介绍过了,这里不再赘述,如果还有不清楚的读者,请参考前面的Nacos系列文章:
《Spring Cloud Alibaba | Nacos服务中心初探》
《Spring Cloud Alibaba | Nacos服务注册与发现》
《Spring Cloud Alibaba | Nacos集群部署》
《Spring Cloud Alibaba | Nacos配置管理》
父工程依赖pom.xml如下:
代码清单:Alibaba/dubbo-spring-cloud-demo/pom.xml
org.springframework.cloud
spring-cloud-dependencies
${spring-cloud.version}
pom
import
com.alibaba.cloud
spring-cloud-alibaba-dependencies
${spring-cloud-alibaba.version}
pom
import
org.springframework.boot
spring-boot-starter-actuator
org.springframework.boot
spring-boot-starter-web
com.alibaba.cloud
spring-cloud-starter-dubbo
com.alibaba.cloud
spring-cloud-starter-alibaba-nacos-discovery
org.projectlombok
lombok
true
org.springframework.boot
spring-boot-starter-test
test
注意:
必须包含spring-boot-starter-actuator
包,不然启动会报错。
spring-cloud-starter-dubbo
包需要注意groupId,根据具体使用的spring cloud alibaba版本依赖来确定。
org.springframework.cloud
com.alibaba.cloud
以上引用未指定版本,需显示的声明
API模块,存放Dubbo服务接口和模型定义,非必要,这里创建仅为更好的代码重用以及接口、模型规格控制管理。
定义抽象接口HelloService.java:
代码清单:Alibaba/dubbo-spring-cloud-demo/dubbo_api/src/main/java/com/springcloud/dubbo_api/service/HelloService.java
public interface HelloService {
String hello(String name);
}
工程依赖pom.xml如下:
代码清单:Alibaba/dubbo-spring-cloud-demo/dubbo_provider/pom.xml
com.springcloud.book
ch13_1_dubbo_api
${project.version}
此处引入公共API模块。
实现Dubbo接口,HelloServiceI.java如下:
代码清单:Alibaba/dubbo-spring-cloud-demo/dubbo_provider/src/main/java/com/springcloud/dubbo_provider/service/HelloServiceI.java
@Service
public class HelloServiceI implements HelloService {
@Override
public String hello(String name) {
return "Hello " + name;
}
}
注意:这里的@Service
注解并不是来自Spring的org.springframework.stereotype.Service
,而是Dubbo的org.apache.dubbo.config.annotation.Service
,千万不要引用错误。这里的@Service
注解仅声明该Java服务(本地)实现为Dubbo服务。
配置文件 application.yml 需要将Java服务(本地)配置为 Dubbo 服务(远程)如下:
代码清单:Alibaba/dubbo-spring-cloud-demo/dubbo_provider/src/main/resources/application.yml
server:
port: 8000
dubbo:
scan:
base-packages: com.springcloud.book.ch13_1_dubbo_provider.service
protocol:
name: dubbo
port: -1
registry:
address: spring-cloud://192.168.44.129
spring:
application:
name: dubbo-spring-cloud-provider
cloud:
nacos:
discovery:
server-addr: 192.168.44.129:8848
main:
allow-bean-definition-overriding: true
注意:在暴露Dubbo服务方面,推荐使用外部化配置的方式,即指定Java服务实现类的扫描基准包。
Dubbo Spring Cloud 继承了 Dubbo Spring Boot 的外部化配置特性,也可以通过标注 @DubboComponentScan 来实现基准包扫描。
dubbo.scan.base-packages
:指定 Dubbo 服务实现类的扫描基准包dubbo.protocol
:Dubbo服务暴露的协议配置,其中子属性name为协议名称,port为协议端口(-1 表示自增端口,从 20880 开始)dubbo.registry
:Dubbo 服务注册中心配置,其中子属性address 的值 "spring-cloud://192.168.44.129",说明挂载到 Spring Cloud 注册中心spring.application.name
:Spring 应用名称,用于 Spring Cloud 服务注册和发现。该值在 Dubbo Spring Cloud 加持下被视作dubbo.application.name
,因此,无需再显示地配置dubbo.application.name
。spring.main.allow-bean-definition-overriding
:在 Spring Boot 2.1 以及更高的版本增加该设定,因为 Spring Boot 默认调整了 Bean 定义覆盖行为。spring.cloud.nacos.discovery
:Nacos 服务发现与注册配置,其中子属性 server-addr 指定 Nacos 服务器主机和端口。创建应用主类Ch131DubboProviderApplication.java:
代码清单:Alibaba/dubbo-spring-cloud-demo/dubbo_provider/src/main/java/com/springcloud/dubbo_provider/DubboProviderApplication.java
@SpringBootApplication
@EnableDiscoveryClient
public class DubboProviderApplication {
public static void main(String[] args) {
SpringApplication.run(DubboProviderApplication.class, args);
}
}
工程依赖pom.xml如下:
代码清单:Alibaba/dubbo-spring-cloud-demo/dubbo_consumer/pom.xml
com.springcloud.book
ch13_1_dubbo_api
${project.version}
工程配置application.yml如下:
代码清单:Alibaba/dubbo-spring-cloud-demo/dubbo_consumer/src/main/resources/application.yml
server:
port: 8080
dubbo:
protocol:
name: dubbo
port: -1
registry:
address: spring-cloud://192.168.44.129
cloud:
subscribed-services: dubbo-spring-cloud-provider
spring:
application:
name: dubbo-spring-cloud-consumer
cloud:
nacos:
discovery:
server-addr: 192.168.44.129:8848
main:
allow-bean-definition-overriding: true
dubbo.cloud.subscribed-services
:表示要订阅服务的服务名,可以配置'*'
,代表订阅所有服务,不推荐使用。若需订阅多应用,使用 "," 分割。测试接口HelloController.java如下:
代码清单:Alibaba/dubbo-spring-cloud-demo/dubbo_consumer/src/main/java/com/springcloud/dubbo_consumer/controller/HelloController.java
@RestController
public class HelloController {
@Reference
private HelloService helloService;
@GetMapping("/hello")
public String hello() {
return helloService.hello("Dubbo!");
}
}
注意:这里的@Reference
注解是org.apache.dubbo.config.annotation.Reference
。
启动主类Ch131DubboConsumerApplication.java如下:
代码清单:Alibaba/dubbo-spring-cloud-demo/dubbo_consumer/src/main/java/com/springcloud/dubbo_consumer/DubboConsumerApplication.java
@SpringBootApplication
@EnableDiscoveryClient
public class DubboConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(DubboConsumerApplication.class, args);
}
}
启动子工程 dubbo_provider 和子工程 dubbo_consumer ,启动完成后,我们可以访问Nacos控制台的服务列表上看到两个服务,如图:
我们打开浏览器访问:http://localhost:8080/hello ,可以看到页面正常显示Hello Dubbo!
,测试成功,如图:
https://github.com/apache/dubbo-spring-boot-project
https://github.com/cicadasmile/spring-cloud-base
https://github.com/meteor1993/SpringCloudLearning/tree/master/Alibaba/dubbo-spring-cloud-demo
https://github.com/cicadasmile/spring-cloud-base
https://juejin.im/post/5d82cf94e51d45620821cf92
https://mp.weixin.qq.com/s/RC8F_D1J75XEv7oR7xdK5Q
https://zhuanlan.zhihu.com/p/36182136
https://juejin.im/post/5ab09943f265da238f125ee8
http://shiyanjun.cn/archives/325.html