天天看點

分布式服務治理 DubboDubbo能解決什麼問題Dubbo 是什麼Dubbo的架構Dubbo 的使用入門負載均衡服務改造服務的最佳實踐

Dubbo能解決什麼問題

  1. 怎麼去維護url

    通過注冊中心去維護url(zookeeper、redis、memcache…)

  2. F5硬體負載均衡器的單點壓力比較大

    軟負載均衡

  3. 怎麼去整理出服務之間的依賴關系

    自動去整理各個服務之間的依賴

  4. 如果伺服器的調用量越來越大,伺服器的容量問題怎麼去評估,擴容的名額

    需要一個監控平台,可以監控調用量、響應時間

Dubbo 是什麼

Dubbo 是一個分布式的服務架構,提供高性能的以及透明化的 RPC 遠端服務調用解決方法,以及 SOA 服務治理方案。

Dubbo的核心部分:

遠端通信

叢集容錯

服務的自動發現

負載均衡

Dubbo的架構

核心角色:

Provider

Consumer

Registry

Monitor

Container

分布式服務治理 DubboDubbo能解決什麼問題Dubbo 是什麼Dubbo的架構Dubbo 的使用入門負載均衡服務改造服務的最佳實踐

Dubbo 的使用入門

簡單實踐

1.建立 dubbo-order 項目,同時建立 order-api 和 order-provider 子產品

<!-- pom.xml(dubbo-order) -->
<dependency>
  <groupId>com.spring.dubbo.order</groupId>
  <artifactId>order-api</artifactId>
  <version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
  <groupId>com.alibaba</groupId>
  <artifactId>dubbo</artifactId>
  <version>2.6.2</version>
</dependency>
<dependency>
  <groupId>com.github.sgroschupf</groupId>
  <artifactId>zkclient</artifactId>
  <version>0.1</version>
</dependency>
<dependency>
  <groupId>org.apache.curator</groupId>
  <artifactId>curator-framework</artifactId>
  <version>4.0.1</version>
</dependency>
<dependency>
  <groupId>org.apache.zookeeper</groupId>
  <artifactId>zookeeper</artifactId>
  <version>3.4.13</version>
</dependency>
<!-- pom.xml(order-provider) -->
<dependency>
    <groupId>com.spring.dubbo.order</groupId>
    <artifactId>order-api</artifactId>
</dependency>
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>dubbo</artifactId>
</dependency>
<dependency>
    <groupId>com.github.sgroschupf</groupId>
    <artifactId>zkclient</artifactId>
</dependency>
<dependency>
  <groupId>org.apache.curator</groupId>
  <artifactId>curator-framework</artifactId>
</dependency>
<dependency>
  <groupId>org.apache.zookeeper</groupId>
  <artifactId>zookeeper</artifactId>
</dependency>
           

2.order-api 子產品

public class DoOrderRequest implements Serializable {
    private static final long serialVersionUID = 4296088277401004361L;
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "DoOrderRequest{" +
                "name='" + name + '\'' +
                '}';
    }
}
public class DoOrderResponse implements Serializable {
    private static final long serialVersionUID = 2243774451440109149L;
    private Object data;

    private String code;

    private String memo;

    public Object getData() {
        return data;
    }

    public void setData(Object data) {
        this.data = data;
    }

    public String getCode() {
        return code;
    }

    public void setCode(String code) {
        this.code = code;
    }

    public String getMemo() {
        return memo;
    }

    public void setMemo(String memo) {
        this.memo = memo;
    }

    @Override
    public String toString() {
        return "DoOrderResponse{" +
                "data=" + data +
                ", code='" + code + '\'' +
                ", memo='" + memo + '\'' +
                '}';
    }
}
public interface IOrderService {

    /**
     * 下單操作
     * @param request
     * @return
     */
    DoOrderResponse doOrder(DoOrderRequest request);

}
           

3.order-provider 子產品下,resources 下添加日志配置檔案

log4j.rootLogger=info, stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m%n
           

4.如果需要搭配 zookeeper,resources 下添加

