RSocket一種新的響應式應用新協議

FeelTouch發表於2019-03-07

簡介

RSocket是在華盛頓特區舉行的SpringOne平臺會議上宣佈的,是一種新的第7層語言無關的應用網路協議。它是一種基於Reactive Streams背壓的雙向,多路複用,基於訊息的二進位制協議。它由Facebook,Netifi和Pivotal等工程師開發,提供Java,JavaScript,C ++和Kotlin等實現。

開源 RSocket 專為服務而設計。它是一種面向連線的訊息驅動協議,在應用程式級別具有內建流控制。它既可以在瀏覽器中同樣使用,也可以在 伺服器上使用。這意味著您可以流式傳輸資料或執行Pub / Sub而無需設定應用程式佇列。它也是二進位制的。它對文字和二進位制資料同樣有效,並且對傳輸的內容負荷進行分段。

該協議專門設計用於與Reactive風格應用配合使用,這些應用程式基本上是非阻塞的,並且通常(但不總是)與非同步行為配對。使所謂Reactive背壓: 即釋出者無法向訂戶傳送資料直到該訂戶已經準備就緒的想法,這是與“非同步”的關鍵區別。反應式程式設計(響應式reactive)是 Java 中高效應用的下一個前沿。但有兩個主要障礙 - 資料訪問和網路。RSocket旨在解決後一個問題,而R2DBC旨在解決前者問題。

HTTP vs RSocket

HTTP的一個重要問題是,它強迫客戶端負擔起所有責任來處理不同型別的錯誤上,包括重試邏輯,超時,斷路器等。使用Reactive架構構建的應用程式可以提高效率並擴充套件。

RSocket與HTTP的不同之處在於它定義了四種互動模型:

  1. Fire-and-Forget:優化請求/響應,在不需要響應時非常有用,例如非關鍵事件日誌記錄。
  2. 請求/響應:當您傳送一個請求並收到一個響應時,就像HTTP一樣。即使在這裡,該協議也具有優於HTTP的優點,因為它是非同步和多路複用的。
  3. 請求/流:類似於返回集合的請求/響應,集合被回送而不是查詢直到完成,因此例如傳送銀行帳號,用實時的帳戶事務流進行響應。
  4. 頻道:允許任意互動模型的雙向訊息流。

基於訊息意味著協議可以支援單個連線上的多路複用。此外,與TCP一樣,它是真正的雙向,因此一旦客戶端啟動與伺服器的連線,連線中的雙方就變得彼此等同 - 實質上,伺服器可以從客戶端請求資料。

RSocket 特性

RSocket還支援基於每個訊息的流量控制

RSocket還支援基於每個訊息的流量控制。在主題演講中,Facebook工程師Steve Gury表示:

當您傳送訊息時,您還要指定您能夠滿足多少響應,並且伺服器必須滿足該約束,但是當我完成處理這些響應後,我可以要求更多。RSocket也可以在鏈中工作,因此如果連結多個RSocket連線,流控制將是端到端地工作。

實質上,RSocket解決的問題是跨流程式的背壓,即網路上的背壓。

當必須在服務網格中呼叫另一個微服務時會發生什麼,我如何保證它不會出現呼叫一大堆資料,並且它不會嘗試向我客戶端傳送所有這些資料?

RSocket與傳輸無關,支援TCP,WebSocket和Aeron UDP,支援混合傳輸協議,不會造成語義損失 - 背壓和流量控制都將繼續工作。

它還支援連線恢復。建立RSocket連線時,您可以指定先前連線的ID,如果伺服器仍在記憶體中有流,則可以恢復流的消耗。

它是一種訊息驅動的二進位制協議,在指定網路連線的情況下,請求者 - 響應者互動被分解為一組離散的幀,這些幀中的每一個都封裝了某種訊息。

框架是二進位制的,而不是人類可讀的,如 JSON 或XML,為機器到機器的通訊提供了顯著的效率。與所有訊息傳遞協議一樣,訊息傳遞的內容有效負荷只是位元組流,因此可以是您想要的任何內容,包括 XML 或JSON。

在Facebook,RSocket用於名為LiveServer的服務,該服務負責響應可被視為GraphQL訂閱的實時查詢。伺服器響應資料,但也響應未來的更新流

RSocket 例項

Demo Java Server:

RSocketFactory.receive()
    .frameDecoder(Frame::retain)
    .acceptor(new PingHandler())
    .transport(TcpServerTransport.create(7878))
    .start()
    .block()
    .onClose();

Demo Java Client:

Mono<RSocket> client =
    RSocketFactory.connect()
        .frameDecoder(Frame::retain)
        .transport(TcpClientTransport.create(7878))
        .start();

PingClient pingClient = new PingClient(client);

Recorder recorder = pingClient.startTracker(Duration.ofSeconds(1));

int count = 1_000;

pingClient
    .startPingPong(count, recorder)
    .doOnTerminate(() -> System.out.println("Sent " + count + " messages."))
    .blockLast();

參考:響應式應用新協議RSocket

相關文章