Dubbo 延遲服務暴露

前言

你們好,今天開始給你們分享 — Dubbo 專題之 Dubbo 延遲服務暴露。在前一個章節中咱們介紹了 Dubbo StubMock,咱們例舉了常見的使用場景而且進行了源碼解析來分析其實現原理,同時咱們知道 Dubbo StubMock 都是基於對調用代理對象的包裝實現的,這樣能夠爲咱們在調用服務時作一些前置或後置處理工做。有的小夥伴可能會遇到這樣的場景:在咱們的應用服務中有不少的本地緩存或者分佈式緩存,這些緩存有可能須要加載一段時間那麼在這個緩存加載過程當中咱們但願接口不要對外提供服務,那有沒有一種機制讓咱們對緩存加載完成後再暴露服務的機制呢?那麼在本章節咱們會經過介紹 Dubbo 延遲暴露服務來解決這個問題。那什麼是延遲服務暴露?以及延遲服務暴露的實現原理是什麼呢?下面就讓咱們快速開始吧!java

1. 延遲服務暴露簡介

在當前咱們使用的Dubbo2.7.x版本中服務暴露時機是 Spring 容器啓動完成並廣播出事件 ApplicationContextEvent 時才進行對服務暴露。那這裏所謂的延遲暴露也就是在接收到 ApplicationContextEvent 事件後開始一個指定時間的延遲直到延遲時間到纔開始對服務進行暴露。延遲服務暴露的核心就是一個延遲調度器,當延遲時間到就開始進行服務暴露。其配置參數爲:delay="5000",這裏的時間單位爲毫秒。git

Tips:其餘的 Dubbo 版本的服務暴露可能有一些出入,讀者以最新版本爲主。

2. 使用方式

延遲服務暴露能夠經過 XML 或者註解的方式進行配置且指定的延遲時間單位爲毫秒。spring

2.1 XML 配置方式

<!--延遲1秒暴露Dubbo服務-->
    <dubbo:service interface="com.muke.dubbocourse.protocol.api.BookFacade" ref="bookFacade" delay="1000" />

若是配置delay="-1"則表示在 Spring 容器初始化完後再暴露服務。數據庫

2.2 註解配置方式

@DubboService(delay = 1000)
public class BookFacadeImpl implements BookFacade {

}

使用@DubboService註解或@Service註解。delay = 1000表示延遲1秒後才進行服務暴露。apache

3. 使用場景

經過上面的延遲服務暴露的簡介咱們能夠了解到:延遲服務暴露其實就是針對須要暴露的服務配置一個固定的延遲時間,延遲時間一到當即開始服務的暴露。那麼咱們基於上面的服務暴露的時效性咱們簡單的介紹一些工做中常使用的場景:編程

  1. 緩存預熱:當咱們的暴露服務須要依賴一些靜態數據,這些靜態數據是經過加載數據庫或者文件而後緩存到應用內存中。此時咱們能夠經過在服務延遲暴露的時間段內進行緩存預加載。
  2. 依賴資源:假設咱們對外提供的服務須要依賴另一個服務,而另一個服務的暴露時間比較緩慢,那麼咱們就能夠把當前對外暴露的服務進行延遲暴露,這樣就能夠減小當調用依賴服務時出現超時異常的狀況。

4. 示例演示

咱們一樣以獲取圖書列表爲例來進行演示。項目結構以下:bootstrap

idea

由於延遲服務暴露是配置服務提供端,全部咱們這裏只看服務提供者的 XML 配置dubbo-provider-xml.xmlapi

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:dubbo="http://dubbo.apache.org/schema/dubbo"
       xmlns="http://www.springframework.org/schema/beans"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
       http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd">

    <dubbo:application name="demo-provider" metadata-type="remote"/>

   <!--註冊中心-->
    <dubbo:registry address="zookeeper://127.0.0.1:2181"/>

    <bean id="bookFacade" class="com.muke.dubbocourse.delayexport.provider.BookFacadeImpl"/>

    <!--延遲1秒暴露Dubbo服務-->
    <dubbo:service interface="com.muke.dubbocourse.common.api.BookFacade" ref="bookFacade" delay="1000"/>

</beans>

上面的 XML 配置中主要配置了delay="1000"表示等 Spring 容器啓動完成後服務延遲1秒鐘後纔開始暴露服務。其註解配置也是相似就再也不演示。緩存

