/dev/null

Cameron Purdy
Sunday Aug 13, 2006

Distributed Systems as Organisms

I have been having a long converstation by phone and email with Bill Venners of Artima regarding distributed systems. Over the past few years, I have often talked about how distributed systems have evolved from being a "collection of introverted servers" to being a "social organism", but I've never taken the time before to write it all down. What follows is my explanation to him:

There are two vastly different approaches to distributed software, which I can sum up as traditional and organic. In a traditional distributed system, each server, each process is an isolated unit, like a single-celled organism. It exists as an independent unit that must fend for itself within its environment, and must always assume the worst, because it is the last -- likely the only -- line of defense for the responsibilities that it carries. For example, it must assume that failure to communicate with another part of the distributed system results in indeterminable conditions, such as in-doubt transactions. As a result, it must consolidate those indeterminate conditions into its own condition, likely preventing it from continuing processing. One would expect this in any two-phase commit system responsible for deterministic outcomes, when the system experiences an unknown outcome in any transaction branch.

Traditional systems utilize "recovery" to achieve deterministic results even when servers fail. The measurement of the likelihood of failure is referred to as MTBF, or Mean (average) Time Between Failure. More importantly, though, is the MTTR, or the Mean Time To Recovery. In a traditional system, the outcome of an in-doubt transaction branch is unavailable until the server on which the branch existed is fully recovered.

Clustering is a proven approach to resolving such dilemmas by significantly reducing -- almost to the point of eliminating -- recovery time. The clustering approach was made popular first in mainframe architectures, and eventually it bubbled down to mid-range UNIX systems. Server redundancy with dedicated "clustering interconnects" allowed a second stand-by server to stay in lock-step with the primary server, allowing the second server to immediately stand in for the responsibilities of the primary server in the event that the primary server failed.

Today, what we refer to as "clustering" is significantly different, although it is intended to achieve the same result. For example, in modern architectures such as Java EE application servers, clustering refers to very high level interconnects, such as TCP/IP sockets, that allow servers to stay in virtual lock-step, and for one server to detect the failure of another server. Conceptually, clustering allows failure to be handled without recovery, by having redundant copies of the state (such as a transaction log) that would otherwise have to be recovered.

The two-server hardware clusters and the more modern software clustering implementations are the origin of what I refer to as "organic systems", which represent multi-cellular organisms that are designed to survive the loss of individual cells. In other words, a distributed system is no longer a collection of independent organisms, but is itself an organism composed of any number of servers that can continue processing -- without any loss of data or transactions -- even when server failure occurs.

This does require a fundamental adjustment in the assumptions behind distributed systems. In particular, in a traditional distributed system, the loss of communication to a particular server would cause all other servers that were communicating with that server to wait for the recovery of that server's responsibilities, whether by server migration, service failover, or actual repair (e.g. reboot) of that server.

On the other hand, in the case of an organic system, the organism is always prepared for the death of any cell, and is never dependent on the survival of any particular cell. In such a system, if a particular server dies, all of its responsibilities can be handled by the other similar servers, and all of the in-flight transactions can be re-routed from the dead server to those other servers. To accomplish this, each state change and each in-flight transaction must be accomplished on at least two servers, just as it is in the well-known clustered hardware implementations. The difference, though, is that an organic system is not limited to only two servers, and it can organize itself as an increasingly resilient mesh of servers, where the failure of any server has a smaller and smaller effect on each other server as the number of servers increases.

No longer is "recovery" the primary mechanism for re-establishing the availability of the system when a server fails. Instead, the technical challenges are the rapid detection of server failure and the need to isolate the failed server from the overall distributed system. I will attempt to explain these two challenges in detail, and why they are so fundamental to the correct and continuous operation of an organic system.

First, when a server fails, it is rather unlikely to have predicted its own demise, and as a failed server, it is also unlikely to be able to communicate its own failed condition. The responsibility for the detection of server failure therefore falls to the organism itself, which is composed of all of the surviving servers. The algorithms for determining server failure are referred to as "death detection algorithms", and typically use a combination of error indications and statistics to ascertain server failure beyond a reasonable doubt. When a server has been determined to have failed, the other servers then assume the responsibilities that the failed server had, and processing of those responsibilities continues without loss of data or in-flight transactions.

