When one define custom mtu to be used for fragment size it significantly degrades performance. Attached example code sends 1M records with size 5 bytes. Before fix it takes 39 seconds. After fix it takes 5 seconds (same time as with no custom fragmentation). We need to enable it, because Websocket max data size is 64kB and we support both transports.
Expected Behavior
Fragmentation setup should not affect performance. Especially when data buffers are smaller than mtu.
Actual Behavior
There is huge performance degradation.
Steps to Reproduce
publicclassRsocketTest {
privatestaticfinalLoggerlogger = LoggerFactory.getLogger(RsocketTest.class);
publicstaticvoidmain(String[] args) {
RSocketrsocket = newRSocket() {
@OverridepublicFlux<Payload> requestStream(Payloadpayload) {
ByteBufferdata = ByteBuffer.wrap(newbyte[5]);
returnFlux.generate(() -> newAtomicInteger(1000000), (state, s) -> {
if (state.decrementAndGet() == 0) {
s.complete();
} else {
s.next(DefaultPayload.create(data));
}
returnstate;
});
}
};
RSocketServer.create(SocketAcceptor.with(rsocket))
.fragment(60000)
.bind(TcpServerTransport.create(
TcpServer.create().host("localhost").port(7000)))
.subscribe();
RSocketsocket = RSocketConnector.create()
.fragment(60000)
.connect(TcpClientTransport.create(
TcpClient.create().host("localhost").port(7000)))
.block();
Flux<Payload> res = socket.requestStream(DefaultPayload.create(ByteBuffer.wrap("Hello".getBytes())));
longstart = System.currentTimeMillis();
res
.limitRate(1000)
.blockLast();
logger.info("Call took: {}", System.currentTimeMillis() - start);
socket.dispose();
}
}Possible Solution
FragmentationDuplexConnection change (I am creating PR now):
@OverridepublicMono<Void> send(Publisher<ByteBuf> frames) {
returndelegate.send(Flux.from(frames)
.concatMap(frame -> {
FrameTypeframeType = FrameHeaderCodec.frameType(frame);
intreadableBytes = frame.readableBytes();
if (!shouldFragment(frameType, readableBytes)) {
returnFlux.just(frame);
}
returnlogFragments(Flux.from(fragmentFrame(alloc(), mtu, frame, frameType)));
}));
}
@OverridepublicMono<Void> sendOne(ByteBufframe) {
FrameTypeframeType = FrameHeaderCodec.frameType(frame);
intreadableBytes = frame.readableBytes();
if (!shouldFragment(frameType, readableBytes)) {
returndelegate.sendOne(frame);
}
Flux<ByteBuf> fragments = Flux.from(fragmentFrame(alloc(), mtu, frame, frameType));
fragments = logFragments(fragments);
returndelegate.send(fragments);
}
protectedFlux<ByteBuf> logFragments(Flux<ByteBuf> fragments) {
if (logger.isDebugEnabled()) {
fragments =
fragments.doOnNext(
byteBuf -> {
logger.debug(
"{} - stream id {} - frame type {} - \n {}",
type,
FrameHeaderCodec.streamId(byteBuf),
FrameHeaderCodec.frameType(byteBuf),
ByteBufUtil.prettyHexDump(byteBuf));
});
}
returnfragments;
}Your Environment
- RSocket version(s) used: 1.0.2
@OlegDokuka can you take a look? Can we please include this into 1.0.4?
When one define custom mtu to be used for fragment size it significantly degrades performance. Attached example code sends 1M records with size 5 bytes. Before fix it takes 39 seconds. After fix it takes 5 seconds (same time as with no custom fragmentation). We need to enable it, because Websocket max data size is 64kB and we support both transports.
Expected Behavior
Fragmentation setup should not affect performance. Especially when data buffers are smaller than mtu.
Actual Behavior
There is huge performance degradation.
Steps to Reproduce
Possible Solution
FragmentationDuplexConnection change (I am creating PR now):
Your Environment
@OlegDokuka can you take a look? Can we please include this into 1.0.4?