Dubbo3 源码解读-宋小生-13:全局视野来看Dubbo3的服务启动生命周期

本文涉及的产品
服务治理 MSE Sentinel/OpenSergo,Agent数量 不受限
云原生网关 MSE Higress,422元/月
注册配置 MSE Nacos/ZooKeeper,118元/月
简介: > 完整电子书下载地址: https://developer.aliyun.com/ebook/7894> Dubbo3 已经全面取代 HSF2 成为阿里的下一代服务框架,2022 双十一基于 Dubbo3 首次实现了关键业务不停推、不降级的全面用户体验提升,从技术上,大幅提高研发与运维效率的同时地址推送等关键资源利用率提升超 40%,基于三位一体的开源中间件体系打造了阿里在云上的单元化最佳实
完整电子书下载地址: https://developer.aliyun.com/ebook/7894

Dubbo3 已经全面取代 HSF2 成为阿里的下一代服务框架,2022 双十一基于 Dubbo3 首次实现了关键业务不停推、不降级的全面用户体验提升,从技术上,大幅提高研发与运维效率的同时地址推送等关键资源利用率提升超 40%,基于三位一体的开源中间件体系打造了阿里在云上的单元化最佳实践和统一标准,同时将规模化实践经验与技术创新贡献开源社区,极大的推动了开源技术与标准的发展。

本文是 Dubbo 社区贡献者宋小生基于 Dubbo3 3.0.8 版本撰写的源码解析博客,在 Dubbo3 开源&内部技术栈统一的情况下,期望能对集团内的开发者了解 Dubbo3 背后的实现原理有所帮助。可点此查看 博客原文

本篇是宋小生系列 13/30 篇。同时,由 Dubbo3 团队领导的源码解读系列也正在进行中,感兴趣的同学可加入钉钉群了解详情: 28165003194

13-Dubbo的三大中心之配置中心

13.1 配置中心简介

百度了一段不错的文字来介绍配置中心,我看了下肯定比我写的好多了,那我就直接拷贝过来一起看:

对于传统的单体应用而言,常使用配置文件来管理所有配置,比如SpringBoot的application.yml文件,但是在微服务架构中全部手动修改的话很麻烦而且不易维护。微服务的配置管理一般有以下需求:

  • 集中配置管理,一个微服务架构中可能有成百上千个微服务,所以集中配置管理是很重要的。
  • 不同环境不同配置,比如数据源配置在不同环境(开发,生产,测试)中是不同的。
  • 运行期间可动态调整。例如,可根据各个微服务的负载情况,动态调整数据源连接池大小等。
  • 配置修改后可自动更新。如配置内容发生变化,微服务可以自动更新配置。

综上所述对于微服务架构而言,一套统一的,通用的管理配置机制是不可缺少的主要组成部分。常见的做法就是通过配置服务器进行管理。

不过对于来看这个文章的小伙伴应该大部分对配置中心都会比较了解,分布式配置中心实现简单一点就是借助Zookeeper来协助存储,变更推送,不过为了实现各种不同的业务需求,市面上已经有很多很可靠的配置中心可用了,比如我从其他地方拷贝过来的图(虽然不是最新的但是可以供大家参考下):

每个配置中心都有自己的实现,如果对配置中心感兴趣的小伙伴可以自行去对应开源项目官网查看,我们这里来看Dubbo对配置中心的支持

多配置中心: Dubbo支持多配置中心,来 保证其中一个配置中心集群出现不可用时能够切换到另一个配置中心集群 ,保证能够正常从配置中心获取全局的配置、路由规则等信息。这也能够满足配置中心在部署上适应各类高可用的部署架构模式。-来自官网

做中间件可能考虑更多的的不仅仅是性能,还要过多的考虑高可用,高可用怎么做呢,其实就是失效转移,主备切换,降级,降级再降级这些理论的运用,多多考虑某一个服务挂了怎么办,Dubbo的多配置中心支持增加了复杂性,不过降低了服务不可用的风险,有一定的人手的公司还是值得做的。

关于Dubbo的配置中心这里我来贴个官网的图:

