mina-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Emmanuel Lécharny <elecha...@gmail.com>
Subject Re: ConcurrentLinkedQueue vs MpscChunkedArrayQueue
Date Mon, 17 Oct 2016 18:01:17 GMT

Le 17/10/16 à 11:12, Guido Medina a écrit :
> Hi Emmanuel,
> At the mina-core class AbstractNioSession the variable:
>     /** the queue of pending writes for the session, to be dequeued by the
> {@link SelectorLoop} */
>     private final Queue<WriteRequest> writeQueue = new DefaultWriteQueue();
> such queue is being consumed by a selector loop? 
It's consumed by the IoProcessor selector loop (so you have many of them).

The thread that has been selected to process the read will go on up to
the point it has written the bytes into teh write queue, then it go back
to teh point it was called from, and the  it processes the writes :

select :
1) read -> head -> filter -> filter -> ... -> handler ->
session.write(something) -> filter -> filter -> ... -> head -> put in
write queue and return (unstacking all teh calls)
2) write -> get the write queue, and write the data in it until the
queue is empty or the socket is full (and in thsi case, set the OP_WRITE

> which makes me think it is
> a single thread loop hence making it MpSc and ideal for low GC optimization.
> But maybe such optimization is so unnoticeable that is not worth.
Actually, we have as many thread as we have IoProcessor instances. The
thing is that I'm not even sure that we need a synchronize queue, as the
IoProcessor is execution all the processing on ts own thread. The
cincurrentQueue is there just because one can use an executor filter,
that will spread the processing into many other threads, and then we
*may* have more than one thread accessing this queue.

Regarding GC, we have removed some useless object allocations in 2.0.15,
so the GC should be slightly less under pressure.

If you want to alleviate the GC load, I think there are other areas
where some improvement can be made. Typically, there is a
BufferAllocator that pool the CachedBufferAllocator that allows you to
reuse buffers. Now, this is a tricky solution, as it has to be
synchronized, so expect some bottleneck here. Ideally, we should have
another implementation that use the ThreadLocalStorage, but that would
be memory expensive.

> That's the only place I think it is worth replacing by a low GC footprint
> queue, it will avoid the creation of GC-able linked nodes
> (ConcurrentLinkedQueue)
> In fact, further in that logic you try to avoid writing to the queue if is
> empty by passing the message directly to the next handler which is a
> micro-optimization,
> isEmpty() will 99.99% of the cases render to be false for systems with high
> load.
Well, it depends. The queue will be emptied if the socket is able to
swallow the data. If your system is under high load, I suspect that all
the socket will be full already, so you'll end up with some bigger
problem ! (typically, the queue will grow, and at some pont, you'll get
a OOM... I have alredy experienced that, so yes, it may happen).

My point is that you shoud always expect that your OS and your network
are capable of allocating enouh buffer for teh sockects, and have enough
bandwith to send them fast enough so that the socket buffer can always
accept any write done on it. In this case, the write queue will always
be empty, except if you are writing a huge message (typically above the
socket buffer size, whoch default to 1Kb - from the top of my head- but
that you can set up to 64Kb more or less). Even on a loaded system.

View raw message