A serious problem, known as the "split brain syndrome," occurs when the failed server may not be aware of its own demise, and it may attempt to continue processing after the other servers have determined it to have failed. This is the role of isolation, which means that the organism is fully aware of the failure of the server, and isolates that failed server from the rest of the organism. This accomplishes two things: First, it prevents the failed server from corrupting the state of the system, because the system is the organism and the organism is the system. Second, it provides the failed server with an unambiguous sign that it (the failed server) has indeed been isolated from the organism. Since the organism is dynamic, growing and shrinking as necessary, the failed server can re-join the organism, but it can only re-join once it understands that it failed, and once it agrees to join with no pre-existing assumptions, just as if it were a new server.

When external resources, such as a database, are also affected by the processing of the organism, the isolation must also prevent a failed server from affecting those resources. To accomplish this, a failed server must respect its isolated state, and it does so through the use of a quorum. A quorum is the defined minimum size for an organism, which could be defined as an absolute number of servers, as the minimum number of servers necessary to provide a particular quality of service or capacity, or as a percentage of the recent size of the organism (before the server was isolated from it). When a server is isolated from the organism, it can form its own single-celled organism (composed only of itself), or it can even form a small multi-celled organism in some split-brain scenarios. In either case, its failure to achieve quorum will cause it to restrict its affects on external resources, thus ensuring that failed servers do not cause damage to the state of either the surviving organism or the external resources that the surviving organism depends on and affects.

(A more complex quorum and continuation logic is used for failover of entire datacenters, in which a split brain could allow either datacenter to provide its own quorum, yet only one datacenter must continue to process.)

In summary, the failure of a server is no longer an exceptional condition, and it affects neither the availability of the overall system nor the state of the data and transactions being managed by the overall system. Thus, an application may still have to deal with the potential for failure, but not the failure of a particular server. Instead, an application must deal with the failure to achieve quorum; in other words, an application must deal with the fact that it is on the server that failed, and in exchange, it no longer has to worry about the failure of some other server.

There are several additional considerations that should be addressed. First of all, a distributed system cannot maintain its availability in the event of a complete network failure; this can be addressed by eliminating single points of failure in the network infrastructure itself. Second of all, a distributed system cannot maintain its availability if all of the servers fail at once, which can happen if the servers lose power; this too can be addressed through the use of battery backups, generators and redundant power systems. However, applications should be built with an understanding of both of these risks, and this leads to the last goal of an organic system: Recoverability.

In the case of a server failure in a traditional system, each server was its own single-celled organism, and each server had to be able to recover itself, for example by using a transaction log. In the case of an organic system, the organism must also be able to recover itself. It typically accomplishes recovery by relying on long-term recoverable storage, such as is provided by relational database systems (RDBMS) to act as its system of record. Recoverability is accomplished by reloading the state of the system from its recoverable storage, and using the completion of the recovery as a pre-requisite of making the organism available to process new requests.

If the benefits of an organic model sound familiar, then you're probably already using the world's most innovative distributed system. If you're still struggling with traditional exception-based or recovery-based approaches to distributed systems (e.g. CORBA, JINI, RMI), then you have my deepest sympathy, but it's not too late to switch (e.g. download, wiki, javadoc, forums).

Comments:

Hello Cameron,

I share similar thoughts. Marc Fleury has blogged along these lines. You really can go pretty far w/ the biological analogies. For example, I see mother nature as a programmer just like you and I. The programs we write are executed with a base 2 number system, while she uses base 4 ( Guanine, Adenine, Cytosine, Thymine) for DNA. Biological systems also have a notion of "functions", or reusable instructions ( genes ).

Our genome is a lot like an old dilapidated code base - 99% of it is "dead code". In other words, very little of our genes are actually relevant. Mother nature is also not very test driven. She uses trial and error, leveraging time. You and I on the other hand have relatively little time, but logic drives the design, usually :)

Posted by Dennis Byrne on August 14, 2006 at 12:10 AM EDT #

