Dubbo點滴(5)之服務註冊中心

來源:互聯網
上載者:User

標籤:dubbo

首先DUBBO本質上是一款RPC架構,不可缺少的2個角色:服務提供者和服務消費者。

已經剖析了服務端暴露連接埠過程。本文簡單說下註冊中心。

1.註冊中心是什麼玩意

這是官網提供的圖例

650) this.width=650;" src="http://s2.51cto.com/wyfs02/M00/8B/F7/wKioL1hd64ujeWFHAAHY0C6Ailg777.png" title="1.png" alt="wKioL1hd64ujeWFHAAHY0C6Ailg777.png" />

通過圖例,可以看出消費者和提供者並不是直接通訊的,中間有個第三者,就是註冊中心。這種結構,可以實現消費者和提供者兩者的依賴,和參數資訊的叢集化。所以這帶來了幾個問題。

  1. 服務註冊

  2. 服務發現

  3. 服務訂閱

  4. 服務通知

2. 服務暴露及服務註冊過程

《Dubbo點滴(4)之暴露服務解析》已經剖析了dubbo協議具體開啟網路連接埠過程。本節內容會隱去這部分內容。因為一個完整的服務暴露,主要涉及2部分內容,1)開啟連接埠等待消費者串連;2)將服務資訊登記到註冊中心,以告知消費者可以串連了。

650) this.width=650;" src="http://s3.51cto.com/wyfs02/M02/8B/FA/wKiom1hd7nHhegDoAADMiy-mF8w911.png" title="2.png" alt="wKiom1hd7nHhegDoAADMiy-mF8w911.png" />

有3點需要說明:

1)首先,根據條件判斷會暴露一個injvm本地服務(step 6);

InjvmProtocol協議完成,主要供同一JVM種的消費者調用,提供RPC效率。

2) 為服務暴露一個dubbo服務(step 12),一般為DubboProtocol完成

3)step 12提供的的服務,註冊到註冊中心(step 13-step 23)。這一步是本文的剖析重點。

3.認識註冊中心

650) this.width=650;" src="http://www.myexception.cn/img/2014/08/01/110353770.jpg" width="854" height="635" alt="110353770.jpg" />

該圖是DUBBO的總體結構圖。重點停留在Resistry層。比較重要的是幾個組件

ZookeeperRegistry :負責與zookeeper進行互動

RegistryProtocol :從註冊中心擷取可用服務,或者將服務註冊到zookeeper,然後提供服務或者提供調用代理。

RegistryDirectory :維護著所有可用的遠程Invoker或者本地的Invoker。這個類實現了NotifyListner。

NotifyListener :負責RegistryDirectory和ZookeeperRegistry的通訊。

FailbackRegistry:繼承自Registry,實現了失敗重試機制。

4. 註冊中心資料模型

650) this.width=650;" src="http://s5.51cto.com/wyfs02/M01/8B/F7/wKioL1hd9GbhoQpFAAB6Ku26nf4144.jpg" title="55.jpg" alt="wKioL1hd9GbhoQpFAAB6Ku26nf4144.jpg" />

流程說明:

  • 服務提供者啟動時

    • 向/dubbo/com.foo.BarService/providers目錄下寫入自己的URL地址。

  • 服務消費者啟動時

    • 訂閱/dubbo/com.foo.BarService/providers目錄下的提供者URL地址。

    • 並向/dubbo/com.foo.BarService/consumers目錄下寫入自己的URL地址。

  • 監控中心啟動時

    • 訂閱/dubbo/com.foo.BarService目錄下的所有提供者和消費者URL地址。

4.Registry 結構樹

650) this.width=650;" src="http://s3.51cto.com/wyfs02/M00/8B/F7/wKioL1hd9eThQ4lUAABw_9KRcyI681.png" title="6.png" alt="wKioL1hd9eThQ4lUAABw_9KRcyI681.png" />

ZookeeperRegistry是常見的註冊中心實現方案,由ZookeeperRegistryFactory負責構造。

AbstractRegistry這個類主要儲存的是已經註冊的服務介面,已經訂閱的服務介面和已經收到通知的介面的URL,不能直接調用。

