索引(index)是幫助MySQL高效獲取數據的數據結構(有序)。在數據之外,資料庫系統還維護著滿足 特定查找演算法的數據結構,這些數據結構以某種方式引用(指向)數據, 這樣就可以在這些數據結構 上實現高級查找演算法,這種數據結構就是索引。 優缺點: 優點: 提高數據檢索效率,降低資料庫的IO成本 通過 ...
本文將基於 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 [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 主要由三個部分組成:代碼風格文件、測試代碼、集成測試。
-
代碼風格文件是開發 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 技能