×
Community Blog A Brief on RSocket and Reactive Programming

A Brief on RSocket and Reactive Programming

This article summarizes some of the author's thoughts when implementing RSocket SDK for Go and Rust.

1

1. Main Features of RSocket

RSocket is an efficient binary network communication protocol that can be used in many scenarios. RSocket is fully reactive; even its APIs are integrated seamlessly with reactive programming.

1.1 Four Communication Modes

FireAndForget

This mode supports sending a request without sending a response message. It can be applied to scenarios, such as event tracking and log reporting. A response in these scenarios is not needed, and it does not matter if several requests are lost.

2

RequestResponse

The requestor sends a request, and the responder receives the request and returns a response. HTTP typically uses the RequestResponse mode.

3

RequestStream

The requester sends a request, and the responder returns N responses. Conventional MQ typically uses the RequestStream mode.

4

RequestChannel

Create a channel context so both parties can send messages. IM is a typical RequstChannel scenario.

5

1.2 Bi-Directional Communication

The process of the Client in RSocket connecting to the Server is called Setup. After the connection is established, the direction logic of message sending and receiving is specified:

  • When the Client sends a request to the Server, the request ID is always an odd number.
  • When the Server sends a request to the Client, the request ID is always an even number.

6

Unlike traditional HTTP requests, RSocket can implement bi-directional communication based on the feature that says parity determines the direction.

1.3 Other Features

  • Compact and efficient binary protocol
  • Multiplexing
  • Frame-based backpressure is consistent with Reactive Streams semantics
  • Flexible Switching of the Transport Layer: TCP, UDP, and WebSocket
  • Support for advanced features, such as Cancel, breakpoint resume, and lease

In summary, RSocket is more efficient and supports more scenarios than HTTP. It eliminates head-of-line blocking. Compared with event-based frameworks, such as SocketIO, RSocket requests have a clear context, are refined, and APIs are easy to use.

7

2. Internal Implementation of RSocket

2.1 Design of Frame

Frame is the minimum unit of RSocket message.

  • A frame consists of a header of 6 bytes and a body. The 4 bytes in the header represent StreamID, 6 bits represent Frame Type, and 10 bits represent Flags. The structure of the body varies among different frame types. Commonly used frames with Payload contain Metadata and Data.
  • If the transport layer does not support frame division (such as TCP), RSocket uses uint24 of 3 bytes to represent the frame length, so the maximum frame size is 16 MB.
  • If a frame exceeds 16 MB, RSocket supports frame division and recombination. In other words, a frame is divided into smaller frames, and the receiver recombines them automatically.

8

2.2 Data Carrier: Payload

Developers generally deal with Payload, which is similar to an HTTP message. Payload can be a request or response. It consists of two binary parts:

  • Metadata: Similar to HTTP header
  • Data: Similar to HTTP body

9

2.3 Architecture

The following figure shows the architecture based on my experience in implementing the Golang SDK. The architecture in Java is similar:

10

  • The transport layer supports encoding and decoding binary streams into frames.
  • RSocket allows you to customize the maximum frame size, which is 16 MB by default. When a frame exceeds 16 MB, it is divided into N small frames and recombined when received. As mentioned when introducing frames, this feature is called Fragmentation.
  • DuplexConnection converts frames into Payloads and takes them as Request/Response contexts. It also performs read and write operations.
  • RSocket assembles Connection as the RSocket Interface, among which Resumable supports breakpoint resume. Reconnection problems can also be handled. Personally, I think this feature is a bit useless but has some advantages in a weak network environment. However, as the unprocessed frames are cached during this period, a lot of system resources are consumed.
  • RSocket uses the Reactor core library to support four communication modes, which are abstracted as advanced APIs.

2.4 Applications

RSocket can be used in many scenarios, such as in traditional RPC. It also can be used in IM. Some of its features can be used in proxy or network penetration.

It can also be used in IoT scenarios. For example, Xiao Ming has a smart air conditioner at home. Xiao Ming wants to control the air conditioner when he is outside through a mobile phone app. How can he solve this control problem gracefully? The most refined solution is "Xiao Ming calls the API of the switch of the air conditioner."

11

Moreover, the most typical application of RSocket is Broker, which is similar to a soft route solution that simplifies service release and access. It can connect to the Broker to release services. The caller can make the Broker forward data transparently using reverse requests. Traditional service governance methods, such as registry and port management, are abandoned in this process.

12

2.5 About RSocket Broker

Broker has many advantages. For example, port listening is not required for releasing services, and Sidecar is not required. Service registration becomes easier. Load balancing becomes easier and safer as zk and etcd are not required. It is less likely to be attacked without a listening port, but there are also a lot of disadvantages. It has some performance losses. Broker is a centralized design similar to global NGINX, but the elegant start-stop of Broker is more complex and limited by the bottlenecks of the entire Broker cluster. In a word, nothing is given without a disadvantage in it.

Many FaaS services implemented by AMap use Broker based on the RSocket architecture. This enabled AMap to handle the large network traffic during the 2021 May Day holiday. The peak QPS exceeded 200,000, while its system remained stable with zero faults.

13

Here, I prepared a Mini Broker to show its mechanism, which demonstrates the scenario where two browsers call each other's services in context. If you are interested, you can refer to the following figure:

14

3. Reactive Programming

Reactive programming is very common and has been everywhere for a long time. Even the SUM function in Excel is essentially reactive. Reactive programming is to respond to changing data streams. RSocket is based on reactive programming but has extended it to the network layer.

3.1 What Reactive Programming Looks Like

15

In our daily work, various operations and transformations are bound to be introduced:

16

3.2 Reactive Streams

JDK has launched reactive standard APIs. Apart from the Processor, its core interfaces only contain Publisher, Subscriber, and Subscription.

  • Publisher is responsible for producing data. The only method in it is subscribe, which starts a new subscription after receiving a Subscriber.
  • Subscriber is responsible for subscribing to consumption data.
  • Subscription defines the context of a Subscription, such as canceling or notifying of obtaining the next N data entries.

Spring Reactor is a standard implementation, and its complete execution process is listed below:

17

  • Create a subscriber and start subscribing to Publisher
  • Generate the context subscription
  • When Publisher is ready, call onSubscribe.
  • Publisher begins to produce data
  • Call back onNext for each successfully produced data entry
  • If production fails, call back onError and end the current subscription.
  • When all the data is produced, call back onComplete and end the current subscription.
  • You can call subscription during the process to cancel the subscription at any time or send a notification about producing the next N elements by request(n). This process is called backpressure.

Since there are inherent advantages, Java is suitable for frameworks, such as RxJava or Reactor, and the code logic is clearly readable. When implementing Go Reactor, I realized that the expressiveness of APIs without generic support is poor. I also hope that the generics of Go2 can be improved.

4. Summary

RSocket is a very interesting network protocol. It may not be popular, but its problem-solving ideas and design are very innovative. If you are interested, you can visit its official website to learn more.

This article summarizes some of my thoughts when implementing RSocket SDK for Go and Rust. If you are interested, click the relevant links below.

References

0 1 0
Share on

Jeffsky

1 posts | 0 followers

You may also like

Comments

Jeffsky

1 posts | 0 followers

Related Products