dubbo_registry註冊中心概述

dubbo中服務的發佈和訂閱都是通過register來實現的,

registeryService定義了註冊模塊向外提供的服務有哪些

public interface RegistryService {

    /**
     * 註冊數據,比如:提供者地址,消費者地址,路由規則,覆蓋規則,等數據。
     * 
     * 註冊需處理契約:<br>
     * 1. 當URL設置了check=false時,註冊失敗後不報錯,在後臺定時重試,否則拋出異常。<br>
     * 2. 當URL設置了dynamic=false參數,則需持久存儲,否則,當註冊者出現斷電等情況異常退出時,需自動刪除。<br>
     * 3. 當URL設置了category=routers時,表示分類存儲,缺省類別爲providers,可按分類部分通知數據。<br>
     * 4. 當註冊中心重啓,網絡抖動,不能丟失數據,包括斷線自動刪除數據。<br>
     * 5. 允許URI相同但參數不同的URL並存,不能覆蓋。<br>
     * 
     * @param url 註冊信息,不允許爲空,如:dubbo://10.20.153.10/com.alibaba.foo.BarService?version=1.0.0&application=kylin
     */
    void register(URL url);

    /**
     * 取消註冊.
     * 
     * 取消註冊需處理契約:<br>
     * 1. 如果是dynamic=false的持久存儲數據,找不到註冊數據,則拋IllegalStateException,否則忽略。<br>
     * 2. 按全URL匹配取消註冊。<br>
     * 
     * @param url 註冊信息,不允許爲空,如:dubbo://10.20.153.10/com.alibaba.foo.BarService?version=1.0.0&application=kylin
     */
    void unregister(URL url);

    /**
     * 訂閱符合條件的已註冊數據,當有註冊數據變更時自動推送.
     * 
     * 訂閱需處理契約:<br>
     * 1. 當URL設置了check=false時,訂閱失敗後不報錯,在後臺定時重試。<br>
     * 2. 當URL設置了category=routers,只通知指定分類的數據,多個分類用逗號分隔,並允許星號通配,表示訂閱所有分類數據。<br>
     * 3. 允許以interface,group,version,classifier作爲條件查詢,如:interface=com.alibaba.foo.BarService&version=1.0.0<br>
     * 4. 並且查詢條件允許星號通配,訂閱所有接口的所有分組的所有版本,或:interface=*&group=*&version=*&classifier=*<br>
     * 5. 當註冊中心重啓,網絡抖動,需自動恢復訂閱請求。<br>
     * 6. 允許URI相同但參數不同的URL並存,不能覆蓋。<br>
     * 7. 必須阻塞訂閱過程,等第一次通知完後再返回。<br>
     * 
     * @param url 訂閱條件,不允許爲空,如:consumer://10.20.153.10/com.alibaba.foo.BarService?version=1.0.0&application=kylin
     * @param listener 變更事件監聽器,不允許爲空
     */
    void subscribe(URL url, NotifyListener listener);

    /**
     * 取消訂閱.
     * 
     * 取消訂閱需處理契約:<br>
     * 1. 如果沒有訂閱,直接忽略。<br>
     * 2. 按全URL匹配取消訂閱。<br>
     * 
     * @param url 訂閱條件,不允許爲空,如:consumer://10.20.153.10/com.alibaba.foo.BarService?version=1.0.0&application=kylin
     * @param listener 變更事件監聽器,不允許爲空
     */
    void unsubscribe(URL url, NotifyListener listener);

    /**
     * 查詢符合條件的已註冊數據,與訂閱的推模式相對應,這裏爲拉模式,只返回一次結果。
     * 
     * @see com.alibaba.dubbo.registry.NotifyListener#notify(List)
     * @param url 查詢條件,不允許爲空,如:consumer://10.20.153.10/com.alibaba.foo.BarService?version=1.0.0&application=kylin
     * @return 已註冊信息列表,可能爲空,含義同{@link com.alibaba.dubbo.registry.NotifyListener#notify(List<URL>)}的參數。
     */
    List<URL> lookup(URL url);

}


