Dubbo全文
特性
- cloud不能使用多注册中心,和dubbo不兼容,需要关闭cloud的注册机制,cloud本身就有服务治理的方案,dubbo主要是去兼容cloud的生态
- 采用boot集成dubbo,可以完全依赖dubbo的服务治理功能
boot继承pom
<dependency>
<groupId>com.java.boot</groupId>
<version>1.0-SNAPSHOT</version>
<artifactId>boot-api</artifactId>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>2.7.7</version>
</dependency>
<dependency>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-client</artifactId>
<version>1.2.1</version>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-dependencies-zookeeper</artifactId>
<version>2.7.7</version>
</dependency>
多注册中心
- 针对多注册中心,同样有负载均衡策略
- 区域优先
dubbo.registries.hangzhou.preferred=true
- 设置权重
dubbo.registries.hangzhou.weight=100
- 指定区域
dubbo.registries.hangzhou.zone=hangzhou
- 服务端配置
dubbo.protocol.name=dubbo
dubbo.protocol.port=-1
dubbo.registries.hunan.address=nacos://localhost:8848
dubbo.registries.hangzhou.address=zookeeper://localhost:2181
dubbo.registries.hanzhou.default=true
- 客户端配置
dubbo.registries.hunan.address=nacos://localhost:8848
dubbo.registries.hangzhou.address=zookeeper://localhost:2181
dubbo.registries.hangzhou.zone=hangzhou
dubbo.registries.hangzhou.weight=100
dubbo.registries.hangzhou.preferred=true
版本支持
- 实现上需要注明服务版本
@DubboService(registry = {"hangzhou", "hunan"}, version = "2.0")
- 使用上指定服务版本
@DubboReference(registry = {"hangzhou", "hunan"}, version = "2.0")
多协议支持
- 一个服务发布多种协议
- 下面以rest为例
服务提供者
- 服务端配置
# 基于netty
dubbo.protocols.dubbo.name=dubbo
dubbo.protocols.dubbo.port=-1
# 基于http
dubbo.protocols.rest.name=rest
dubbo.protocols.rest.port=-1
# 配置服务容器
dubbo.protocols.rest.server=jetty
- 接口实现需要制定协议
@DubboService(registry = {"hangzhou", "hunan"}, protocol = {"dubbo", "rest"})
接口
- 接口,需要额外注释
@Path("/")
public interface IHelloService {
@GET
@Path("/hello")
String hello(String username);
}
- pom
<!-- 基于resteasy的支持-->
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-jaxrs</artifactId>
<version>3.13.0.Final</version>
</dependency>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-client</artifactId>
<version>3.13.0.Final</version>
</dependency>
<!-- 基于jetty的支持-->
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-server</artifactId>
<version>9.4.19.v20190610</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-servlet</artifactId>
<version>9.4.19.v20190610</version>
</dependency>
效果
- 可以直接通过80端口访问到服务
负载均衡
- 设置,只需要设置客户端配置
@DubboReference(registry = {"hangzhou", "hunan"}, loadbalance = "consistenthash")
Random
- 默认使用加权随机算法,根据权重大小生成区间,生成随机数,看这个随机数落到哪个区间就使用哪个
RandomLoadBalance
源码体现
Roundrobin
- 加权轮询
RoundRobinLoadBalance
一致性哈希
- 普通哈希,如果节点数改变,会导致前后取模不一样
- 采用哈希环,固定取模的数为2^32 - 1,当有数据进行取模时,找到距离当前位置顺时针最近的服务器节点
- 服务器节点分布不均匀,导致数据分布不均匀,设置虚拟节点,各个服务器在环上都有自己的虚拟节点,当有数据指向虚拟节点,其实也就是指向服务器
ConsistentHashLoadBalance
,默认使用根据第一个参数进行hash取模
最小活跃度
LeastActiveLoadBalance
- 根据目标集群服务器列表,处理性能最高的,权重也越高,处理性能较低的,权重也比较低
- 根据请求处理的吞吐量,发起一次请求,计数器+1,完成后,计数器-1,如果计数器值比较低,服务器处理能力高
最小响应时间
ShortestResponseLoadBalance
,筛选成功调用响应最短的服务器,并调整权重
集群容错
- 容忍错误的能力,网络的不确定性,导致访问的不确定性
- 要保证重试多次是幂等请求,发起多次请求后,只修改一次
- 默认开启
failover
,进行失败自动切换服务器进行重试,默认重试2次,适合查询业务
@DubboService(cluster = "failover", retries = 2)
failfast cluster
快速失败,立马报错,不希望重试带来的不幂等性failsafe cluster
出现异常,直接吞掉,日志操作failback cluster
失败自动回复,记录失败的请求,定时重发,对于事务,需要保证最终数据一致forking cluster
并行调用多个服务节点,只要其中一个成功,就返回结果broadcast cluster
广播调用,一个请求调用所有的服务提供者,只要其中一个节点报错,那么就请求失败
泛化
- 不提供公共接口进行远程调用,不再依赖统一的接口
- 服务端直接注册服务
@DubboService(protocol = {"dubbo"})
public class RunServiceImpl implements IRunService {
@Override
public String run(String name) {
return "Run " + name;
}
}
- 客户端通过
GenericService
调用,传入方法名,方法参数类型和方法值
@DubboReference(interfaceName = "com.java.bootproducer.service.IRunService", generic = true)
GenericService genericService;
@GetMapping("/run")
public String run(String name) {
// 如果参数为POJO 需要转换成map,如果返回值为POJO,也会转换成map
// Object result = genericService.$invoke("findPerson", new String[]{"com.xxx.Person"}, new Object[]{person});
// person为Map<String, Object>
return genericService.$invoke("run", new String[]{"java.lang.String"}, new Object[]{name}).toString();
}
服务降级
- 消费者调用服务,需要设置
mock
,指定服务降级的处理方式即可
@DubboReference(registry = {"hangzhou", "hunan"}, loadbalance = "consistenthash",
mock = "com.java.bootconsumer.MockHelloService", timeout = 500, cluster = "failfast")
MockHelloService
public class MockHelloService implements IHelloService {
@Override
public String hello(String username) {
return "server fall back " + username;
}
}
常见配置
- 启动时检查,启动时,如果注册中心有问题,服务启动失败
# 提供者配置
dubbo.registries.hangzhou.check=true
// 消费者配置
在DubboReference,配置check=true
- 主机绑定,服务启动之后,ip获取
// 源码调用
// 1. 启动参数是否有`DUBBO_IP_TO_BIND`,如果有则将这个作为服务ip
// 2. 读取配置文件`protocolConfig.getHost();` 获取 dubbo.protocol.host= 指定host
// 3. 获取本机ip `InetAddress.getLocalHost().getHostAddress();`
// 4. 通过socket连接注册中心,获取本机IP
// 5. 轮询本机网卡,找到合适的IP地址
// 6. 校验`DUBBO_IP_TO_REGISTRY`环境变量,如果指定了注册IP,那么就使用指定的,如果没有指定,就是用绑定的
host = this.findConfigedHosts(protocolConfig, registryURLs, map);
Integer port = this.findConfigedPorts(protocolConfig, name, map);
配置优先级
- 服务端配置的信息会形成url的参数,客户端优先,
- 负载均衡针对客户端,在客户端调用时决定调用哪一个服务节点
- 如果客户端和服务端都配置了负载均衡,客户端优先
- 优先级,如果优先级相同,优先客户端的
- 方法级别的配置,注解上配置
method
属性,值为@Method
- 接口配置
- 全局配置
dubbo.module.*
- dubbo本身的配置优先级
- 启动参数
- 配置文件
application.properites
- API
- 加载本地文件配置,本地dubbo文件
多序列化协议
- 指定协议的序列化
dubbo.protocols.dubbo.serialization=kryo
- pom
<dependency>
<groupId>com.esotericsoftware</groupId>
<artifactId>kryo</artifactId>
<version>4.0.2</version>
</dependency>
<dependency>
<groupId>de.javakaffee</groupId>
<artifactId>kryo-serializers</artifactId>
<version>0.45</version>
</dependency>
性能调优
- 方法调用链路
actives
决定服务消费者每个方法的最大并发调用数connections
决定服务提供者的连接数量,dubbo为长连接,可以开启复用连接accepts
服务提供者最大连接数iothreads
服务提供者io线程池,接收连接池,不建议配置,与CPU相关,默认CPU+1threadpool
服务提供者线程池大小,业务线程池,默认200queues
服务提供者线程等待队列,默认是0,线程执行完了就拒绝,让请求重试其他服务器executes
服务提供者每方法最大的并发执行数
缓存文件
- 服务中心不可以,也要保证服务的高可用,缓存服务地址
- 配置注册缓存文件
dubbo.registries.hanzhou.file=/Users/mzx/Desktop/java/springcloudalibaba/dubbo_hangzhou.cache
dubbo.registries.hunan.file=/Users/mzx/Desktop/java/springcloudalibaba/dubbo_hunan.cache
动态配置中心
- 把dubbo的配置存储在外部的配置中心
- 通过
dubbo-admin
的配置文件,将自定义配置注册到zookeeper上
zookeeper无法进行实时同步,只作为统一的管理
- 工程配置
dubbo.config-center.address=zookeeper://localhost:2181
,使用zookeeper的配置 - 存在失败的问题,注解上的配置早于全局配置中心的加载时间,注解上无法使用全局配置中心的配置
元数据中心
- 由于dubbo是通过url进行交互的,如果url参数过多会影响网络通信
- 元数据中心,将url后面的参数抽取为
metadata
进行管理 - 抽取成json