RSocket — це прикладний протокол для мультиплексованого дуплексного зв'язку за протоколами TCP, WebSocket та іншими механізмами передачі байтових потоків, що використовує одну з таких моделей взаємодії:

  • Request-Response — надсилання одного повідомлення та отримання одного у відповідь.

  • Request-Stream — надсилання одного повідомлення та отримання потоку повідомлень у відповідь.

  • Channel — надсилання потоків повідомлень в обох напрямках.

  • Fire-and-Forget — надсилання одностороннього повідомлення.

Після встановлення початкового з'єднання різниця між "клієнтом" і "сервером" втрачається, оскільки обидві сторони стають симетричними, і кожна сторона може ініціювати одну з перерахованих вище взаємодій. Саме тому в протоколі сторони, що беруть участь, називаються "реквестер (запитувач)" і "респондер (відповідач)", авказані вище взаємодії — "потоки запитів" або просто "запити".

Основні особливості та переваги протоколу RSocket:

  • Семантика Reactive Streams по межі мережі — для потокових запитів, таких як Request-Stream і Channel, сигнали зворотної реакції проходять між реквестером і респондером, дозволяючи реквестеру уповільнити респондер у джерела, що знижує залежність від контролю навантажень на мережевому рівні, а також необхідність буферизації на мережевому рівні або на будь-якому іншому рівні.

  • Регулювання (дроселювання запитів) — ця функція названа "Leasing (обмежене користування)" на ім'я кадру LEASE, який може бути відправлений з будь-якої сторони для обмеження загальної кількості запитів, дозволених іншою стороною за певний час. Періоди обмеженого використання періодично продовжуються.

  • Відновлення сеансу — призначене для випадків втрати зв'язку та вимагає збереження певного стану. Управління станом для програм організовано прозоро і добре працює у поєднанні зі зворотною реакцією, яку може зупинити постачальник, коли це можливо, та зменшити величину необхідного стану.

  • Фрагментація та повторне складання великих повідомлень.

  • Keepalive (heartbeat-повідомлення).

У RSocket є реалізації кількома мовами. Бібліотека Java побудована на основі Project Reactor, а для передачі використовується Reactor Netty. Це означає, що сигнали від публікаторів Reactive Streams у твоєму додатку прозоро поширюватимуться через RSocket мережею.

Протокол

Однією з переваг RSocket є те, що він має чітко прописану логіку роботи "на льоту" і зрозумілу специфікацію, а також певні розширення протоколу. Тому доречно прочитати специфікацію, незалежно від реалізації мови та API фреймворків вищого рівня. Цей розділ містить короткий опис створення певного контексту.

Підключення

Спочатку клієнт підключається до сервера через низькорівневий потоковий засіб передачі, як-то протокол TCP або WebSocket, і посилає серверу кадр SETUP для встановлення параметрів з'єднання.

Сервер може відхилити кадр SETUP, але зазвичай після його відправки (для клієнта) та отримання (для сервера) обидві сторони можуть почати надсилати запити, якщо тільки SETUP не вказує на використання семантики обмеженого використання для обмеження кількості запитів, і в цьому випадку обидві сторони повинні дочекатися кадру LEASE з іншого боку, щоб дозволити робити запити.

Виконання запитів

Після встановлення з'єднання обидві сторони можуть ініціювати запит через один із кадрів REQUEST_RESPONSE, REQUEST_STREAM, REQUEST_CHANNEL або REQUEST_FNF. Кожен із цих кадрів несе одне повідомлення від реквестера до респондера.

Респондер може потім повернути кадри PAYLOAD з повідомленнями у відповідь, а у разі REQUEST_CHANNEL реквестер може також відпарвувати кадри PAYLOAD з додатковими повідомленнями-запитами.

Якщо запит містить потік повідомлень, як-от Request-Stream і Channel, респондер зобов'язаний слідувати сигналам запиту від реквестера. Запит виражається у кількості повідомлень. Початковий запит вказується у кадрах REQUEST_STREAM та REQUEST_CHANNEL. Наступні запити сигналізуються за допомогою кадрів REQUEST_N.

Кожна сторона також може надсилати через кадр METADATA_PUSH повідомлення про метадані, які стосуються не окремого запиту, а з'єднання в цілому.

Формат повідомлення

Повідомлення RSocket містять дані та метадані. Метадані можуть бути використані для відправлення маршруту, токена безпеки тощо. Дані та метадані можуть бути по-різному відформатовані. MIME-типи для кожного з них оголошуються у кадрі SETUP і застосовуються до всіх запитів для цього з'єднання.

Хоча всі повідомлення можуть містити метадані, зазвичай метадані, такі як маршрут, надаються щодо кожному запиту і, отже, включаються тільки до першого повідомлення запиту, тобто до одного з кадрів REQUEST_RESPONSE, REQUEST_STREAM, REQUEST_CHANNEL або REQUEST_FNF.

Розширення протоколу визначають загальні формати метаданих для використання у додатках:

Реалізація Java

Java-реалізація для RSocket побудована на основі Project Reactor. Механізми передачі для TCP та WebSocket побудовані на базі Reactor Netty. Будучи бібліотекою Reactive Streams, Reactor полегшує роботу з реалізації протоколу. У додатках цілком природним є використання Flux та Mono з декларативними операторами та прозорою підтримкою зворотної реакції.

API в RSocket для Java навмисно спрощено і є базовим. У ньому особливу увагу приділено особливостям протоколу та збереженню моделі прикладного програмування (наприклад, генератор коду для RPC порівняно з іншими) як незалежну функціональність вищого рівня.

Основний контракт io.rsocket.RSocket моделює чотири типи взаємодії запитів, водночас Mono надає проміс одного повідомлення, Flux — потік повідомлень, а io.rsocket.Payload — саме повідомлення з доступом до даних та метаданих у вигляді байтових буферів. Контракт RSocket використовується симетрично. У частині надсилання запитів програмі надається RSocket для виконання запитів. У частині надсилання відповідей програма реалізує RSocket для обробки запитів.

Цей опис не є вичерпним вступом. Здебільшого додаткам Spring не доведеться безпосередньо використовувати його API. Однак може бути важливо побачити або поекспериментувати з RSocket окремо від Spring. Java-репозиторій для RSocket містить низку прикладів додатків, що демонструють API та можливості протоколу.

Засоби підтримки у Spring

Модуль spring-messaging містить таке:

  • RSocketRequester — текучий API для виконання запитів через io.rsocket.RSocket з кодуванням/декодуванням даних та метаданих.

  • Анотовані респондери — анотовані за допомогою @MessageMapping методи обробника для передачі відповіді.

Модуль spring-web містить реалізації Encoder та Decoder, такі як Jackson CBOR/JSON і Protobuf, які, швидше за все, знадобляться додаткам на RSocket. Він також містить PathPatternParser, який можна підключити для ефективного зіставлення маршруту.

Spring Boot 2.2 підтримує створення сервера RSocket через протоколи TCP або WebSocket, включно з можливістю використання RSocket через WebSocket у сервері WebFlux. Також є підтримка клієнта та автоконфігурація для RSocketRequester.Builder та RSocketStrategies. Докладнішу інформацію див. у розділі, присвяченому RSocket у довіднику з Spring Boot.

Spring Security 5.2 передбачає підтримку RSocket.

Spring Integration 5.2 передбачає вхідні та вихідні шлюзи для взаємодії з клієнтами та серверами RSocket. Докладнішу інформацію див. у довідковому посібнику Spring Integration Reference Manual.

Spring Cloud Gateway підтримує з'єднання на основі RSocket.