Multiplexer and child channels

Hi everyone,

we are currently planning the architecture of the RSocket protocol implementation using SwiftNIO.
RSocket, much like HTTP2, multiplexes many streams over a single connection e.g. TCP.
The SwiftNIO HTTP2 implementation creates a new HTTP2StreamChannel for each stream and we thought we should do the same for the RSocket implementation.


In the image above you can see a simplified version of our current plan for the Channel and Pipeline setup.
TCP, LengthFieldBasedFrameDecoder and LengthFieldPrepender are already provided by SwiftNIO and can also be replaced by a WebSocket connection.
RSocketFrameDecoder parses a ByteBuffer into an RSocketFrame and passes it to the next ChannelHandler.
The interesting part happens in the Multiplexer/Demultiplexer. Depending on the Stream ID (Int32), which is included in every RSocketFrame, the Multiplexer may create a new channel, stores it in a dictionary for possible following frames, and forwards the RSocketFrame to it.

The Channel implementation of HTTP2StreamChannel looks quite complex and we are now looking for a simpler Channel & Multiplexer implementation. We would like to push the whole state logic into a ChannelHandler, if possible.

Does anyone know of a Channel implementation which can be used for this kind of use case?
The multiplexing part sound like a common use case to use.

Also, the child channel for each stream will probably only have one or two ChannelHandlers. Maybe a channel is to much for this use case and we should just handle message sending/receiving in a custom type.

What are your thought on this part of the Architecture? Any feedback is welcome :slight_smile:

PS: We already have a bigger picture which includes initial connection establishment, pipeline setup and other things. If you want, I can post a Diagram of the overall architecture as well.

3 Likes

This seems like a really interesting project!

The multiplexer complexity has come up before in other conversations with the Swift on Server community. When swift-nio-http2 was the only implementation we were reluctant to try to design a general solution because it was not clear that such a solution would be a good fit for a wide range of use-cases. However, swift-nio-ssh now also deploys a multiplexer (derived from the HTTP/2 implementation) and that represents a second use-case that may help us derive more generality.

My initial recommendation would be that it is sensible to start without a multiplexer. The reason to use a multiplexer is if you want users to be able to perform arbitrary protocol composition: that is, you intend your users to access a Channel. If you plan to hide that from them and expose some other interface, the multiplexer probably just incurs complexity that you don't need.

Going forward the biggest wrinkle with a general multiplexer is the question of having a general child Channel type. Channels are quite complex, with their most complex element being flow control management. It seems like a substantial design challenge to build a general Channel implementation that can manage flow control sensibly: it's definitely the most complex part of the implementation to get right.

1 Like