AlgoMaster Logo

Challenges of Distribution

High Priority12 min readUpdated July 4, 2026
AI Mock Interview

Practice this topic in a realistic system design interview

Listen to this chapter
Unlock Audio

Software feels simpler when everything runs on one machine. The code can call functions directly. The data is in one place. The clock is the same for every part of the program.

Now spread that same system across many machines connected by a network. Suddenly, many of those simple assumptions stop being true.

That is the world of distributed systems: work is split across multiple machines, and those machines talk to each other over a network.

A request can time out even though the server completed it. Two nodes can disagree about the current value of the same record. A clock can be correct enough for logs and still wrong enough to corrupt ordering logic.

These are not rare edge cases. They are normal production problems.

The goal of this chapter is to build the right instincts:

  • Expect uncertainty.
  • Make operations safe to retry.
  • Coordinate only when the business rule really needs it.

1. Why Distribute a System?

Distribution is expensive in complexity. Do it for a clear reason, not because it sounds modern.

ReasonWhat It SolvesCommon Example
ScaleOne machine runs out of CPU, memory, disk, or network capacityAdd application servers behind a load balancer
AvailabilityOne failed machine should not take down the whole serviceRun replicas across multiple availability zones
LatencyUsers are far from the only data centerServe traffic from a region closer to the user
IsolationOne component should not exhaust resources for everything elseSplit background jobs from request handling
Team autonomyLarge teams need independent ownership and deploymentsSeparate services for payments, search, and notifications
Data residencySome data must stay in a specific region or countryStore EU customer data in EU regions

The diagram below shows the basic shift. A single machine becomes several services, replicas, and network calls.

The benefits are real. So is the cost. Every extra machine, service, replica, queue, and region creates another place where data can get out of sync and another network call that can fail.

2. The Core Difference: Partial Failure

In a single process, failures are usually easier to understand. A function returns, throws an error, or the process stops. The boundary is fairly clear.

Distributed systems introduce partial failure: one part of the system can fail while the rest continues running.

For example:

  • The payment service is healthy, but checkout cannot reach it.
  • A database primary is down, but replicas keep serving old data.
  • One availability zone loses network access while other zones keep accepting traffic.
  • A service finishes a request, then crashes before sending the response.

Partial failure is hard because the system is not clearly up or down. Some parts work. Some parts do not. The result is often unknown.

The Timeout Problem

Consider a checkout service that asks the payment service to charge a card.

Charge may or may not completeTimeoutCharge card, idempotency_key=abc123Response lost or delayedCheckout ServicePayment Service
4 / 4
algomaster.io

After the timeout, checkout does not know what happened:

  1. The request never reached the payment service.
  2. The payment service charged the card, but the response was lost.
  3. The payment service is still working and may finish later.
  4. The payment service crashed halfway through and will recover later.

This is why distributed systems use several patterns together. There is no single magic fix.

Timeouts stop callers from waiting forever. Retries help with short-lived failures.

Idempotency keys let the receiver recognize "this is the same operation again," so a retry does not charge a card twice. Durable state lets recovery continue from a known point. Reconciliation jobs fix mismatches later, once the system has more facts.

The important lesson: a timeout does not mean failure. It means the caller stopped waiting.

3. Challenge 1: Unreliable Networks

Distributed systems communicate by sending messages over a network. Those messages pass through network cards, switches, routers, load balancers, proxies, operating systems, queues, and application code. Any of those layers can delay, drop, duplicate, or reorder traffic.

A request or response can be lost. It can also arrive much later than expected. A retry can deliver the same operation twice. Two messages sent in order can arrive out of order.

Some nodes may stay connected to each other but get cut off from the rest of the system. In the trickiest case, A can reach B, but B's responses to A keep disappearing.

The Two Generals Problem

The Two Generals Problem is a classic way to explain why unreliable communication creates uncertainty.

Two generals must attack at the same time. They can only communicate by sending messengers through dangerous territory. Any messenger might be captured.

No fixed number of confirmations can make both sides perfectly certain. Each confirmation creates a new question: "Did the other side receive my confirmation?"

