Paul Paul Public Builder & 全栈工程师
search
arrow_back 返回标签拓扑

Dubbo

共 5 篇。

2026-08-30 · 约 1 分钟

Dubbo3 应用级服务发现的取舍

Dubbo3 把接口级发现改成应用级(服务自省),本质是用元数据中心换注册中心的压力:注册数据量从 O(接口数) 降到 O(应用数)。 MetadataService.java java content_copy 复制代码 // 应用级发现的关键:Provider 暴露 MetadataService, // Consumer 先查元数据再建立订阅 ServiceInstancesChangedListener listener = serviceDiscovery.createListener(serviceNames); 疑问还没想清楚:元数据版本冲突时 Consumer 的回退策略,在规模上去之后会不会成为新瓶颈。

阅读全文 arrow_forward
newest_tech 2022-08-07 · 约 1 分钟

Dubbo3.0-DubboBootstrap模型讲解

前言 Dubbo3.0有很多新的类(较2.0来说),本文主要就3.0中DubboBootstrap及其相关的类进行讲解,主要为想了解Dubbo3.0启动模型的同学做参考。 版本说明 Dubbo版本:3.0.9 DubboBootstrap的组成部分 DubboBootstrap的关键属性有4个,分别是ApplicationModel、ConfigManager、Environment、ApplicationDeployer。他们功能分别是应用的定义(可以理解为领域对象中的Entity)、配置管理、环境变量管理、应用声明周期管理。 ApplicationModel讲解 讲到ApplicationModel就不得不提到Dubbo的另外两个领域模型FrameworkModel和ModuleModel。 模型之间的依赖关系 这三个模型紧密相连,整个Dubbo共用一个FrameworkModel,一个FrameworkModel中允许有多个ApplicationModel存在,同时在一个ApplicationModel里面又允许有多个ModuleModel同时存在。同时,ApplicationModel又保留FrameworkModel的引用,ModuleModel也保留了ApplicationModel的引用。(也就是说FrameworkModel和ApplicationModel之间保持了双向引用,ApplicationModel和ModuleModel之间也保持了双向引用) 模型共有的特性 这三个模型都集成自ScopeModel,其中我想重点讲的是classLoaders、extensionScope、extensionDirector这三个。 每个Model其实都有自己的classLoader,他们都通过自己的classLoader来加载类(在没有特殊指定的情况下默认是使用AppClassLoader) extensionScope和extensionDirector配合使用来控制SPI扩展点的的实例(ExtensionLoader)。ExtensionLoader现在不是全局单例的,而是在ExtensionScope维度下是单例的(可以理解是按照ExtensionScope维度对SPI扩展点的加载做了隔离,不能跨scope获取SPI实例)。 模型的差别 这三个模型大致功能相同,不同的点在于功能维度不同。FrameworkModel主要提供的是已经暴露过的Provider信息的查询。ApplicationModel和ModuleModel的差别主要体现在Environment、ServiceRepository、ConfigManager、Deployer上。 ApplicationModel中可以查询整个应用的配置、环境变量,以及应用的初始化。 ModuleModel中只能查当前进程里面的相关应用配置、环境变量,同时他的ModuleModel也只负责服务的暴露和引用。 ConfigManager讲解 Config和Environment是有差别的,前者代表的是写在应用内的配置(可以理解为必须要的配置,比如:想要应用启动那一定要配置registry的配置,想要暴露一个服务就必须定义一个ServiceConfig),后者代表外部化配置(可以理解为一个值的获取方式,比如:RegistryConfig的地址是${spring.zookeeper.url},而它的取值方式可以是多种多样的,从spring、环境变量、JVM变量等等。我们可以通过这种方式,让部分属性值做到根据不同环境来设置不同的值) Dubbo将配置做了抽象,比如:ProtocolConfig、RegistryConfig、ReferenceConfig、ServiceConfig、ApplicationConfig等等。每个Config代表的是Dubbo的配置,比如:注册中心的配置在RegistryConfig中、服务暴露的配置在ServiceConfig中等等。当然也没什么说的,这个类主要是提供配置的查询功能,唯一要注意的是ModuleConfigManager和ConfigManager其实就是能加载的配置不一样(在各自构造函数中限制了能加载那些配置)。 Environment讲解 Dubbo的环境变量有几种来源方式,比如:系统环境变量、Spring环境变量。详情可以参考小马哥的文章 ApplicationDeployer讲解 ApplicationDeployer和ModuleDeployer两个类的创建都需要Model(ApplicationDeployer的创建需要ApplicationModel,ModuleDeployer的创建需要ModuleModel),而我们知道Model是有双向引用的,因此这两个Deployer可以通过Model互通。 在DubboBootstrap中我们也能看到这两个类的互调,比如:org.apache.dubbo.config.deploy.DefaultApplicationDeployer#start -> org.apache.dubbo.config.deploy.DefaultApplicationDeployer#doStart -> org.apache.dubbo.config.deploy.DefaultApplicationDeployer#startModules 通过这个调用链我们可以看到ApplicationDeployer调用ModuleDeployer,org.apache.dubbo.config.deploy.DefaultModuleDeployer#start我们从这个方法里面也能看到很多ApplicationDeployer的身影。 两个Deployer的差别 ApplicationDeployer负责应用的启动和初始化,ModuleDeployer负责服务的暴露和引用。 这两个类的差别其实就是功能上的差别,其他的都是由于功能差别导致的(比如内部属性的差异、接口的差异,这些其实都是由他们的职责差异导致的)。

