dubbo的服务注册原理分析


前言

Dubbo的服务注册原理主要基于注册中心来实现服务的动态发布和引用,其中Zookeeper是常用的注册中心之一
本文是基于 dubbo-3.1.0 版本,zookeeper注册中心进行分析
在这里插入图片描述


一、getRegistry

1、RegistryProtocol.export

	@Override
    public <T> Exporter<T> export(final Invoker<T> originInvoker) throws RpcException {
        // url to registry 获取注册中心
        final Registry registry = getRegistry(registryUrl);
        final URL registeredProviderUrl = getUrlToRegistry(providerUrl, registryUrl);

        // decide if we need to delay publish (provider itself and registry should both need to register)
        // 是否延迟发布 提供者本身和注册表都需要注册
        boolean register = providerUrl.getParameter(REGISTER_KEY, true) && registryUrl.getParameter(REGISTER_KEY, true);
        if (register) {
        	// 存在注册中心,需要注册
            register(registry, registeredProviderUrl);
        }
    }

2、RegistryProtocol.getRegistry

  • 获取对应的registryFactory
  • 根据具体协议,从registryFactory中获得指定的注册中心实现
    从org.apache.dubbo.registry.RegistryFactory,可以看到扩展点有
service-discovery-registry=org.apache.dubbo.registry.client.ServiceDiscoveryRegistryFactory
wrapper=org.apache.dubbo.registry.RegistryFactoryWrapper
multicast=org.apache.dubbo.registry.multicast.MulticastRegistryFactory
zookeeper=org.apache.dubbo.registry.zookeeper.ZookeeperRegistryFactory
nacos=org.apache.dubbo.registry.nacos.NacosRegistryFactory
multiple=org.apache.dubbo.registry.multiple.MultipleRegistryFactory
    protected Registry getRegistry(final URL registryUrl) {
    	// 获取registryFactory扩展点
        RegistryFactory registryFactory = ScopeModelUtil.getExtensionLoader(RegistryFactory.class, registryUrl.getScopeModel()).getAdaptiveExtension();
        // 通过扩展点获取对应的注册中心
        return registryFactory.getRegistry(registryUrl);
    }

3、RegistryFactory.getRegistry

RegistryFactory的实现, 发现它里面有一个自适应的方法,根据url中protocol传入的值进行适配

@SPI(scope = APPLICATION)
public interface RegistryFactory {

    /**
     * Connect to the registry
     * <p>
     * Connecting the registry needs to support the contract: <br>
     * 1. When the check=false is set, the connection is not checked, otherwise the exception is thrown when disconnection <br>
     * 2. Support username:password authority authentication on URL.<br>
     * 3. Support the backup=10.20.153.10 candidate registry cluster address.<br>
     * 4. Support file=registry.cache local disk file cache.<br>
     * 5. Support the timeout=1000 request timeout setting.<br>
     * 6. Support session=60000 session timeout or expiration settings.<br>
     *
     * @param url Registry address, is not allowed to be empty
     * @return Registry reference, never return empty value
     */
    @Adaptive({PROTOCOL_KEY})
    Registry getRegistry(URL url);

}

代理类为RegistryFactory$Adaptive
如果没有特殊配置,那从发布的原理我们知道,url中的protocol默认为zookeeper,那么这个时候根据zookeeper获得的spi扩展点应该是RegistryFactoryWrapper->ZookeeperRegistryFactory
通过RegistryFactoryWrapper的装饰,最后返回ListenerRegistryWrapper的包装类

4、AbstractRegistryFactory.getRegistry

通过锁保证只创建一个registry

public abstract class AbstractRegistryFactory implements RegistryFactory, ScopeModelAware {
    @Override
    public Registry getRegistry(URL url) {
        // 省略部分代码***
        // Lock the registry access process to ensure a single instance of the registry
        registryManager.getRegistryLock().lock();
        try {
            // double check
            // fix https://github.com/apache/dubbo/issues/7265.
            defaultNopRegistry = registryManager.getDefaultNopRegistryIfDestroyed();
            if (null != defaultNopRegistry) {
                return defaultNopRegistry;
            }
			// 获取缓存
            registry = registryManager.getRegistry(key);
            if (registry != null) {
                return registry;
            }

			// 创建registry ,交由具体的扩展点去实现,这里是ZookeeperRegistryFactory
            // create registry by spi/ioc
            registry = createRegistry(url);
            if (check && registry == null) {
                throw new IllegalStateException("Can not create registry " + url);
            }

            if (registry != null) {
                registryManager.putRegistry(key, registry);
            }
        } catch (Exception e) {
            if (check) {
                throw new RuntimeException("Can not create registry " + url, e);
            } else {
                // 1-11 Failed to obtain or create registry (service) object.
                LOGGER.warn("1-11", "", "",
                    "Failed to obtain or create registry ", e);
            }
        } finally {
            // Release the lock
            registryManager.getRegistryLock().unlock();
        }

        return registry;
    }

}

