徹底搞懂 RSocket 協議

2025.04.23
我們知道,常見的 RESTful Web 服務採用的都是基於 HTTP 協定實現的請求 - 響應式互動方式。這種互動方案很簡單,但是因為只支援單一的互動方式,也就無法應付所有日常開發需求場景,例如服務端主動向客戶端推送資料。

那麼,能不能在網路協定層上具備更豐富的互動方式呢?答案是肯定的,這就是我們今天要討論的 RSocket 協定。 RSocket 協定提供了多種用戶端和服務端之間的互動方式,它並不是 HTTP 協定的補充,而是基於響應式程式設計技術的全新的、高效能網路通訊協定。


在引入 RSocket 協議之前,你必須要了解為什麼需要這樣一個協議,讓我們從傳統的請求 - 回應模式所存在的問題開始說起。

RSocket 協定解決了什麼問題?
請求 - 回應模式的問題
請求 - 回應模式的一個問題是,高並發場景下,效能和響應性上存在瓶頸。因為整個處理過程是同步阻塞的,如果某個請求的回應時間過長,會導致其他請求無法及時回應。這一點我之前在之前的響應式程式設計一課中有詳細講解。

更重要的是,對許多應用場景來說,HTTP 協定提供的請求 - 回應模式是不合適的。典型的例子是訊息推送,如果客戶端需要取得最新的推播訊息,就必須使用輪詢,客戶端不停的發送請求到伺服器來檢查更新,無疑這會造成了大量資源浪費。
你可能會說,我們可以使用伺服器發送事件(Server-Sent Events,SSE)技術實現從服務端向客戶端推送訊息。不過,SSE 也是建構在 HTTP 協定上的處理機制,一般只用來傳送文本,提供的功能非常有限。

幸運的是,業界認識到了非同步、多向互動通訊的必要性。在 2015 年,RSocket 協定就在這樣的背景下誕生了。
RSocket 協定的解決方案
RSocket 是一種語言無關的二進位網路協議,用來解決現有網路傳輸協議存在的單一請求 - 回應模式以及效能問題。那麼,它是怎麼解決這個問題的呢?

RSocket 以非同步訊息的方式提供 4 種互動模式,除了請求 - 回應(request/response)模式之外,還包括請求 - 回應流(request/stream)、即發即棄(fire-and-forget)和通道(channel)這三種新的互動模式。
我們來看這四種互動模式的特點:

請求 - 回應模式:這是最典型也最常見的模式。發送方在發送訊息給接收方之後,等待與之對應的回應訊息

請求 - 回應流模式:發送方的每個請求訊息,都對應接收方的一個訊息流作為回應

即發即忘模式:發送方的請求訊息沒有與之對應的回應

通道模式:在發送方和接收方之間建立一個雙向傳輸的通道

我們可以從請求與回應的數量對應關係來對上述四種互動模式做一個總結。
可以看到,當我們選擇具體的互動模式時,請求 - 回應、請求 - 回應流和即發即忘這三種互動模式的請求數量都是 1,並且能夠獲得不同數量的回應結果。我們就可以根據此特性來重構現有的請求處理過程。而通道模式則比較特殊,它的請求數量和回應數量都是 N,決定了我們可以選擇它來應付雙向的資料流處理場景。

RSocket 協定專門設計用來和響應式程式設計技術風格的應用程式配合使用,在使用 RSocket 協定時,響應式程式設計系統中的資料流機制仍然有效。
為了更好的理解 RSocket 協議,我們比較它和 HTTP 協議。在互動模式上,與 HTTP 的請求 - 回應這種單向互動模式不同,RSocket 倡導的是對等通訊。這種對等通訊不是傳統單向互動模式的改進,而是在客戶端和服務端之間可以自由的相互發送和處理請求。
另一方面,從效能上講,我們知道 HTTP 協定為了相容各種應用方式,本身有一定的複雜性和冗餘性,效能一般。而 RSocket 採用的是自訂二進位協議,本身的定位就是高效能通訊協議,效能上比 HTTP 高出一個數量級。

如何正確使用 RSocket 協定?
到這裡,我們就明白了 RSocket 協定是要解決什麼問題,以及是如何解決的了。接下來,我們具體來看看如何正確使用 RSocket 協定。
RSocket 介面
我們先來看看 RSocket 協定中最核心的接口,即 RSocket 接口的定義,如下所示。
顯然,RSocket 介面透過四個方法分別實現了它所提供的四種互動模式,這裡的 Payload 代表的就是一種訊息對象,由兩部分組成,即元資訊 metadata 和資料 data,類似於常見的訊息通訊中的訊息頭和訊息體的概念。

同時,你注意到嗎,這裡出現了兩個新的資料結構 Mono 和 Flux。在響應式程式設計中,Mono 代表只包含 0 個或 1 個元素的資料流,而對應的 Flux 則是一個包含 0 到 n 個元素的資料流。
所以 fireAndForget() 方法回傳的是一個 Mono 流,符合即發 - 即棄模式的語意。而 requestStream() 作為請求 - 回應流模式的實現,與 requestResponse() 的區別在於它的返回值是一個 Flux 流,而不是一個 Mono 物件。而且,RSocket 提供的請求 - 回應模式也比 HTTP 更具優勢,因為它是非同步且多工的。

另一方面,與其他方法不同,requestChannel() 方法返回的並不是一個 Payload 訊息對象,而是一個代表響應式流的 Publisher 對象,意味著這種模式下的輸入輸出都是響應式流,也就是說可以實現客戶端和服務端之間的雙向交互,這也和通道模式的定義一致。
RSocket 與框架集成
RSocket 介面過於底層,開發人員需要考慮伺服器端和用戶端的特定建置方式以及手動實作遠端呼叫的細節。所以,我通常不建議直接使用 RSocket 介面進行應用程式的開發,而是傾向於借助特定的開發框架。如果你使用的是 Spring Boot 框架,就可以建立如下所示一個簡單 Controller:
這裡引入了一個新的註解@MessageMapping,類似 Spring MVC 中的@RequestMapping 註解,@MessageMapping 是,Spring 中提供,用來指定 RSocket 協定中訊息處理的目的地。然後,我們輸入了一個 String 類型的參數並傳回一個 Mono 對象,符合請求 - 回應互動模式的定義。

為了存取這個 RSocket 端點,我們需要建立一個 RSocketRequester 請求物件。基於該對象,我們就可以透過它的 route() 方法路由到前面透過@MessageMapping 註解建構的"hello"端點,如下所示:
我們再來看一個請求 - 回應流的範例,如下所示:

這裡我們根據輸入的 Request 對象,傳回一個 Flux 流,每一秒發送一個新的 Message 物件。

如果你想在其他框架中使用 RSocket 協議,也有很多選擇。 Dubbo 在 3.0.0-SNAPSHOT 版本里基於 RSocket 對響應式編程提供了支持,開發人員可以非常方便的使用 RSocket 的 API。而隨著 Spring 框架的持續升級,5.2 版本中也把 RSocket 作為缺省的網路通訊協定。

目前,RSocket 協定的應用已經越來越廣泛。相信隨著這項技術的不斷成熟,日常開發過程中也會出現更多的應用場景和解決方案。
總結
今天我們系統討論了 RSocket 這款新的高效能網路通訊協定。與 HTTP 協定相比,RSocket 提供了四種不同的互動模式來實現多樣化的網路通訊。同時,RSocket 也無縫整合了響應式程式設計技術,我們可以透過 RSocket 協定來實現非同步、非阻塞式的網路通訊。