/META-INF/spring/order-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:context="http://www.springframework.org/schema/context"
       xmlns:dubbo="http://dubbo.apache.org/schema/dubbo"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
       http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd" default-autowire="byName">

    <!-- 目前項目在整個分布式架構的唯一名稱,計算依賴關系的标簽 -->
    <dubbo:application name="order-provider" owner="spring"/>

    <!-- dubbo這個服務所要暴露的服務位址所對應的注冊中心 -->
    <!-- 不使用注冊中心<dubbo:registry address="N/A"/>-->
    <!-- 使用 zookeeper 來做為注冊中心 -->
    <!--<dubbo:registry address="zookeeper://192.168.174.128:2181?backup=192.168.174.129:2181,192.168.174.130:2181"/>-->
    <!-- 寫在前面的不一定是leader,等同于下面 -->
    <!--<dubbo:registry protocol="zookeeper" address="192.168.174.128:2181,192.168.174.129:2181,192.168.174.130:2181"/>-->
    <dubbo:registry address="zookeeper://192.168.174.128:2181"/>

    <!-- 目前服務釋出所依賴的協定:webservice,Thrift,Hessian,http -->
    <dubbo:protocol name="dubbo" port="20880"/>

    <!-- 服務釋出的配置,需要暴露的服務接口 -->
    <dubbo:service interface="com.spring.dubbo.order.IOrderService" ref="orderService"/>

    <!-- Bean 的定義 -->
    <bean id="orderService" class="com.spring.dubbo.order.OrderServiceImpl"/>
</beans>
           

5.order-provider 子產品的實作

public class OrderServiceImpl implements IOrderService {
    @Override
    public DoOrderResponse doOrder(DoOrderRequest request) {
        System.out.println("曾經來過:" + request);
        DoOrderResponse response = new DoOrderResponse();
        response.setCode("1000");
        response.setMemo("處理成功");
        return response;
    }
}
public class App {
    public static void main(String[] args) {
        Main.main(args);
    }
}
           

6.将 order-api 子產品打包,已被 dubbo-user 使用

7.建立 dubbo-user 項目,同時引入 order-api-1.0-SNAPSHOT.jar

<dependency>
  <groupId>com.alibaba</groupId>
  <artifactId>dubbo</artifactId>
  <version>2.5.3</version>
</dependency>
<dependency>
  <groupId>com.github.sgroschupf</groupId>
  <artifactId>zkclient</artifactId>
  <version>0.1</version>
</dependency>
           
public class App {
    public static void main( String[] args ) {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("order-consumer.xml");

        // 使用者下單過程
        IOrderService service = (IOrderService) context.getBean("orderService");

        DoOrderRequest request = new DoOrderRequest();
        request.setName("spring");
        DoOrderResponse response = service.doOrder(request);
        System.out.println(response);
    }
}
           

8.在 dubbo-user 項目 resources 中添加檔案 order-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://dubbo.apache.org/schema/dubbo"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd">

    <!-- 目前項目在整個分布式架構的唯一名稱,計算依賴關系的标簽 -->
    <dubbo:application name="order-provider" owner="spring"/>

    <!-- 使用 zookeeper,dubbo這個服務所要暴露的服務位址所對應的注冊中心 -->
    <dubbo:registry address="zookeeper://192.168.174.128:2181"/>

    <!-- 生成一個遠端服務的調用代理 -->
    <dubbo:reference id="orderService" interface="com.spring.dubbo.order.IOrderService"/>
    <!-- 不使用 zookeeper 時,dubbo:reference 标簽需要添加 url="dubbo://192.168.174.1:20880/com.spring.dubbo.order.IOrderService" -->
</beans>
           

服務位址分析

啟動 order-provider 時,控制台會列印服務所要暴露的服務位址:

dubbo://192.168.174.1:20880/com.spring.dubbo.order.IOrderService

?anyhost=true&application=order-provider&dubbo=2.5.3&interface=com.spring.dubbo.order.IOrderService&methods=doOrder&owner=spring&pid=15320&side=provider&timestamp=1586852986986, dubbo version: 2.5.3, current host: 127.0.0.1