Regarding the genes and the 99% dilapitated code, I suggest a reading on "Selfish Genes and Selfish Memes" by Richard Dawkins, and then come back to unit testing...

Posted by Andres Almiray on August 14, 2006 at 12:46 AM EDT #

Any chance you can summarize the read? In all honesty I am simply never going to get around to reading it.

Posted by Dennis Byrne on August 14, 2006 at 12:56 AM EDT #

Well, then basic idea is that nature tends to form stable strutcures, at the beginning of life, he organic molecules started to align themselves and recombine until one structure was capable of copying itself, the first replicator. This new structures needed food and space, so they competed with each other. Eventually some replicators started to hunt other replicators, even parasitic replicators were spurned. Some started to build survival machines, membranes, to protect themselves against other replicators. Million years later the replicators have evolved into genes, and we (humans, animals and plants) are just survival machines. There is a new kind of stable replicator, memes (the ideas) that also spreading.

Getting back to programming, the meme of developer testing is definetely a good replicator, the programming best practices also are memes that replicate themselves into a developer's mind (some fail as we are no longer programming in structured languages, or so we think).

So we as programmers want to build good programs that hopefully need lower maintenance, we're looking for stable structures that can be replicated unless we reinvent the wheel again and again. The ideas we use to obtain them are also replicating.

For a similar point of view on memes, please check

http://junkerhq.net/MGS2/index.html

Posted by Andres Almiray on August 14, 2006 at 01:59 AM EDT #

Good post.......

"If the benefits of an organic model sound familiar, then you're probably already using........"

Maybe, but you could have been listening to Werner Vogels back in March 2005:

http://www.itconversations.com/shows/detail459.html

I've got a copy of the slides lying around somewhere as well if anyone's interested.

Also, I think there's some examples in the outside world that don't fit the basic two-way classification you've outlined (I think they're a combination of both types). That would be Google and Amazon and some others (checkout Google's GFS and BigTable and Wogels' discussion about organisms in the talk above).

Posted by Dan Creswell on August 14, 2006 at 10:30 AM EDT #

hi dan,

Can you let us know how to get hold of the slides you mention ?

thank you,

BR,
~A

Posted by anjan bacchu on August 14, 2006 at 11:53 AM EDT #

Dan - we started designing this approach (including the quite-original "conference room" clustering model) back in 2000, and a certain large book-seller did indeed roll it into production a year or two ago ;-).

Peace.

Posted by Cameron Purdy on August 14, 2006 at 12:23 PM EDT #

"Dan - we started designing this approach (including the quite-original "conference room" clustering model) back in 2000, and a certain large book-seller did indeed roll it into production a year or two ago ;-)."

Urgh, so I didn't really make myself clear - you guys (Werner and yourself) are using similar terms but I'm not sure you're thinking/building the same thing.

Werner seems to be talking about some less deterministic behaviours, epidemics and gossip protocols.

Posted by Dan Creswell on August 14, 2006 at 01:14 PM EDT #

Hi Dan -

Agreed :-) .. I was trying to show that it is not a recent movement, even if the actual production usage in some environments is more recent.

Peace.

Posted by Cameron Purdy on August 14, 2006 at 01:42 PM EDT #

Oooh, I see, it ain't a data grid anymore, it has become more like cancer, right?

And remember, you did *not* invent the Information Superhighway - that was me!

Al

Posted by Al Gore on August 14, 2006 at 04:47 PM EDT #

In the context of a larger distributed system, or rather, one that span multiple domains, say a service oriented architecture (to use an overhyped term), I'd expect to see less of the behavior that you are describing. What I mean by this is that I'd expect to find these clusters within a service, but not so much between them.

By desigining loosely coupled interactions between services, it has been my experience that one server in service A would not wait, or need to handle failure conditions of a different server found in serive B.

There are intra-service designs, though, which can also skirt many of the problems you discuss. By distributing the software of the service across multiple servers by finding the inherent fracture points of the software, we can have multiple independent elements running on separate servers. An example of such a fracture point would be "customer type" in a "Sales" service. The logic itself is divided along the lines of whether a customer is a "corporate customer" or not. If we design specific (and separate) message types for corporate customers, we could easily have dedicated channels for those message types and dedicated servers listening to those channels.

