1. 程式人生 > >Dubbo實戰介紹2

Dubbo實戰介紹2

註冊中心

dubbo支援多註冊中心,不僅支援多種形式的註冊中心,還支援向多個註冊中心註冊。目前dubbo支援的註冊中心有如下四種

Multicast註冊中心

   該註冊中心不需要啟動任何中心節點,只要廣播地址一樣,就可以互相發現。組播受網路結果影響,只適合小規模的應用或開發階段使用。

ZooKeeper 註冊中心

   是一個樹形的目錄服務,為分散式應用提供一致性服務,還支援變更推送功能,推薦生產環境使用

Redis註冊中心

   基於redis實現的註冊中心,使用key/value結構儲存服務的url地址和過期時間,同時使用redis的publish/subscribe事件通知資料變更。

Simple註冊中心

   它本身就是一個dubbo服務,可以減少第三方的依賴,是整體通訊方式一致。

由於dubbo建議使用zk作為註冊中心,所以本文主要介紹zk註冊中心。

我們在服務提供者、消費者的配置檔案使用了<dubbo:registry/>標籤後指定zk的地址後,就可以使用zk註冊中心了配置如下,兩種方式

<dubbo:registry address="zookeeper://127.0.0.1:2181"/>
<dubbo:registry protocol="zookeeper" address="127.0.0.1:2181"/>

dubbo目前支援zkclient和curator兩種zk的客戶端實現,預設是zkclient,如果想要使用curator,則可以定製client="curator"

<dubbo:registry address="zookeeper://127.0.0.1:2181" client="curator"/>

還可以使用group屬性將同一個zk分成多組註冊中心,程式碼如下

<dubbo:registry id="shanghairegistry" address="zookeeper://127.0.0.1:2181" group="shanghai"/>
<dubbo:registry id="beijingregistry"  address="zookeeper://127.0.0.1:2181" group="beijing"/>

前面說的都是單機配置,那麼zk的叢集配置方式呢?兩種方式如下  

<dubbo:registry address="zookeeper://127.0.0.1:2181?backup=127.0.0.2:2181,127.0.0.3:2181" />
<dubbo:registry protocol="zookeeper" address="127.0.0.1:2181,127.0.0.2:2181,127.0.0.3:2181" />

除了可以向zk的叢集模式註冊中心註冊,還可以向多個註冊中心註冊

<dubbo:registry id= "shanghairegistry" address="zookeeper://127.0.0.1:2181"/>
<dubbo:registry id= "beijingregistry" address="zookeeper://127.0.0.1:2182"/>
<dubbo:service interface="com.yang.test.api.TestService" ref="testServcie" registry="shanghairegistry,beijingregistry"/>

服務暴露

在通過註冊中心註冊後,是如何提供服務給消費者使用的呢?這就需要<dubbo:service/>標籤進行服務暴露了,用法如下

<dubbo:service interface="com.yang.test.api.TestService" ref="testServcie"/>

其中,interface屬性提供服務的介面,ref屬性是該介面的具體實現類的引用。

如果服務需要預熱的時間,比如初始化快取,等待相關資源就位等,可以使用delay屬性進行服務延遲暴露,用法如下

<dubbo:service interface="com.yang.test.api.TestService" ref="testServcie" delay="5000"/> //或者設定-1,表示延遲到spring初始化完成後暴露服務

如果一個服務的併發量過大,超出了伺服器的承載能力,可以使用executes屬性控制併發。

<dubbo:service interface="com.yang.test.api.TestService" ref="testServcie" executes="10"/>//併發執行(或佔用的執行緒池的執行緒數)不能超過10個

除了限制介面,還可以具體到介面內的某一個方法,程式碼如下

<dubbo:service interface="com.yang.test.api.TestService" ref="testServcie">
    <dubbo:method name="sayHello" executes="10"/>
</dubbo:service>

以上是從提供者實現的併發控制,客戶端同樣可以實現控制併發,即通過active屬性限制程式碼如下

<dubbo:service interface="com.yang.test.api.TestService" ref="testServcie" actives="10" />//限制每個客戶端的併發執行(佔線程的請求數)不超過10個

同服務提供者一樣,也可以限制到具體的方法

<dubbo:service interface="com.yang.test.api.TestService" ref="testServcie">
        <dubbo:method name="sayHello" actives="10"/>
        <!--不建議在客戶端控制併發,應由服務提供者來控制-->
 </dubbo:service>

如果執行緒超過了給定的值,就會報異常。

為了保障服務的 穩定性,除了限制併發執行緒,還可以限制服務端的連結數量。