如果使用 zookeeper 時,在 zookeeper 中可以擷取如下的資訊:

分布式服務治理 DubboDubbo能解決什麼問題Dubbo 是什麼Dubbo的架構Dubbo 的使用入門負載均衡服務改造服務的最佳實踐

dubbo://192.168.174.1/com.spring.dubbo.order.IOrderService

%3Fanyhost%3Dtrue%26application%3Dorder-provider%26dubbo%3D2.5.3%26interface%3Dcom.spring.dubbo.order.IOrderService%26methods%3DdoOrder%26owner%3Dspring%26pid%3D4200%26side%3Dprovider%26timestamp%3D1586856057540

新版 dubbo-admin 控制台的安裝

控制中心是用來做服務治理的,比如控制服務的權重、服務的路由。

1.下載下傳dubbo的源碼(源碼 github 位址,新版 dubbo-admin github 位址)

2.新版 dubbo-admin 分為 dubbo-admin-server 和 dubbo-admin-ui 兩個子產品

3.dubbo-admin-server 為一個 spring boot 項目,可以在

resources/application.properties

中指定注冊中心位址修改(同時可以修改登入的賬号密碼),可通過正常的 spring boot 項目方式啟動

4.dubbo admin ui 由 npm 管理和建構,在開發環境中,可以運作:

npm install
npm run dev
           

5.頁面通路 通路 http://localhost:8081

分布式服務治理 DubboDubbo能解決什麼問題Dubbo 是什麼Dubbo的架構Dubbo 的使用入門負載均衡服務改造服務的最佳實踐

simple 監控中心

監控服務的調用次數、調用關系、響應事件,github 位址

Monitor 也是一個dubbo服務,是以也會有端口和url。

1.修改

/conf/dubbo.properties

dubbo.registry.address=zookeeper://127.0.0.1:2181
           

2.修改服務端配置,即 order-provider 的 order-provider.xml:

<dubbo:monitor protocol="registry"/>
           
分布式服務治理 DubboDubbo能解決什麼問題Dubbo 是什麼Dubbo的架構Dubbo 的使用入門負載均衡服務改造服務的最佳實踐

telnet

telnet ip port

ls、cd、pwd、clear、invoker

啟動服務檢查

dubbo:reference

屬性:

check

,預設值是true

如果提供方沒有啟動的時候,預設回去檢查所有以來的服務是否正常提供服務。如果 check 為 false,表示啟動的時候不去檢查。當服務出現循環依賴的時候,check 設定成 false。

dubbo:consumer check=false

,關閉所有服務的啟動時檢查:(沒有提供者時報錯)

dubbo:registry check=false

,關閉注冊中心啟動時檢查:(注冊訂閱失敗時報錯)

多協定支援

dubbo 支援的協定:dubbo,RMI,hessian,webservice,http,Thrift

hessian 協定示範

1.引入 jar 包

<dependency>
  <groupId>com.caucho</groupId>
  <artifactId>hessian</artifactId>
  <version>4.0.38</version>
</dependency>
 <dependency>
     <groupId>javax.servlet</groupId>
     <artifactId>servlet-api</artifactId>
     <version>2.5</version>
 </dependency>
<dependency>
  <groupId>org.mortbay.jetty</groupId>
  <artifactId>jetty</artifactId>
  <version>6.1.26</version>
</dependency>
           

2.修改 order-provider.xml 檔案

<!-- 增加 hessian 協定 -->
<dubbo:protocol name="hessian" port="8090" server="jetty"/>
<!-- 指定 service 服務的協定版本号 -->
<dubbo:service interface="com.spring.dubbo.order.IOrderService" ref="orderService" protocol="hessian"/>
           

3.消費端改造

<!-- 指定引用服務所需要的協定版本 -->
<dubbo:reference id="orderService" interface="com.spring.dubbo.order.IOrderService" protocol="hessian"/>
           

服務端在 zookeeper 中注冊的服務位址:

hessian://192.168.174.1:8090/com.spring.dubbo.order.IOrderService

多注冊中心支援

<!-- 多注冊中心 -->
<dubbo:registry id="zkOne" address="zookeeper://192.168.174.128:2181"/>
<dubbo:registry id="zkTwo" address="zookeeper://192.168.174.129:2181"/>
<!-- 針對服務指定注冊中心 -->
<dubbo:service interface="com.spring.dubbo.order.IOrderService" ref="orderService" registry="zkOne" />
           

多版本支援

服務端:

<dubbo:service interface="com.spring.dubbo.order.IOrderService" ref="orderService" version="1.0.0"/>
    <dubbo:service interface="com.spring.dubbo.order.IOrderService" ref="orderService2" version="2.0.0"/>
           

消費端:

dubbo://192.168.174.1:20880/com.spring.dubbo.order.IOrderService?..&version=1.0.0

dubbo://192.168.174.1:20880/com.spring.dubbo.order.IOrderService?..&version=2.0.0

異步調用

消費端,

async="true"

表示接口異步傳回:

<dubbo:reference id="orderService" interface="com.spring.dubbo.order.IOrderService" async="true"/>
<!-- 可單指定某個方法 -->
<!-- <dubbo:method name="doOrder" async="true"/> -->
           
public class App {
    public static void main( String[] args ) throws ExecutionException, InterruptedException {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("order-consumer.xml");

        // 使用者下單過程
        IOrderService service = (IOrderService) context.getBean("orderService");

        DoOrderRequest request = new DoOrderRequest();
        request.setName("spring");
        service.doOrder(request);

        Future<DoOrderResponse> response = RpcContext.getContext().getFuture();
        DoOrderResponse r = response.get();
        System.out.println(r);
    }
}
           
分布式服務治理 DubboDubbo能解決什麼問題Dubbo 是什麼Dubbo的架構Dubbo 的使用入門負載均衡服務改造服務的最佳實踐

主機綁定

provider://192.168.174.1:20880

org.apache.dubbo.config.ServiceConfig#findConfigedHosts

String hostToBind = getValueFromConfig(protocolConfig, DUBBO_IP_TO_BIND);
if (hostToBind != null && hostToBind.length() > 0 && isInvalidLocalHost(hostToBind)) {
    throw new IllegalArgumentException("Specified invalid bind ip from property:" + DUBBO_IP_TO_BIND + ", value:" + hostToBind);
}
if (StringUtils.isEmpty(hostToBind)) {
    hostToBind = protocolConfig.getHost();
    if (provider != null && StringUtils.isEmpty(hostToBind)) {
        hostToBind = provider.getHost();
    }
    if (isInvalidLocalHost(hostToBind)) {
        anyhost = true;
        try {
            logger.info("No valid ip found from environment, try to find valid host from DNS.");
            hostToBind = InetAddress.getLocalHost().getHostAddress();
        } catch (UnknownHostException e) {
            logger.warn(e.getMessage(), e);
        }
        if (isInvalidLocalHost(hostToBind)) {
            if (CollectionUtils.isNotEmpty(registryURLs)) {
                for (URL registryURL : registryURLs) {
                    if (MULTICAST.equalsIgnoreCase(registryURL.getParameter("registry"))) {
                        // skip multicast registry since we cannot connect to it via Socket
                        continue;
                    }
                    try (Socket socket = new Socket()) {
                        SocketAddress addr = new InetSocketAddress(registryURL.getHost(), registryURL.getPort());
                        socket.connect(addr, 1000);
                        hostToBind = socket.getLocalAddress().getHostAddress();
                        break;
                    } catch (Exception e) {
                        logger.warn(e.getMessage(), e);
                    }
                }
            }
            if (isInvalidLocalHost(hostToBind)) {
                hostToBind = getLocalHost();
            }
        }
    }
}
           
  1. 通過

    dubbo:protocol host

    配置的位址去找
  2. hostToBind = InetAddress.getLocalHost().getHostAddress();
  3. 通過socket發起連接配接連接配接到注冊中心的位址。再擷取連接配接過去以後本地的ip位址
  4. hostToBind = getLocalHost()

