Welcome back to the Architecture Corner.
I'm your host and really glad you could join us for Part 2 of
our five part journey into application availability.
Yeah, it's great to be back. So last time we sort of set the
stage, didn't we? Talk about availability itself,
why segmenting your app is so crucial?
Exactly. And today we're getting into the
nuts and bolts. Really 2 core ideas you
absolutely need for keeping things running, redundancy and
persistence. Hmm.
The safety Nets, essentially. Right, so let's unpack this.
We'll look at how having backups, backup systems, and
managing data the right way can save you when things inevitably
go sideways. OK, so redundancy first, it's
hard. It's just, well, it's about
having more than one of something.
Multiple instances of a resource.
Could be compute, storage, anything really.
And breaks. Exactly.
If one resource goes offline, traffic just gets rerouted
pretty quickly to one of its siblings.
Another healthy instance. OK, so it's kind of like having
a backup generator for your house, but maybe for your web
servers instead? That's a decent analogy, yeah.
And a common way to handle this, I think the article by Mario
Bittencourt touches on this, is using things like reverse
proxies or load balancers. Traffic cops.
Pretty much the client talks to the proxy, and the proxy is
smart enough to send that request only to servers that are
actually up and running. In that list of healthy servers
changes dynamically, right? It's not static.
Oh absolutely, that's key. The load balancer is constantly
checking. If a server fails a health
check, boom, stops getting traffic.
This happens automatically even in say, Kubernetes environments.
Requests just flow between healthy pods as they spin up or
down. OK, but here's where it gets a
bit tricky. I think redundancy isn't always
straightforward, especially if your application isn't
stateless. Right, that's a huge factor.
If your app needs to remember things between requests, like
user sessions or stores temporary data locally, well,
switching to a totally new instance can cause problems.
Because the new instance doesn't have that context.
Exactly that session info, that local data, it isn't shared
automatically. Stateless services much easier.
They don't store that local context, so any instance can
handle any request. It makes redundancy simpler to
implement. Got it.
So that's compute redundancy, but what about the data itself?
Well, that brings us nicely to persistence.
See, most applications have the code, the logic, and then the
data it works with. The code might not change often,
but the data does constantly OK, so making sure your data is
redundant. Achieving persistence has its
own set of challenges. A single change to the data can
make different copies instantly out of sync.
Right, so how do you keep all those copies consistent if you
have multiple databases, say? Good question.
The main approach is boil down to two types of replication,
synchronous and asynchronous. OK, sync and async.
What's the? Difference.
Well, with synchronous replication, a piece of data
isn't considered saved until multiple servers.
The primary end replicas confirm they've.
Got it. So it waits for everyone.
Kind of, yeah. It waits for confirmation from
multiple places. The big advantage you get
guarantees no data loss and strong consistency.
Everyone sees the same data. But the downside is.
Latency. Because you're waiting for those
confirmations. Every right takes longer and
handling failures gets a bit more complex too.
OK, So what about asynchronous? Asynchronous is different.
Data is marked saved as soon as the primary server gets it, then
replication of the other servers happens while in the background.
So it feels faster to the user initially a.
Definitely lower latency and it's generally simpler to
manage. But, and this is important for
you, comes with tradeoffs. Big ones like what potential
data loss if the primary server fails before it manages to
replicate the data will that data might be gone out.
And the other issue is you might serve stale data.
If you read from a replica that hasn't received the latest
update yet, you could see old information.
That's the classic read after write consistency issue.
Right, so you update something immediately, read it back and
you might get the old version. Exactly.
So how does this play out in the real world like of cloud
providers, AWS for example? Yeah, AWS provides good
examples. They heavily use their
availability zone AZZ for this. Think of Aziz as separate data
centres, physically isolated but connected with really fast
networks. They're the building blocks for
redundancy. And different services use these
AZ differently for persistence. They do take RDS, their
relational database service. You can set up synchronous
replication to a replica and a different azz.
That gives you high up time, maybe 99.95%, but failover if
the primary dies might take say 30 to 60 seconds.
OK. Still some downtime potential
there the. Little yeah.
Then there's Aurora. It's designed differently.
Data is automatically copied across 6 storage nodes and three
AZ. Even if you don't set up read
replicas yourself, it aims for super low replication lag, often
under 100 milliseconds. Wow, that's fast, but still
asynchronous. Fundamentally, yes.
So there's still that tiny, tiny chance of reading slightly stale
data from a replica, though they work hard to minimize it.
Interesting. And Dynamo DB that's different
again isn't. It very different.
Dynamodb uses a really interesting hybrid approach.
When you write data, it's synchronously copied to two
nodes in different azz, ensuring durability.
Then it's asynchronously copied to 1/3 node in another azz.
So you get the safety of three copies across AZ, but you only
wait for two confirmations. Exactly.
It's a balance between durability, availability and
latency. And then when you read data from
Dynamodb, you the user get a choice.
A choice. Yep, you can ask for an
eventually consistent read, which is faster but might return
stale data. Or you can request a strongly
consistent read which guarantees the absolute latest data, but
might be slightly slower because it always goes to the primary
node cluster. So you tailor the consistency to
your application specific need for that particular read.
Precisely, it puts the trade off decision in your hands.
OK, so wrapping this up, it seems like redundancy, whether
for compute or data persistence is fundamental for availability,
but it's never free. Never.
You're always playing with trade-offs, the safety of having
multiple copies versus potentially higher latency, or
the complexities of eventual consistency.
Which leads to a really critical question for you listening How
do you actually decide what level of consistency or what
latency is genuinely good enough for your application?
Yeah, that's not always obvious. It depends entirely on the
specific requirements and failure modes you're willing to
tolerate. It's definitely not A1 size fits
all situation. Absolutely.
And there's still more to cover. We've really just scratched the
surface here. Join us next time as we continue
exploring availability, looking at concepts like graceful
degradation and asynchronous processing.
More tools for your resilience toolkit.
Definitely, And for more details on today's topics and some
deeper dives, do check out the description for this discussion.
And please don't forget to subscribe for free to the
Architecture Corner newsletter over at
architecturecorner.substack.com. Thanks so much for joining us in
the Architecture Corner. We'll see you next time.