分佈式RPC系統框架Dubbo

導讀

  Apache Dubbo是一款高性能輕量級開源Java RPC框架,它提供了三大核心能力;面向接口遠程方法調用智能容錯負載均衡,以及服務自動註冊發現html

dubbo官網:點我直達java

第一個Dubbo程序(小試牛刀)

建立業務接口工程

項目結構

建立包和接口類

安裝項目

建立提供者Provider工程

項目結構

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.cyb</groupId>
    <artifactId>02-first-provider</artifactId>
    <version>1.0-SNAPSHOT</version>

    <!--編譯器依賴-->
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>13</maven.compiler.source>
        <maven.compiler.target>13</maven.compiler.target>
        <!--自定義版本號-->
        <spring-version>4.3.16.RELEASE</spring-version>
    </properties>
    <dependencies>
        <!--自定義工程依賴-->
        <dependency>
            <groupId>org.cyb</groupId>
            <artifactId>01-common</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <!--dubbo依賴-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>dubbo</artifactId>
            <version>2.6.7</version>
        </dependency>
        <!--netty-->
        <dependency>
            <groupId>io.netty</groupId>
            <artifactId>netty-all</artifactId>
            <version>4.1.32.Final</version>
        </dependency>


        <!--spring依賴-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
            <version>${spring-version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>${spring-version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring-version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-expression</artifactId>
            <version>${spring-version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>${spring-version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aspects</artifactId>
            <version>${spring-version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-tx</artifactId>
            <version>${spring-version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>${spring-version}</version>
        </dependency>
    </dependencies>
</project>

注意

spring-dubbo-provider.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd">
    <!--當前工程名稱,該名稱將在監控平臺使用-->
    <dubbo:application name="02-first-provider"/>
    <!--註冊Service,未來服務的提供者-->
    <bean id="someService" class="com.cyb.service.SomeServiceImpl"></bean>
    <!--暴露服務,採用直連的方式-->
    <dubbo:service interface="com.cyb.service.SomeService" ref="someService" registry="N/A"></dubbo:service>
</beans>

SomeServiceImpl.java

package com.cyb.service;

public class SomeServiceImpl implements SomeService{
    @Override
    public String hello(String name) {
        System.out.println("Dubbo World Welcome You"+name);
        return "chenyanbin";
    }
}

RunProvider.java

package com.cyb.run;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import java.io.IOException;

public class RunProvider {
    public static void main(String[] args) throws IOException {
        //建立spring容器
        ApplicationContext ac = new ClassPathXmlApplicationContext("spring-dubbo-provider.xml");
        //啓動spring容器
        ((ClassPathXmlApplicationContext) ac).start();
        //將當前主線程阻塞
        System.in.read();
    }
}

建立消費者Consumer工程

項目結構圖

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.cyb</groupId>
    <artifactId>02-first-consumer</artifactId>
    <version>1.0-SNAPSHOT</version>
    <!--編譯器依賴-->
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>13</maven.compiler.source>
        <maven.compiler.target>13</maven.compiler.target>
        <!--自定義版本號-->
        <spring-version>4.3.16.RELEASE</spring-version>
    </properties>

    <dependencies>
        <!--自定義工程依賴-->
        <dependency>
            <groupId>org.cyb</groupId>
            <artifactId>01-common</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <!--dubbo依賴-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>dubbo</artifactId>
            <version>2.6.7</version>
        </dependency>
        <!--netty-->
        <dependency>
            <groupId>io.netty</groupId>
            <artifactId>netty-all</artifactId>
            <version>4.1.32.Final</version>
        </dependency>
        <!--spring依賴-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
            <version>${spring-version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>${spring-version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring-version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-expression</artifactId>
            <version>${spring-version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>${spring-version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aspects</artifactId>
            <version>${spring-version}</version>
        </dependency>
    </dependencies>
</project>

spring-dubbo-consumer.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd">
    <!--當前工程的名稱,監控中心使用-->
    <dubbo:application name="02-first-consumer"/>
    <!--消費引用-->
    <dubbo:reference id="someSerivce" interface="com.cyb.service.SomeService" url="dubbo://localhost:20880"></dubbo:reference>
</beans>

注:端口號20880固定算法

RunConsumer.java

package com.cyb.run;

import com.cyb.service.SomeService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class RunConsumer {
    public static void main(String[] args) {
        //建立Spring容器
        ApplicationContext ac=new ClassPathXmlApplicationContext("spring-dubbo-consumer.xml");
        SomeService service = (SomeService) ac.getBean("someSerivce");
        service.hello("tom");
    }
}

運行

Zookeeper註冊中心&Zookeeper集羣(Dubbo官網推薦)

拷貝生產者和消費者工程

註冊中心其餘方式

地址:http://dubbo.apache.org/zh-cn/docs/user/references/registry/introduction.htmlspring

Zookeeper工程搭建

配置參考地址:點我直達數據庫

啓動zookeeper服務

修改提供者工程

pom.xml添加curator客戶端依賴 

        <!-- zk客戶端依賴:curator-framework-->
        <dependency>
            <groupId>org.apache.curator</groupId>
            <artifactId>curator-framework</artifactId>
            <version>4.0.1</version>
        </dependency>

注意事項

修改spring-dubbo-provider.xml

代碼拷貝區

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd">
    <!--當前工程名稱,該名稱將在監控平臺使用-->
    <dubbo:application name="03-provider-zk"/>
    <!--註冊Service,未來服務的提供者-->
    <bean id="someService" class="com.cyb.service.SomeServiceImpl"></bean>

    <!-- 聲明zk服務中心 -->
    <!-- 單機版 -->
    <!-- 方式一 -->
    <dubbo:registry address="zookeeper://192.168.1.111:2181"/>
    <!-- 方式二 -->
    <!-- <dubbo:registry protocol="zookeeper" address=""/> -->

    <!-- 集羣配置 -->
    <!-- 方式一 -->
    <!-- <dubbo:registry address="zookeeper://10.20.153.10:2181?backup=10.20.153.11:2181,10.20.153.12:2181" /> -->
    <!-- 方式二 -->
    <!-- <dubbo:registry protocol="zookeeper" address="10.20.153.10:2181,10.20.153.11:2181,10.20.153.12:2181" /> -->

    <!-- 同一Zookeeper,分紅多組註冊中心 -->
    <!-- <dubbo:registry id="chinaRegistry" protocol="zookeeper" address="10.20.153.10:2181" group="china" />
    <dubbo:registry id="intlRegistry" protocol="zookeeper" address="10.20.153.10:2181" group="intl" /> -->

    <!-- 暴露服務,將服務暴露給zk服務中心 -->
<!-- <dubbo:service interface="com.cyb.service.SomeService" ref="someService" registry="N/A"></dubbo:service> -->
    <dubbo:service interface="com.cyb.service.SomeService" ref="someService"></dubbo:service>

</beans>

修改消費者工程

pom.xml添加curator客戶端依賴

        <!-- zk客戶端依賴:curator-framework-->
        <dependency>
            <groupId>org.apache.curator</groupId>
            <artifactId>curator-framework</artifactId>
            <version>4.0.1</version>
        </dependency>

修改spring-dubbo-consumer.xml

代碼拷貝區

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd">
    <!--當前工程的名稱,監控中心使用-->
    <dubbo:application name="03-consumer-zk"/>

    <!-- 聲明zk服務中心 -->
    <!-- 單機版 -->
    <dubbo:registry address="zookeeper://192.168.1.111:2181"/>

    <!--消費引用-->
    <!-- <dubbo:reference id="someSerivce" interface="com.cyb.service.SomeService" url="dubbo://localhost:20880"></dubbo:reference> -->
    <dubbo:reference id="someSerivce" interface="com.cyb.service.SomeService"></dubbo:reference>
</beans>

運行

Dubbo聲明式緩存

   了進一步提升消費者對用戶的響應速度減小提供者的壓力Dubbo提供基於結果的聲明式緩存。該緩存基於消費者端的,因此使用很簡單,只需修改消費者配置文件與提供者無關express

修改消費者配置文件

  僅需在<dubbo:reference />中添加cache="true"便可apache

修改RunConsumer.java

緩存VS無緩存

  先不加緩存,發現提供者執行2次,加上緩存提供者只執行一次緩存

dubbo提供了三種結果緩存機制

  1. lru:服務級別緩存的默認機制。該機制默承認以緩存1000個結果。若超出1000,將採用最近最少使用原則來刪除緩存,以保證最熱的數據被緩存。
  2. threadlocal:當前線程緩存。當多個線程要對當前線程進行某一操做時首先須要查詢當前線程的某個信息,經過線程緩存,則可有效減小查詢。
  3. jcache:能夠橋接各類緩存實現,即第三方緩存產品。

spring-dubbo-consumer.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd">
    <!--當前工程的名稱,監控中心使用-->
    <dubbo:application name="03-consumer-zk"/>

    <!-- 聲明zk服務中心 -->
    <!-- 單機版 -->
    <dubbo:registry address="zookeeper://192.168.1.111:2181"/>

    <!-- <dubbo:reference id="someSerivce" interface="com.cyb.service.SomeService" url="dubbo://localhost:20880"></dubbo:reference> -->
    <!-- <dubbo:reference id="someSerivce" interface="com.cyb.service.SomeService"></dubbo:reference> -->

    <!--消費引用:基於服務級別的聲明式緩存(結果緩存)-->
    <!--<dubbo:reference id="someSerivce" interface="com.cyb.service.SomeService" cache="true"></dubbo:reference>-->

    <!--消費引用:基於方法級別的聲明式緩存(結果緩存)-->
    <dubbo:reference id="someSerivce" interface="com.cyb.service.SomeService" >
        <!--lru-->
        <dubbo:method name="hello" cache="lru"></dubbo:method>
        <!--threadlocal-->
        <dubbo:method name="hello" cache="threadlocal"></dubbo:method>
    </dubbo:reference>
</beans>

結果緩存的應用場景

  Dubbo的結果緩存能夠應用查詢結果不變的場景。即不能使用在以下場景:消費者A調用的業務方法後從DB查詢到一個結果a,此後,消費者B對DB中的該結果相關數據進行了修改,已使該查詢結果變爲b,但因爲使用告終果緩存,消費者A中調用業務方法後的查詢結果將長時間爲a,直到該結果因爲緩存空間滿而被消除,不然,永遠沒法獲得更新過的結果b。微信

多版本控制

  Dubbo的多版本控制指的是,服務名稱(接口名)相同的狀況下提供不一樣的服務(實現類不一樣) ,然而消費者是經過服務名稱(接口名)進行服務查詢並進行消費的。提供者所提供的服務名稱相同,如何讓消費者經過名稱進行服務查找呢?爲服務添加一個版本號,使用「服務名稱」+「版本號」的方式來惟一肯定一個服務。併發

  多版本控制主要的應用場景是:當一個接口的實現類須要升級時,可使用版本號進行過渡(根據開閉原則,不能直接修改原實現類,只能添加新的實現類)。須要注意的是,版本號不一樣的服務間是不能互相引用的,由於新版本存在的目的是替換老版本。在生產環境中若存在多個提供者須要升級,通常不會一次性所有進行升級,而是會在低壓力時間段先升級一部分,而後在下次再進行部分升級,直到所有升級完成。那麼,這期間就須要使用版本號進行過渡。

項目準備

拷貝項目

提供者(04-provider-version)

 

修改配置文件

 

消費者(04-consumer-version)

 

執行

服務分組

   服務分組與多版本控制使用方式幾乎是相同的,只要將version替換爲group便可。但使用目的不一樣。使用版本控制的目的是爲了升級,將原有老版本替換掉,未來再也不提供老版本的服務,因此不一樣版本間不能出現相互調用。而分組目的則不一樣,其也是針對相同接口給出了多種實現類,但不一樣的是,這些不一樣實現並無替換掉誰的意思,是針對不一樣需求,或針對不一樣功能模塊鎖給出的實現這些實現所提供的服務是並存的,因此他們間能夠出現相互調用關係。例如,支付服務的實現,能夠有微信支付實現與支付寶實現等。

服務暴露延遲

  若是咱們的服務啓動過程當中須要warmup事件(預熱事件,與JVM重啓後的預熱過程類似,在啓動後一小段事件後性能才能達到最佳狀態)。好比初始化緩存,等待相關資源就位等。可使用deplay進行延遲暴露。

  值須要在服務提供者的<dubbo:service/>標籤中添加delay屬性,其值若爲整數,則單位爲毫秒,表示在指定事件後再發布服務;若爲-1,則表示在spring初始化完畢後再暴露服務。

 

多註冊中心

  不少時候一個項目中會有多個註冊中心。

同一個服務註冊到多箇中心

  同一個服務能夠註冊不一樣地域的多個註冊中心,以便爲不一樣地域的服務消費者提供更爲快捷的服務。

修改服務提供者配置文件。多個註冊中心之間使用逗號分隔。

 

注:不是集羣!!!

不一樣服務註冊到不一樣中心

修改服務提供者配置文件

同一個服務引用自不一樣的中心

  同一個消費者須要調用兩個不一樣中心服務,而調用的該服務的名稱(接口)、版本等都是相同的。不一樣中心的這個相同名稱的服務調用時不一樣數據庫中的數據,即相同服務最終執行的結果是不一樣的。

修改服務消費者配置文件

 

多協議支持

服務暴露協議

  前面的示例中,服務提供者與服務消費者都是經過zookeeper鏈接協議鏈接上ZooKeeper註冊中心的。

 

  提供者與消費者均鏈接上了註冊中心,那麼消費者就理所固然的能夠享受提供者提供的服務了麼?

  實際狀況並非這樣的。前述ZooKeeper協議,是消費者/提供者鏈接註冊中心的鏈接協議,而非消費者與提供者間的鏈接協議。

  當消費者鏈接上註冊中心後,在消費服務以前,首先須要鏈接上這個服務提供者。雖然消費者經過註冊中心能夠獲取到服務提供者,但提供者對於消費者來講倒是透明的,消費者並不知道真正的服務提供者是誰。不過,不管提供者是誰,消費者都必須鏈接上提供者才能夠獲取到真正的服務,而這個鏈接也是須要專門的鏈接協議的。這個協議稱爲服務暴露協議。

  但是咱們以前的代碼示例中並無看到服務暴露協議的相關配置,但仍可正常運行項目,這是爲何呢?由於採用了默認的暴露協議:Dubbo服務暴露協議。處理Dubbo服務暴露協議外,Dubbo框架還支持另外七種服務暴露協議:Hessian協議、HTTP協議、RMI協議、WebService協議、Thrift協議、Memcached協議、Redis協議;但在實際生產中,使用最多的就是Dubbo服務暴露協議。

  Dubbo服務暴露協議,適合於小數據量大併發的服務調用,以及服務消費者主機數遠大於服務提供者主機數的狀況。

服務暴露協議用法

  在服務提供者的spring配置文件中首先須要註冊暴露協議,而後在暴露服務時具體制定所使用的已註冊的暴露協議。

 

注:protocol屬性用於指定當前服務所使用的暴露協議

同一服務支持多種協議

  直接修改服務提供者的配置文件

 

不一樣服務使用不一樣協議

  直接修改服務提供者配置文件

 

Dubbo的高級設置及使用建議

在提供者上儘可能多配置消費者端屬性

  提供者上儘可能多配置消費者端的屬性,讓提供者實現着一開始就思考提供者服務特色、服務質量等問題。由於做服務的提供者,比服務使用方更清楚服務性能參數,如調用的超時時間、合理的重試次數等。在提供者端配置後,消費者不配置則會使用提供者端的配置值,即提供者配置能夠做爲消費者的缺省值。不然,消費者會使用消費者端的全局設置,這對提供者是不可控的,而且每每不合理的。

  如下屬性在<dubbo:method/>上則是針對指定方法,配置在<dubbo:service/>上則是針對整個服務。

  • timeout:遠程服務調用超時時限。
  • retries:失敗重試次數,默認值是2。
  • loadbalance:負載均衡算法,默認是隨機的random。還能夠有輪詢roundrobin、最不活躍優先leastactive等。
  • actives:消費者最大併發調用限制,即當Consumer對一個服務的併發調用到上限後,新調用會阻塞直到超時。

提供者上配置合理的提供者端屬性

  • threads:用於指定服務線程池大小
  • executes:一個服務提供者並行執行請求上限,即當提供者對一個服務的併發調用達到上限後,新調用會阻塞,此時消費者可能會超時,該屬性配置在<dubbo:method/>上則是針對指定方法的,配置在<dubbo:service/>上則是針對整個服務
相關文章
相關標籤/搜索