Distributed Systems: Time, Failure, and Coordination
Understand why networked components behave differently from a single process and how to design around partial failure.
Partial Failure, Timeouts, and Deadlines
In a distributed system, one component can fail while others continue. A client may time out even though the server completed the request; a response may be lost after a database commit. Therefore, “no response” is not the same as “no operation occurred.”
Use bounded connection, request, and total deadlines. A deadline expresses how long the caller can still wait; propagate the remaining budget downstream. Retries should be limited, use exponential backoff with jitter, and apply only when the operation is safe to retry or protected by idempotency.
Retries can worsen overload if every layer retries independently. If three layers each retry four times, one user request may trigger many downstream attempts. Choose one retry owner where possible, cap attempts, and stop retrying when the deadline or circuit-breaker policy says further work is harmful.
- Design for partial failure as a normal condition.
- Timeouts need explicit retry and idempotency policies.
- Uncoordinated retries can multiply load during an outage.
A client times out after submitting a request. What can safely be concluded?
Clocks, Ordering, and Unique IDs
Wall clocks on different machines can drift and jump. Do not assume timestamps from two hosts provide a perfect total order. NTP reduces clock skew but does not make distributed clocks identical. Use monotonic clocks for measuring elapsed time and wall-clock timestamps for human-oriented event time.
Identifiers can be generated centrally, randomly, or in a distributed fashion. UUIDs reduce coordination but may be less compact or less locality-friendly depending on version and storage. Snowflake-style IDs combine time and worker identity, requiring careful worker allocation and clock rollback handling. Database-generated sequences are simple but may create a central dependency.
If order matters, define what kind: per-entity order, partition order, causal order, or global order. Global ordering is expensive and often unnecessary. Use sequence numbers, optimistic versions, partitioned logs, or consensus only when the required semantics justify the cost.
- Timestamps do not guarantee a global event order.
- Choose IDs based on uniqueness, locality, and coordination needs.
- Specify the scope of ordering before implementing it.
Leader Election, Leases, and Consensus Basics
Distributed coordination is needed when multiple nodes must agree on ownership or a shared decision. Leader election chooses a node to coordinate a task, but a leader can pause, become partitioned, or lose connectivity while other nodes continue.
A lease grants ownership for a bounded period, yet clock drift and pauses can make stale owners dangerous. Fencing tokens solve an important class of stale-owner problems: each new owner receives a monotonically increasing token, and the protected resource rejects operations carrying an older token.
Consensus protocols such as Raft help a group of nodes agree on a replicated log despite certain failures, assuming a majority can communicate. Consensus is not a magic global lock; it has latency, quorum, membership, and operational constraints. Use established coordination systems rather than inventing a protocol for production.
If a process pauses past its lease and later resumes, it may still try to write. Fencing tokens or equivalent resource-side validation can prevent stale ownership from corrupting state.
- Leader election does not eliminate stale-leader risks.
- Fencing tokens protect resources from expired owners.
- Use proven consensus implementations and understand quorum assumptions.