阅读全文 arrow_forward
newest_tech 2022-08-06 · 约 1 分钟

Dubbo3.0-服务自省

前言 Dubbo3.0中有个特别的机制“服务自省”,对于这个机制很多人都很陌生,我用自己的理解来讲讲这个机制。 版本说明 Dubbo版本:3.0.9 定义 所谓的服务自省就是一个元数据同步机制。在Dubbo3.0中,原来面向RPC定义的注册中心数据被拆分为服务元数据和服务地址信息,Dubbo的流量管理能力依赖服务的元数据,因此需要一个机制能很好的去把Provider端的元数据同步到Consumer端。 机制讲解 服务自省是Consumer端获取Provider端服务元数据的一个机制,那么肯定Provider端和Consumer端都有对应的处理。 Provider暴露MetadataService Provider需要提供服务的元数据,所以在Provider端启动时会先暴露所有的业务服务,当所有业务服务都准备好之后(启动并且已经向注册中心注册),暴露MetadataService供Consumer端来查询元数据(此时业务服务也元数据服务都能正常调用,注册中心也有了元数据和应用地址数据)。 Consumer监听MetadataService Consumer端需要在调用时决定调用哪个后端服务(也就是说要进行流量管理),因此在Consumer端启动时先通过应用名查询注册中心得到后端Provider的地址,并完成订阅。拿到Provider地址后,直接发起元数据查询,通过MetadataService得到服务端元数据,并且会有一个监听器,监听服务端元数据的变化(即reversion机制),一旦服务端元数据发生变化,Consumer就会重新发起MetadataService调用获取元数据。 源码解析 Provider暴露MetadataService Dubbo暴露服务的起点是org.apache.dubbo.config.ServiceConfig#export,当然实际的暴露动作是委托给org.apache.dubbo.rpc.Protocol#export。但这是单个服务的暴露,MetadataService肯定是要在所有业务服务暴露完之后再暴露,因此我们需要从DubboBootstrap中去寻找答案(因为现在Dubbo的启动都是由这个类完成)。 DubboBootstrap这个类的结构我们这次不讲,我们需要了解的是Dubbo3.0有两个Deployer类负责启动。ApplicationDeployer负责应用的初始化和启动,ModuleDeployer负责服务的暴露和引用。因此我们可以到ModuleDeployer中找答案。 org.apache.dubbo.config.deploy.DefaultModuleDeployer#start 从这个模板方法里面我们可以看到在暴露和引用服务之后我们会调用org.apache.dubbo.config.deploy.DefaultModuleDeployer#onModuleStarted后续的调用链路如下。 org.apache.dubbo.config.deploy.DefaultApplicationDeployer#notifyModuleChanged -> org.apache.dubbo.config.deploy.DefaultApplicationDeployer#prepareApplicationInstance -> org.apache.dubbo.config.deploy.DefaultApplicationDeployer#exportMetadataService -> org.apache.dubbo.config.metadata.ExporterDeployListener#onModuleStarted -> org.apache.dubbo.config.metadata.ConfigurableMetadataServiceExporter#export 最终暴露元数据服务的动作就在org.apache.dubbo.config.metadata.ConfigurableMetadataServiceExporter#export中。 Consumer监听MetadataService 这里和Provider的分析过程刚好相反,因为Consumer需要让每个ReferenceConfig都要监听服务端的元数据变化,否则流量管理能力会失效。所以,我们直接从org.apache.dubbo.config.ReferenceConfig#get看就好。 首先初始化过程会调用init方法,我们直接跳过一些其他的配置代码,我们知道代理类的创建其实也是委托给org.apache.dubbo.rpc.Protocol#refer,具体来说调用链路如下。 org.apache.dubbo.registry.integration.RegistryProtocol#refer -> org.apache.dubbo.registry.integration.RegistryProtocol#doRefer -> org.apache.dubbo.registry.integration.RegistryProtocol#interceptInvoker -> org.apache.dubbo.registry.client.migration.MigrationRuleListener#onRefer -> org.apache.dubbo.registry.client.migration.MigrationRuleHandler#doMigrate -> org.apache.dubbo.registry.client.migration.MigrationRuleHandler#refreshInvoker -> org.apache.dubbo.registry.client.migration.ServiceDiscoveryMigrationInvoker#migrateToApplicationFirstInvoker -> org.apache.dubbo.registry.client.migration.MigrationInvoker#refreshServiceDiscoveryInvoker -> org.apache.dubbo.registry.integration.RegistryProtocol#getServiceDiscoveryInvoker -> org.apache.dubbo.registry.integration.RegistryProtocol#doCreateInvoker -> org.apache.dubbo.registry.integration.DynamicDirectory#subscribe ->org.apache.dubbo.registry.client.ServiceDiscoveryRegistry#subscribe -> org.apache.dubbo.registry.client.ServiceDiscoveryRegistry#doSubscribe -> org.apache.dubbo.registry.client.ServiceDiscoveryRegistry#subscribeURLs 最终在org.apache.dubbo.registry.client.ServiceDiscoveryRegistry#subscribeURLs中我们能看到整个Consumer端的服务自省过程。 关键代码如下: java content_copy 复制代码 public class ServiceDiscoveryRegistry { protected void subscribeURLs(URL url, NotifyListener listener, Set<String> serviceNames) { serviceNames = toTreeSet(serviceNames); String serviceNamesKey = toStringKeys(serviceNames); //... Lock appSubscriptionLock = getAppSubscription(serviceNamesKey); try { appSubscriptionLock.lock(); ServiceInstancesChangedListener serviceInstancesChangedListener = serviceListeners.get(serviceNamesKey); if (serviceInstancesChangedListener == null) { serviceInstancesChangedListener = serviceDiscovery.createListener(serviceNames); serviceInstancesChangedListener.setUrl(url); for (String serviceName : serviceNames) { List<ServiceInstance> serviceInstances = serviceDiscovery.getInstances(serviceName); if (CollectionUtils.isNotEmpty(serviceInstances)) { serviceInstancesChangedListener.onEvent(new ServiceInstancesChangedEvent(serviceName, serviceInstances)); } } serviceListeners.put(serviceNamesKey, serviceInstancesChangedListener); } if (!serviceInstancesChangedListener.isDestroyed()) { serviceInstancesChangedListener.setUrl(url); listener.addServiceListener(serviceInstancesChangedListener); serviceInstancesChangedListener.addListenerAndNotify(protocolServiceKey, listener); serviceDiscovery.addServiceInstancesChangedListener(serviceInstancesChangedListener); } else { logger.info(String.format("Listener of %s has been destroyed by another thread.", serviceNamesKey)); serviceListeners.remove(serviceNamesKey); } } finally { appSubscriptionLock.unlock(); } } } 从上面看到org.apache.dubbo.registry.client.event.listener.ServiceInstancesChangedListener被创建,并且在监听ServiceInstancesChangedEvent,通过org.apache.dubbo.registry.client.event.listener.ServiceInstancesChangedListener#onEvent -> org.apache.dubbo.registry.client.event.listener.ServiceInstancesChangedListener#doOnEvent 这里就是Consumer端发生服务自省的地方。从代码中可以看到对MetadataService的调用是通过org.apache.dubbo.registry.client.ServiceDiscovery#getRemoteMetadata(java.lang.String, java.util.List<org.apache.dubbo.registry.client.ServiceInstance>)

