前言
dubbo3发布的最大的特性就是应用级服务发现机制,原先的是接口级服务发现机制,那么应用级服务发现机制能带来什么好处呢,按官方说法,以下是官网的原文
相比于 2.x 版本中的基于接口粒度的服务发现机制,3.x 引入了全新的基于应用粒度的服务发现机制, 新模型带来两方面的巨大优势:
- 进一步提升了 Dubbo3 在大规模集群实践中的性能与稳定性。新模型可大幅提高系统资源利用率,降低 Dubbo 地址的单机内存消耗(50%),降低注册中心集群的存储与推送压力(90%), Dubbo 可支持集群规模步入百万实例层次。
- 打通与其他异构微服务体系的地址互发现障碍。新模型使得 Dubbo3 能实现与异构微服务体系如Spring Cloud、Kubernetes Service、gRPC 等,在地址发现层面的互通, 为连通 Dubbo 与其他微服务体系提供可行方案。
在 Dubbo3 前期版本将会同时提供对两套地址发现模型的支持,以最大程度保证业务升级的兼容性
那么接下来就了解以下接口级和应用级服务发现都做了什么改变
接口级服务发现
首先我使用dubbo3.0.6版本搭建了自己的一个简单的远程调用服务,根据官方说明,dubbo3默认会同时开启接口和应用级服务发现,为了兼容老版本2.x的接口级服务发现,方便升级
那么这里我首先只开启接口级服务发现,然后看一下注册到zookeeper上的数据有什么特点,application.properties中设置
#interface 只接口级注册(/dubbo)
#instance 只应用级注册(/service)
#all
dubbo.application.register-mode=interface
如启动生产者,只注册一个接口SayHelloService,代码如下
@DubboService(
protocol = {"dubbo"},scope = Constants.SCOPE_REMOTE,
loadbalance = "random",
cluster = "failover",
retries = 2)
public class SayHelloServiceImpl implements SayHelloService {
@Override
public String sayHello(String msg) {
System.out.println("msg:" + msg);
return "msg:" + msg;
}
}
启动后注册到zk后的截图如下
分析一下各个目录
- metadata:元数据中心,存储了注册上来的接口的各种信息,在SayHelloService目录下得provider的myprovider节点存储了当前接口的各种信息,比如负载均衡、重试此时等,这个元数据中心是为应用级注册中心存在的,等会再分析
- com.example.api.SayHelloService:接口级目录,每个接口都会在这里注册一个全路径,里面的providers目录下面存储了每个实例的该接口信息,这个就是dubbo中最重要的url,这个url里面存储了该接口的所有关键数据,比如负载均衡、容错、重试次数等,一个接口多个实例在会在下面创建多个url
- config:用于dubbo的动态配置使用,这里不关注
如果次数消费者要消费SayHelloService接口,那么消费者应该怎么做?首先消费者肯定会先获取com.example.api.SayHelloService的所有实例,从其中的一个url中获取容错策略、当前的负载均衡策略等,然后最终定位到其中一个url,进行远程调用,最终就可以实现远程调用了
那么这种接口级服务注册有什么特点呢
首先,体现接口级就体现在dubbo/com.example.api.SayHelloService/providers/url,如果一个应用有100个接口,并且该应用部署了10台机器,那么dubbo目录下会注册100个接口,并且每个接口的providers下都会注册10个不同的url,但是这些url除了ip和端口,其它的参数基本都是一样的,比如同一个接口的容错、重试次数、负载均衡策略肯定都是相同的,那么为什么还要冗余到注册中心上增加注册中心的压力呢
接口级服务注册有这样一些缺点
- 每个接口下会注册多个实例url,每个url上冗余的参数太多,增加了注册中心的压力
- 消费者需要订阅每个接口的providers目录,因为要监听接口的上下线感知,来更新本地接口列表
- 当一个实例下线时,如果有100个接口,那么消费端会受到100个订阅通知,对消费端来说短时间内必定增加了消费端的压力
简单来说要优化的点有以下几点
- 冗余参数能否取消
- 订阅目录能否减少,因为我只想监听实例的上下线,为什么需要监听接口呢?
应用级服务发现
只开启应用级服务发现来看看zookeeper上的节点情况
可以发现之前基于接口的url不见了,取而代之的是一个services目录和一个dubbo/mapping目录,那么此时如果消费者来消费应该是怎么样呢
首先消费者只需要订阅services/myprovider目录即可,上下线服务,消费者只需要收到一个通知,更新自己的实例列表即可,这就是应用级服务注册,只监听应用级(ip:port)即可
然后比如要调用com.example.api.SayHelloService接口,那么通过mapper目录的该接口先找到是哪个实例,这里找到实例名称myprovider(com.example.api.SayHelloService的value=myprovider)
根据myprovider找到所有实例列表,在dubbo/metadata/com.example.api.SayHelloService下找到对应实例的该接口相关参数,每一种相同类型的实例,对一个接口只保存一份数据,解决了url参数的冗余
根据参数选择到对应的容错、负载均衡等参数,在实例列表中选择实例进行调用即可
可以看到应用级服务发现接口了接口级服务发现的两大缺点了
分析
可以看到dubbo在3版本才更新了应用级服务发现,确实可以看到之前的接口级服务发现在设计上存在很大的缺陷,而相对于其他微服务框架,如SpringCloud,一开始SpringCloud的设计就是基于应用级实例的注册与消费,在注册中心上的数据非常少,不会存储接口相关的信息,而dubbo即使是在应用级服务发现仍然在元数据中心保存了大量和接口相关的数据,增加了注册中心的压力,但是相应的dubbo在个性化功能上存在了一些优势,比如dubbo可以在服务发布方对接口设置一些默认值,比如某个接口的默认容错策略、默认重试机制等