一、背景
1、服务治理的原因
service和rest写在一个项目中,这样其他项目也需要调用同样的service,需要再写一遍,代码无法复用;
service和rest分开部署,rest的pom中添加service的依赖,这样如果一个service的实现逻辑需要修改,所有的rest都要重新打包部署;
service只暴露接口(即api),rest只依赖这个接口,不关心service的逻辑实现,因为在rest的pom中只引用了api,使用Autowired注解是发现不了服务的。
.......
对于这样的一系列问题,dubbo和springcloud都是比较成熟的服务治理解决方案框架。
2、RPC远程调用协议
RPC Remote Procedure Call Protocol 协议是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议。也就是说两台服务器A,B,一个应用部署在A服务器上,想要调用B服务器上应用提供的函数/方法,由于不在一个内存空间,不能直接调用,需要通过网络来表达调用的语义和传达调用的数据。
二、dubbo介绍
1、简介:
是一款Java RPC框架,致力于提供高性能的RPC远程服务调用方案。Dubbo 作为主流的微服务框架之一,为开发人员带来了非常多的便利。
2、核心功能
Dubbo主要提供了3大核心功能:面向接口的远程方法调用,智能容错和负载均衡,以及服务自动注册和发现。
1)远程方法调用
网络通信框架,提供对多种NIO框架抽象封装,包括“同步转异步”和“请求-响应”模式的信息交换方式。
2)智能容错和负载均衡
提供基于接口方法的透明远程过程调用,包括多协议支持,以及软负载均衡,失败容错,地址路由,动态配置等集群支持。
3)服务注册和发现
服务注册,基于注册中心目录服务,使服务消费方能动态的查找服务提供方,使地址透明,使服务提供方可以平滑增加或减少机器。
3、核心组件
3.1、注册中心(registry)
生产者在此注册并发布内容,消费者在此订阅并接收发布的内容。
如果注册中心挂了,consumer还能调用provider,因为刚开始初始化的时候,consumer会将需要的所有提供者的地址等信息拉取到本地缓存,所以注册中心挂了可以继续通信。但是provider挂了,那就没法调用了。
3.2、消费者(consumer)
客户端,从注册中心获取到方法,可以调用生产者中的方法。
3)生产者(provider)
服务端,生产内容,生产前需要依赖容器(先启动容器)。
4)容器(container)
生产者在启动执行的时候,必须依赖容器才能正常启动(默认依赖的是spring容器),
5)监控(Monitor)
统计服务的调用次数与时间等。
4、Dubbo的架构设计
- 左边(淡蓝背景):为服务消费方使用的接口
- 右边(淡绿色背景):为服务提供方使用的接口
- 位于中轴线上:为双方都用到的接口。
Dubbo 框架设计一共划分了10个层:
1. 服务接口层(Service)
该层是与实际业务逻辑相关的,根据服务提供方和服务消费方的业务设计对应的接口和实现。
2. 配置层(Config)
对外配置接口,以ServiceConfig和ReferenceConfig为中心,可以直接new配置类,也可以通过spring解析配置生成配置类。
3.服务代理层(Proxy)
服务接口透明代理,生成服务的客户端Stub和服务器端Skeleton,以ServiceProxy为中心,扩展接口为ProxyFactory。
4.服务注册层(Registry)
封装服务地址的注册与发现,以服务URL为中心,扩展接口为RegistryFactory、Registry和RegistryService。可能没有服务注册中心,此时服务提供方直接暴露服务。
5.集群层(Cluster)
封装多个提供者的路由及负载均衡,并桥接注册中心,以Invoker为中心,扩展接口为Cluster、Directory、Router和LoadBalance。将多个服务提供方组合为一个服务提供方,实现对服务消费方来透明,只需要与一个服务提供方进行交互。
6.监控层(Monitor)
RPC调用次数和调用时间监控,以Statistics为中心,扩展接口为MonitorFactory、Monitor和MonitorService。
7.远程调用层(Protocol)
封将RPC调用,以Invocation和Result为中心,扩展接口为Protocol、Invoker和Exporter。Protocol是服务域,它是Invoker暴露和引用的主功能入口,它负责Invoker的生命周期管理。Invoker是实体域,它是Dubbo的核心模型,其它模型都向它靠扰,或转换成它,它代表一个可执行体,可向它发起invoke调用,它有可能是一个本地的实现,也可能是一个远程的实现,也可能一个集群实现。
8. 信息交换层(Exchange)
封装请求响应模式,同步转异步,以Request和Response为中心,扩展接口为Exchanger、ExchangeChannel、ExchangeClient和ExchangeServer。
9.网络传输层(Transport)
抽象mina和netty为统一接口,以 Message 为中心,扩展接口为 Channel、Transporter、Client、Server和Codec。
10.数据序列化层(Serialize)
可复用的一些工具,扩展接口为 Serialization、 ObjectInput、ObjectOutput和ThreadPool。
5、dubbo的调用流程
1、服务提供者启动,开启Netty服务,创建Zookeeper客户端,向注册中心注册服务;
2、服务消费者启动,通过Zookeeper向注册中心获取服务提供者列表,与服务提供者通过Netty建立长连接;
3、服务消费者通过接口开始远程调用服务,ProxyFactory通过初始化Proxy对象,Proxy通过创建动态代理对象;
4、动态代理对象通过invoke方法,层层包装生成一个Invoker对象,该对象包含了代理对象;
5、Invoker通过路由,负载均衡选择了一个最合适的服务提供者,在通过加入各种过滤器,协议层包装生成一个新的DubboInvoker对象;
6、再通过交换成将DubboInvoker对象包装成一个Reuqest对象,该对象通过序列化通过NettyClient传输到服务提供者的NettyServer端;
(7)到了服务提供者这边,再通过反序列化、协议解密等操作生成一个DubboExporter对象,再层层传递处理,会生成一个服务提供端的Invoker对象;
(8)这个Invoker对象会调用本地服务,获得结果再通过层层回调返回到服务消费者,服务消费者拿到结果后,再解析获得最终结果。
6、dubbo支持的协议
dubbo支持多种协议,默认为dubbo协议,详见下一篇。
7、代码规范
拆分出api、service、rest三个组件:
api中定义基本的dto和service接口;
serivce(pom)依赖api,实现service接口,并注册到注册中心;
rest(pom)依赖api,从注册中心消费service服务。
部署时,api不用部署,只需要部署service和rest。
注册中心、service、rest三者可独立部署到不同机器上,通过注册中心去注册和发现服务。
api和服务一般是一对一的,即一套api对应一套service,service、rest为一对多,一个rest可以调用多个service。
三、与spring cloud比较
1、dubbo优缺点
优点:
1)支持各种通信协议,而且消费方和服务方使用长链接方式交互,通信速度上略胜 ;
2)采用rpc方式,性能上比Spring Cloud的rpc更好;
3)dubbo的网络消耗小于springcloud
缺点:
1)如果我们使用配置中心、分布式跟踪这些内容都需要自己去集成;
2)开发难度较大,原因是dubbo的jar包依赖问题很多大型工程无法解决;
2、Spring Cloud优缺点
优点:
1)产出于Spring大家族,Spring在企业级开发框架中来头很大,可以保证后续的更新、完善。
2)spring cloud社区活跃,教程丰富,遇到问题很容易找到解决方案;
3)spring cloud功能比dubbo更加完善;
4)spring cloud采用rest访问方式,rest的技术无关性使用效果更棒;
5)spring cloud轻轻松松几行代码就完成了熔断、均衡负责、服务中心的各种平台功能;
6)提供了微服务的一整套解决方案:服务发现注册、配置中心、消息总线、负载均衡、断路器、数据监控等;作为一个微服务治理的大家伙,考虑的很全面,几乎服务治理的方方面面都考虑到了,方便开发开箱即用;
3、dubbo和feign的区别
3.1、协议支持方面:
(1)Feign更加优雅简单。Feign是通过REST API实现的远程调用,基于Http传输协议,服务提供者需要对外暴露Http接口供消费者调用,服务粒度是http接口级的。通过短连接的方式进行通信,不适合高并发的访问。Feign追求的是简洁,少侵入(因为就服务端而言,在SpringCloud环境下,不需要做任何额外的操作,而Dubbo的服务端需要配置开放的Dubbo接口)。
(2)Dubbo方式更灵活。Dubbo是通过RPC调用实现的远程调用,支持多传输协议(Dubbo、Rmi、http、redis等等),可以根据业务场景选择最佳的方式,非常灵活。默认的Dubbo协议:利用Netty,TCP传输,单一、异步、长连接,适合数据量小、高并发和服务提供者远远少于消费者的场景。Dubbo通过TCP长连接的方式进行通信,服务粒度是方法级的。从协议层选择看,Dubbo是配置化的,更加灵活。Dubbo协议更适合小数据高并发场景。
3.2、通信性能方面:
(1)Feign基于Http传输协议,底层实现是rest。从OSI 7层模型上来看rest属于应用层。
在高并发场景下性能不够理想,成为性能瓶颈(虽然他是基于Ribbon以及带有熔断机制可以防止雪崩),需要改造。具体需要改造的内容需要时再研究。
(2)Dubbo框架的通信协议采用RPC协议,属于传输层协议,性能上自然比rest高。提升了交互的性能,保持了长连接,高性能。
Dubbo性能更好,比如支持异步调用、Netty性能更好。Dubbo主要是配置而无需改造。
RPC | REST | |
耦合性 | 强耦合 | 松耦合 |
消息协议 | 二进制 thrift/protobuf | 文本 xml、jason |
通信协议 | TCP | HTTP |
接口契约IDL | thrift/protobuf | swagger |
开发调试 | 消息不可读 | 可读,可调试 |
对外开放 | 一般作为内部各个系统的通信框架 | 对接外部系统 |
3.3、负载均衡方面:
Feign默认使用Ribbon作为负载均衡的组件。Dubbo和Ribbon(Feign默认集成Ribbon)都支持负载均衡策略,但是Dubbo支持的更灵活。
(1)Ribbon的负载均衡策略:随机、规则轮询、空闲策略、响应时间策略。
(2)Dubbo的负载均衡策略:Dubbo支持4种算法,随机、权重轮询、最少活跃调用数、一致性Hash策略。而且算法里面引入权重的概念。
Dubbo可以使用路由策略,然后再进行负载均衡;Dubbo配置的形式不仅支持代码配置,还支持Dubbo控制台灵活动态配置。
Dubbo负载均衡的算法可以精准到某个服务接口的某个方法,而Ribbon的算法是Client级别的。Ribbon需要进行全局配置,个性化配置比较麻烦。
3.4、容错机制方面:
Feign默认使用Hystix作为服务熔断的组件。Hystix提供了服务降级,服务熔断,依赖隔离,监控(Hystrix Dashboard)等功能。Feign是利用熔断机制来实现容错的,与Dubbo处理的方式不一样。
Dubbo支持多种容错策略,FailOver、FailFast、Failsafe、FailBack、Aviailable、Broadcast、Forking策略等,以及Mock。也引入了retry次数,timeout等配置参数。Dubbo自带了失败重试的功能。