Availability, Latency, Durability, and Correctness Trade-offs

LESSON

Reliability Engineering Foundations

004 25 min intermediate

Availability, Latency, Durability, and Correctness Trade-offs

By the end of this lesson, you will be able to...

  • Distinguish availability, latency, durability, and correctness as separate reliability dimensions.

  • Explain why improving one dimension can make another dimension worse under real constraints.

  • Use a trade-off matrix to review a reliability decision for a checkout service.

Idea in one sentence: Reliability is not one number; it is a set of user promises that can conflict, so good engineering means naming which dimension you are protecting and what you are spending.

Core Insight

The checkout team has a promise, an SLI, and an SLO.

Promise:
  valid checkout attempts should receive a clear result within 3 seconds
  and should not create duplicate charges

SLI:
  clear-result rate

SLO:
  99.5% over 28 days

Now a real pressure appears.

The payment provider is slow for some requests. The checkout API can still receive traffic. The database is healthy. The web page is loaded. But payment confirmation sometimes takes 8 seconds.

The team has several options:

Option 1:
  Wait for the payment provider until the final answer is known.

Option 2:
  Return quickly with "order pending" and finish payment asynchronously.

Option 3:
  Fail fast when payment is uncertain.

Option 4:
  Accept the order before durable storage and hope reconciliation fixes it later.

Which option is "more reliable"?

That question is too vague.

Each option protects one reliability dimension and spends another.

Plain meaning:

Reliability has different kinds of promises. A service can be reachable but slow, fast but wrong, correct but unavailable, or available but unsafe.

In this scenario:

Checkout reliability includes whether users can reach checkout, how long they wait, whether accepted orders survive failure, and whether payment/order state is correct.

Technical names:

The common dimensions are availability, latency, durability, and correctness.

Once you separate them, reliability decisions become more honest.

You stop saying:

"This makes checkout more reliable."

You start saying:

"This protects correctness and durability, but it may hurt latency and availability during payment-provider slowness."

That second sentence is less shiny. It is much more useful.

The Single-Number Trap

The naive model is:

Reliability = uptime.

Or, after learning SLOs:

Reliability = one SLO number.

This model is tempting because one number is easy to report.

checkout reliability: 99.5%

But one number hides what kind of failure users experienced.

Consider four checkout outcomes:

A. The checkout page will not load.
B. The checkout page loads, but payment takes 20 seconds.
C. The user sees "success," but the order is lost after a database failover.
D. The user is charged twice for one checkout attempt.

All four are reliability problems.

They are not the same problem.

Outcome A is mostly about availability. The user cannot use the service.

Outcome B is mostly about latency. The service eventually responds, but too slowly for the promise.

Outcome C is about durability. The service accepted something that did not survive.

Outcome D is about correctness. The service produced the wrong business result.

If the team only says "checkout reliability dropped," they may choose the wrong response.

More servers may help A.

More servers may do almost nothing for C or D.

A longer timeout may help avoid an ambiguous payment result, but it can make B worse.

A faster response may make B better, but if it returns "success" before durable storage, it can make C worse.

Reliability work needs dimension language because dimensions point to different mechanisms.

The Four Dimensions

Availability

Availability asks:

Can the user reach the service and get it to attempt the promised work?

For checkout, availability includes whether users can open checkout, submit payment, and receive some handled response instead of total failure.

Availability is not the same as success.

A declined card can still be an available checkout path if the user receives a clear decline.

Latency

Latency asks:

How long does the user wait for the promised result?

For checkout, latency matters because waiting changes behavior. Users may refresh, retry, abandon the cart, or contact support.

Latency is not just "server time."

The promise is about the time until the user gets a clear result. That may include backend work, frontend rendering, redirects, third-party calls, and client-visible state changes.

Durability

Durability asks:

If the service says something was accepted, will that fact survive failures?

For checkout, durability means an accepted order and payment decision should not vanish after a crash, failover, deployment, or queue restart.

Durability often requires writing state before telling the user the work is accepted.

That write can cost latency.

Correctness

Correctness asks:

Did the service produce the right result according to the promise and business rules?

For checkout, correctness includes not charging twice, not accepting impossible inventory, not marking failed payments as paid, and not showing success for an order that cannot exist.

Correctness often requires checks, coordination, idempotency, or stricter boundaries.

Those mechanisms can cost availability or latency.

A Worked Trade-off Matrix

Return to the slow payment-provider incident.

The system knows:

valid checkout attempts are arriving
payment provider sometimes takes 8 seconds
checkout SLO expects a clear result within 3 seconds
duplicate charges are especially harmful
orders should survive process and database failover

Compare the options:

Option Availability Latency Durability Correctness Main risk
Wait for final payment answer lower during slowness worse strong if state is written carefully strong Users wait too long and retry.
Return "order pending" quickly higher better for initial response depends on durable pending record good if state machine is clear Users may not understand pending state.
Fail fast when payment is uncertain lower for checkout completion better strong strong Some valid purchases are rejected.
Accept order before durable storage high-looking fast-looking weak weak Success can vanish or become inconsistent.

No option wins every column.

That is the point.

If the team only optimizes availability, it may keep accepting checkouts while payment state is unclear. Users can keep clicking, but correctness may suffer.

If the team only optimizes latency, it may return quickly before durable state exists. Users see speed, but recovery after a crash becomes dangerous.

If the team only optimizes correctness, it may reject uncertain purchases. Users are safer from double charges, but more valid checkouts fail.

If the team only optimizes durability, it may force every path through a strong write before responding. Accepted work survives better, but latency may rise.

A good reliability decision names the chosen trade-off:

During payment-provider slowness, we prefer a durable "pending" state over
pretending checkout succeeded. We will return a clear pending result quickly,
show the user what will happen next, prevent duplicate attempts with an
idempotency key, and finish the payment decision asynchronously.

This design does not remove all risk.

It chooses which risk is acceptable.

Check: Why is "return success immediately and reconcile later" dangerous for checkout?

Think first, then reveal.

Answer: It may improve apparent availability and latency, but it can hurt durability and correctness. If the accepted order is not durable or the payment state later disagrees, users may see success for work the system cannot safely complete.

What This Changes About SLOs

The previous lesson introduced one SLO:

99.5% clear checkout result within 3 seconds

That SLO mostly protects latency and clarity.

It does not fully protect all reliability dimensions.

The team may need additional indicators or objectives:

availability:
  percentage of valid checkout attempts that reach handled checkout logic

latency:
  percentage of valid attempts with clear result within 3 seconds

durability:
  percentage of accepted orders recoverable from durable storage within 1 minute

correctness:
  duplicate charge rate per checkout attempt
  paid orders with matching order record

Do not turn this into dashboard confetti.

The goal is not to create twenty SLOs because four dimensions exist.

The goal is to avoid hiding a serious promise behind the wrong number.

If duplicate charge correctness is rare but severe, it may deserve a separate SLO or a stricter alert even if the latency SLO is green.

If order durability is critical, it may need a recovery check rather than a request latency chart.

The dimensions help the team ask:

Which promise are we measuring?
Which dimension does this metric protect?
Which dimension might get worse if we optimize this one?

Worked Classification

Classify these production symptoms before choosing a fix:

Symptom Primary dimension Why
Users cannot load checkout at all. Availability The service is not reachable for the promised workflow.
Checkout usually works, but p95 clear-result time is 9 seconds. Latency The user gets a result, but not inside the time promise.
The user sees success, then the order disappears after failover. Durability An accepted fact did not survive failure.
One checkout attempt creates two payment authorizations. Correctness The result violates the business rule and user trust.
The service rejects all uncertain payment-provider responses. Availability/correctness trade-off It protects against wrong payment state, but valid users may fail checkout.
The service shows "pending" after durable order creation. Latency/correctness/durability trade-off It avoids false success and preserves state, but delays final completion.

This classification step is small, but it prevents bad fixes.

If the symptom is duplicate authorization, adding more web servers is probably not the first move. The team should inspect idempotency, retry behavior, payment state transitions, and duplicate prevention.

If the symptom is slow clear-result time, stricter idempotency may not help unless retries are causing the delay. The team should inspect dependency latency, timeout policy, queueing, and result-page state.

If the symptom is accepted orders disappearing after failover, a faster response makes the user feel better for a moment and makes recovery worse later. The team should inspect when state is durably written and what the service promises before that write.

The point is to diagnose the dimension before prescribing the mechanism.

Common Confusions

Confusion: "Availability includes everything"

Why it is tempting:

People often use "available" to mean "working."

Better model:

Availability means the service can be reached and can attempt the work. It does not guarantee fast, durable, or correct outcomes.

Confusion: "Latency is only performance, not reliability"

Why it is tempting:

Teams often put performance and reliability in separate buckets.

Better model:

Latency becomes reliability when the user promise includes time. If checkout promises a clear result within 3 seconds, slow checkout is a reliability failure.

Confusion: "Durability only matters for databases"

Why it is tempting:

Durability sounds like a storage term.

Better model:

Durability matters whenever the service tells a user that work was accepted. The team must know which accepted facts survive crashes, retries, and failovers.

Confusion: "Correctness can be fixed later"

Why it is tempting:

Incorrect states sometimes look smaller than outages because the service keeps running.

Better model:

Correctness failures can destroy trust faster than downtime. A checkout system that double-charges users is not reliable even if it is available and fast.

Trade-offs and Limits

Separating dimensions improves judgment.

It helps the team avoid vague arguments like:

"This is more reliable."

and replace them with:

"This improves latency but weakens durability unless we write the pending order first."

It also has limits.

First, dimensions overlap. A timeout can be a latency problem for the user, an availability problem for a dependency, and a correctness risk if retries are unsafe.

Second, dimensions do not choose priorities for you. Product risk, user harm, legal obligations, operational cost, and business context decide which dimension wins in a conflict.

Third, dimensions can make the system look more complex. That complexity is real. The purpose of the language is to make the complexity inspectable, not to make the decision feel easy.

The trade-off is:

One reliability number is easy to communicate but easy to misread.
Several named dimensions are harder to discuss but harder to fool yourself with.

Practice

Review this design change:

When the payment provider is slow, checkout will immediately show "success"
and place the order in a background reconciliation queue. If payment later
fails, support will contact the user.

Classify the effect:

  1. Which dimension improves?
  2. Which dimensions may get worse?
  3. What safer alternative would you propose?

Model answer:

Improves:
  Initial latency and apparent availability. The user sees a fast response.

May get worse:
  Correctness, because the user sees success before payment is actually known.
  Durability, if the accepted order is not written durably before the response.
  User trust, because later reversal by support is surprising.

Safer alternative:
  Write a durable pending order first. Return a clear "payment pending" result
  within the latency promise. Use an idempotency key to prevent duplicate
  attempts. Complete payment asynchronously and show a clear final state later.

Your answer can differ. The important test is whether you name the dimensions instead of saying only "more reliable" or "less reliable."

Resources

Key Takeaways

PREVIOUS SLOs and Error Budgets NEXT Toil, Automation, and Operational Load