領先一步
VMware 提供培訓和認證,助您快速進步。
瞭解更多時間:約 15 分鐘。
在多樣化的微服務世界中,HTTP 是代理間通訊無可爭議的領導者。它成熟、完善且無處不在。但在某些情況下,HTTP 的請求-響應模式可能很麻煩。如果您需要超越傳統請求-響應的通訊模式,例如即發即棄或流式傳輸,該怎麼辦?如果您想向任一方向傳送訊息,又該怎麼辦?
透過 HTTP,有一些方法可以實現這些,但這不是該協議構建的目的。許多解決方案帶有額外的權衡或缺點。此外,並沒有規定說“你必須始終使用 HTTP”,像 AMQP 這樣的訊息協議已經證明了這一點。因此,瞭解您的選擇是好的,並且偶爾在您的列表中新增一些新技術也是有益的。本文就介紹了一種這樣的替代方案——RSocket。
RSocket 是一種新的訊息協議,旨在解決一些常見的微服務通訊挑戰。透過 RSocket,您將獲得一個靈活的協議,它可以透過 TCP 或 WebSockets 工作。這意味著您可以直接傳輸二進位制訊息而無需轉換。您將獲得現代控制,如多路複用、背壓、恢復和路由,以及多種訊息模式,包括即發即棄、請求-響應和流式傳輸。RSocket 也完全是反應式的,因此它非常適合您的高吞吐量微服務應用。早期採用者包括 Netflix、Pivotal、阿里巴巴和 Facebook——它們都是提供可擴充套件網際網路服務的專家。
在本文(本系列的第一篇)中,您將學習如何開始使用 RSocket。您將熟悉它的工作原理,並體驗它的一些強大之處。到本系列結束時,您將把 RSocket 新增到您的技能庫中,以便下次您權衡各種選擇時,您將多一個可供選擇的協議。
由於請求-響應模式對大多數 Web 開發人員來說都很熟悉,我們將從這種模式開始我們的 RSocket 之旅。請求-響應的語義相當直接,您傳送一個請求,得到一個響應。HTTP 就是建立在這種基本互動模式之上的,並且非常普遍。
在本教程中,您將瞭解如何使用 Spring Boot 作為伺服器、終端應用作為客戶端來使用 RSocket 實現請求-響應模式。
請求-響應只是 Spring 和 RSocket 支援的四種互動模型之一。我們將在未來的文章中介紹其他模型。
當您按照以下步驟操作時,您會注意到使用 Spring Boot 構建 RSocket 伺服器所需的程式碼量非常少。程式碼已在此處為您提供,但如果您願意,也可以在幾分鐘內從頭開始自己編寫程式碼。
首先,檢查您是否安裝了以下先決條件
如果您是 Windows 使用者,請切換到 Microsoft 的適用於 Linux 的 Windows 子系統。Microsoft 關於如何執行此操作的說明在此處。
現在,將下載的專案資料夾設定為您在終端中的當前目錄
cd spring-rsocket-demo
接下來,將由Toshiaki Maki開發的優秀的RSocket Client CLI下載到您克隆或提取程式碼的rsocket-server
資料夾中。還有官方的 RSocket CLI 在其他地方,但 Toshiaki 的更容易使用一些。在終端中,按如下方式下載 JAR 檔案:
cd rsocket-server
wget -O rsc.jar https://github.com/making/rsc/releases/download/0.4.2/rsc-0.4.2.jar
稍後您將使用此客戶端與 RSocket 伺服器通訊,但現在,透過呼叫幫助命令來測試它是否正常工作,如下所示:
java -jar rsc.jar --help
您應該會看到如下所示(我已截斷)的輸出,解釋了命令的用法和選項。
usage: rsc Uri [Options]
Non-option arguments:
[String: Uri]
Option Description
------ -----------
--channel Shortcut of --im REQUEST_CHANNEL
-d, --data [String] Data. Use '-' to read data from
...
將此終端視窗保持開啟狀態,稍後您會需要它。
在您的 IDE 中開啟 rsocket-server 專案並檢查程式碼。如您所見,使用 Spring Boot 啟動 RSocket 伺服器所需的程式碼量非常少。以下是一些重點:
在專案的pom.xml
檔案中,您可以看到 Spring Boot RSocket 伺服器所需的<dependencies>
。之所以使用 Spring Boot 版本2.2.5.RELEASE
,是因為在撰寫本文時,該版本擁有最適用於生產的 RSocket 特性。該專案還依賴於lombok
和spring-boot-starter-rsocket
庫。Lombok 為 Java 資料類添加了建構函式、getter、setter 和 equals 方法,同時也簡化了對日誌等內容的訪問。用於 RSocket 的 Spring Boot Starter 將 RSocket 與 Spring Boot 整合,並在執行時自動為您配置一些 RSocket 基礎設施。
在application.properties
檔案中,RSocket 伺服器的 TCP 埠設定為7000
,並且 Spring Boot 的延遲初始化特性已開啟。
spring.rsocket.server.port=7000
spring.main.lazy-initialization=true
第一個需要詳細檢視的類叫做Message.java
。這個 Lombok @Data
類用於建模客戶端和伺服器之間(如果您願意,也可以稱之為“請求者”和“響應者”之間)的請求和響應訊息。該類看起來像這樣…
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Message {
private String origin;
private String interaction;
private long index;
private long created = Instant.now().getEpochSecond();
public Message(String origin, String interaction) {
this.origin = origin;
this.interaction = interaction;
this.index = 0;
}
public Message(String origin, String interaction, long index) {
this.origin = origin;
this.interaction = interaction;
this.index = index;
}
}
使用這個類,您可以說明訊息的來源(它的origin
)、打算使用的訊息傳遞樣式(interaction
)以及訊息在訊息序列中的序號(它的index
)。Lombok 透過提供建構函式、getter、setter、toString 和 hashcode 的實現來簡化程式碼。
RSocket 伺服器的控制器程式碼可以在RSocketController.java
檔案中找到。該類被註解為 Spring 的@Controller
,這實質上意味著它聲明瞭服務終點——在本例中是 RSocket 終點。
@Controller
public class RSocketController {
@MessageMapping("request-response")
Message requestResponse(Message request) {
log.info("Received request-response request: {}", request);
// create a single Message and return it
return new Message(SERVER, RESPONSE);
}
}
在該類內部,有一個名為requestResponse()
的方法,它接受一個Message
物件(請求)並返回一個Message
物件(響應)。
您會注意到,這個requestResponse()
方法使用@MessageMapping("request-response")
註解進行了修飾。這個註解宣告,任何元資料中包含 RSocket 路由request-response
的訊息都應由該方法處理。稍後,當您從客戶端傳送請求訊息時,您將使用這個路由。
您是否注意到這與 Spring 的 REST 控制器略有不同?對於 REST 控制器,使用
/hello
這樣的 URL 路徑對映將 HTTP 呼叫與其處理方法關聯起來。
程式碼就是這些。我們來試試吧。
保持您現有的終端視窗開啟,在第二個終端視窗中,將rsocket-server
資料夾設為當前目錄。然後使用以下命令構建並執行 RSocket 伺服器:
./mvnw clean package spring-boot:run -DskipTests=true
或者,如果您願意,也可以使用 Java IDE 中的“構建”和“執行”命令。
接下來,您將使用在步驟 1 中下載並測試過的 RSocket 客戶端rsc.jar
向執行中的伺服器傳送訊息。回到顯示--help
文字的原始終端視窗,併發出以下命令:
java -jar rsc.jar --debug --request --data "{\"origin\":\"Client\",\"interaction\":\"Request\"}" --route request-response tcp://:7000
您會注意到,該命令聲明瞭一個 RSocket 訊息路由(透過新增--route
選項並指定路由名稱來實現)。在本例中,路由是request-response
,它與RSocketController.java
中請求-響應處理方法中宣告的@MessageMapping
匹配。
命令執行時,您將在終端視窗中看到一些除錯資訊,解釋了請求-響應互動期間發生的情況。它看起來像這樣:
2020-02-27 11:20:21.806 DEBUG --- [actor-tcp-nio-1] i.r.FrameLogger : sending ->
Frame => Stream ID: 1 Type: REQUEST_RESPONSE Flags: 0b100000000 Length: 69
Metadata:
+-------------------------------------------------+
| 0 1 2 3 4 5 6 7 8 9 a b c d e f |
+--------+-------------------------------------------------+----------------+
|00000000| 10 72 65 71 75 65 73 74 2d 72 65 73 70 6f 6e 73 |.request-respons|
|00000010| 65 |e |
+--------+-------------------------------------------------+----------------+
Data:
+-------------------------------------------------+
| 0 1 2 3 4 5 6 7 8 9 a b c d e f |
+--------+-------------------------------------------------+----------------+
|00000000| 7b 22 6f 72 69 67 69 6e 22 3a 22 43 6c 69 65 6e |{"origin":"Clien|
|00000010| 74 22 2c 22 69 6e 74 65 72 61 63 74 69 6f 6e 22 |t","interaction"|
|00000020| 3a 22 52 65 71 75 65 73 74 22 7d |:"Request"} |
+--------+-------------------------------------------------+----------------+
2020-02-27 11:20:21.927 DEBUG --- [actor-tcp-nio-1] i.r.FrameLogger : receiving ->
Frame => Stream ID: 1 Type: NEXT_COMPLETE Flags: 0b1100000 Length: 81
Data:
+-------------------------------------------------+
| 0 1 2 3 4 5 6 7 8 9 a b c d e f |
+--------+-------------------------------------------------+----------------+
|00000000| 7b 22 6f 72 69 67 69 6e 22 3a 22 53 65 72 76 65 |{"origin":"Serve|
|00000010| 72 22 2c 22 69 6e 74 65 72 61 63 74 69 6f 6e 22 |r","interaction"|
|00000020| 3a 22 52 65 73 70 6f 6e 73 65 22 2c 22 69 6e 64 |:"Response","ind|
|00000030| 65 78 22 3a 30 2c 22 63 72 65 61 74 65 64 22 3a |ex":0,"created":|
|00000040| 31 35 38 32 38 30 32 34 32 31 7d |1582802421} |
+--------+-------------------------------------------------+----------------+
{"origin":"Server","interaction":"Response","index":0,"created":1582802421}
您看到的除錯輸出分為三個“訊息幀”。第一個訊息幀標記為Metadata
。在本例中,它顯示了傳送到伺服器的路由元資料(request-response
)。第二個幀顯示客戶端傳送到伺服器的Data
訊息(一個 JSON 字串)。第三個幀顯示伺服器返回給客戶端的響應訊息(也是一個 JSON 字串)。
在最後一行,您可以看到伺服器返回的 JSON 格式的響應被單獨打印出來,確認我們的命令訊息已成功被伺服器接收並確認。
{"origin":"Server","interaction":"Response","index":0,"created":1582802421}
恭喜!您已完成。您剛剛使用 RSocket 傳送了一條請求-響應訊息。現在您可以透過在終端視窗中按下Ctrl-C
或關閉視窗來停止 RSocket 伺服器。如果您使用的是 IDE 執行 RSocket 伺服器,則可以按照通常的方式在 IDE 中停止程序。
您下載的 RSocket rsc
客戶端使用 RSocket 訊息協議向RSocketController
傳送請求訊息。訊息透過 TCP 傳送到地址tcp://:7000
,伺服器正在該地址等待。
第一個訊息幀中傳送了訊息路由指令。此路由指令使用 CLI 客戶端的--route
選項設定,並設定為request-response
。Spring 使用此路由資訊來選擇要呼叫的正確@MessageMapping
端點,在本例中是requestResponse(Message request)
方法。該方法然後返回自己的訊息作為響應。CLI 客戶端將整個互動過程以訊息幀序列的形式列印在終端視窗中。
如果您跟著操作,您會看到使用 Spring Boot 編寫一個簡單的 RSocket 伺服器是多麼容易。您檢查了所需的 Java 程式碼,然後在本地啟動了 Spring Boot 伺服器。然後您向 RSocket 伺服器傳送了一條訊息並觀察了響應。您還學習瞭如何在 Spring 中使用 RSocket 訊息路由功能來路由您的 RSocket 訊息。在下一篇文章中,您將學習如何使用 Spring Boot 開始構建您自己的 RSocket 客戶端。