天天看點

Dubbo 入門系列之快速部署一個微服務應用

作者:Java碼農之路

本文将基于 Dubbo Samples 示例示範如何快速搭建并部署一個微服務應用。

背景

Dubbo 入門系列之快速部署一個微服務應用

Dubbo 作為一款微服務架構,最重要的是向使用者提供跨程序的 RPC 遠端調用能力。如上圖所示,Dubbo 的服務消費者(Consumer)通過一系列的工作将請求發送給服務提供者(Provider)。

為了實作這樣一個目标,Dubbo 引入了注冊中心(Registry)元件,通過注冊中心,服務消費者可以感覺到服務提供者的連接配接方式,進而将請求發送給正确的服務提供者。

目标

了解微服務調用的方式以及 Dubbo 的能力

難度

環境要求

  • 系統:Windows、Linux、MacOS
  • JDK 8 及以上(推薦使用 JDK17)
  • Git
  • Docker (可選)

動手實踐

本章将通過幾個簡單的指令,一步一步教你如何部署并運作一個最簡單的 Dubbo 用例。

1. 擷取測試工程

在開始整個教程之前,我們需要先擷取測試工程的代碼。Dubbo 的所有測試用例代碼都存儲在 apache/dubbo-samples 這個倉庫中,以下這個指令可以幫你擷取 Samples 倉庫的所有代碼。

git clone --depth=1 --branch master [email protected]:apache/dubbo-samples.git
           

2. 認識 Dubbo Samples 項目結構

在将 apache/dubbo-samples 這個倉庫 clone 到本地以後,本小節将就倉庫的具體組織方式做說明。

.
├── codestyle        // 開發使用的 style 配置檔案

├── 1-basic          // 基礎的入門用例
├── 2-advanced       // 進階用法
├── 3-extensions     // 擴充使用示例
├── 4-governance     // 服務治理用例
├── 10-task          // Dubbo 學習系列示例

├── 99-integration   // 內建測試使用
├── test             // 內建測試使用
└── tools            // 三方元件快速啟動工具
           

如上表所示,apache/dubbo-samples 主要由三個部分組成:代碼風格檔案、測試代碼、內建測試。

  1. 代碼風格檔案是開發 Dubbo 代碼的時候可以使用,其中包括了 IntelliJ IDEA 的配置檔案。
  2. 測試代碼即本教材所需要的核心内容。目前包括了 5 個部分的内容:面向初學者的 basic 入門用例、面向開發人員的 advanced 進階用法、面向中間件維護者的 extensions Dubbo 周邊擴充使用示例、面向生産的 governance 服務治理用例以及 Dubbo 學習系列。本文将基于 basic 入門用例中最簡單的 Dubbo API 使用方式進行講解。
  3. 內建測試是 Dubbo 的品質保證體系中重要的一環,Dubbo 的每個版本都會對所有的 samples 進行回歸驗證,保證 Dubbo 的所有變更都不會影響 samples 的使用。

3. 啟動一個簡易的注冊中心

從這一小節開始,将正式通過三個指令部署一個微服務應用。

從 背景 一節中可知,運作起 Dubbo 應用的一個大前提是部署一個注冊中心,為了讓本教程更易于上手,我們提供了一個基于 Apache Zookeeper 注冊中心的簡易啟動器,如果您需要在生産環境部署注冊中心,請參考生産環境初始化一文部署高可用的注冊中心。

Windows:
./mvnw.cmd clean compile exec:java -pl tools/embedded-zookeeper

Linux / MacOS:
./mvnw clean compile exec:java -pl tools/embedded-zookeeper

注:需要開一個獨立的 terminal 運作,指令将會保持一直執行的狀态。

Docker:
docker run --name some-zookeeper --restart always -d zookeeper
           

在執行完上述指令以後,等待一會出現如下圖所示的日志即代表注冊中心啟動完畢,可以繼續執行後續任務。

4. 啟動服務提供者

在啟動了注冊中心之後,下一步是啟動一個對外提供服務的服務提供者。在 dubbo-samples 中也提供了對應的示例,可以通過以下指令快速拉起。

Windows:
./mvnw.cmd clean compile exec:java -pl 1-basic/dubbo-samples-api -Dexec.mainClass="org.apache.dubbo.samples.provider.Application"

Linux / MacOS:
./mvnw clean compile exec:java -pl 1-basic/dubbo-samples-api -Dexec.mainClass="org.apache.dubbo.samples.provider.Application"

注:需要開一個獨立的 terminal 運作,指令将會保持一直執行的狀态。
           

在執行完上述指令以後,等待一會出現如下圖所示的日志(DubboBootstrap awaiting)即代表服務提供者啟動完畢,标志着該服務提供者可以對外提供服務了。

[19/01/23 03:55:49:049 CST] org.apache.dubbo.samples.provider.Application.main()  INFO bootstrap.DubboBootstrap:  [DUBBO] DubboBootstrap awaiting ..., dubbo version: 3.2.0-beta.3, current host: 169.254.44.42
           