public abstract class AbstractRegistry implements Registry {    // 本地磁碟緩衝,其中特殊的key值.registies記錄註冊中心列表,其它均為notified服務提供者列表    private final Properties properties = new Properties();    // 檔案快取定時寫入    private final ExecutorService registryCacheExecutor = Executors.newFixedThreadPool(1, new NamedThreadFactory("DubboSaveRegistryCache", true));    //是否是同步儲存檔案    private final boolean syncSaveFile ;    private final AtomicLong lastCacheChanged = new AtomicLong();    private final Set<URL> registered = new ConcurrentHashSet<URL>();    private final ConcurrentMap<URL, Set<NotifyListener>> subscribed = new ConcurrentHashMap<URL, Set<NotifyListener>>();    private final ConcurrentMap<URL, Map<String, List<URL>>> notified = new ConcurrentHashMap<URL, Map<String, List<URL>>>();    ...    }

FailbackRegistry 繼承自AbstractRegistry ,實現了失敗重試機制。

public abstract class FailbackRegistry extends AbstractRegistry {// 定時任務執行器private final ScheduledExecutorService retryExecutor = Executors.newScheduledThreadPool(1, new NamedThreadFactory("DubboRegistryFailedRetryTimer", true));// 失敗重試定時器,定時檢查是否有請求失敗,如有,無限次重試private final ScheduledFuture<?> retryFuture;private final Set<URL> failedRegistered = new ConcurrentHashSet<URL>();private final Set<URL> failedUnregistered = new ConcurrentHashSet<URL>();private final ConcurrentMap<URL, Set<NotifyListener>> failedSubscribed = new ConcurrentHashMap<URL, Set<NotifyListener>>();private final ConcurrentMap<URL, Set<NotifyListener>> failedUnsubscribed = new ConcurrentHashMap<URL, Set<NotifyListener>>();private final ConcurrentMap<URL, Map<NotifyListener, List<URL>>> failedNotified = new ConcurrentHashMap<URL, Map<NotifyListener, List<URL>>>();...}


5.服務提供者啟動的註冊過程

服務提供者啟動時 向/dubbo/com.foo.BarService/providers目錄下寫入自己的URL地址。接下來,找尋下代碼執行路徑。RegistryProtocol 作為註冊中心的核心組件,作為代碼的入口,還要明確一點,這是個註冊登記過程。

//入口public class RegistryProtocol implements Protocol {final Registry registry = getRegistry(originInvoker);final URL registedProviderUrl = getRegistedProviderUrl(originInvoker);registry.register(registedProviderUrl);}public abstract class AbstractRegistry implements Registry {    public void register(URL url) {        if (url == null) {            throw new IllegalArgumentException("register url == null");        }        if (logger.isInfoEnabled()){            logger.info("Register: " + url);        }        registered.add(url);    }...}public abstract class FailbackRegistry extends AbstractRegistry {public void register(URL url) {    super.register(url);    failedRegistered.remove(url);    failedUnregistered.remove(url);    try {        // 向伺服器端發送註冊請求        doRegister(url);    } catch (Exception e) {    ...    }        // 將失敗的註冊請求記錄到失敗列表,定時重試        failedRegistered.add(url);    }    protected abstract void doRegister(URL url);        protected abstract void doUnregister(URL url);        protected abstract void doSubscribe(URL url, NotifyListener listener);        protected abstract void doUnsubscribe(URL url, NotifyListener listener);...}     public class ZookeeperRegistry extends FailbackRegistry {     public ZookeeperRegistry(URL url, ZookeeperTransporter zookeeperTransporter) {        super(url);        //如果provider的url是“0.0.0.0”或者在參數中帶anyHost=true則拋出異常登入位址不存在        if (url.isAnyHost()) {          throw new IllegalStateException("registry address == null");       }        //服務分組(預設“dubbo”)        String group = url.getParameter(Constants.GROUP_KEY, DEFAULT_ROOT);        if (! group.startsWith(Constants.PATH_SEPARATOR)) {            group = Constants.PATH_SEPARATOR + group;        }        //服務分組根地址        this.root = group;        zkClient = zookeeperTransporter.connect(url);        //添加狀態監聽器        zkClient.addStateListener(new StateListener() {            public void stateChanged(int state) {               if (state == RECONNECTED) {               try {          recover();       } catch (Exception e) {          logger.error(e.getMessage(), e);       }               }            }        });    }      protected void doRegister(URL url) {            try {                //串連註冊中心註冊,在zk上建立節點               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);            }        } }

6. 註冊中心關係類圖

650) this.width=650;" src="http://s1.51cto.com/wyfs02/M01/8B/FB/wKiom1hd--Pyk5anAADYmQZPcMI910.png" title="22.png" alt="wKiom1hd--Pyk5anAADYmQZPcMI910.png" />

重要概念:

ZookeeperRegistry :負責與zookeeper進行互動

RegistryProtocol :從註冊中心擷取可用服務,或者將服務註冊到zookeeper,然後提供服務或者提供調用代理。

RegistryDirectory :維護著所有可用的遠程Invoker或者本地的Invoker。這個類實現了NotifyListner。

NotifyListener :負責RegistryDirectory和ZookeeperRegistry的通訊。

FailbackRegistry:繼承自Registry,實現了失敗重試機制。

本文出自 “簡單” 部落格,請務必保留此出處http://dba10g.blog.51cto.com/764602/1885719

Dubbo點滴(5)之服務註冊中心

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.