<i id="bcuty"><sub id="bcuty"></sub></i>

<b id="bcuty"></b>

您的位置:首頁 >聚焦 >

天天滾動:新一代通信協議—— RSocket

2023-03-04 13:42:17    來源:程序員客棧
一、簡介

RSocket 是一種二進制字節流傳輸協議,位于 OSI 模型中的5~6層,底層可以依賴 TCP、WebSocket、Aeron 協議。最初由 Netflix 開發,支持 Reactive Streams。其開發背后的動機是用開銷更少的協議取代超文本傳輸協議(HTTP),HTTP 協議對于許多任務(如微服務通信)來說效率低下。

二、設計目標

支持對象傳輸,包括 Fire-and-Forget、Request/Response、Request/Stream、Channel

支持應用層流量控制


(資料圖)

支持單連接雙向、多次復用

支持連接修復

更好的使用WebSocket和Aeron協議

三、消息驅動

網絡通信是異步的,RSocket 協議包含這一點,并將所有通信建模為在單個網絡連接(TCP)上的、多路復用的消息流,在等待響應時從不同步阻塞。

響應式宣言指出:

反應式系統依賴異步的消息傳遞,從而確保了松耦合、隔離、位置透明的組件之間有著明確邊界。這一邊界還提供了將失敗作為消息委托出去的手段。使用顯式的消息傳遞,可以通過在系統中塑造并監視消息流隊列, 并在必要時應用回壓, 從而實現負載管理、 彈性以及流量控制。使用位置透明的消息傳遞作為通信的手段, 使得跨集群或者在單個主機中使用相同的結構成分和語義來管理失敗成為了可能。非阻塞的通信使得接收者可以只在活動時才消耗資源, 從而減少系統開銷。

此外,HTTP/2 FAQ 很好地解釋了在持久連接上采用多路復用的面向消息的協議的動機:

HTTP/1.x 有一個叫做 “head-of-line blocking(隊頭阻塞)” 的問題,在這種情況下,即在一個連接上一次只能有一個未完成請求。

HTTP/1.1 試圖通過流水線(Pipelining)來解決這個問題,但它并沒有完全解決這個問題(大的或慢的響應仍然會阻塞后面的其他響應)。此外,人們發現流水線很難部署,因為許多代理和服務器不能正確地處理它。

在HTTP/1中使用并發連接和域名分片來緩解HOL問題

并發連接,瀏覽器針對每個源(域名)可以打開4-8個TCP連接,提升并發度。

域名分片,瀏覽器和HTTP/1限制了并發連接的數量,那么就把多個域名指向一臺服務器,從而提升連接數量。

這迫使客戶端使用一些啟發式方法(通常是猜測)來確定什么請求在什么時候放在與源站的哪個連接上;由于加載一個頁面的次數通常是可用連接數量的10倍或者更多。這會導致被阻塞的請求“瀑布式”的增長,從而嚴重的影響性能。

多路復用通過允許多個請求和響應消息在一個連接上同時傳輸來解決這些問題;甚至可以將一條消息的部分與另一條消息的部分混合在一起。

使用HTTP/1,瀏覽器為每個源打開4-8個連接,由于許多站點使用多個源,這可能意味著打開單個頁面要加載30多個TCP連接。

一個應用程序同時打開如此多的連接,打破了TCP所建立的許多假設;由于每個連接都會在響應中傳輸大量的數據,因此TCP緩沖區很大可能會溢出,從而導致擁塞事件和超時重傳。

一個應用程序同時打開如此多的連接,此外,使用如此多的連接不公平地壟斷了網絡資源,“竊取”了其他性能更好的應用程序(如VoIP)的資源。

四、Interaction Models(交互模型)

不合適的協議會增加系統開發的成本。它可能是一個不匹配的抽象,但是我們必須將系統設計強加到他允許的交互模型中。這迫使開發人員花費額外的時間來解決它的缺點,以處理錯誤并獲得可接受的性能。在多語言環境中,這個問題被放大了,因為不同的語言將使用不同的方法來解決這個問題,這需要團隊之間的額外協調。到目前為止,通信協議事實上的標準是HTTP,它只支持請求/響應的交互模式。在某些情況下,這可能不是最理想通信模型。

一個例子是推送通知。使用request/respones交互模型,客戶端必須使用輪訓不斷檢查服務端的狀態。應用程序每秒執行大量的請求,只是為了輪詢,然后被告知沒有適合它們的東西。這對于客戶端、服務器、網絡來說是巨大的浪費?;ㄙM金錢;并增加了基礎設施的規模、運營的復雜性,從而提高了可用性。它還通常會增加用戶接收通知時的延遲,因為輪詢會縮減到更長的間隔以試圖降低成本。

出于這個和其他原因,RSocket不僅僅局限于一個交互模型。下面描述的各種支持的交互模型為系統設計提供了強大的新可能性:

4.1 Fire-and-Forget(即發即棄)

即發即棄是請求/響應的優化,在不需要響應時很有用。它允許顯著的性能優化,不僅僅是通過跳過響應來節省網絡使用,而且還可以減少客戶端和服務器的處理時間,因為客戶端不需要記錄和等待請求關聯的響應和取消請求。

此交互模型對于支持有損的用例非常有用,例如非關鍵事件日志記錄。

可以這樣使用:

FuturecompletionSignalOfSend=socketClient.fireAndForget(message);

4.2 Request/Response (single-response)(請求/響應(單響應))

