領先一步
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 的 CLI 更易於使用。在終端中,按如下方式下載 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 控制器,URL 路徑對映(如
/hello)用於將 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 伺服器傳送了一條訊息並觀察了響應。你還學習瞭如何使用 RSocket 訊息路由功能在 Spring 中路由 RSocket 訊息。在下一篇文章中,你將學習如何開始使用 Spring Boot 構建自己的 RSocket 客戶端。