关于官网的介绍可以自行去官网看详细内容: 部署架构(注册中心、配置中心、元数据中心

13.2 启动配置中心

在上一个博客中说到了《12-全局视野来看Dubbo3.0.8的服务启动生命周期》Dubbo应用的启动过程DefaultApplicationDeployer的initialize()方法的全生命周期,在初始化方法中通过调用startConfigCenter();方法来启动配置中心的加载。后面就来详细看下:

DefaultApplicationDeployer类型的startConfigCenter()代码如下:

private void startConfigCenter() {

        // load application config
        //加载应用程序配置 (配置可能有多个地方可以配置需要遵循Dubbo约定的优先级进行设置,也可能是多应用,多注册中心这样的配置)
      configManager.loadConfigsOfTypeFromProps(ApplicationConfig.class);

        // try set model name
        if (StringUtils.isBlank(applicationModel.getModelName())) {
        //设置一下模块名字和模块描述(我们再Debug里面经常会看到这个描述信息 toString直接返回了Dubbo为我们改造的对象信息)
            applicationModel.setModelName(applicationModel.tryGetApplicationName());
        }

        // load config centers
        //加载配置中心配置
        //配置可能有多个地方可以配置需要遵循Dubbo约定的优先级进行设置,也可能是多应用,多注册中心这样的配置)
        configManager.loadConfigsOfTypeFromProps(ConfigCenterConfig.class);
        //出于兼容性目的,如果没有明确指定配置中心,并且registryConfig的UseAConfigCenter为null或true,请使用registry作为默认配置中心
        useRegistryAsConfigCenterIfNecessary();

        // check Config Center
        //配置管理器中获取配置中心
        Collection<ConfigCenterConfig> configCenters = configManager.getConfigCenters();
        //配置中心配置不为空则刷新配置中心配置将其放入配置管理器中
        //下面开始刷新配置中心配置,如果配置中心配置为空则执行空刷新
        if (CollectionUtils.isEmpty(configCenters)) {
        //配置中心不存在的配置刷新
            ConfigCenterConfig configCenterConfig = new ConfigCenterConfig();
            configCenterConfig.setScopeModel(applicationModel);
            configCenterConfig.refresh();
            //验证配置
            ConfigValidationUtils.validateConfigCenterConfig(configCenterConfig);
            if (configCenterConfig.isValid()) {
            //配置合法则将配置放入配置管理器中
                configManager.addConfigCenter(configCenterConfig);
                configCenters = configManager.getConfigCenters();
            }
        } else {
        //一个或者多个配置中心配置存在的情况下的配置刷新
            for (ConfigCenterConfig configCenterConfig : configCenters) {
                configCenterConfig.refresh();
                //验证配置
                ConfigValidationUtils.validateConfigCenterConfig(configCenterConfig);
            }
        }

        //配置中心配置不为空则将配置中心配置添加到environment中
        if (CollectionUtils.isNotEmpty(configCenters)) {
        //多配置中心本地动态配置对象创建CompositeDynamicConfiguration
            CompositeDynamicConfiguration compositeDynamicConfiguration = new CompositeDynamicConfiguration();
            //获取配置中心的相关配置
            for (ConfigCenterConfig configCenter : configCenters) {
                // Pass config from ConfigCenterBean to environment
                //将配置中心的外部化配置,更新到环境里面
                environment.updateExternalConfigMap(configCenter.getExternalConfiguration());
                //将配置中心的应用配置,添加到环境里面
                environment.updateAppExternalConfigMap(configCenter.getAppExternalConfiguration());

                // Fetch config from remote config center
                //从配置中心拉取配置添加到组合配置中
                compositeDynamicConfiguration.addConfiguration(prepareEnvironment(configCenter));
            }
            //将配置中心中的动态配置信息 设置到environment的动态配置属性中
            environment.setDynamicConfiguration(compositeDynamicConfiguration);
        }
    }

13.2.1 配置管理器加载配置

前面我们看到了配置管理器会从系统属性中加载配置这里我们来详细看下,配置往往是我们使用者比较关注的内容,

configManager.loadConfigsOfTypeFromProps(ApplicationConfig.class);

配置管理器加载配置代码:
来自ConfigManager的父类型AbstractConfigManager中

public <T extends AbstractConfig> List<T> loadConfigsOfTypeFromProps(Class<T> cls) {
        List<T> tmpConfigs = new ArrayList<>();
        //获取属性配置 dubbo properties in classpath
        //这个配置信息回头说
        PropertiesConfiguration properties = environment.getPropertiesConfiguration();

        // load multiple configs with id
        //多注册中心配置id查询
       
       /*
       搜索属性并提取指定类型的配置ID。
       例如如下配置
       # 配置信息 properties
       dubbo.registries.registry1.address=xxx
       dubbo.registries.registry2.port=xxx
      
       # 提取配置的id extract  
       Set configIds = getConfigIds(RegistryConfig.class)
      
       # 提取的配置id结果 result
       configIds: ["registry1", "registry2"]
       */
        Set<String> configIds = this.getConfigIdsFromProps(cls);
        configIds.forEach(id -> {
            //遍历这些配置id 判断配置缓存(configsCache成员变量)中是否已经存在当前配置
            if (!this.getConfig(cls, id).isPresent()) {
                T config;
                try {
                    //创建配置对象 为配置对象初始化配置id
                    config = createConfig(cls, scopeModel);
                    config.setId(id);
                } catch (Exception e) {
                    throw new IllegalStateException("create config instance failed, id: " + id + ", type:" + cls.getSimpleName());
                }

                String key = null;
                boolean addDefaultNameConfig = false;
                try {
                    // add default name config (same as id), e.g. dubbo.protocols.rest.port=1234
                    key = DUBBO + "." + AbstractConfig.getPluralTagName(cls) + "." + id + ".name";
                    if (properties.getProperty(key) == null) {
                        properties.setProperty(key, id);
                        addDefaultNameConfig = true;
                    }
                //刷新配置信息 好理解点就是Dubbo配置属性重写 
                    config.refresh();
                    //将当前配置信息添加到配置缓存中configsCache成员变量
                    this.addConfig(config);
                    tmpConfigs.add(config);
                } catch (Exception e) {
                    logger.error("load config failed, id: " + id + ", type:" + cls.getSimpleName(), e);
                    throw new IllegalStateException("load config failed, id: " + id + ", type:" + cls.getSimpleName());
                } finally {
                    if (addDefaultNameConfig && key != null) {
                        properties.remove(key);
                    }
                }
            }
        });

        // If none config of the type, try load single config
        //如果没有该类型的配置,请尝试加载单个配置
        if (this.getConfigs(cls).isEmpty()) {
            // load single config
            List<Map<String, String>> configurationMaps = environment.getConfigurationMaps();
            if (ConfigurationUtils.hasSubProperties(configurationMaps, AbstractConfig.getTypePrefix(cls))) {
                T config;
                try {
                    config = createConfig(cls, scopeModel);
                    config.refresh();
                } catch (Exception e) {
                    throw new IllegalStateException("create default config instance failed, type:" + cls.getSimpleName());
                }

                this.addConfig(config);
                tmpConfigs.add(config);
            }
        }

        return tmpConfigs;
    }

13.2.2 默认使用注册中心地址为配置中心

出于兼容性目的,如果没有明确指定配置中心,并且registryConfig的UseAConfigCenter为null或true,请使用registry作为默认配置中心
调用方法useRegistryAsConfigCenterIfNecessary()来处理逻辑
我们来看下代码:

private void useRegistryAsConfigCenterIfNecessary() {
        // we use the loading status of DynamicConfiguration to decide whether ConfigCenter has been initiated.
        //我们使用DynamicConfiguration的加载状态来决定是否已启动ConfigCenter。配置中心配置加载完成之后会初始化动态配置defaultDynamicConfiguration
        if (environment.getDynamicConfiguration().isPresent()) {
            return;
        }
        //从配置缓存中查询是否存在config-center相关配置 ,如果已经存在配置了就无需使用注册中心的配置地址直接返回
        if (CollectionUtils.isNotEmpty(configManager.getConfigCenters())) {
            return;
        }

        // load registry
        //加载注册中心相关配置
        configManager.loadConfigsOfTypeFromProps(RegistryConfig.class);

        //查询是否有注册中心设置了默认配置isDefault 设置为true的注册中心则为默认注册中心列表,如果没有注册中心设置为默认注册中心,则获取所有未设置默认配置的注册中心列表
        List<RegistryConfig> defaultRegistries = configManager.getDefaultRegistries();
        //存在注册中心
        if (defaultRegistries.size() > 0) {
            defaultRegistries
                .stream()
                //判断当前注册中心是否可以作为配置中心
                .filter(this::isUsedRegistryAsConfigCenter)
                //将注册中心配置映射转换为配置中心
                .map(this::registryAsConfigCenter)
                //遍历配置中心流
                .forEach(configCenter -> {
                    if (configManager.getConfigCenter(configCenter.getId()).isPresent()) {
                        return;
                    }
                    //配置管理器中添加配置中心,方便后去读取配置中心的配置信息
                    configManager.addConfigCenter(configCenter);
                    logger.info("use registry as config-center: " + configCenter);

                });
        }
    }

13.2.2.1 如何判断当前注册中心是否可以为配置中心

isUsedRegistryAsConfigCenter

private boolean isUsedRegistryAsCenter(RegistryConfig registryConfig, Supplier<Boolean> usedRegistryAsCenter,
                                           String centerType,
                                           Class<?> extensionClass) {
        final boolean supported;
            //这个useAsConfigCenter参数是来自注册中心的配置 如果配置了这个值则以这个值为准,如果配置了false则这个注册中心不能做为配置中心
        Boolean configuredValue = usedRegistryAsCenter.get();
        if (configuredValue != null) { // If configured, take its value.
            supported = configuredValue.booleanValue();
        } else {                       // Or check the extension existence
            //这个逻辑的话是判断下注册中心的协议是否满足要求,我们例子代码中使用的是zookeeper
            String protocol = registryConfig.getProtocol();
            //这个扩展是否支持的逻辑判断是这样的扫描扩展类 看一下当前扩展类型是否有对应协议的扩展 比如在扩展文件里面这样配置过后是支持的 protocol=xxxImpl
            //动态配置的扩展类型为:interface org.apache.dubbo.common.config.configcenter.DynamicConfigurationFactory
            //zookeeper协议肯定是支持的因为zookeeper协议实现了这个动态配置工厂 ,这个扩展类型为ZookeeperDynamicConfigurationFactory
            //代码位置在dubbo-configcenter-zookeeper包中的org.apache.dubbo.common.config.configcenter.DynamicConfigurationFactory扩展配置中内容为zookeeper=org.apache.dubbo.configcenter.support.zookeeper.ZookeeperDynamicConfigurationFactory
            supported = supportsExtension(extensionClass, protocol);
            //配置中心走注册中心会打印一条日志
            if (logger.isInfoEnabled()) {
                logger.info(format("No value is configured in the registry, the %s extension[name : %s] %s as the %s center"
                    , extensionClass.getSimpleName(), protocol, supported ? "supports" : "does not support", centerType));
            }
        }

        //配置中心走注册中心会打印一条日志
        if (logger.isInfoEnabled()) {
            logger.info(format("The registry[%s] will be %s as the %s center", registryConfig,
                supported ? "used" : "not used", centerType));
        }
        return supported;
    }

这个扩展是否支持的逻辑判断是这样的扫描扩展类 看一下当前扩展类型是否有对应协议的扩展 比如在扩展文件里面这样配置过后是支持的 protocol=xxxImpl
配置中心的动态配置的扩展类型为 org.apache.dubbo.common.config.configcenter.DynamicConfigurationFactory

zookeeper协议肯定是支持的因为zookeeper协议实现了这个动态配置工厂 ,这个扩展类型为ZookeeperDynamicConfigurationFactory代码位置在dubbo-configcenter-zookeeper包中的org.apache.dubbo.common.config.configcenter.DynamicConfigurationFactory扩展配置中内容为

zookeeper=org.apache.dubbo.configcenter.support.zookeeper.ZookeeperDynamicConfigurationFactory

13.2.2.2 注册中心配置转配置中心配置

这个逻辑是registryAsConfigCenter方法,我来贴一下代码:

private ConfigCenterConfig registryAsConfigCenter(RegistryConfig registryConfig) {
        //注册中心协议获取这里例子中的是zookeeper协议
        String protocol = registryConfig.getProtocol();
        //注册中心端口 2181
        Integer port = registryConfig.getPort();
        //在Dubbo中配置信息 很多情况下都以URL形式表示,这里转换后的地址为zookeeper://127.0.0.1:2181
        URL url = URL.valueOf(registryConfig.getAddress(), registryConfig.getScopeModel());
        //生成当前配置中心的id 封装之后的内容为:
        //config-center-zookeeper-127.0.0.1-2181
        String id = "config-center-" + protocol + "-" + url.getHost() + "-" + port;
        //配置中心配置对象创建
        ConfigCenterConfig cc = new ConfigCenterConfig();
        //config-center-zookeeper-127.0.0.1-2181
        cc.setId(id);
        cc.setScopeModel(applicationModel);
        if (cc.getParameters() == null) {
            cc.setParameters(new HashMap<>());
        }
        if (CollectionUtils.isNotEmptyMap(registryConfig.getParameters())) {
            cc.getParameters().putAll(registryConfig.getParameters()); // copy the parameters
        }
        cc.getParameters().put(CLIENT_KEY, registryConfig.getClient());
        //zookeeper
        cc.setProtocol(protocol);
        //2181
        cc.setPort(port);
        if (StringUtils.isNotEmpty(registryConfig.getGroup())) {
            cc.setGroup(registryConfig.getGroup());
        }
        //这个方法转换地址是修复bug用的可以看bug https://github.com/apache/dubbo/issues/6476
        cc.setAddress(getRegistryCompatibleAddress(registryConfig));
        //注册中心分组做为配置中心命名空间 这里为null
        cc.setNamespace(registryConfig.getGroup());
        //zk认证信息
        cc.setUsername(registryConfig.getUsername());
         //zk认证信息
        cc.setPassword(registryConfig.getPassword());
        if (registryConfig.getTimeout() != null) {
            cc.setTimeout(registryConfig.getTimeout().longValue());
        }
        //这个属性注释中已经建议了已经弃用了默认就是false了
        //如果配置中心被赋予最高优先级,它将覆盖所有其他配置,
        cc.setHighestPriority(false);
        return cc;
    }

13.3 配置刷新逻辑

来自AbstractConfig类型的refresh()方法

public void refresh() {
        refreshed.set(true);
        try {
            // check and init before do refresh
            //刷新之前执行的逻辑 这里并做什么逻辑
            preProcessRefresh();
        
            //获取当前域模型的环境信息对象
            Environment environment = getScopeModel().getModelEnvironment();
            List<Map<String, String>> configurationMaps = environment.getConfigurationMaps();

            // Search props starts with PREFIX in order
            String preferredPrefix = null;
            for (String prefix : getPrefixes()) {
                if (ConfigurationUtils.hasSubProperties(configurationMaps, prefix)) {
                    preferredPrefix = prefix;
                    break;
                }
            }
            if (preferredPrefix == null) {
                preferredPrefix = getPrefixes().get(0);
            }
            // Extract sub props (which key was starts with preferredPrefix)
            Collection<Map<String, String>> instanceConfigMaps = environment.getConfigurationMaps(this, preferredPrefix);
            Map<String, String> subProperties = ConfigurationUtils.getSubProperties(instanceConfigMaps, preferredPrefix);
            InmemoryConfiguration subPropsConfiguration = new InmemoryConfiguration(subProperties);

            if (logger.isDebugEnabled()) {
                String idOrName = "";
                if (StringUtils.hasText(this.getId())) {
                    idOrName = "[id=" + this.getId() + "]";
                } else {
                    String name = ReflectUtils.getProperty(this, "getName");
                    if (StringUtils.hasText(name)) {
                        idOrName = "[name=" + name + "]";
                    }
                }
                logger.debug("Refreshing " + this.getClass().getSimpleName() + idOrName +
                    " with prefix [" + preferredPrefix +
                    "], extracted props: " + subProperties);
            }

            assignProperties(this, environment, subProperties, subPropsConfiguration);

            // process extra refresh of subclass, e.g. refresh method configs
            processExtraRefresh(preferredPrefix, subPropsConfiguration);

        } catch (Exception e) {
            logger.error("Failed to override field value of config bean: " + this, e);
            throw new IllegalStateException("Failed to override field value of config bean: " + this, e);
        }

        postProcessRefresh();
    }

13.4 配置中心配置大全

ConfigCenterConfig类型
下面配置信息来自官网
dubbo:config-center 配置

配置中心。对应的配置类:org.apache.dubbo.config.ConfigCenterConfig

属性 对应URL参数 类型 是否必填 缺省值 描述 兼容性
protocol config.protocol string 可选 zookeeper 使用哪个配置中心:apollo、zookeeper、nacos等。 以zookeeper为例 1. 指定protocol,则address可以简化为127.0.0.1:2181; 2. 不指定protocol,则address取值为zookeeper://127.0.0.1:2181 2.7.0+
address config.address string 必填 配置中心地址。 取值参见protocol说明 2.7.0+
highest-priority config.highestPriority boolean 可选 true 来自配置中心的配置项具有最高优先级,即会覆盖本地配置项。 2.7.0+
namespace config.namespace string 可选 dubbo 通常用于多租户隔离,实际含义视具体配置中心而不同。 如: zookeeper - 环境隔离,默认值dubbo; apollo - 区分不同领域的配置集合,默认使用dubboapplication 2.7.0+
cluster config.cluster string 可选 含义视所选定的配置中心而不同。 如Apollo中用来区分不同的配置集群 2.7.0+
group config.group string 可选 dubbo 含义视所选定的配置中心而不同。 nacos - 隔离不同配置集 zookeeper - 隔离不同配置集 2.7.0+
check config.check boolean 可选 true 当配置中心连接失败时,是否终止应用启动。 2.7.0+
config-file config.configFile string 可选 dubbo.properties 全局级配置文件所映射到的key zookeeper - 默认路径/dubbo/config/dubbo/dubbo.properties apollo - dubbo namespace中的dubbo.properties键 2.7.0+
timeout config.timeout integer 3000ms 获取配置的超时时间 2.7.0+
username string 如果配置中心需要做校验,用户名 Apollo暂未启用 2.7.0+
password string 如果配置中心需要做校验,密码 Apollo暂未启用 2.7.0+
parameters Map<string, string> 扩展参数,用来支持不同配置中心的定制化配置参数 2.7.0+
include-spring-env boolean 可选 false 使用Spring框架时支持,为true时,会自动从Spring Environment中读取配置。 默认依次读取 key为dubbo.properties的配置 key为dubbo.properties的PropertySource 2.7.0+
相关实践学习
基于MSE实现微服务的全链路灰度
通过本场景的实验操作,您将了解并实现在线业务的微服务全链路灰度能力。
目录
相关文章
|
1月前
|
监控 Dubbo Java
dubbo学习三:springboot整合dubbo+zookeeper,并使用dubbo管理界面监控服务是否注册到zookeeper上。
这篇文章详细介绍了如何将Spring Boot与Dubbo和Zookeeper整合,并通过Dubbo管理界面监控服务注册情况。
81 0
dubbo学习三:springboot整合dubbo+zookeeper,并使用dubbo管理界面监控服务是否注册到zookeeper上。
|
3月前
|
JSON Dubbo Java
【Dubbo协议指南】揭秘高性能服务通信,选择最佳协议的终极攻略!
【8月更文挑战第24天】在分布式服务架构中,Apache Dubbo作为一款高性能的Java RPC框架,支持多种通信协议,包括Dubbo协议、HTTP协议及Hessian协议等。Dubbo协议是默认选择,采用NIO异步通讯,适用于高要求的内部服务通信。HTTP协议通用性强,利于跨语言调用;Hessian协议则在数据传输效率上有优势。选择合适协议需综合考虑性能需求、序列化方式、网络环境及安全性等因素。通过合理配置,可实现服务性能最优化及系统可靠性提升。
58 3
|
3月前
|
缓存 Dubbo Java
Dubbo服务消费者启动与订阅原理
该文章主要介绍了Dubbo服务消费者启动与订阅的原理,包括服务消费者的启动时机、启动过程以及订阅和感知最新提供者信息的方式。
Dubbo服务消费者启动与订阅原理
|
3月前
|
C# 开发者 Windows
勇敢迈出第一步:手把手教你如何在WPF开源项目中贡献你的第一行代码,从选择项目到提交PR的全过程解析与实战技巧分享
【8月更文挑战第31天】本文指导您如何在Windows Presentation Foundation(WPF)相关的开源项目中贡献代码。无论您是初学者还是有经验的开发者,参与这类项目都能加深对WPF框架的理解并拓展职业履历。文章推荐了一些适合入门的项目如MvvmLight和MahApps.Metro,并详细介绍了从选择项目、设置开发环境到提交代码的全过程。通过具体示例,如添加按钮点击事件处理程序,帮助您迈出第一步。此外,还强调了提交Pull Request时保持专业沟通的重要性。参与开源不仅能提升技能,还能促进社区交流。
44 0
|
3月前
|
缓存 负载均衡 Dubbo
Dubbo服务集群容错原理(重要)
该文章主要介绍了Dubbo服务集群容错的原理,包括集群容错技术的概念、Dubbo中使用的集群容错技术种类及其原理。
|
6月前
|
Dubbo Java 应用服务中间件
微服务学习 | Springboot整合Dubbo+Nacos实现RPC调用
微服务学习 | Springboot整合Dubbo+Nacos实现RPC调用
|
29天前
|
Dubbo Java 应用服务中间件
Spring Cloud Dubbo:微服务通信的高效解决方案
【10月更文挑战第15天】随着信息技术的发展,微服务架构成为企业应用开发的主流。Spring Cloud Dubbo结合了Dubbo的高性能RPC和Spring Cloud的生态系统,提供高效、稳定的微服务通信解决方案。它支持多种通信协议,具备服务注册与发现、负载均衡及容错机制,简化了服务调用的复杂性,使开发者能更专注于业务逻辑的实现。
53 2
|
3月前
|
Dubbo Java 应用服务中间件
💥Spring Cloud Dubbo火爆来袭!微服务通信的终极利器,你知道它有多强大吗?🔥
【8月更文挑战第29天】随着信息技术的发展,微服务架构成为企业应用开发的主流模式,而高效的微服务通信至关重要。Spring Cloud Dubbo通过整合Dubbo与Spring Cloud的优势,提供高性能RPC通信及丰富的生态支持,包括服务注册与发现、负载均衡和容错机制等,简化了服务调用管理并支持多种通信协议,提升了系统的可伸缩性和稳定性,成为微服务通信领域的优选方案。开发者仅需关注业务逻辑,而无需过多关心底层通信细节,使得Spring Cloud Dubbo在未来微服务开发中将更加受到青睐。
85 0
|
1月前
|
Dubbo Java 应用服务中间件
Dubbo学习圣经:从入门到精通 Dubbo3.0 + SpringCloud Alibaba 微服务基础框架
尼恩团队的15大技术圣经,旨在帮助开发者系统化、体系化地掌握核心技术,提升技术实力,从而在面试和工作中脱颖而出。本文介绍了如何使用Dubbo3.0与Spring Cloud Gateway进行整合,解决传统Dubbo架构缺乏HTTP入口的问题,实现高性能的微服务网关。
|
2月前
|
Dubbo 应用服务中间件 Apache
Star 4w+,Apache Dubbo 3.3 全新发布,Triple X 领衔,开启微服务通信新时代
在 Apache Dubbo 突破 4w Star 之际,Apache Dubbo 团队正式宣布,Dubbo 3.3 正式发布!作为全球领先的开源微服务框架,Dubbo 一直致力于为开发者提供高性能、可扩展且灵活的分布式服务解决方案。此次发布的 Dubbo 3.3,通过 Triple X 的全新升级,突破了以往局限,实现了对南北向与东西向流量的全面支持,并提升了对云原生架构的友好性。
139 7