dubbo 服務隻訂閱

dubbo 服務隻注冊

隻提供服務

負載均衡

1.複制一份 dubbo-order 項目,修改端口号

2.同時啟動 兩個 dubbo-order

3.消費端調用

public class App {
    public static void main( String[] args ) throws InterruptedException {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("order-consumer.xml");

        // 使用者下單過程
        IOrderService service = (IOrderService) context.getBean("orderService");

        DoOrderRequest request = new DoOrderRequest();
        request.setName("spring");
        for (int i = 0; i < 10; i++){
            DoOrderResponse r = service.doOrder(request);
            System.out.println(r);
            TimeUnit.SECONDS.sleep(1);
        }
    }
}
           

負載均衡算法

在叢集負載均衡時,Dubbo 提供了多種均衡政策,預設為 random 随機調用。可以自行擴充負載均衡政策。

Random LoadBalance

(預設)随機,按權重設定随機機率。

在一個截面上碰撞的機率高,但調用量越大分布越均勻,而且按機率使用權重後也比較均勻,有利于動态調整提供者權重。

roundRobin LoadBalance

輪循,按公約後的權重設定輪循比率。存在慢的提供者累積請求的問題,比如:第二台機器很慢,但沒挂,當請求調到第二台時就卡在那,久而久之,所有請求都卡在調到第二台上。

LeastActive LoadBalance

最少活躍調用數,相同活躍數的随機,活躍數指調用前後計數差。使慢的提供者收到更少請求,因為越慢的提供者的調用前後計數差會越大。

Consistent LoadBaleance

一緻性Hash,相同參數的請求總是發到同一提供者。當某一台提供者挂時,原本發往該提供者的請求,基于虛拟節點,平攤到其它提供者,不會引起劇烈變動。

連接配接逾時 timeout

必須要設定服務的處理的逾時時間

叢集容錯

Failover cluster

(預設),失敗的時候自動切換并重試其他伺服器。 通過

retries=2

,來設定重試次數

failfast cluster

快速失敗,隻發起一次調用 ; 寫操作。比如新增記錄的時候, 非幂等請求

failsafe cluster

失敗安全。 出現異常時,直接忽略異常

failback cluster

失敗自動恢複。 背景記錄失敗請求,定時重發

forking cluster

并行調用多個伺服器,隻要一個成功就傳回。 隻能應用在讀請求

broadcast cluster

廣播調用所有提供者,逐個調用。其中一台報錯就會傳回異常

配置的優先級

消費端有限最高,其次服務端

分布式服務治理 DubboDubbo能解決什麼問題Dubbo 是什麼Dubbo的架構Dubbo 的使用入門負載均衡服務改造服務的最佳實踐

服務改造

1.dubbo-order 項目和其 order-provider 子產品引入 spring 相關 jar 包

dubbo 中已經省缺配置了

org.springframework:spring-context:jar:4.3.10.RELEASE

<dependency>
  <groupId>com.spring.dubbo.order</groupId>
  <artifactId>order-api</artifactId>
  <version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-core</artifactId>
  <version>${org.springframework-version}</version>
</dependency>
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-beans</artifactId>
  <version>${org.springframework-version}</version>
</dependency>
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-context-support</artifactId>
  <version>${org.springframework-version}</version>
</dependency>
           

2.order-provider.xml

<!-- 不需要在xml中引入bean,可以直接通過注解方式引入bean,@Service(value = "orderService") -->
<context:component-scan base-package="com.spring.dubbo.order"/>
           

3.order-api 添加

resources\META-INF\client\order-customer.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:context="http://www.springframework.org/schema/context"
       xmlns:dubbo="http://dubbo.apache.org/schema/dubbo"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
       http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd" default-autowire="byName">
    <!-- 生成一個遠端服務的調用代理 -->
    <dubbo:reference id="orderServiceSpring" interface="com.spring.dubbo.order.IOrderService" protocol="dubbo" version="2.0.0"/>