Don't forget that there are different volatility characteristics and transactional requirements for different kinds of data. These too can be used as fracture points for distribution.

Anyway, I've rambled on long enough. I've got more on these topics on my blog (http://www.UdiDahan.com) as well as the Dr. Dobb's site (http://www.ddj.com/blog/webservicesblog/archives/freelancer_blog/index.htm).

A really great topic - I'm looking forward to hearing more on the subject.

Posted by Udi Dahan - The Software Simplist on August 15, 2006 at 05:39 PM EDT #

Cameron

Interesting post. The systems level view seems to be a recurring theme whenever a new level of abstraction begins to make sense, so that requirements such as 'availability' become completely system level responsibilities.

For example, consider lower level cases such as multiple processes on a CPU. Very few people still need to think of a single piece of work as being bound to a single thread or process. It is a CPU level concern.

What you describe in the case of distributed systems is the ability to treat a quorum of machines as if they were a single machine, and in turn to not think of work as being machine-bound. Responsibilities can be shared.

The implication of this observation is that while the 'social' or 'organic' viewpoints may help focus our intuitions, they are not new. What is new is the emergence of a set of infrastructure components enabling a holistic view of distributed systems in terms of processes.

The end of your post suggests the solution to an outstanding problem, giving it a 'conclusive' tone. Whereas I'd prefer to suggest that the industry is only starting to understand the implications of this new infrastructure. Not all the components are here yet. Not all the models are agreed upon. It's exciting.

Posted by alexis on August 16, 2006 at 08:16 AM EDT #

Cameron,

Why do you think Jini can not be used to build such "Organic" systems?

Posted by 69.142.10.148 on August 16, 2006 at 12:52 PM EDT #

That's simple: JINI is based on the traditional "single cell" model. It's unwieldy for building large-scale applications, and inappropriate for building continuously available applications.

I believe that there are fundamental reasons why it never caught on, and why Sun ultimately dropped it.

Peace.

Posted by Cameron Purdy on August 16, 2006 at 05:53 PM EDT #

Jini is based (mainly) on RemoteException which is not needed for well-behaved (organic?) clusters.

Posted by alexis on August 16, 2006 at 06:10 PM EDT #

It's also the notion of indeterminate outcomes, as dictated by leases (see the oft-quoted mis-use of "Lease.FOREVER"), time-outs and the potential for failed connections.

Peace.

Posted by Cameron Purdy on August 16, 2006 at 09:34 PM EDT #

"That's simple: JINI is based on the traditional "single cell" model".

Jini makes no such assumption, it's left up to the individual service implementation to determine what model it wishes to support and present via it's interface.

"Jini is based (mainly) on RemoteException".

Also not correct. It's perfectly possible to build services with interfaces that don't make use of RemoteException, don't use RMI and are resilient such that a client can be completely unaware of failover.

In such cases, you'd need to harden the network and power infrastructure as Cameron has already mentioned but that's driven from your need for constant availability which is ultimately when you wouldn't have RemoteExceptions on interfaces and need hardware always available to run your software.

Posted by Dan Creswell on August 17, 2006 at 09:56 AM EDT #

Actually Dan, I could see RemoteException as being a useful indicator in an organic system, but only if it indicated that the node getting the exception were dead ;-)

I would obviously love to talk some of this through in more detail with you some time. I think the analogies only can carry us so far.

Peace.

Posted by Cameron Purdy on August 17, 2006 at 10:18 AM EDT #

Cameron - nice to see people think outside the traditional software are engineering "box".

Without doubt, leveraging biological principles will usher the next wave of software innovation; the effects being truely disruptive to the current software industry. However, I'd suggest that biologically inspired systems and current approaches to mainstream enterprise software remain poles apart!

Jini at least made an attempt! But even Jini falls far short of what is actually required.

Clearly, one first needs to appreciate the underlying principles that are common to such systems. Complex Adaptive Systems (CAS) - of which biological systems are just one of a number of examples - provide the clues/guidance we need.

