Our application in some use cases writes massive amount (~10K) of reads/writes
per thread and this is causing "request queue size > 10K" exceptions. No issues were noticed if same throughput happens across multiple threads.
If we understood this statement correctly, "
Lettuce does not await completion of earlier commands before dispatching a new command as Lettuce uses Netty pipelining", in the context of request queue size per connection when a single thread executes many commands.
My understanding is:
Within a specific connection, when you execute a command using AbstractRedisAsyncCommands, it is dispatched and written using ClusterDistributionChannelWriter -> DefaultEndpoint.channelWriteAndFlush where we are tracking QUEUE_SIZE but not actually storing the requests in any stack. Netty then takes over the command and passes it to its event loop executor to be executed, this includes encoding and Netty AbstractChannelHandlerContext$WriteAndFlushTask uses CommandHandler reference which again also tracks request queue size using an ArrayDeque stack (
Is this the protocol stack?) and when Netty gets the response, the objects are decoded and commands popped from stack.
Questions:
Why are we tracking request queue size in both io.lettuce.core.protocol.DefaultEndpoint vs io.lettuce.core.protocol.CommandHandler?
When request queue size is full exception occurs, it could be due to slow encoding/decoding, low number of Netty IO/CPU bound threads or due to actual response from Redis coming slowly. What happens when Redis does not respond, how do we remove from stack all entries that did not arrive on time?
What if we did not care about the write response or the order, how can we make writes faster?
When you say Lettuce/Netty pipelining, you are really referring to the Netty channel queueing one by one?
How is Lettuce/Netty pipelining or batching different from using Multi SET commands for performance? How can we ignore the disconnect buffer altogether for performance?