</beans>
           

4.建立一個簡單的 springmvc 項目

pom.xml

<properties>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
    <org.springframework-version>4.3.10.RELEASE</org.springframework-version>
    <commons-logging-version>1.1.1</commons-logging-version>
</properties>
<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-core</artifactId>
        <version>${org.springframework-version}</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>${org.springframework-version}</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-beans</artifactId>
        <version>${org.springframework-version}</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-test</artifactId>
        <version>${org.springframework-version}</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-jdbc</artifactId>
        <version>${org.springframework-version}</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-tx</artifactId>
        <version>${org.springframework-version}</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context-support</artifactId>
        <version>${org.springframework-version}</version>
    </dependency>
    <dependency>
        <groupId>commons-logging</groupId>
        <artifactId>commons-logging</artifactId>
        <version>${commons-logging-version}</version>
    </dependency>
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>dubbo</artifactId>
        <version>2.6.2</version>
    </dependency>
    <dependency>
        <groupId>com.spring.dubbo.order</groupId>
        <artifactId>order-api</artifactId>
        <version>1.0-SNAPSHOT</version>
    </dependency>
    <dependency>
        <groupId>com.github.sgroschupf</groupId>
        <artifactId>zkclient</artifactId>
        <version>0.1</version>
    </dependency>
    <dependency>
        <groupId>org.apache.curator</groupId>
        <artifactId>curator-framework</artifactId>
        <version>4.0.1</version>
    </dependency>
    <dependency>
        <groupId>org.apache.zookeeper</groupId>
        <artifactId>zookeeper</artifactId>
        <version>3.4.13</version>
    </dependency>
</dependencies>
<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>2.0.2</version>
            <configuration>
                <source>1.8</source>
                <target>1.8</target>
            </configuration>
        </plugin>
    </plugins>
</build>
           
<!-- web.xml -->
<!DOCTYPE web-app PUBLIC
        "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
        "http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
    <display-name>dubbo-spring</display-name>
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:spring/application*.xml</param-value>
    </context-param>
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

    <servlet>
        <servlet-name>springmvc</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:spring/springmvc.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <!--配置全局方法的攔截-->
    <servlet-mapping>
        <servlet-name>springmvc</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
</web-app>
<!-- applictionContext.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:context="http://www.springframework.org/schema/context"
       xmlns:dubbo="http://dubbo.apache.org/schema/dubbo"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context-3.0.xsd
       http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd" default-autowire="byName">

    <context:component-scan base-package="com.spring">
        <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
    </context:component-scan>

    <dubbo:application name="dubbo-spring"/>
    <dubbo:registry protocol="zookeeper" address="192.168.174.128:2181"/>

    <import resource="classpath*:META-INF/client/order-customer.xml"/>
</beans>
<!-- springmvc.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:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
       http://www.springframework.org/schema/context
	   http://www.springframework.org/schema/context/spring-context.xsd">

    <!-- 掃描 controller -->
    <context:component-scan base-package="com.spring.controller" use-default-filters="false">
        <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
        <context:include-filter type="annotation" expression="org.springframework.web.bind.annotation.ControllerAdvice"/>
    </context:component-scan>

    <mvc:annotation-driven/>
    <!-- 對靜态資源檔案的通路 -->
    <mvc:resources location="/system/" mapping="/system/**"/>

    <!-- 配置jsp視圖 -->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/jsp/"/>
        <property name="suffix" value=".jsp"/>
    </bean>
</beans>
           
@Controller
@RequestMapping("/home")
public class HomeController {

    @Autowired
    private UserService userService;

    // 按名稱注入,變量名需要與api.jar提供的id相同
    @Autowired
    IOrderService orderServiceSpring;

    @RequestMapping(value = "/index")
    public ModelAndView index(){
        DoOrderRequest request = new DoOrderRequest();
        request.setName("dubbo-spring");
        orderServiceSpring.doOrder(request);
        userService.insert();
        return new ModelAndView("index");
    }
}
           

服務的最佳實踐

