Welcome to the architecture. Corner glad to be.
Here today we're looking at your notes and articles on keeping
applications running smoothly, specifically digging into Active
Active Patterns. Our mission really is to cut
through some of the complexity here.
We want to arm you with the insights you need to build apps
that stay up even if, say, an entire region goes offline.
Exactly. It's sort of the Holy Grail of
availability, isn't it? The idea that a whole region can
have a major problem but for your users.
Nothing changes they. Don't even notice, that's the
benchmark we're aiming for with these multi region active active
setups. OK, so let's picture it.
An application, all its bits, services, databases, everything
running in let's say 2 or more regions at the same time.
Yeah. What's the first big challenge
you hit? Right away it's name resolution
getting that flawless. You can have your servers
everywhere, but if your DNS setup can't instantly flip users
from a failed region to a working 1.
Well, it's pointless. OK, DNS.
What else? Then there's application
synchronization. You need all those application
instances across all your regions to be absolutely
identical and stay that. Way right, So deploying the code
consistently, that's one piece, but often the real headache
isn't it the data? Like what happens if people in
different regions try to write to the same database record
almost simultaneously? Precisely data synchronization.
That's usually the biggest challenge.
You mentioned concurrent rights. Imagine two people trying to buy
the very last widget in stock but from different regions,
without really careful handling, end up with race conditions.
You know, where the timing just messes everything up, gives you
wrong results, the complexity there and the cost.
It just shoots up. Which brings up a really
important question. Then, given all that extra
complexity, the cost is a full active active setup always the
right answer? Oh, definitely not.
No, you absolutely need a careful return on investment.
Check an ROI assessment. It's often smarter to apply an
active active pattern to just a part of your application that's.
The really critical. Bits exactly the most critical
components that helps manage the complexity and keeps the costs
reasonable. It's about being strategic,
surgical even. That makes a lot of sense.
Yeah. OK, so let's maybe walk through
the main patterns then. There are three key ones, right?
First is Read local, write global.
How's that one work? So with this one, users read
data from the closest region to them, which is fast, but all the
right operations. Every single one gets sent to 1
single primary global region. OK, the beauty of it is
simplicity, really. It naturally avoids those
difficult race conditions because, well, everything's
being written in one. Place simple for consistency.
Got it. But the downside for the user
must. Be latency, Yeah, if you're a
user who's physically far from that one designated right
region, you're right, operations will take longer.
It's noticeable. So it's best for apps that
mostly read data. Exactly.
High read to write ratio and where maybe losing a few seconds
of data during replication isn't catastrophic.
OK, so if read local, write global is simple but potentially
slow for writes, how do we improve that write latency?
That sounds like the next pattern.
Read local, write partitioned. Right, so again, reads are
always local fast. But for writes, the application
itself has logic to decide which region handles the right.
It's based on some custom rules you define.
Like what? Maybe based on the user's
profile or perhaps where they first started their session.
Like if you start shopping on an ecommerce site via Regina, maybe
all your rights for that session get pinned to region A AH.
OK, seems more balanced for latency then.
What's the catch with this one? Well, you're basically building
sharding logic, the rules for distributing data directly into
your application code. That adds complexity and if the
region designated for your rights goes down.
You can't update your stuff. Exactly.
You won't be able to modify your specific data until it recovers.
So this pattern is good for latency sensitive apps.
Maybe with a more even read write mix, but you have to
accept that some user data might be temporarily read only during
an outage. Alright.
And the third one Read local, write local sounds like the
dream scenario. Low latency for reads and
writes. It is from a latency
perspective, yes. Both reads and writes happen in
the users local region. But there's always a but.
There's always a, but because rights are happening everywhere,
you're almost guaranteed to run into race conditions eventually.
Think about a loyalty point system.
A user buys something in region A earning points, while maybe a
refund is processed for them in region B, deducting points all
around the same time. Your application has to be smart
enough to reconcile these conflicting updates.
Does one win? Do they merge somehow?
Right, you need conflict resolution logic.
You absolutely do so. This pattern best for really
write heavy applications where low latency is paramount, but
you need to be prepared to handle those data conflicts.
OK. So let's make this concrete.
And you mentioned applying this surgically.
Yeah, how would you do that for, say, an ecommerce app?
You would make the whole thing active Active.
Probably not. You'd identify the critical
flows taking new orders that's likely core business needs very
fast recovery. So you make that act.
Active, but maybe not everything.
Else right, fulfilling orders or maybe updating the product
catalog. Perhaps those can tolerate a few
hours of downtime if a region fails depending on the business
impact. So your deployment tools,
hopefully using infrastructure as code, would only deploy that
critical order taking subset to all your active regions.
And routing, how do users get to the right place?
Usually DNS maybe like Route 53 with health checks directing
users to their closest healthy region.
Simple and effective. And the data sync for that
ecommerce example orders versus catalog.
Yeah, good question. For the sales catalog, updates
often come from one internal source, right?
So you could use cross region replication, just streaming
those changes out. If the source region fails, no
new updates flow, but the existing catalog is readable
everywhere. OK.
And for the shopping? Cart that's more user specific.
Something like bidirectional replication may be using
Dynamodb. Global tables works well.
Users tend to stick to one region for their session, which
minimizes flashes, and even with acing replication where there's
a slight delay, you often use a last writer wins strategy to
sort out consistency when things recover.
What really stands out here is that this isn't just one team's
job achieving this high availability.
It's multidisciplinary. Totally.
It seems like it has to start with a really solid risk
assessment, understanding how critical each piece of your
application actually is. Absolutely, you need that
business context. 1st and then once you know that, you can pick
the right tool for the job from those patterns, read local,
write global, read local write partition or read local, write
local, applying them strategically.
And if we zoom out for a second, it connects to the bigger
picture. Yes, active active patterns give
you potentially the fastest recovery times possible near 0
sometimes. But that power comes with
significant complexity and. Cost.
So you need that ROI justification.
Always you need that careful strategic assessment for every
application, maybe even every service.
The real skill, the art perhaps, is knowing when and where to
deploy this level of resilience. Getting it right turns that
potential chaos of an outage into, well, seamless continuity
for your users. A great thought to end on
turning chaos into continuity. You can find more details and
links related to our discussion today in the description.
Definitely check those. Out and for more insights like
this, please do subscribe. It's free to the Architecture
Corner newsletter. You can find it at
architecturecorner.substack.com. It's a.
Great resource. Finally, a huge thank you to
Mario Bittencourt, whose excellent work really formed the
basis for this conversation. Yes, Thank you, Mario.
We'll catch you next time on the architecture corner.