配置项的分类
- 服务发现:表示该配置项用于服务的注册与发现,目的是让消费方找到提供方。
- 服务治理:表示该配置项用于治理服务间的关系,或为开发测试提供便利条件。
- 性能调优:表示该配置项用于调优性能,不同的选项对性能会产生影响。
所有配置最终都将转换为 URL 表示,并由服务提供方生成,经注册中心传递给消费方,各属性对应 URL 的参数,参见配置项一览表中的 “对应URL参数” 列。
具体的标签功能和使用方式,可以参考官方文档。
配置的形式
Dubbo的配置方式主要有:
- XML配置
- 属性配置
- 注解配置
- JVM参数
其中官方推荐的是XML配置方式。如果应用很简单,也可以采用其他的方式。
1.XML文件配置
在resource文件夹下创建xml文件,通过spring的注入方式将配置属性注入到spring容器中。
2.properties文件属性配置
在resource文件夹下创建 dubbo.properties,同样可以将 xml 的 tag 名和属性名组合起来,用 ‘.’ 分隔。每行一个属性。
如果采用的是SpringBoot,也可以在application.properies文件中配置属性,优先级和xml文件是一样的。
3.注解配置
也就是整合了SpringBoot,将配置属性写在类中,再注入容器。
4.JVM参数
如是是IDEA环境下,VM option下添加相应的配置-D参数即可。
常用的配置
启动检查
Dubbo 默认会在启动时检查依赖的服务是否可用,不可用时会抛出异常,阻止 Spring 初始化完成,以便上线时,能及早发现问题,默认 check=“true”。
可以通过 check=“false” 关闭检查,比如,测试时,有些服务不关心,或者出现了循环依赖,必须有一方先启动。但是到了真正使用服务的时候,还是会检查服务是否可用。
例如消费者引用某个服务,没有提供者的时候就会报错:
<dubbo:reference id="providerService"
interface="com.example.dubbo.provider.service.ProviderService"
check="false"/>
例如消费者关闭了注册中心检查,注册订阅失败的时候就会报错:
<dubbo:registry address="zookeeper://localhost:2181" check="false"/>
还可以关闭所有服务的启动检查:
<dubbo:consumer check="false" />
超时
消费者调用提供者暴露的服务的时候,具有超时属性,也就是规定时间内可以调用到服务就是一次成功调用,如果超出了规定时间,那么就算是失败的调用。
标签中添加timeout属性即可,单位是毫秒。
<dubbo:reference id="providerService"
interface="com.example.dubbo.provider.service.ProviderService"
timeout="2000"/>
重试次数
一般超时属性需要配合重试次数进行使用。
当某个服务应为网络等原因导致调用超时失败,可以通过配置重试次数,多次尝试调用。
标签中添加retries属性即可,表示可以重试的次数,即不包含第一次的调用。
<dubbo:reference id="providerService"
interface="com.example.dubbo.provider.service.ProviderService"
timeout="2000"
retries="3"/>
多版本
在 Dubbo 中为同一个服务配置多个版本。
当一个接口实现,出现不兼容升级时,可以用版本号过渡,版本号不同的服务相互间不引用。
可以按照以下的步骤进行版本迁移:
- 在低压力时间段,先升级一半提供者为新版本
- 再将所有消费者升级为新版本
- 然后将剩下的一半提供者升级为新版本
在标签中添加version属性即可。
服务提供者的配置示例:
<dubbo:service
interface="com.example.dubbo.provider.service.ProviderService"
ref="providerService"
version="1.0.1"/>
调用的时候,也设置相同的版本,就能成功调用:
<dubbo:reference id="providerService"
interface="com.example.dubbo.provider.service.ProviderService"
version="1.0.1"/>
本地存根
在 Dubbo 中利用本地存根在客户端执行部分逻辑。感觉就像是一个切面编程,调用服务的时候,执行其他的逻辑,而这个逻辑就存在本地存根代码中。
远程服务后,客户端通常只剩下接口,而实现全在服务器端,但提供方有些时候想在客户端也执行部分逻辑,比如:做 ThreadLocal 缓存,提前验证参数,调用失败后伪造容错数据等等,此时就需要在 API 中带上 Stub,客户端生成 Proxy 实例,会把 Proxy 通过构造函数传给 Stub ,然后把 Stub 暴露给用户,Stub 可以决定要不要去调 Proxy。
本地存根代码可以写在提供者,也可以写在消费者中,下面看一个写在消费者中的例子。
在配置文件中添加标签stub即可,内容就是本地存根类的全限定名称,类名就是服务接口名后面添加Stub即可,如果stub属性中传入的true,那么Dubbo可以自动识别这个类就是本地存根。
<dubbo:reference id="providerService"
interface="com.example.dubbo.provider.service.ProviderService"
stub="com.example.dubbo.provider.service.ProviderServiceStub"/>
然后该目录下添加存根实现类。
package com.example.dubbo.provider.service;
public class ProviderServiceStubimplements ProviderService{
private final ProviderService providerService;
// 构造函数传入真正的远程代理对象
public BarServiceStub(ProviderService providerService){
this.providerService= providerService;
}
public String sayHello(String name) {
// 此代码在客户端执行, 你可以在客户端做ThreadLocal本地缓存,或预先验证参数是否合法,等等
try {
return providerService.sayHello(name);
} catch (Exception e) {
// 你可以容错,可以做任何AOP拦截事项
return "容错数据";
}
}
}
序列化
在dubbo RPC中,同时支持多种序列化方式,例如:
- dubbo序列化:阿里尚未开发成熟的高效java序列化实现,阿里不建议在生产环境使用它
- hessian2序列化:hessian是一种跨语言的高效二进制序列化方式。但这里实际不是原生的hessian2序列化,而是阿里修改过的hessian lite,它是dubbo RPC默认启用的序列化方式
- Kryo是一种非常成熟的序列化实现,已经在Twitter、Groupon、Yahoo以及多个著名开源项目(如Hive、Storm)中广泛的使用。
- FST是一种较新的序列化实现,目前还缺乏足够多的成熟使用案例,
- json序列化:目前有两种实现,一种是采用的阿里的fastjson库,另一种是采用dubbo中自己实现的简单json库,但其实现都不是特别成熟,而且json这种文本序列化性能一般不如上面两种二进制序列化。
- java序列化:主要是采用JDK自带的Java序列化实现,性能很不理想。
序列化启用非常简单,在xml中配置添加属性即可。
<dubbo:protocol name="dubbo" serialization="kryo"/>
如果使用kryo序列化,最好将那些需要被序列化的类注册到dubbo系统中,例如,我们可以实现如下回调接口:
public class SerializationOptimizerImpl implements SerializationOptimizer {
public Collection<Class> getSerializableClasses() {
List<Class> classes = new LinkedList<Class>();
classes.add(BidRequest.class);
classes.add(BidResponse.class);
classes.add(Device.class);
classes.add(Geo.class);
classes.add(Impression.class);
classes.add(SeatBid.class);
return classes;
}
}
然后在XML配置中添加:
<dubbo:protocol name="dubbo" serialization="kryo" optimizer="org.apache.dubbo.demo.SerializationOptimizerImpl"/>
配置的覆盖关系
配置的优先级从高到低:
- JVM -D 参数:当你部署或者启动应用时,它可以轻易地重写配置,比如,改变 dubbo 协议端口;
- XML:XML 中的当前配置会重写 dubbo.properties 中的;
- Properties:默认配置,仅仅作用于以上两者没有配置时。
不同粒度配置的覆盖关系:
- 方法级优先,接口级次之,全局配置再次之。
- 如果级别一样,则消费方优先,提供方次之。
也就是说配置的粒度越细,优先级越高,这也十分符合使用逻辑,特殊情况特殊处理。
SpringBoot整合
三种方式:
- pom中导入dubbo-starter,在applicatio.properties配置属性,使用@Service暴露服务,使用@Reference引用服务。需要在SpringBoot的Application类中添加@EnableDubbo开启dubbo的注解功能。
- pom中导入dubbo-starter,保留dubbo的xml配置文件,然后在SpringBoot的Application类中添加@ImportRecourse(location=“classpath:path.xml”),添加配置文件。
- 使用注解API方式,将所有配置写一个配置类,配置类上添加注解@Configuration,配置属性就是方法,添加注解@Bean。手动将每个组件创建到容器当中,让dubbo来扫描。
还是用xml比较明了。
基本配置示例
下面采用zookeeper+Dubbo的方式配置一个基本的消费者调用提供者的示例。
服务提供者
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd">
<!--当前项目在整个分布式架构里面的唯一名称,计算依赖关系的标签-->
<dubbo:application name="provider" owner="example">
<dubbo:parameter key="qos.enable" value="true"/>
<dubbo:parameter key="qos.accept.foreign.ip" value="false"/>
<dubbo:parameter key="qos.port" value="55555"/>
</dubbo:application>
<dubbo:monitor protocol="registry"/>
<!--dubbo这个服务所要暴露的服务地址所对应的注册中心-->
<dubbo:registry address="zookeeper://localhost:2181" check="false"/>
<!--当前服务发布所依赖的协议;webserovice、Thrift、Hessain、http-->
<dubbo:protocol name="dubbo" port="20880"/>
<!--服务发布的配置,需要暴露的服务接口-->
<dubbo:service
interface="com.example.dubbo.provider.service.ProviderService"
ref="providerService"/>
<!--Bean bean定义-->
<bean id="providerService" class="com.example.dubbo.provider.service.ProviderServiceImpl"/>
</beans>
消费者
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.example.dubbo.provider.service"></context:component-scan>
<!--当前项目在整个分布式架构里面的唯一名称,计算依赖关系的标签-->
<dubbo:application name="consumer" owner="example"/>
<!--dubbo这个服务所要暴露的服务地址所对应的注册中心-->
<dubbo:registry address="zookeeper://localhost:2181" check="false"/>
<!--生成一个远程服务的调用代理-->
<dubbo:reference id="providerService"
interface="com.example.dubbo.provider.service.ProviderService"/>
</beans>