仍然支持標準請求/響應語義,并且仍有望代表 RSocket 連接上的大多數請求。這些請求/響應交互可以被認為是優化的“只有 1 個響應的流”,并且是在單個連接上多路復用的異步消息。

消費者“等待”響應消息,所以它看起來像一個典型的請求/響應,但它從不同步阻塞。

可以這樣使用:

Futureresponse=socketClient.requestResponse(requestPayload);

4.3 Request/Stream (multi-response, finite)(請求/流(多響應,有限))

從request/response延伸出來的是request/stream,它允許多條消息流回。將此視為“集合”或“列表”響應,但不是將所有數據作為單個響應返回,而是按順序流回每個元素。

用例可能包括以下內容:

獲取視頻列表

在目錄中獲取產品

逐行檢索文件

可以這樣使用:

Publisherresponse=socketClient.requestStream(requestPayload);

4.4 Channel(通道)

通道是雙向的,在兩個方向上都有消息流。

受益于此交互模型的示例用例是:

客戶端請求一個數據流,該數據流最初會破壞當前的世界視圖

當發生變化時,增量/差異從服務器發送到客戶端

客戶端隨時間更新訂閱以添加/刪除標準/主題/等。

如果沒有雙向通道,客戶端將不得不取消初始請求,重新請求并從頭開始接收所有數據,而不是僅僅更新訂閱并有效地獲取差異。

可以這樣使用:

Publisheroutput=socketClient.requestChannel(Publisherinput);

五、協議形式

連接上傳輸的數據是流(Stream)

流(Stream)由幀(Frame)組成

幀(Frame)包含了元數據(MetaData)與業務數據(Data)

基于 RSocket 協議,我們的業務數據會被打包成幀,并以幀流的形式在客戶端與服務端互相傳輸。所以 RSocket 的所有特性都是基于這個幀流實現的。協議詳情可以參考:https://rsocket.io/about/protocol

RSocket是一個二進制協議,也就是說在一個RSocket連接上傳輸的消息體對數據格式沒有任何要求,應用程序可以為所欲為的壓縮數據量的大小。

這樣的二進制協議通常來說能給性能帶來極大的提升,但是產生的代價是,網絡中間件也會因為無法解讀消息體中的數據,喪失了在對具體應用流量進行監控,日志和路由的能力。RSocket通過把每個消息體分成data和metadata的方式,在保證高效傳輸的前提下,提供了暴露少量元數據給網絡中間件的能力。

對于每個data和metadata,應用可以采用不同的序列化方法。

data一般作為應用本身需要傳遞的業務數據,采取自定義的高效序列化方式,且對網絡基礎設施不可見。

metadata可以采用網絡基礎設施一致默認的格式。在分布式傳輸的過程中,這些中間件可以按需求對metadata進行讀寫,然后監控應用健康狀況或者調整路由。

六、RSocket與其它協議有什么區別?6.1 對比Http1.x

Http1.x只支持request/response,但是現實應用中并不是所有請求都需要有回應(Fire And Forget)、有的需求需要一個請求返回一個數據流(request/stream)、有的還需要雙向數據傳輸(channel)。

6.2 對比Http2.x

http2.x不支持應用層流量控制、偽雙向傳輸,即服務端push數據本質上還是對客戶端請求的響應,而不是直接推送。RSocket做到了真正的雙向傳輸,使得服務端可以調用客戶端服務,使得服務端和客戶端在角色上完全對等,即兩邊同時是Requester和Responder。

6.3 對比grpc

grpc需要依賴protobuf,本質上還是http2.x。RSocket不限制編解碼,可以是xml、json、protobuf等。

性能上grpc要差一些:詳見壓測對比,https://dzone.com/articles/rsocket-vs-grpc-benchmark

6.4 對比TCP

一個應用層的協議、一個傳輸層的協議,其實兩者不在一個層面,為啥要作比較呢,因為netty讓tcp層的編程也很容易,但是需要自定義傳輸協議,比如定義header、body長度等等,用起來還是很麻煩的。

6.5 對比WebSockets

websocket不支持應用層流量控制,本質上也是一端請求另一端響應,不支持連接修復。

七、RSocket適用于哪些場景?

移動設備與服務器的連接

數據雙向傳輸,且支持流量控制。支持背壓,背壓的意思:如果客戶端請求服務端過快,那么服務端會堆積請求,最終耗光資源。有了背壓機制,服務端可以根據自己的資源來控制客戶端的請求速度,即調用客戶端告訴它別發那么快。

支持連接修復,比如手機進地鐵之后,網絡斷開一段時間,其他協議需要重新建立連接,RSocket則可以修復連接繼續傳輸幀數據。

微服務場景

spring cloud目前支持的http協議,不能fire and forget、不能請求流數據、不能單連接雙向調用;替換成RSocket之后可以滿足以上需求的同時提高性能。且針對服務治理、負載均衡等RSocket都在慢慢完善。

由于微服務和移動設備的普及,RSocket火起來應該就是這幾年的事兒,讓我們拭目以待吧。


歡迎大家關注我的公眾號【老周聊架構】,Java后端主流技術棧的原理、源碼分析、架構以及各種互聯網高并發、高性能、高可用的解決方案。

關鍵詞: 流量控制 應用程序 多路復用

相關閱讀

巨胸护士在线播放视频二区

<i id="bcuty"><sub id="bcuty"></sub></i>

<b id="bcuty"></b>