分包

  1. 服務接口,請求服務模型,異常資訊都放在 api 裡面,符合重用釋出等價原則,共同重用原則
  2. api 裡面放入 spring 的引用配置。也可以放在子產品的包目錄下。com.spring.dubbo.order/***-reference.xml

粒度

  1. 盡可能把接口設定成粗粒度,每個服務方法代表一個獨立的功能,而不是某個功能的步驟。否則就會涉及到分布式事務
  2. 服務接口建議以業務場景為機關劃分。并對相近業務做抽象,防止接口暴增
  3. 不建議使用過于抽象的通用接口,接口沒有明确的語義,帶來後期的維護

版本

  1. 每個接口都應該定義版本,為後續的相容性提供前瞻性的考慮
  2. 建議使用兩位版本号,因為第三位版本号表示的相容性更新,隻有不相容時才需要變更服務版本
  3. 當接口做到不相容更新的時候,先更新一半或者一台提供者為新版本,再将消費全部更新新版本,然後再将剩下的一半提供者更新新版本(預釋出環境)

推薦配置

  1. 在 provider 端盡可能配置 consumer 端的屬性,比如timeout、retires、線程池大小、LoadBalance
  2. 配置管理者資訊,application 上面配置的 owner ,owner建議配置2個人以上。因為owner都能夠在監控中心看到
  3. 配置 dubbo 緩存檔案

配置 dubbo 緩存檔案

<!-- dubbo-spring,消費端配置 -->
<dubbo:registry protocol="zookeeper" file="/Users/spring_zhang/Code/dubbo.cache" address="127.0.0.1:2181"/>
           

緩存:注冊中心的清單,服務提供者清單

dubbo.cache

#Dubbo Registry Cache
#Thu Apr 16 21:01:06 CST 2020
com.spring.dubbo.order.IOrderService\:2.0.0=empty\://10.1.1.231/com.spring.dubbo.order.IOrderService?application\=dubbo-spring&category\=configurators&dubbo\=2.6.2&interface\=com.spring.dubbo.order.IOrderService&methods\=doOrder&pid\=5340&protocol\=dubbo&revision\=1.0-SNAPSHOT&side\=consumer&timestamp\=1587042064681&version\=2.0.0 empty\://10.1.1.231/com.spring.dubbo.order.IOrderService?application\=dubbo-spring&category\=routers&dubbo\=2.6.2&interface\=com.spring.dubbo.order.IOrderService&methods\=doOrder&pid\=5340&protocol\=dubbo&revision\=1.0-SNAPSHOT&side\=consumer&timestamp\=1587042064681&version\=2.0.0 dubbo\://10.1.1.231\:20880/com.spring.dubbo.order.IOrderService2?anyhost\=true&application\=order-provider&dubbo\=2.6.2&generic\=false&interface\=com.spring.dubbo.order.IOrderService&methods\=doOrder&owner\=spring&pid\=4201&revision\=2.0.0&side\=provider&timestamp\=1587040010193&version\=2.0.0
com.spring.dubbo.user.IUserService=empty\://10.1.1.231/com.spring.dubbo.user.IUserService?application\=dubbo-spring&category\=configurators&dubbo\=2.6.2&interface\=com.spring.dubbo.user.IUserService&methods\=toLogin,login&pid\=5340&revision\=1.0-SNAPSHOT&side\=consumer&timestamp\=1587042066209 empty\://10.1.1.231/com.spring.dubbo.user.IUserService?application\=dubbo-spring&category\=routers&dubbo\=2.6.2&interface\=com.spring.dubbo.user.IUserService&methods\=toLogin,login&pid\=5340&revision\=1.0-SNAPSHOT&side\=consumer&timestamp\=1587042066209 dubbo\://10.1.1.231\:20881/com.spring.dubbo.user.IUserService?anyhost\=true&application\=user-provider&dubbo\=2.6.2&generic\=false&interface\=com.spring.dubbo.user.IUserService&methods\=toLogin,login&owner\=spring&pid\=4142&side\=provider&timestamp\=1587039921924