一、getRegistry

1、RegistryProtocol.export

	@Override
    public <T> Exporter<T> export(final Invoker<T> originInvoker) throws RpcException {
        // url to registry 获取注册中心
        final Registry registry = getRegistry(registryUrl);
        final URL registeredProviderUrl = getUrlToRegistry(providerUrl, registryUrl);

        // decide if we need to delay publish (provider itself and registry should both need to register)
        // 是否延迟发布 提供者本身和注册表都需要注册
        boolean register = providerUrl.getParameter(REGISTER_KEY, true) && registryUrl.getParameter(REGISTER_KEY, true);
        if (register) {
        	// 存在注册中心,需要注册
            register(registry, registeredProviderUrl);
        }
    }
    private void register(Registry registry, URL registeredProviderUrl) {
        registry.register(registeredProviderUrl);
    }

2、ListenerRegistryWrapper.register

通过上面我们可以知道返回的是ListenerRegistryWrapper的包装类,目的是增加了一个监听器的处理过程。

public class ListenerRegistryWrapper implements Registry {
    @Override
    public void register(URL url) {
        try {
            if (registry != null) {
                registry.register(url);
            }
        } finally {
            if (CollectionUtils.isNotEmpty(listeners) && !UrlUtils.isConsumer(url)) {
                RuntimeException exception = null;
                for (RegistryServiceListener listener : listeners) {
                    if (listener != null) {
                        try {
                        	// 后置处理 监控拓展
                            listener.onRegister(url, registry);
                        } catch (RuntimeException t) {
                            logger.error(t.getMessage(), t);
                            exception = t;
                        }
                    }
                }
                if (exception != null) {
                    throw exception;
                }
            }
        }
    }

 }

3、FailbackRegistry.register

public abstract class FailbackRegistry extends AbstractRegistry {
@Override
    public void register(URL url) {
        if (!acceptable(url)) {
            logger.info("URL " + url + " will not be registered to Registry. Registry " + this.getUrl() + " does not accept service of this protocol type.");
            return;
        }
        super.register(url);
        removeFailedRegistered(url);
        removeFailedUnregistered(url);
        try {
            // Sending a registration request to the server side
            // 开始注册
            doRegister(url);
        } catch (Exception e) {
            Throwable t = e;

            // If the startup detection is opened, the Exception is thrown directly.
            boolean check = getUrl().getParameter(Constants.CHECK_KEY, true)
                    && url.getParameter(Constants.CHECK_KEY, true)
                    && (url.getPort() != 0);
            boolean skipFailback = t instanceof SkipFailbackWrapperException;
            if (check || skipFailback) {
                if (skipFailback) {
                    t = t.getCause();
                }
                throw new IllegalStateException("Failed to register " + url + " to registry " + getUrl().getAddress() + ", cause: " + t.getMessage(), t);
            } else {
                logger.error("Failed to register " + url + ", waiting for retry, cause: " + t.getMessage(), t);
            }

            // Record a failed registration request to a failed list, retry regularly
            addFailedRegistered(url);
        }
    }
}

4、ZookeeperRegistry.doRegister

public class ZookeeperRegistry extends CacheableFailbackRegistry {
    @Override
    public void doRegister(URL url) {
        try {
            checkDestroyed();
            // 想zk中创建节点 实现zk监听的机制
            zkClient.create(toUrlPath(url), url.getParameter(DYNAMIC_KEY, true));
        } catch (Throwable e) {
            throw new RpcException("Failed to register " + url + " to zookeeper " + getUrl() + ", cause: " + e.getMessage(), e);
        }
    }
}

通过zk节点的注册,就完成了服务注册了


在这里插入图片描述

总结

Dubbo的服务注册原理基于注册中心实现服务的动态发布和引用。服务提供者在启动时将自己的服务信息注册到注册中心,服务消费者在需要调用服务时从注册中心查询服务提供者列表,并进行服务调用。注册中心在Dubbo系统中占据了重要的地位,它实现了服务的动态发布和引用、服务健康检查、负载均衡和配置管理等功能,为Dubbo服务的稳定运行提供了有力保障。

  • 7
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值