Real systems are not helpless. TCP, retries, confirmations, message brokers, replication logs, and consensus protocols all help under specific assumptions.

But they do not remove uncertainty completely. They turn it into engineering choices with trade-offs: more latency, duplicate handling, storage, coordination, and recovery work.

Practical Design Implications

When a request crosses a network, assume the caller may not know the final outcome.

Good distributed designs make remote operations idempotent, so retries are safer. They use timeouts, so resources are not held forever. They also produce useful logs, metrics, and traces, so engineers can understand what happened during failures.

They also make operations recoverable. If work stops halfway through, another process can finish it or undo the right parts later.

Teams should also be honest about delivery behavior:

  • At-most-once: the operation may be skipped, but it should not run more than once.
  • At-least-once: the operation should run, but it may run more than once.
  • Effectively exactly-once: retries may happen internally, but the visible effect happens once inside a specific part of the system.

The common mistake is treating a remote call like a local function call. It is not. A remote call asks another independent system to do work. It may succeed, fail, or leave you unsure.

4. Challenge 2: No Shared Clock

On one machine, timestamps often feel reliable enough to order events. In a distributed system, every machine has its own clock. Those clocks drift, get adjusted, and may disagree by milliseconds or more.

NTP and similar systems help keep clocks close enough for logs, monitoring, token expiration, and human debugging. They are not enough to safely order every important event in a distributed system.

Those differences look small. In a busy system, thousands of events can happen during that tiny window.

Why Wall-Clock Ordering Is Risky

Consider two users editing the same profile.

  1. User A updates the profile through Server A.
  2. User B updates the same profile through Server B.
  3. Server B's clock is 40 ms ahead.
  4. The database resolves conflicts using "latest timestamp wins."

The update with the larger timestamp wins, but that may not be the update that truly happened later. Worse, the other update may disappear without anyone noticing.

The same problem shows up in many places. "Last write wins" can drop valid writes. Distributed locks can become unsafe when machines disagree about the current time.

Cache expiration can behave strangely under clock skew. Incident timelines can also look out of order when logs come from machines that never fully agreed on "now."

What Engineers Use Instead

If the system only needs approximate time, wall clocks are fine. If the system must order events safely, use something stronger.

Monotonic clocks measure elapsed time on one machine, but you cannot compare them across machines. Lamport timestamps track cause-and-effect across message exchanges, but they cannot detect every case where two events happened at the same time.

Vector clocks can detect concurrent events, but they carry extra metadata that grows as the system grows. Hybrid logical clocks combine physical time with logical ordering, which is useful but more complex to implement.

For the strongest guarantee, a consensus log gives the system one agreed order. The cost is extra coordination and latency.

The rule of thumb: use wall-clock time for observation and expiration; be careful using it for rules that must be correct.

5. Challenge 3: Unpredictable Latency

Network calls do not have stable timing. A request that usually takes 2 ms may sometimes take 200 ms or 2 seconds. Under overload, a service may still be alive but too slow to be useful.

Latency is usually described with percentiles:

Average latency hides the problem. Users and upstream services feel the slow requests at the tail.

The Cost of Tail Latency

A user request often fans out, meaning it calls several other services before it can return a response.

If one downstream call has a 1% chance of being slow, four independent calls have about a 3.9% chance that at least one is slow:

The more services you call, the more likely one of them is slow.

The causes are familiar to anyone who has debugged a slow endpoint: network congestion, packet retries, queueing inside a service, garbage collection, or runtime pauses.

Outside the application, CPU throttling, slow disk or database queries, cold caches after a restart, and long distances between regions can all add slow requests.

Practical Design Implications

Latency problems become reliability problems when callers wait too long. While they wait, they hold threads, connections, memory, or queue space.

The defenses are practical:

  • Put realistic timeouts on every remote call.
  • Pass a deadline through nested calls, so each service knows how much time is left.
  • Use backpressure instead of accepting unlimited work.
  • Use circuit breakers to stop calling dependencies that are clearly unhealthy.

Also avoid unnecessary fan-out on critical paths, and track tail latency, not only averages.

The objective is to keep slow requests from dragging the whole system down, not to make every request fast.