Registry接口繼承了以上接口,來實現具體的註冊操作:public interface Registry extends Node, RegistryService {}


FailbackRegistry 繼承了 AbstractRegistry,主要完成失敗後註冊的定時重新連接,


    public FailbackRegistry(URL url) {
        super(url);
        int retryPeriod = url.getParameter(Constants.REGISTRY_RETRY_PERIOD_KEY, Constants.DEFAULT_REGISTRY_RETRY_PERIOD);
        this.retryFuture = retryExecutor.scheduleWithFixedDelay(new Runnable() {
            public void run() {
                // 檢測並連接註冊中心
                try {
                    retry();
                } catch (Throwable t) { // 防禦性容錯
                    logger.error("Unexpected error occur at failed retry, cause: " + t.getMessage(), t);
                }
            }
        }, retryPeriod, retryPeriod, TimeUnit.MILLISECONDS);
    }

FailbackRegistry類也是抽象類,只完成了RegistryService接口的功能框架,具體的註冊/訂閱方法由具體的了類實現

    @Override
    public void register(URL url) {
        super.register(url);
        failedRegistered.remove(url);
        failedUnregistered.remove(url);
        try {
            // 向服務器端發送註冊請求
            doRegister(url);
        } catch (Exception e) {
            Throwable t = e;

            // 如果開啓了啓動時檢測,則直接拋出異常
            boolean check = getUrl().getParameter(Constants.CHECK_KEY, true)
                    && url.getParameter(Constants.CHECK_KEY, true)
                    && ! Constants.CONSUMER_PROTOCOL.equals(url.getProtocol());
            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);
            }

            // 將失敗的註冊請求記錄到失敗列表,定時重試
            failedRegistered.add(url);
        }
    }

doRegister(url)由具體子類實現,如ZookeeperRegistry類

public class ZookeeperRegistry extends FailbackRegistry {

    protected void doRegister(URL url) {
        try {
        	zkClient.create(toUrlPath(url), url.getParameter(Constants.DYNAMIC_KEY, true));
        } catch (Throwable e) {
            throw new RpcException("Failed to register " + url + " to zookeeper " + getUrl() + ", cause: " + e.getMessage(), e);
        }
    }

註冊工廠,通過鎖保證註冊中心單一實例

public interface RegistryFactory {

    /**
     * 連接註冊中心.
     * 
     * 連接註冊中心需處理契約:<br>
     * 1. 當設置check=false時表示不檢查連接,否則在連接不上時拋出異常。<br>
     * 2. 支持URL上的username:password權限認證。<br>
     * 3. 支持backup=10.20.153.10備選註冊中心集羣地址。<br>
     * 4. 支持file=registry.cache本地磁盤文件緩存。<br>
     * 5. 支持timeout=1000請求超時設置。<br>
     * 6. 支持session=60000會話超時或過期設置。<br>
     * 
     * @param url 註冊中心地址,不允許爲空
     * @return 註冊中心引用,總不返回空
     */
    @Adaptive({"protocol"})
    Registry getRegistry(URL url);

}

   public Registry getRegistry(URL url) {
    	url = url.setPath(RegistryService.class.getName())
    			.addParameter(Constants.INTERFACE_KEY, RegistryService.class.getName())
    			.removeParameters(Constants.EXPORT_KEY, Constants.REFER_KEY);
    	String key = url.toServiceString();
        // 鎖定註冊中心獲取過程,保證註冊中心單一實例
        LOCK.lock();
        try {
            Registry registry = REGISTRIES.get(key);
            if (registry != null) {
                return registry;
            }
            registry = createRegistry(url);
            if (registry == null) {
                throw new IllegalStateException("Can not create registry " + url);
            }
            REGISTRIES.put(key, registry);
            return registry;
        } finally {
            // 釋放鎖
            LOCK.unlock();
        }
    }



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章