什么是Dubbo
Dubbo是一个分布式服务框架,致力于提供高性能和透明化的RPC远程服务调用方案,以及SOA服务治理方案。
注:SOA服务-面向服务的体系结构。它将应用程序的不同功能单元(称为服务)通过这些服务之间定义良好的接口和契约联系起来。
核心组成
其主要包括远程通讯、集群容错和自动发现。
1. 远程通讯
提供多种基于长连接的NIO框架抽象封装,包括多种线程模型,序列化,以及“请求-响应”模式的信息交换方式。
2. 集群容错
提供基于接口方法的透明远程过程调用,包括多协议支持,以及软负载均衡,失败容错,地址路由,动态配置等集群支持。
3. 自动发现
基于注册中心目录服务,使服务消费方能动态的查找服务提供方,使地址透明,使服务提供方可以平滑增加或减少机器。
Dubbo的优点
- 使用简单
- 透明性(无侵入)
- 轻量级(不依赖容器)
- 功能完善(同步、异步、分组、降级……)
- 可扩展性(微内核,平等对待第三方)
Dubbo能做什么?
- 透明化的远程方法调用,就像调用本地方法一样调用远程方法,只需简单配置,没有任何API侵入。
- 软负载均衡及容错机制,可在内网替代F5等硬件负载均衡器,降低成本,减少单点。
- 服务自动注册与发现,不再需要写死服务提供方地址,注册中心基于接口名查询服务提供者的IP地址,并且能够平滑添加或删除服务提供者。
Dubbo工作原理
注释:
Provider: 暴露服务的服务提供方。
Consumer: 调用远程服务的服务消费方。
Registry: 服务注册与发现的注册中心。
Monitor: 统计服务的调用次调和调用时间的监控中心。
Container: 服务运行容器。
过程:
1. 服务提供者启动,根据协议信息绑定到配置的IP和端口上,如果已有服务绑定过相同IP和端口的则跳过
2. 注册服务信息至注册中心
3. 客户端启动,根据接口和协议信息订阅注册中心中注册的服务,注册中心将存活的服务地址通知到客户端,当有服务信息变更时客户端可以通过定时通知得到变更信息
4. 在客户端需要调用服务时,从内存中拿到上次通知的所有存活服务地址,根据路由信息和负载均衡机制选择最终调用的服务地址,发起调用
5. 通过filter分别在客户端发送请求前和服务端接收请求后,通过异步记录一些需要的信息传递到monitor做监控或者统计
注:同步就是指一个进程在执行某个请求的时候,若该请求需要一段时间才能返回信息,那么这个进程将会一直等待下去,直到收到返回信息才继续执行下去;异步是指进程不需要一直等下去,而是继续执行下面的操作,不管其他进程的状态。当有消息返回时系统会通知进程进行处理,这样可以提高执行的效率。
Dubbo功能介绍
本地服务和远程服务
本地服务:
<bean id="XXXService" class ="com.xxx.XxxServiceImpl"/>
<bean id="xxxAction" class = "com.xxx.XxxAction">
<property name ="xxxService" ref = "xxxService">
</bean>
远程服务:
<bean id="XXXService" class ="com.xxx.XxxServiceImpl"/>
<dubbo:sercice interface = "com.xxx.XxxService" ref="xxxService"/>
<dubbo:reference id = "xxxService" interface="com.xxx.XxxService"/>
<bean id="xxxAction" class = "com.xxx.XxxAction">
<property name ="xxxService" ref = "xxxService">
</bean>
Dubbo通过Spring配置
DUBBO加载Spring的集成时在dubbo-config下面的dubbo-config-spring模块下面,其中有一个类DubboNamespaceHandler,它实现了Spring提供的接口NamespaceHandlerSupport。那么Spring怎么发现整个实现类的呢?在该模块的META-INF文件夹下有两个文件: spring.handlers和spring.schemas,这两个文件里面制定了dubbo的namespace的XSD文件(XSD是指XML结构定义,描述了XML文档的结构可以用一个指定的XML Schema来验证某个XML文档,以检查该XML文档是否符合其要求。文档设计者可以通过XML Schema指定一个XML文档所允许的结构和内容,并可据此检查一个XML文档是否是有效的。XML Schema本身是一个XML文档,它符合XML语法结构。可以用通用的XML解析器解析它。)的位置以及dubbo的namespace由DubboNamespaceHandler来处理解析。
简单而言就是有专门的函数(registerBeanDefinitionParser)来解析配置信息。具体的可以配置的信息包括如下的application,module,registry,monitor,provider,consumer,protocol,service,reference和annotation一共十种信息。
public class DubboNamespaceHandler extends NamespaceHandlerSupport {
public DubboNamespaceHandler() {
}
public void init() {
this.registerBeanDefinitionParser("application", new DubboBeanDefinitionParser(ApplicationConfig.class, true));
this.registerBeanDefinitionParser("module", new DubboBeanDefinitionParser(ModuleConfig.class, true));
this.registerBeanDefinitionParser("registry", new DubboBeanDefinitionParser(RegistryConfig.class, true));
this.registerBeanDefinitionParser("monitor", new DubboBeanDefinitionParser(MonitorConfig.class, true));
this.registerBeanDefinitionParser("provider", new DubboBeanDefinitionParser(ProviderConfig.class, true));
this.registerBeanDefinitionParser("consumer", new DubboBeanDefinitionParser(ConsumerConfig.class, true));
this.registerBeanDefinitionParser("protocol", new DubboBeanDefinitionParser(ProtocolConfig.class, true));
this.registerBeanDefinitionParser("service", new DubboBeanDefinitionParser(ServiceBean.class, true));
this.registerBeanDefinitionParser("reference", new DubboBeanDefinitionParser(ReferenceBean.class, false));
this.registerBeanDefinitionParser("annotation", new DubboBeanDefinitionParser(AnnotationBean.class, true));
}
static {
Version.checkDuplicate(DubboNamespaceHandler.class);
}
}
获取远程调用方法和执行远程方法:
eg:
BankService bankService = (BankService)context.getBean("bankService");//获取远程服务代理
QueryResponse response = bankService.queryBlance(new QueryRequest());//执行远程方法
<dubbo:service/>
服务配置,用于暴露一个服务,定义服务的元信息,一个服务可以用多个协议暴露,一个服务也可以注册到多个注册中心。
<dubbo:reference/>
引用配置,用于创建一个远程服务代理,一个引用可以指向多个注册中心。
<dubbo:protocol/>
协议配置,用于配置提供服务的协议信息,协议由提供方指定,消费方被动接受。
<dubbo:application/>
应用配置,用于配置当前应用信息,不管该应用是提供者还是消费者。
<dubbo:module/>
模块配置,用于配置当前模块信息,可选。
<dubbo:registry/>
注册中心配置,用于配置连接注册中心相关信息。
<dubbo:monitor/>
监控中心配置,用于配置连接监控中心相关信息,可选。
<dubbo:provider/>
提供方的缺省值,当ProtocolConfig和ServiceConfig某属性没有配置时,采用此缺省值,可选。
<dubbo:consumer/>
消费方缺省配置,当ReferenceConfig某属性没有配置时,采用此缺省值,可选。
<dubbo:method/>
方法配置,用于ServiceConfig和ReferenceConfig指定方法级的配置信息。
<dubbo:argument/>
用于指定方法参数配置。
配置继承
服务分组
当一个接口有多重实现的时候,可以用group分组。
Provider:
<dubbo:service group="feedback" interface="com.xxx.IndexService"/>
<dubbo:service group="member" interface="com.xxx.IndexService"/>
版本区分
当一个接口实现出现不兼容升级时候,可以使用版本号过度。版本号不同的服务相互之间不引用。
Provider:
<dubbo:service interface="com.xxx.IndexService" version="1.0.0"/>
<dubbo:service interface="com.xxx.IndexService" version="2.0.0"/>
集群与容错
在集群调用失败时,Dubbo提供了多种容错方案,缺省为failover重试。
这里的Invoker是Provider的一个可调用Service的抽象,Invoker封装了Provider地址及Service接口信息。
Directory代表多个Invoker,可以把它看成List,但与List不同的是,它的值可能是动态变化的,比如注册中心推送变更。
Cluster将Directory中的多个Invoker伪装成一个Invoker,对上层透明,伪装过程包含了容错逻辑,调用失败后,重试另一个。
Router负责从多个Invoker中按路由规则选出子集,比如读写分离,应用隔离等。
LoadBalance负责从多个Invoker中选出具体的一个用于本次调用,选的过程包含了负载均衡算法,调用失败后,需要重选。
集群容错模式
Failover Cluster
失败自动切换,当出现失败,重试其它服务器。(缺省)
通常用于读操作,但重试会带来更长延迟。
可通过retries=”2”来设置重试次数(不含第一次)。
Failfast Cluster
快速失败,只发起一次调用,失败立即报错。
通常用于非幂等性的写操作,比如新增记录。
Failsafe Cluster
失败安全,出现异常时,直接忽略。
通常用于写入审计日志等操作。
Failback Cluster
失败自动恢复,后台记录失败请求,定时重发。
通常用于消息通知操作。
Forking Cluster
并行调用多个服务器,只要一个成功即返回。
通常用于实时性要求较高的读操作,但需要浪费更多服务资源。
可通过forks=”2”来设置最大并行数。
Broadcast Cluster
广播调用所有提供者,逐个调用,任意一台报错则报错。(2.1.0开始支持)
通常用于通知所有提供者更新缓存或日志等本地资源信息。
多协议
- 不同服务不同协议
- 同一服务多协议暴露
参数回调
参数回调方式与调用本地callback或listener相同,只需要在Spring的配置文件中声明哪个参数是callback类型即可,Dubbo将基于长连接生成反向代理,这样就可以从服务器端调用客户端逻辑。
泛化调用
配置
<dubbo:reference id="xxxService" interface="***" version= "1.0.0" generic="true">
同步转异步
本地执行部分代码
在客户端执行部分代码如在客户端缓存已查询过的数据,如当服务器全部不可用时伪造容错数据。
流量控制
属性配置
如果公共配置很简单,没有多注册中心,多协议等情况,或者想多个Spring容器想共享配置,可以使用dubbo.properties作为缺省配置。Dubbo将自动加载classpath根目录下的dubbo.properties,可以通过JVM启动参数:-Ddubbo.properties.file=xxx.properties 改变缺省配置位置。如果classpath根目录下存在多个dubbo.properties,比如多个jar包中有dubbo.properties,Dubbo会任意加载,并打印。
映射规则
将XML配置的标签名,加属性名,用点分隔,多个属性拆成多行:
比如:dubbo.application.name=foo等价于<dubbo:application name="foo" />
比如:dubbo.registry.address=10.20.153.10:9090等价于<dubbo:registry address="10.20.153.10:9090" />
如果XML有多行同名标签配置,可用id号区分,如果没有id号将对所有同名标签生效:
比如:dubbo.protocol.rmi.port=1234等价于 (协议的id没配时,缺省使用协议名作为id)
比如:dubbo.registry.china.address=10.20.153.10:9090等价于<dubbo:registry id="china" address="10.20.153.10:9090" />
eg:典型配置
dubbo.properties
dubbo.application.name=foo
dubbo.application.owner=bar
dubbo.registry.address=10.20.153.10:9090
覆盖策略
JVM启动-D参数优先,这样可以使用户在部署和启动时进行参数重写,比如在启动时需改变协议的端口。
XML次之,如果在XML中有配置,则dubbo.properties中的相应配置项无效。
Properties最后,相当于缺省值,只有XML没有配置时,dubbo.properties的相应配置项才会生效,通常用于共享公共配置,比如应用名。