CAS systems appear to be grounded upon the following concepts:

1) Seperation of functional runtime structure/behavior from descriptive form. IoC / DI techniques are a small step - but only a small step - in this direction.
2) Dynamic assemblies of functional populations - at runtime - into functional hierarchies.
3) "Stigmergy" - The dynamic response of individuals in a population - to the emergent properties of that population.
4) Apoptosis - programmed cell death, and replenishment; services are cycled - not on an exception basis, but as part of the natural operating cycle of the system; this an extension of recovery oriented principles.
5) Adaption / Evolution - Continuous optimisation of a systems overall "fitness" in response to a changing "landscape". Both with a service, generation, and across generations.

Those interested in such patterns / behaviours, and the sorts of software systems that result when trying to apply these - may be interested in the Newton project hosted at http://www.codecauldron.org. Newton leverages a fusion of Jini, OSGi and SCA (service component architecture) standards, but more important than implementation detail, Newton architecture has been guided from its inception by such CAS principles.

For those of you that want to really dig into this fascinating subject further, Cauldron also maintains links to CAS research.

Cheers

Richard

Posted by richard nicholson on August 17, 2006 at 10:32 AM EDT #

Dan

I hear what you're saying - and confess not having followed the more recent developments in Jini too closely. For me, Jini was designed to address a much broader class of problems, of which the Cameronian examples are special cases which can be addressed as a class. For instance, I think that for the types of 'moderately coupled' systems Cameron is referring to, one could introduce more 'cluster transparent' features as a layer on top of Jini. (As, I believe, some of Richard's team have done in some cases?)

Ultimately you rarely want a cache to throw RemoteExceptions - it should be a (local) service not a server.

It would of course be fun to discuss these things at more length as Cameron said above.



Posted by alexis on August 17, 2006 at 11:33 AM EDT #

Alexis, Cameron,

Cool on all points. Be boring if we all agreed wouldn't it - there'd be no excuse for beer-fuelled debate :)

Dan.

Posted by Dan Creswell on August 17, 2006 at 12:01 PM EDT #

Next time I'm in London, then? ;-)

(And this math problem blocking my post is getting old.)

Posted by Cameron Purdy on August 17, 2006 at 12:43 PM EDT #

Yup - any idea when that'll be?

Posted by alexis on August 17, 2006 at 01:04 PM EDT #

"Jini makes no such assumption, it's left up to the individual service implementation to determine what model it wishes to support and present via it's interface."

One of the fundamental issues that most people fail to recognize, is that a software API is a starting point, which enables certain things to be standardized. Things that aren't present in an API are typically the things which can't be cast in stone, or which there is no significant practicle experience to drive an API into shape/existance.

Dan's statement, in response to the "That's simple: JINI is based on the traditional "single cell" model", is spot on. Just because something isn't in the Jini APIs doesn't mean that the Jini tool set and the overall mantra of "something will break, just wait" are not valuable.

Indeed, Java's mobile code empowers the developer to solve problems in a plethora of ways. It's only the narrow view that you might have from only looking at the APIs which shields you, or misguides you to such thoughts and beliefs.

Posted by Gregg Wonderly on August 17, 2006 at 01:06 PM EDT #

Greg - I'm working on a follow-up article, but (just to spoil it) I think you are way off.

