Java-第十九部分-Dubbo-特性

257 阅读6分钟

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>

多注册中心

  • 针对多注册中心,同样有负载均衡策略
  1. 区域优先dubbo.registries.hangzhou.preferred=true
  2. 设置权重dubbo.registries.hangzhou.weight=100
  3. 指定区域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端口访问到服务 image.png

负载均衡

  • 设置,只需要设置客户端配置
@DubboReference(registry = {"hangzhou", "hunan"}, loadbalance = "consistenthash")

Random

  • 默认使用加权随机算法,根据权重大小生成区间,生成随机数,看这个随机数落到哪个区间就使用哪个 image.png
  • RandomLoadBalance源码体现 image.png

Roundrobin

  • 加权轮询RoundRobinLoadBalance

一致性哈希

  • 普通哈希,如果节点数改变,会导致前后取模不一样
  1. 采用哈希环,固定取模的数为2^32 - 1,当有数据进行取模时,找到距离当前位置顺时针最近的服务器节点
  2. 服务器节点分布不均匀,导致数据分布不均匀,设置虚拟节点,各个服务器在环上都有自己的虚拟节点,当有数据指向虚拟节点,其实也就是指向服务器
  • ConsistentHashLoadBalance,默认使用根据第一个参数进行hash取模

最小活跃度

  • LeastActiveLoadBalance
  • 根据目标集群服务器列表,处理性能最高的,权重也越高,处理性能较低的,权重也比较低
  1. 根据请求处理的吞吐量,发起一次请求,计数器+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的参数,客户端优先,
  1. 负载均衡针对客户端,在客户端调用时决定调用哪一个服务节点
  2. 如果客户端和服务端都配置了负载均衡,客户端优先
  • 优先级,如果优先级相同,优先客户端的
  1. 方法级别的配置,注解上配置method属性,值为@Method
  2. 接口配置
  3. 全局配置dubbo.module.*
  • dubbo本身的配置优先级
  1. 启动参数
  2. 配置文件application.properites
  3. API
  4. 加载本地文件配置,本地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>

性能调优

  • 方法调用链路
  1. actives决定服务消费者每个方法的最大并发调用数
  2. connections决定服务提供者的连接数量,dubbo为长连接,可以开启复用连接
  3. accepts服务提供者最大连接数
  4. iothreads服务提供者io线程池,接收连接池,不建议配置,与CPU相关,默认CPU+1
  5. threadpool服务提供者线程池大小,业务线程池,默认200
  6. queues服务提供者线程等待队列,默认是0,线程执行完了就拒绝,让请求重试其他服务器
  7. executes服务提供者每方法最大的并发执行数 image.png

缓存文件

  • 服务中心不可以,也要保证服务的高可用,缓存服务地址
  • 配置注册缓存文件
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的配置存储在外部的配置中心 image.png
  • 通过dubbo-admin的配置文件,将自定义配置注册到zookeeper上

zookeeper无法进行实时同步,只作为统一的管理

  • 工程配置dubbo.config-center.address=zookeeper://localhost:2181,使用zookeeper的配置
  • 存在失败的问题,注解上的配置早于全局配置中心的加载时间,注解上无法使用全局配置中心的配置

元数据中心

  • 由于dubbo是通过url进行交互的,如果url参数过多会影响网络通信
  • 元数据中心,将url后面的参数抽取为metadata进行管理 image.png
  • 抽取成json image.png