5. 實現原理

下面咱們簡單的經過服務暴露的源碼進行分析。咱們都知道當 Spring 容器啓動完成會發出 ApplicationContextEvent 事件,咱們能夠看到這個`org.apache.dubbo.config.spring.context
.DubboBootstrapApplicationListener#
onApplicationContextEvent`方法核心代碼:微信

public void onApplicationContextEvent(ApplicationContextEvent event) {
        if (event instanceof ContextRefreshedEvent) {
            //Spring 容器啓動完成
            onContextRefreshedEvent((ContextRefreshedEvent) event);
        } else if (event instanceof ContextClosedEvent) {
            //Spring 容器關閉
            onContextClosedEvent((ContextClosedEvent) event);
        }
    }

當接收到ContextRefreshedEvent事件後會最終會調用`org.apache.dubbo.config.bootstrap.
DubboBootstrap#start`方法啓動服務註冊核心代碼以下:

public DubboBootstrap start() {
         //判斷服務是否啓動 防止重複暴露服務 注意:這裏是原子操做
        if (started.compareAndSet(false, true)) {
            initialize();
            //..
            // 暴露Dubbo服務
            exportServices();

            //...
        }
        return this;
    }

上面的代碼先進行原子操做去設置啓動標識防止重複暴露服務,其exportServices代碼以下:

/***
     *
     * dubbo服務導出
     *
     * @author liyong
     * @date 16:23 2020-03-01
     * @param
     * @exception
     * @return void
     **/
    private void exportServices() {
        //循環全部須要服務暴露的配置
        configManager.getServices().forEach(sc -> {
            // TODO, compatible with ServiceConfig.export()
            ServiceConfig serviceConfig = (ServiceConfig) sc;
            serviceConfig.setBootstrap(this);

            //是否異步導出
            if (exportAsync) {
                //獲取線程池
                ExecutorService executor = executorRepository.getServiceExporterExecutor();
                Future<?> future = executor.submit(() -> {
                    //異步服務暴露
                    sc.export();
                });
                asyncExportingFutures.add(future);
            } else {
                //同步服務暴露導出
                sc.export();
                exportedServices.add(sc);
            }
        });
    }

上面的代碼是循環對全部的 Dubbo 服務進行暴露,注意這裏有一個exportAsync標識來判斷是否異步暴露服務(異步暴露服務是指在另外的線程執行不阻塞當前線程)。下面咱們看到主要的服務暴露代碼org.apache.dubbo.config.ServiceConfig#export方法:

/**
     *
     * 服務暴露
     *
     * @author liyong 
     * @date 10:55 PM 2020/11/18 
     * @param  
     * @exception 
     * @return void 
     **/
    public synchronized void export() {

       //...

        //是否延遲暴露判斷
        if (shouldDelay()) {
            //延遲暴露
            DELAY_EXPORT_EXECUTOR.schedule(this::doExport, getDelay(), TimeUnit.MILLISECONDS);
        } else {
            //服務暴露
            doExport();
        }
    }

上面便是咱們延遲服務暴露的核心代碼 DELAY_EXPORT_EXECUTOR.schedule(this::doExport, getDelay(), TimeUnit.MILLISECONDS)使用延時調度器進行服務暴露。

6. 小結

在本小節中咱們主要學習了 Dubbo 中延遲服務暴露以及使用方式,同時也分析了延遲服務暴露實現的原理,其本質上是經過延遲調度器進行服務暴露,其中延遲調度器是關鍵所在。

本節課程的重點以下:

  1. 理解 Dubbo 延遲服務暴露
  2. 瞭解了延遲服務暴露的使用方式
  3. 瞭解延遲服務暴露使用場景
  4. 瞭解 延遲服務暴露實現原理

做者

我的從事金融行業,就任過易極付、思建科技、某網約車平臺等重慶一流技術團隊,目前就任於某銀行負責統一支付系統建設。自身對金融行業有強烈的愛好。同時也實踐大數據、數據存儲、自動化集成和部署、分佈式微服務、響應式編程、人工智能等領域。同時也熱衷於技術分享創立公衆號和博客站點對知識體系進行分享。關注公衆號: 青年IT男 獲取最新技術文章推送!

博客地址: http://youngitman.tech

微信公衆號:

相關文章
相關標籤/搜索