Practices of Reliable Software Design
entropicthoughts.com
Practices of Reliable Software Design
1–10 of 58 posts
Re: Practices of Reliable Software Design
#2The way to build reliable software systems is to have multiple independent paths to success.
This is the Erlang "let it crash" strategy restated, but I've also found it embodied in things like the architecture of Google Search, Tandem Computer, Ethereum, RAID 5, the Space Shuttle, etc. Basically, you achieve reliability through redundancy. For any given task, compute the answer multiple times in parallel, ideally in multiple independent ways. If the answer agrees, great, you're done. If not, have some consensus mechanism to detect the true answer. If you can't compute the answer in parallel, or you still don't get one back, retry.
The reason for this is simply math. If you have n different events that must all go right to achieve success, the chance of this happening is x1 * x2 * ... * xn. This product goes to zero very quickly - if you have 20 components connected in series that are all 98% reliable, the chance of success is only 2/3. If instead you have n different events where any one can go right to achieve success, the chance of success is 1 - (1 - y1) * (1 - y2) * ... * (1 - yn). This inverse actually increases as the number of alternate pathways to success goes up and fast. If you have 3 alternatives each of which has just an 80% chance of success, but any of the 3 will work, then doing them all in parallel has a 97% chance of success.
This is why complex software systems that must stay up are built with redundancy, replicas, failover, retries, and other similar mechanisms in place. And the presence of those mechanisms usually trumps anything you can do to increase the reliability of individual components, simply because you get diminishing returns to carefulness. You might spend 100x more resources to go from 90% reliability to 99% reliability, but if you can identify a system boundary and correctness check, you can get that 99% reliability simply by having 2 teams each build a subsystem that is 90% reliable and checking that their answers agree.
Re: Practices of Reliable Software Design
#3Re: Practices of Reliable Software Design
#4Re: Practices of Reliable Software Design
#5There is a bunch of good advice here, but it's missed the most useful principal in my experience, probably because the motivating example is too small in scope: The way to build reliable software systems is to have multiple independent paths to success. This is the Erlang "let it crash" strategy restated, but I've also found it embodied in things like the architecture of Google Search, Tandem Computer, Ethereum, RAID…
Failovers, redundancies, and backups are all important for building systems that are resilient in the face of problems, for reasons you've pointed out.
However, failovers, redundancies and backups are inefficient. Solving a problem with 1 thing is always going to be more efficient that solving the same problem with 10 things.
It's interesting to see this tradeoff play out in real-life. We see people coalescing around one or two services because that's the most efficient path, and then we see them diversifying across multiple services once bad things happen to the centralised services.
Re: Practices of Reliable Software Design
#6Re: Practices of Reliable Software Design
#7There is a bunch of good advice here, but it's missed the most useful principal in my experience, probably because the motivating example is too small in scope: The way to build reliable software systems is to have multiple independent paths to success. This is the Erlang "let it crash" strategy restated, but I've also found it embodied in things like the architecture of Google Search, Tandem Computer, Ethereum, RAID…
In the limit, there is a hard tradeoff between efficiency and reliability. Failovers, redundancies, and backups are all important for building systems that are resilient in the face of problems, for reasons you've pointed out. However, failovers, redundancies and backups are inefficient. Solving a problem with 1 thing is always going to be more efficient that solving the same problem with 10 things. It's interesting…
Re: Practices of Reliable Software Design
#8There is a bunch of good advice here, but it's missed the most useful principal in my experience, probably because the motivating example is too small in scope: The way to build reliable software systems is to have multiple independent paths to success. This is the Erlang "let it crash" strategy restated, but I've also found it embodied in things like the architecture of Google Search, Tandem Computer, Ethereum, RAID…
5 independent systems with 90% chance of success is mathematically as reliable as one that is 99.999%.
100x 90% systems would get you to 100 "9s" of reliability aka 99.99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999%
Re: Practices of Reliable Software Design
#9There is a bunch of good advice here, but it's missed the most useful principal in my experience, probably because the motivating example is too small in scope: The way to build reliable software systems is to have multiple independent paths to success. This is the Erlang "let it crash" strategy restated, but I've also found it embodied in things like the architecture of Google Search, Tandem Computer, Ethereum, RAID…
the simple basic reality of statistics, a binomial distribution. 5 independent systems with 90% chance of success is mathematically as reliable as one that is 99.999%. 100x 90% systems would get you to 100 "9s" of reliability aka 99.99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999%
(a) failures are correlated, not independent, and
(b) many failures happen not at the component level but at the plane where components interact, and regardless of how much redundancy there is at the component level, there is ultimately just one plane at which they finally interact to produce a result.
Re: Practices of Reliable Software Design
#10There is a bunch of good advice here, but it's missed the most useful principal in my experience, probably because the motivating example is too small in scope: The way to build reliable software systems is to have multiple independent paths to success. This is the Erlang "let it crash" strategy restated, but I've also found it embodied in things like the architecture of Google Search, Tandem Computer, Ethereum, RAID…
In the 1930's, yes, component redundancy was the way to reliability. This worked at the time because components were flaky and technical systems were simple aggregations of components. Today, components themselves are more reliable, but even when they are not, redundancy adds only a little reliability because there's a new, large, source of failure: interactive complexity.
Today's systems are so complicated that many failures stem from insufficient, misunderstood, or ambiguous specifications. These errors happen not because a component failed -- all components work exactly as they were intended to -- it is only that in their intended interactions they produce an unintended result. Failure is an emergent property.
The solution is to approach reliability from a system theoretic perspective. This very early draft contains the core of the idea, but not yet fleshed out or edited: https://entropicthoughts.com/root-cause-analysis-youre-doing...