5. 啟動服務消費者

最後一步是啟動一個服務消費者來調用服務提供者,也即是 RPC 調用的核心,為服務消費者提供調用服務提供者的橋梁。

Windows:
./mvnw.cmd clean compile exec:java -pl 1-basic/dubbo-samples-api -Dexec.mainClass="org.apache.dubbo.samples.client.Application"

Linux / MacOS:
./mvnw clean compile exec:java -pl 1-basic/dubbo-samples-api -Dexec.mainClass="org.apache.dubbo.samples.client.Application"
           

在執行完上述指令以後,等待一會出現如下圖所示的日志(hi, dubbo),列印出的資料就是服務提供者處理之後傳回的,标志着一次服務調用的成功。

Dubbo 入門系列之快速部署一個微服務應用
Receive result ======> hi, dubbo
           

延伸閱讀

1. 消費端是怎麼找到服務端的?

在本用例中的步驟 3 啟動了一個 Zookeeper 的注冊中心,服務提供者會向注冊中心中寫入自己的位址,供服務消費者擷取。

Dubbo 會在 Zookeeper 的 /dubbo/interfaceName 和 /services/appName 下寫入服務提供者的連接配接資訊。

如下所示是 Zookeeper 上的資料示例:

[zk: localhost:2181(CONNECTED) 5] ls /dubbo/org.apache.dubbo.samples.api.GreetingsService/providers
[dubbo%3A%2F%2F30.221.146.35%3A20880%2Forg.apache.dubbo.samples.api.GreetingsService%3Fanyhost%3Dtrue%26application%3Dfirst-dubbo-provider%26background%3Dfalse%26deprecated%3Dfalse%26dubbo%3D2.0.2%26dynamic%3Dtrue%26environment%3Dproduct%26generic%3Dfalse%26interface%3Dorg.apache.dubbo.samples.api.GreetingsService%26ipv6%3Dfd00%3A1%3A5%3A5200%3A3218%3A774a%3A4f67%3A2341%26methods%3DsayHi%26pid%3D85639%26release%3D3.1.4%26service-name-mapping%3Dtrue%26side%3Dprovider%26timestamp%3D1674960780647]

[zk: localhost:2181(CONNECTED) 2] ls /services/first-dubbo-provider
[30.221.146.35:20880]
[zk: localhost:2181(CONNECTED) 3] get /services/first-dubbo-provider/30.221.146.35:20880
{"name":"first-dubbo-provider","id":"30.221.146.35:20880","address":"30.221.146.35","port":20880,"sslPort":null,"payload":{"@class":"org.apache.dubbo.registry.zookeeper.ZookeeperInstance","id":"30.221.146.35:20880","name":"first-dubbo-provider","metadata":{"dubbo.endpoints":"[{\"port\":20880,\"protocol\":\"dubbo\"}]","dubbo.metadata-service.url-params":"{\"connections\":\"1\",\"version\":\"1.0.0\",\"dubbo\":\"2.0.2\",\"release\":\"3.1.4\",\"side\":\"provider\",\"ipv6\":\"fd00:1:5:5200:3218:774a:4f67:2341\",\"port\":\"20880\",\"protocol\":\"dubbo\"}","dubbo.metadata.revision":"871fbc9cb2730caea9b0d858852d5ede","dubbo.metadata.storage-type":"local","ipv6":"fd00:1:5:5200:3218:774a:4f67:2341","timestamp":"1674960780647"}},"registrationTimeUTC":1674960781893,"serviceType":"DYNAMIC","uriSpec":null}
           

更多關于 Dubbo 服務發現模型的細節,可以參考服務發現一文。

2. 消費端是如何發起請求的?

在 Dubbo 的調用模型中,起到連接配接服務消費者和服務提供者的橋梁是接口。

服務提供者通過對指定接口進行實作,服務消費者通過 Dubbo 去訂閱這個接口。服務消費者調用接口的過程中 Dubbo 會将請求封裝成網絡請求,然後發送到服務提供者進行實際的調用。

在本用例中,定義了一個 GreetingsService 的接口,這個接口有一個名為 sayHi 的方法。

// 1-basic/dubbo-samples-api/src/main/java/org/apache/dubbo/samples/api/GreetingsService.java

package org.apache.dubbo.samples.api;

public interface GreetingsService {

    String sayHi(String name);

}
           

服務消費者通過 Dubbo 的 API 可以擷取這個 GreetingsService 接口的代理,然後就可以按照普通的接口調用方式進行調用。得益于 Dubbo 的動态代理機制,這一切都像本地調用一樣。

// 1-basic/dubbo-samples-api/src/main/java/org/apache/dubbo/samples/client/Application.java

// 擷取訂閱到的 Stub
GreetingsService service = reference.get();
// 像普通的 java 接口一樣調用
String message = service.sayHi("dubbo");
           

3. 服務端可以部署多個嗎?

可以,本小節将示範如何啟動一個服務端叢集。

1)啟動一個注冊中心,可以參考動手實踐中第 3 小節的教程