<dubbo:protocol name="dubbo" port="20880" accepts="10"/>
<dubbo:provider protocol="dubbo" accepts="10"/>

同樣,也可以限制客戶端的使用連線數量

<dubbo:service interface="com.yang.test.api.TestService" ref="testServcie" connections="10"/>
<dubbo:reference id="testService" interface="com.yang.test.api.TestService" connections="10"/>

如果<dubbo:service/> <dubbo:reference/> 都配置了connections,則<dubbo:reference/>優先,由於服務提供者更瞭解自身的承載能力,建議服務提供者控制連線數。

在服務報暴露過程中,除了控制併發,控制連線數,服務隔離也是一項重要的措施,dubbo提供了分組隔離,即前面的group屬性分組。

引用服務

在服務提供者暴露了服務後,消費者就可以使用如下方式引用服務了。

 <dubbo:reference id="testService" interface="com.yang.test.api.TestService"/>

在預設情況下使用同步方式遠端呼叫的,如果想使用非同步方式,則可以設定async屬性為true,並使用Future獲取返回值,程式碼如下

<dubbo:reference id="testService" interface="com.yang.test.api.TestService">
    <dubbo:method name="sayHello" async="true"/>
</dubbo:reference>

然後在程式碼中通過以下方式非同步呼叫

@RestController
@RequestMapping("/")
public class TestController {

    @Autowired
    private TestService testService;

    @RequestMapping("test")
    public String hello() throws Exception{
        testService.sayHello("Hello springboot-dubbo!");
        //拿到future引用
        Future<String> future = RpcContext.getContext().getFuture();
        //如果已返回,則直接拿到返回值,否則執行緒等待(wait),直到拿到返回值,執行緒才會被喚醒(notify)
        String result = future.get();
        return result;
    }
}

在非同步呼叫中還可以設定是否需要等待發送和返回值,設定如下

sent = "true" ,等待訊息發出,訊息傳送失敗丟擲異常。

sent =  "false" 不等待訊息發出,將訊息放入I/O佇列,即可返回。

return = "false" 只是想非同步,完全忽略返回值 以減少Future物件的建立和管理

<dubbo:reference id="testService" interface="com.yang.test.api.TestService">
        <dubbo:method name="sayHello" async="true" sent="true"/>
</dubbo:reference>
<dubbo:reference id="testService" interface="com.yang.test.api.TestService">
        <dubbo:method name="sayHello" async="true" sent="false"/>
    </dubbo:reference>
<dubbo:reference id="testService" interface="com.yang.test.api.TestService">
     <dubbo:method name="sayHello" async="true" return="false"/>
</dubbo:reference>

Dubbo中的非同步呼叫時基於N/O的非阻塞機制實現的,客戶端不需要開始多執行緒即可實現,相對執行緒開銷小。

Dubbo回撥

Dubbo遠端呼叫過程中如果出現了異常或著需要回調,則可以使用dubbo的事件通知機制,主要一下三總

oninvoke(原引數1,原引數2。。。) 為在發起遠端呼叫之前觸發的事件

onreturn(返回值,原引數1,原引數2。。。) 為在遠端呼叫之後的回撥事件

onthrow(Throwable ex原引數1,原引數2。。。,) 為出現異常時候觸發的事件,可以在該事件實現服務降級。

在消費者實現事件通知時候,先定義一個INotify,並實現相關業務。

public interface INotify {
    void onreturn(String resStr,String inSter);
    void onthrow(Throwable ex,String resStr,String inSter);
    void oninvoke(String resStr,String inSter);
}

實現介面

public class notiryImpl implements INotify{
    @Override
    public void onreturn(String resStr, String inSter) {
        System.out.println("after");
    }

    @Override
    public void onthrow(Throwable ex, String resStr, String inSter) {
        System.out.println("yichang");
    }

    @Override
    public void oninvoke(String resStr, String inSter) {
        System.out.println("before");
    }
}

然後就是在配置檔案中配置

<dubbo:reference id="testService" interface="com.yang.test.api.TestService">
        <dubbo:method name="sayHello" async="true" onreturn="notify.onreturn"                 onthrow="notify.onthrow"/>
</dubbo:reference>

Dubbo快取

dubbo為了加速熱門資料的訪問速度,提供了宣告式快取,可以在消費方配置cache屬性開始快取功能.

<dubbo:reference id="testService" interface="com.yang.test.api.TestService" cache="lru" />

快取型別:

   lru 基於最近最少使用原則刪除多餘的快取,保持最熱的資料被快取

  Threadlocal:當前的執行緒快取   jache :如jsr107繼承,可以橋接各種快取實現。