前言
本章基于dubbo2.7.6。
分析应用级别服务注册与发现特性,使用默认local模式元数据服务。
主要内容包括:
1)rpc服务级别 vs 应用级别
2)DubboBootstrap#start API的作用,整体流程梳理
3)应用级别服务注册发现如何适配rpc服务级别老逻辑
该特性在rpc调用期间没有变更(运行期间也不依赖注册中心),主要在启动阶段和注册表变更阶段做了适配。
现状
2.7.5之前dubbo仅支持rpc服务级别注册与发现。
注册中心以zk为例。
provider在暴露rpc服务阶段,向注册中心注册数据如下,在/dubbo/{rpc服务}/providers下列举了所有服务提供者:
在同一个rpc服务下,会有多个providers,每个provider对应一个url,如:
dubbo://127.0.0.1:20881/org.apache.dubbo.demo.DemoService?anyhost=true&application=heihei-app&deprecated=false&dubbo=2.0.2&dynamic=true&generic=false&interface=org.apache.dubbo.demo.DemoService&methods=sayHello,sayHelloAsync&pid=7451&release=&scope=remote&side=provider×tamp=1679471005075
consumer在引用阶段,根据订阅rpc服务,找到所有providers,用url构造Invoker缓存在RegistryDirectory中。
优势
假设DemoService要进行迁移,从a服务迁移到b服务。
在传统Dubbo中,对于consumer来说不需要关心谁提供了这个服务,不需要进行代码变更。
而用SpringCloud+OpenFeign,如果DemoService迁移,我们就需要改代码。
consumer在rpc调用阶段,从RegistryDirectory选择invoker,调用目标节点的rpc服务。
虽然FeignClient注解支持根据Environment解析占位符,但是本质上consumer对于服务迁移有感知。
劣势
1)和当下的流行的服务注册发现模型不匹配
比如SpringCloud服务注册发现的模型都是基于应用级别,每个ServiceInstance代表一个应用实例。
2)注册中心压力大
压力大体现在几个方面:
如果1个应用有n个实例,每个实例提供m个rpc服务,则注册中心会有n*m条数据;
如果1个实例下线,该实例有n个rpc服务,每个rpc服务有m个consumer,则注册中心需要通知n*m个consumer;
单从zk的znode存储来看,providers的url包含了大量数据,随着特性越来越多,数据也越来越多;
DubboBootstrap
针对于上述基于rpc服务级别服务注册发现带来的问题,dubbo提出了服务自省架构。
笔者认为通俗来说,一个是应用级别服务注册发现,另一个是元数据服务。
为了支撑新的服务自省架构,在用户侧提供了全新的DubboBootstrap api,统一管理dubbo的配置和启动时序。
案例
服务提供方:
ServiceConfig<DemoServiceImpl> service = new ServiceConfig<>();
service.setInterface(DemoService.class);
service.setRef(new DemoServiceImpl());
// DubboBootstrap单例对象创建
DubboBootstrap bootstrap = DubboBootstrap.getInstance();
RegistryConfig registryConfig = new RegistryConfig("zookeeper://127.0.0.1:2181");
registryConfig.setParameters(new HashMap<>());
// 【关键】 开启【应用级别】服务注册发现
registryConfig.getParameters().put(
RegistryConstants.REGISTRY_TYPE_KEY/*registry-type*/,
RegistryConstants.SERVICE_REGISTRY_TYPE/*service*/);
bootstrap.application(new ApplicationConfig("hahaha-app"))
.registry(registryConfig)
.service(service)
.start() // 启动dubbo
.await();
复制代码
服务消费方:
ReferenceConfig<DemoService> reference = new ReferenceConfig<>();
reference.setInterface(DemoService.class);
// 【关键】设置rpc服务提供方应用名称(可省略)
// reference.setProvidedBy("hahaha-app");
RegistryConfig registryConfig = new RegistryConfig("zookeeper://127.0.0.1:2181");
// 【关键】 开启【应用级别】服务注册发现
registryConfig.setParameters(new HashMap<>());
registryConfig.getParameters().put(
RegistryConstants.REGISTRY_TYPE_KEY/*registry-type*/,
RegistryConstants.SERVICE_REGISTRY_TYPE/*service*/);
// DubboBootstrap单例对象创建
DubboBootstrap bootstrap = DubboBootstrap.getInstance();
bootstrap.application(new ApplicationConfig("service-consumer-app"))
.registry(registryConfig)
.reference(reference)
.start(); // 启动dubbo
DemoService demoService = ReferenceConfigCache.getCache().get(reference);
String message = demoService.sayHello("dubbo");
System.out.println(message);
复制代码
效果
基于上述改动,provider注册到zk里的数据如下。
rpc服务->应用列表:
应用->应用实例列表: