One of point of failure of massive asynchronous server is out of memory on growing read or write queues.
The problem is separated in two case :

  • slow processing of incoming bytes (Read throttling)
  • too fast writing of the server, on slower clients (Write throttling)

Read

Not sure if the solution is OK, but here the way it's done in MINA 2.0 : http://www.nabble.com/Dropping-traffic-throttling-from-2.0-td16092085.html

Write

Write is by far the hardest issue. It's occurring when you are sending too much data on slower clients (mainly slower network).

A good example is the way the problem is hitting Apache Directory. When you do a somewhat big request (for example 2M bytes of result set), when the server write the result chunks, it can saturate the write queue and create an out-of-memory (OOM) error.

A solution could be to send the data, wait for session write queue to be depleted, than process the next result chunk, but here we go in a 1 thread blocking model for processing a client query. This solution is implementable using current MINA 2.0 feature, by monitoring ioSession write queue (scheduledWriteByte & schedluedWriteMessages), but you need to check those variables, reschedule your write to later due to the absence of "write ready" event notifications. even if this is implementable, it's having a lot of drawback (blocking thread, a few big request can block small requests, etc..).

Emmanuel Lécharny proposed an asynchronous solution, since we know in the IoProcessor of a session when the socket is ready for write, we could send the event (to filter chain or Iohandler). For Apache Directory writing of resultset, the strategy could be :

  • try to write result chunk until the write queue is full,
  • when write queue is full, attach a result cursor to the session and exit
  • continue the cursor processing on the "socket ready for write" event

This solution would be fair between small & big queries and block no thread by making everything asynchronous.

I think it's actually achievable using WriteFuture and using the future listener for writing the next part of the result set. The listener will be triggered only when the written data is flushed to the socket, and the action will be executed by the IoProcessor executor.

Comments ?

  • No labels