I'm currently reworking the internals of the mapper to be more stable
and to have more separated responsibilities. Work can be observed in
[1].
The reason for all this being that we've seen problem areas of Nanite
in production, especially in scenarios where bigger backlogs in the
request and heartbeat exist, and e.g. offline support is enabled. The
reasons for this are a combination of how EventMachine, AMQP and
Nanite work together, and I'm not happy with the failure potential.
Nanite would be so busy to read from one queue (thanks to EM and AMQP)
that it takes ages to get to the next. Worst case scenario is even
that the offline queue support keeps the mapper so incredibly busy
that it'll never get to work off other queues.
I'm currently splitting up the different responsibilities to be able
to split it up into different processes, so that they don't block each
other reading tons of data from sockets. There'll still be a
standalone mapper available that runs everything in one process,
because for some use cases it doesn't matter that much.
However, there's problems with the approach that Nanite currently
takes to e.g. handling requests (with blocks attached to them). These
are stored within the mapper process (and obviously lost when the
mapper goes down).
Long story long, there's parts of Nanite I'd like to remove at some
point, or parts that simply won't be available in a model where the
mapper runs separated into different processes, because e.g. the
process that handles offline queues won't have access to the currently
active jobs, unless they're stored somewhere else, e.g. serialized in
Redis or even inside the message (which I'm seriously considering),
but that'd also mean they'd lose the closure of they're original
environment. Which is an acceptable tradeoff in my opinion, since that
makes it all the more reliable and less dependent on the surroundings.
I for one even discourage the use of requests (instead use pushes),
because they rely on shared and (currently) unrecoverable state in the
mapper.
Another candidate would be to remove support for intermediate messages
(where you can yield at any point from within an actor method), and
sending files. You can still send files of course, (which you
shouldn't though), but instead just serialize them into a message.
I'd like to get some opinions on this or even people who say: for the
love of shared state, please don't remove it!
Otherwise I may remove it for now and bring it back at a later point,
because the stability and reliability of Nanite itself is more
important to me right now. For stability and reliability I'm willing
to remove things that complicate the source code, but I'm putting it
up for discussion first. I'd like to remove as few things as possible,
and obviously not change the public interface of Nanite in any way
possible.
The next release (0.5.0 will be a consolidation release with the
reworkings in place), the following will have a model where the mapper
can be split up into different processes. That's the plan for now.
Let me know what you think!
Cheers, Mathias
[1] http://github.com/ezmobius/nanite/compare/mapper_rework
--
http://paperplanes.de
http://twitter.com/roidrage
Moving it to the agent side was pretty much exactly the idea I came up
with in the end. The request functionality still makes sense, but not
in the mapper tier. It would be more appropriate to consider someone
sending a request to be just another end point in the agent system.
That'd be much cheaper than keeping all the state in the mapper
itself, instead it'll be left to the fake agent if you will, to take
care of that. The mapper would simply do what it's supposed to do:
route.
Regarding a modular Nanite, that's certainly where I'm taking it at
the moment. Most things that were tightly coupled in the mapper are
now based on a simple notiication system which I'll extend to support
remote notifications inside the mapper, so one process can notify
others of certain things, but that's restricted to the mapper itself.
See above, that's pretty much what I'm working on, though I'm not sure
I want to take the agent in the same direction. The functionality is
simple enough on the mapper end that it could be a normal part of it
instead of being patched into it. To me it was more of a question to
get as much state as possible out of the mapper. Both parties would
still need to know about the existence of a request in some sense, so
having it as modular as possible is probably making things more
complicated than it's making them easier to maintain.
After giving it some more thought I certainly still see advantages in
keeping the request support, but in a different manner. It's useful to
even have stuff like evented web apps, that fire off a request into
the backend and return the web reply when they get a reply back from
Nanite. But for that it'd be sufficient to have the end sending the
request be something like an agent but one that doesn't offer any
services.
Cheers, Mathias
--
http://scalarium.com | http://paperplanes.de
http://twitter.com/roidrage