阅读全文 arrow_forward
newest_tech 2022-08-03 · 约 1 分钟

Dubbo3.0-SpringBoot+Triple

前言 前面讲过使用Dubbo原生API的方式使用Triple,我们发现这个方式不太方便,实际开发中可能并不是很常见这种使用方式,今天我们讲讲在如何在日常项目中使用Triple协议。 快速搭建 环境准备 操作系统:Windowns JDK版本:1.8 编辑工具:IntelliJ IDEA Community Edition 2021.1.2 x64 Zookeeper:3.5.6(3.4或3.5以上的版本都行) 创建项目 项目有三个模块,分别是api、consumer、provider。proto文件都放在api中,consumer放消费端的代码,provider放服务提供者的代码。 api 依赖 xml content_copy 复制代码 <dependencies> <dependency> <groupId>org.apache.dubbo</groupId> <artifactId>dubbo</artifactId> <version>3.0.9</version> </dependency> <dependency> <groupId>io.grpc</groupId> <artifactId>grpc-all</artifactId> <version>1.44.1</version> </dependency> </dependencies> proto插件 这里也是定义在pom中 xml content_copy 复制代码 <build> <extensions> <extension> <groupId>kr.motd.maven</groupId> <artifactId>os-maven-plugin</artifactId> <version>1.6.1</version> </extension> </extensions> <plugins> <plugin> <groupId>org.xolstice.maven.plugins</groupId> <artifactId>protobuf-maven-plugin</artifactId> <version>0.6.1</version> <configuration> <protocArtifact>com.google.protobuf:protoc:${protoc.version}:exe:${os.detected.classifier} </protocArtifact> <pluginId>grpc-java</pluginId> <pluginArtifact>io.grpc:protoc-gen-grpc-java:${grpc.version}:exe:${os.detected.classifier} </pluginArtifact> <protocPlugins> <protocPlugin> <id>dubbo</id> <groupId>org.apache.dubbo</groupId> <artifactId>dubbo-compiler</artifactId> <version>0.0.4.1</version> <mainClass>org.apache.dubbo.gen.tri.Dubbo3TripleGenerator</mainClass> </protocPlugin> </protocPlugins> </configuration> <executions> <execution> <goals> <goal>compile</goal> <goal>test-compile</goal> <goal>compile-custom</goal> <goal>test-compile-custom</goal> </goals> </execution> </executions> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>${maven-compiler-plugin.version}</version> <configuration> <source>1.8</source> <target>1.8</target> </configuration> </plugin> </plugins> </build> proto文件 地址:看这里

