Current Status of Nanite

26 views
Skip to first unread message

Mathias Meyer

unread,
Oct 14, 2010, 10:43:41 AM10/14/10
to nanite
Hi,

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

ccooke

unread,
Oct 16, 2010, 7:27:44 PM10/16/10
to Nanite

(Parts of this are thoughts based on a conversation I had with you a
few
days ago on #nanite. Just been shaping them up a bit. It's quite
likely
not what you actually want, but it never hurts to suggest :-) )

On Oct 14, 3:43 pm, Mathias Meyer <pomonra...@googlemail.com> wrote:
> Hi,
>
> 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].
>
<snip>
>
> 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.

As I said before, my uses of Nanite rather require the request
functionality... but I don't see any reason for that functionality to
actually be in the core of Nanite. If there were a means by which
loadable modules could plug functionality in, it could be done
entirely
on the agent side. That certainly could be done now - but a modular
Nanite with the features to support this sort of extension would be
lovely. It should be possible to rip out everything from the Nanite
core
apart from the ability to send a message (push style) and handle
exceptions - absolutely everything else that's currently supported
could
be built in terms of that simple core.

In terms of the current request behaviour, I'd be happy to reimplement
that as a module. It's necessary to support tools I'm currently
building, anyway.

Most of what I'd be interested in is easy already within Ruby modules
-
the 'request' module might simply be Nanite::Module::Request and
loading it would patch in the request() method to the Nanite core.
Hell,
having request() in the core automatically print a "this is going to
be
deprecated, add 'require "nanite/module/request" to continue using
this
functionality' message and then go on to automatically load the
'request'
module would be nice.

That handles the requester side easily - but to support this sort of
functionality, the Agent needs to know what sort of request is being
made and must have the relevant code loaded. One method of handling
that
would be a hooks system. Each method carries data on the features it
requires from the message recipient, and the Agent calls into the hook
system on various events: When an exported message yields, when it
returns, when an exception is thrown, etc. This would keep the API as
close as possible to current: Apart from loading the modules,
everything
will work transparently using the current methods. The 'request'
method
would be provided entirely by the module, and add 'request' to the
feature request parameter for any message it pushes, while loading the
module providing intermediate messages could add 'intermediate' to the
feature request parameters of every outgoing message. Exception
handlers
fit this method very well, too.

> 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.

I'd personally go for removing as much as possible! Move everything
non-essential into modules which can be tested and loaded
individually.

> 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.

Sounds good, whether you agree with me or not :-)

--
for((P=10**8,Q=P/100,X=320*Q/(`tput cols`-1),Y=210*Q/`tput
lines`,y=-105*Q,v=-2\
20*Q,x=v;y<105*Q;x=v,y+=Y));do for((;x<P;a=b=i=k=c=0,x+=X));do
for((;a*a+b*b<4*\
P*P&&i++<99;a=((c=a)*a-b*b)/P+x,b=2*c*b/P+y));do :;done;(((j=(i<99?i
%16:0)+30)>\
37?k=1,j-=8:0));echo -ne "\E[$k;$j"mE;done;echo -e \\E[0m;done #
Charles Cooke

Mathias Meyer

unread,
Oct 23, 2010, 5:41:02 AM10/23/10
to nan...@googlegroups.com
On Sun, Oct 17, 2010 at 1:27 AM, ccooke <cec...@gmail.com> wrote:
>
> As I said before, my uses of Nanite rather require the request
> functionality... but I don't see any reason for that functionality to
> actually be in the core of Nanite. If there were a means by which
> loadable modules could plug functionality in, it could be done
> entirely
> on the agent side. That certainly could be done now - but a modular
> Nanite with the features to support this sort of extension would be
> lovely. It should be possible to rip out everything from the Nanite
> core
> apart from the ability to send a message (push style) and handle
> exceptions - absolutely everything else that's currently supported
> could
> be built in terms of that simple core.
>
I gave things some more thought while I reworked the mapper's
internals, and here's what i came up with, subject to change, but the
picture is getting clearer and clearer.

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

Reply all
Reply to author
Forward
0 new messages