Complex systems tend to reflect their architectures, and complex concepts tend to reflect the axioms on which their conceptualizers relied. The axioms behind JINI reflect a client/server view of the world, where JINI is the server. An organic system views physical servers as temporary, expendable members of the overall system, and its axioms reflect that. I do fundamentally believe that JINI (as but one example of the traditional approach to distributed computing) is a poor and potentially invalid solution for the types of challenges that we (in this case, me, my co-workers, our company's partners and customers) face on a day-to-day basis.

As for your comment about 'the overall mantra of "something will break, just wait"', it is very similar to our own mantra, which is "in a large scale distributed system, something is always going to be going wrong at every moment". (I can even think of examples that I've personally witnessed today in the tests that we are doing to prepare for our upcoming 3.2 release.)

However, that very fact is why the organic model is so valuable as an evolution of though in distributed systems, because it can actually continue despite the breakage, and with deterministic outcomes.

As for my "misguided thoughts and beliefs", I am glad you are willing to disagree. Please don't take my arguments as being offensive, and I will attempt to do the same with yours. I quite enjoy the learning process through debate, and I'm glad you're willing to interject your own differing point of view.

Peace.

Posted by Cameron Purdy on August 17, 2006 at 03:47 PM EDT #

BTW - where are you located? If you are ever in Boston, let me know, and I'd be glad to meet up with you.

Peace.

Posted by Cameron Purdy on August 17, 2006 at 03:49 PM EDT #

Hmmm, so there's some interesting stuff going on here - couldn't resist a little thought experiement. Here's a Jini Service interface:

public interface ConferenceRoom {
void send(byte[] someStuff) throws NotEnroledException;

byte[] recv() throws NotEnroledException;
}

Here's the proxy for that service:

public class ConferenceProxy implements ConferenceRoom {
private MulticastSocket _socket;

private synchronized MulticastSocket getSocket() throws NotEnroledException {
if (_socket == null) {
// init......
// If init fails, throw exception
}

return _socket;
}

void send(byte[] someStuff) throws NotEnroledException {
MulticastSocket mySocket = getSocket();

reliableSend(mySocket, someStuff);
}

byte[] recv() throws NotEnroledException {
MulticastSocket mySocket = getSocket();

return getMessage(mySocket);
}
}

That's it - I now have a service that provides a multicast based form of group communication - on top of this I can build voting etc. I can have clients lookup the conference room and talk to each other. Those clients might be communicating cache processes or chat room clients or cache clients talking to a collection of cache processes or whatever.

Obviously, we're using multicast here but I can have other implementations based on, for example, JXTA or http or any of the XML IM protocols. I could even have a fallback policy where we try multicast first and then move through the other protocols 'til we find one that works.

Note that this proxy has no back-end. All it needs is something to publish it (and we could have multiple things each publishing one of these to give us redundant copies). Note also that the proxy is downloaded to the client at lookup time, no need for anything other than the ConferenceRoom interface to be on the classpath.


Posted by Dan Creswell on August 18, 2006 at 03:52 AM EDT #

Dan -

It's been easy in Java to send/receive data on the wire (including using multicast) since '96 .. when I referred to the conference room model, I was referring to an n-point protocol implemented as a finite state machine, not to the ability to send / receive messages or bytes ;-)

Peace.

Posted by Cameron Purdy on August 18, 2006 at 08:26 AM EDT #

"It's been easy in Java to send/receive data on the wire (including using multicast) since '96 .. when I referred to the conference room model, I was referring to an n-point protocol implemented as a finite state machine, not to the ability to send / receive messages or bytes ;-) "

I'm fully aware of the complexity involved but that's not really the point I was trying to illustrate which is that you can do n-point communication with no back-end (i.e. no classic client/server) in Jini.

Further, as I also hinted, you would either put more intelligence in the proxy or build a further layer on top (which could be another proxy which embeds the first) to get the state machine etc you would need.

Posted by Dan Creswell on August 18, 2006 at 08:41 AM EDT #

Hi Cameron.

Well written article, I enjoyed reading it. I like the analogy.

A few comments though, regarding the split brain problem and quorums (and perhaps you meant to address this when you referred to more complex continuaton logic in datacentres), is that this can often be a lot harder in practice to determine which 'half' of the split brain treats itself as 'dead'. It is one thing to consider one or two nodes that get isolated from the rest of the cluster, another when you have a near-equal number of nodes on each side of the split. Quorums with regards to minimum nodes may apply to either group (while percentage based quorums may apply to neither).

Cheers,
Manik

Posted by Manik Surtani on August 18, 2006 at 09:03 AM EDT #

Post a Comment:
Comments are closed for this entry.

Archives
Links
Referrers

The views expressed on this blog are my own and do not necessarily reflect the views of my employer.
Content copyright 2002, 2003, 2004, 2005, 2006, 2007 by Cameron Purdy. All rights reserved.