阅读全文 arrow_forward
newest_tech 2022-07-25 · 约 1 分钟

Dubbo3.0-Triple协议

前言 Dubbo3.0推出了一个新的协议Triple,我们今天简单看看它的用法。 Triple总览 官方说明:看这里 ,总结为以下几点: 打通 gRPC 生态。 网关友好。(dubbo协议 只能 HTTP 转 泛化Dubbo 调用后端服务,现在可以接入Ingress方案) 异步和流式支持。(dubbo协议 多用于响应式的场景,不适合传大规模的数据。3.0增加流式场景,支持大规模数据的传输) 快速搭建 环境准备 操作系统:Windowns JDK版本:1.8 编辑工具:IntelliJ IDEA Community Edition 2021.1.2 x64 Zookeeper:3.5.6(3.4或3.5以上的版本都行) 创建项目 项目有三个模块,分别是api、consumer、provider。proto文件都放在api中,consumer放消费端的代码,provider放服务提供者的代码。 api 依赖 xml content_copy 复制代码 <dependencies> <dependency> <groupId>org.apache.dubbo</groupId> <artifactId>dubbo</artifactId> <version>3.0.9</version> </dependency> <dependency> <groupId>io.grpc</groupId> <artifactId>grpc-all</artifactId> <version>1.44.1</version> </dependency> </dependencies> proto插件 这里也是定义在pom中 xml content_copy 复制代码 <build> <extensions> <extension> <groupId>kr.motd.maven</groupId> <artifactId>os-maven-plugin</artifactId> <version>1.6.1</version> </extension> </extensions> <plugins> <plugin> <groupId>org.xolstice.maven.plugins</groupId> <artifactId>protobuf-maven-plugin</artifactId> <version>0.6.1</version> <configuration> <protocArtifact>com.google.protobuf:protoc:${protoc.version}:exe:${os.detected.classifier} </protocArtifact> <pluginId>grpc-java</pluginId> <pluginArtifact>io.grpc:protoc-gen-grpc-java:${grpc.version}:exe:${os.detected.classifier} </pluginArtifact> <protocPlugins> <protocPlugin> <id>dubbo</id> <groupId>org.apache.dubbo</groupId> <artifactId>dubbo-compiler</artifactId> <version>0.0.4.1</version> <mainClass>org.apache.dubbo.gen.tri.Dubbo3TripleGenerator</mainClass> </protocPlugin> </protocPlugins> </configuration> <executions> <execution> <goals> <goal>compile</goal> <goal>test-compile</goal> <goal>compile-custom</goal> <goal>test-compile-custom</goal> </goals> </execution> </executions> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>${maven-compiler-plugin.version}</version> <configuration> <source>1.8</source> <target>1.8</target> </configuration> </plugin> </plugins> </build> proto文件 地址:看这里

阅读全文 arrow_forward