本文將基於 Dubbo Samples 示例演示如何快速搭建並部署一個微服務應用。
背景
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 git@github.com: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 主要由三個部分組成:程式碼風格檔案、測試程式碼、整合測試。
-
程式碼風格檔案是開發 Dubbo 程式碼的時候可以使用,其中包括了 IntelliJ IDEA 的配置檔案。
-
測試程式碼即本教材所需要的核心內容。目前包括了 5 個部分的內容:面向初學者的 basic 入門用例、面向開發人員的 advanced 高階用法、面向中介軟體維護者的 extensions Dubbo 周邊擴充套件使用示例、面向生產的 governance 服務治理用例以及 Dubbo 學習系列。本文將基於 basic 入門用例中最簡單的 Dubbo API 使用方式進行講解。
-
整合測試是 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
),列印出的資料就是服務提供者處理之後返回的,標誌著一次服務呼叫的成功。
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 遠端呼叫的基礎流程,透過啟動註冊中心、服務提供者、服務消費者三個節點來模擬一個微服務的部署架構。
下一個教程中,將就服務提供者和服務消費者分別都做了什麼配置進行講解,從零告訴你如何搭建一個微服務應用。
歡迎在 https://github.com/apache/dubbo 給 Dubbo Star。
搜尋關注官方微信公眾號:Apache Dubbo,瞭解更多業界最新動態,掌握大廠面試必備 Dubbo 技能