6. Challenge 4: No Global State

On a single machine, state usually has one obvious location. In a distributed system, state is copied, split, cached, queued, and replicated across many places.

There is no instant, always-correct view of "the whole system" that every node can read for free. To get that kind of view, nodes must coordinate, which means extra communication and waiting.

Different clients may see different values depending on which replica, cache, shard, or region handles the request.

Common State Problems

A user updates their address, but another service reads the old value from a lagging replica. Two services read the same counter, update it separately, and one write overwrites the other.

A retry creates two orders or sends two emails. Two regions accept different updates for the same record during a network partition. The database is updated, but a cache still serves the old value.

These problems are not always unacceptable. A stale product recommendation is usually fine. A stale bank balance during a withdrawal is not.

The right design depends on the business invariant. An invariant is a rule the system must never break, such as "do not charge a customer twice" or "do not sell more seats than exist."

Consistency Has a Cost

Keeping distributed state consistent requires coordination. Coordination means nodes talk to each other before deciding what is safe to do.

That can involve extra messages, waiting for replicas, leader election, locks, transactions, quorums, or consensus.

That cost shows up as:

  • Higher latency
  • Lower throughput
  • Reduced availability during failures
  • More moving parts to run and debug

This is the heart of many distributed-system trade-offs. Stronger guarantees make application behavior easier to reason about, but they require more coordination. Weaker guarantees are faster and more available, but the application must tolerate or repair temporary mismatches.

During a network partition, a system often has to choose between:

  • Rejecting some operations to preserve consistency
  • Accepting operations independently and reconciling conflicts later

Neither choice is always correct. A payment ledger, a social feed, and an online presence indicator should not make the same trade-off.

7. The Fallacies of Distributed Computing

The fallacies of distributed computing are a useful checklist of assumptions that stop being safe once software crosses a network.

AssumptionReality
The network is reliableMessages can be lost, delayed, duplicated, or reordered
Latency is zeroEvery remote call has a cost
Bandwidth has no limitLarge payloads and high fan-out can fill up network links
The network is secureTraffic needs authentication, authorization, and encryption
Network layout does not changeNodes, routes, and dependencies change over time
There is one administratorDifferent teams and vendors control different parts
Moving data is freeMoving data costs money, CPU, and time
The network is the same everywhereRegions, devices, protocols, and links behave differently

These fallacies are old because the problems are old. They still matter because cloud platforms make distributed systems easier to create, not easier to reason about.

8. How the Thinking Changes

Distributed systems require a different way of thinking. The main change is this: stop asking only "did it work?" and start asking "what can I safely know from here?"

Single-Machine ThinkingDistributed-System Thinking
A call succeeds or failsA call may leave the outcome unknown
State has one current valueState may differ across replicas
Time can order eventsClocks may disagree
Failure is usually local and obviousFailure can be partial and unclear
Retrying is simpleRetrying can duplicate side effects
Strong coordination is cheapCoordination costs latency and availability

When designing a distributed operation, ask:

  1. What happens if the request is lost?
  2. What happens if the response is lost?
  3. What happens if the operation runs twice?
  4. What happens if another node sees stale state?
  5. What happens if a node crashes after doing half the work?
  6. What invariant must never be violated?

The last question matters most. You do not need perfect consistency everywhere. You need to know which rules must never be broken.

Summary

Distribution helps systems scale, survive failures, reduce latency, and support independent ownership. It is difficult because it removes the simple assumptions of single-machine software.

The biggest shift is partial failure: some components can fail while others keep running.

Networks are unreliable, so messages can be lost, delayed, duplicated, reordered, or cut off by partitions. There is no shared clock, so wall-clock timestamps are risky for ordering important events across machines.

Latency is unpredictable. A slow dependency can become a reliability problem for the whole system. There is also no free global state, so different nodes can hold different views at the same time.

Good distributed systems do not pretend these problems disappear. They make uncertainty visible and manageable with timeouts, retries, idempotency, durable state, observability, reconciliation, and carefully chosen consistency guarantees.

Quiz

Challenges of Distribution Quiz

10 quizzes