2)修改服務提供者傳回的資料,讓第一個啟動的服務提供者傳回 hi, dubbo. I am provider 1.

修改 1-basic/dubbo-samples-api/src/main/java/org/apache/dubbo/samples/provider/GreetingsServiceImpl.java檔案的第 25 行如下所示。

// 1-basic/dubbo-samples-api/src/main/java/org/apache/dubbo/samples/provider/GreetingsServiceImpl.java

package org.apache.dubbo.samples.provider;

import org.apache.dubbo.samples.api.GreetingsService;

public class GreetingsServiceImpl implements GreetingsService {
    @Override
    public String sayHi(String name) {
        return "hi, " + name + ". I am provider 1.";
    }
}
           

3)啟動第一個服務提供者,可以參考動手實踐中第 4 小節的教程

4)修改服務提供者傳回的資料,讓第二個啟動的服務提供者傳回 hi, dubbo. I am provider 2.

修改 1-basic/dubbo-samples-api/src/main/java/org/apache/dubbo/samples/provider/GreetingsServiceImpl.java檔案的第 25 行如下所示。

// 1-basic/dubbo-samples-api/src/main/java/org/apache/dubbo/samples/provider/GreetingsServiceImpl.java

package org.apache.dubbo.samples.provider;

import org.apache.dubbo.samples.api.GreetingsService;

public class GreetingsServiceImpl implements GreetingsService {
    @Override
    public String sayHi(String name) {
        return "hi, " + name + ". I am provider 2.";
    }
}
           

4)啟動第二個服務提供者,可以參考動手實踐中第 4 小節的教程

5)啟動服務消費者,可以參考動手實踐中第 5 小節的教程。多次啟動消費者可以看到傳回的結果是不一樣的。

在 dubbo-samples 中也提供了一個會定時發起調用的消費端應用org.apache.dubbo.samples.client.AlwaysApplication,可以通過以下指令啟動。

Windows:
./mvnw.cmd clean compile exec:java -pl 1-basic/dubbo-samples-api -Dexec.mainClass="org.apache.dubbo.samples.client.AlwaysApplication"

Linux / MacOS:
./mvnw clean compile exec:java -pl 1-basic/dubbo-samples-api -Dexec.mainClass="org.apache.dubbo.samples.client.AlwaysApplication"
           

啟動後可以看到類似以下的日志,消費端會随機調用到不同的服務提供者,傳回的結果也是遠端的服務提供者覺得其結果。

Sun Jan 29 11:23:37 CST 2023 Receive result ======> hi, dubbo. I am provider 1.
Sun Jan 29 11:23:38 CST 2023 Receive result ======> hi, dubbo. I am provider 2.
Sun Jan 29 11:23:39 CST 2023 Receive result ======> hi, dubbo. I am provider 2.
Sun Jan 29 11:23:40 CST 2023 Receive result ======> hi, dubbo. I am provider 1.
Sun Jan 29 11:23:41 CST 2023 Receive result ======> hi, dubbo. I am provider 1.
           

4. 這個用例複雜嗎?

不,Dubbo 隻需要簡單的配置就可以實作穩定、高效的遠端調用。

以下是一個服務提供者的簡單示例,通過定義若幹個配置就可以啟動。

// 1-basic/dubbo-samples-api/src/main/java/org/apache/dubbo/samples/provider/Application.java

// 定義所有的服務
ServiceConfig<GreetingsService> service = new ServiceConfig<>();
service.setInterface(GreetingsService.class);
service.setRef(new GreetingsServiceImpl());

// 啟動 Dubbo
DubboBootstrap.getInstance()
        .application("first-dubbo-provider")
        .registry(new RegistryConfig(ZOOKEEPER_ADDRESS))
        .protocol(new ProtocolConfig("dubbo", -1))
        .service(service)
        .start();
           

以下是一個服務消費者的簡單示例,通過定義若幹個配置啟動後就可以擷取到對應的代理對象,之後使用者完全不需要感覺這個對象背後的複雜實作,一切隻需要和本地調用一樣就行了。

// 1-basic/dubbo-samples-api/src/main/java/org/apache/dubbo/samples/client/Application.java

// 定義所有的訂閱
ReferenceConfig<GreetingsService> reference = new ReferenceConfig<>();
reference.setInterface(GreetingsService.class);

// 啟動 Dubbo
DubboBootstrap.getInstance()
        .application("first-dubbo-consumer")
        .registry(new RegistryConfig(ZOOKEEPER_ADDRESS))
        .reference(reference)
        .start();

// 擷取訂閱到的 Stub
GreetingsService service = reference.get();
// 像普通的 java 接口一樣調用
String message = service.sayHi("dubbo");
           

更多

本用例介紹了一個 RPC 遠端調用的基礎流程,通過啟動注冊中心、服務提供者、服務消費者三個節點來模拟一個微服務的部署架構。

下一個教程中,将就服務提供者和服務消費者分别都做了什麼配置進行講解,從零告訴你如何搭建一個微服務應用。

繼續閱讀