領先一步
VMware 提供訓練和認證,以加速您的進展。
了解更多時間:約 15 分鐘。
在多樣化的微服務世界中,HTTP 是代理程式對代理程式通訊中無可爭議的領導者。它成熟、完善且無處不在。但在某些情況下,HTTP 請求-回應可能會很麻煩。如果您需要超越傳統請求-回應的通訊模式,例如單向發送或串流處理,該怎麼辦?如果您想要在任一方向發送訊息,又該怎麼辦?
使用 HTTP,有一些方法可以實現這一點,但這並不是該協定設計的目的。許多解決方案都帶有額外的權衡或缺點。此外,沒有規定說「你應該總是使用 HTTP」,像 AMQP 這樣的訊息協定已經證明了這一點。因此,了解您的選擇是好的,並且偶爾在您的列表中添加一些新技術也是健康的。這篇文章是關於其中一種替代方案——RSocket。
RSocket 是一種新的訊息協定,旨在解決一些常見的微服務通訊挑戰。使用 RSocket,您可以獲得一個靈活的協定,可在 TCP 或 WebSockets 上運作。這表示您可以進行二進位訊息傳輸而無需轉換。您可以使用多工處理、背壓、恢復和路由等現代控制功能,並且可以使用多種訊息傳輸模式,包括單向發送、請求-回應和串流處理。RSocket 也完全是反應式的,因此非常適合您的高吞吐量微服務應用程式。早期的採用者包括 Netflix、Pivotal、阿里巴巴和 Facebook——它們都是交付可擴展的網際網路服務的專家。
在這篇文章(本系列的第一篇)中,您將學習如何開始使用 RSocket。您將熟悉它的運作方式,並體驗它的一些強大功能。在本系列結束時,您將把 RSocket 添加到您的技能組合中,以便下次您在考慮選項時,您可以多一個協定可供選擇。
由於請求-回應是大多數 Web 開發人員熟悉的領域,我們將從這種模式開始我們的 RSocket 之旅。請求-回應的語意非常簡單,您發送一個請求,您會收到一個回應。HTTP 是建立在這種基本互動之上的,而且非常常見。
在本教學課程中,您將了解如何使用 RSocket 和 Spring Boot 作為您的伺服器,以及終端機應用程式作為您的用戶端來執行請求-回應。
請求-回應只是 Spring 和 RSocket 支援的四種互動模型之一。我們將在未來的文章中介紹其他模型。
當您按照以下步驟操作時,您會注意到使用 Spring Boot 建立 RSocket 伺服器所需的程式碼量非常少。程式碼已在此處提供給您,但如果您願意,您也可以在幾分鐘內從頭開始編寫程式碼。
首先,檢查您是否已安裝以下先決條件
如果您是 Windows 使用者,請切換到 Microsoft 的 Windows Subsystem for Linux。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 伺服器通訊,但現在,請呼叫 help 命令來測試它是否正常運作,如下所示
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")
註解進行裝飾。此註解宣告,任何具有包含 request-response
的 RSocket 路由的中繼資料的訊息都應由此方法處理。您稍後將在從用戶端發送請求訊息時使用此路由。
您是否注意到這與 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://127.0.0.1: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://127.0.0.1:7000
。
訊息路由指示在第一個訊息框架中發送。此路由指示是使用 CLI 用戶端的 --route
選項設定的,並設定為 request-response
。Spring 使用此路由資訊來選取要呼叫的正確 @MessageMapping
端點,在本例中為 requestResponse(Message request)
方法。然後,該方法會使用自己的訊息回應。CLI 用戶端將整個互動作為一系列訊息框架列印在終端機視窗中。
如果您一路跟隨,您就會看到使用 Spring Boot 編寫一個簡單的 RSocket 伺服器是多麼容易。您檢查了所需的 Java 程式碼,然後在本機啟動了 Spring Boot 伺服器。然後,您向 RSocket 伺服器發送了一條訊息並觀察了回應。您還學習了如何使用 RSocket 訊息路由功能在 Spring 中路由您的 RSocket 訊息。在下一篇文章中,您將學習如何開始使用 Spring Boot 建置您自己的 RSocket 用戶端。