Monthly research note. Theme: Distributed Systems Under Failure.

TL;DR

A focused memo on Membership & Reconfiguration: Changing the Set Without Breaking Safety: define the model, state the properties, then design the system so those properties remain true under failure and adversaries.

Key insight

Treat “timeouts” as a third outcome: not success, not failure—ambiguity you must model.

Key takeaways

  • Write the safety property first; liveness is always conditional on timing assumptions.
  • Treat membership changes and compaction as protocol events—not operational details.
  • Mixed-version operation is the default; upgrades must preserve invariants.
  • Treat retries, reordering, and partial failure as default conditions.
  • Make failure modes explicit and observable.

Why this matters

  • Safety failures are permanent; liveness failures are (sometimes) recoverable.
  • Most protocol bugs hide in timeouts, retries, and membership changes.
  • State compaction and snapshots are where correctness goes to die quietly.
  • Observability must explain protocol state, not just latency.

Key questions

  • Where do you pay for liveness (timeouts, leader election, reconfiguration)?
  • What does “read” mean under replication lag?
  • What is the failure model (crash, byzantine, partitions, reordering)?
  • What is your reconfiguration model (joint consensus, epochs, leases)?
  • How do clients discover leaders safely (and what happens during flaps)?
  • Which components require determinism for reproducibility?

Assumptions

  • Packets can be duplicated and reordered; acks can be lost.
  • Clients retry and amplify load right when the system is weakest.
  • Nodes restart with partial state unless you prove durability.
  • Workload is skewed: hot keys exist and dominate.

Non-goals

  • Pretending backpressure is an implementation detail.
  • Relying on global time for ordering without strong synchronization assumptions.
Attack surface

Parsing is an attacker-controlled interface—validate early and fail fast.

Model & invariants

A common safety shape for replicated logs:

i: Committed(i)r: Logr[i]=Logleader[i].\forall i:\ \text{Committed}(i)\Rightarrow \forall r:\ \text{Log}_r[i] = \text{Log}_\text{leader}[i].

Treat membership changes as protocol events, not control-plane side effects.

Make overload explicit: admission control is a protocol boundary.

Invariant

If the system can enter an invalid state, it eventually will—usually during an incident.

Security properties

  • Least authority: privileges are scoped by purpose and time.
  • Authenticity: actions are bound to identity and purpose.
  • Downgrade resistance: negotiation can’t silently weaken security posture.
  • Evidence: critical actions emit verifiable audit events.

Failure modes

  • Resource exhaustion (CPU/bandwidth/storage) turning into correctness failures.
  • Mixed-version behavior that violates assumptions silently.
  • Recovery paths that only work when nothing is broken.
  • Timeout ambiguity causing double-apply or partial state transitions.
Pitfall

Mixed-version deployments create states you never tested—plan for them explicitly.

Design sketch

flowchart TD
  client["Client"] --> leader["Leader"]
  leader --> log["Replicated Log"]
  log --> snap["Snapshot"]
  snap --> recover["Recovery / Catch-up"]
  leader --> reconfig["Reconfiguration"]

Implementation notes

Your protocol is an interface between failures and invariants. Encode both.

Rule of thumb

Acknowledge only after durability (or make “ack” explicitly best-effort).

type LogIndex = u64;

#[derive(Clone, Debug)]
struct Entry {
  index: LogIndex,
  term: u64,
  bytes: Vec<u8>,
}

// Persist(term, vote, log) before acknowledging anything.

Verification strategy

  • Linearizability checks for read/write APIs that claim it.
  • Upgrade tests: mixed versions and rolling deploy invariants.
  • Model checking the smallest core (timeouts, election, reconfiguration).
  • Jepsen-style fault injection: partitions + reordering + client retries.
  • Stress + skew tests: hot keys, slow disks, noisy neighbors.

Operational notes

  • Expose protocol state: term/epoch, leader, commit index, config version.
  • Prefer monotonic time sources for leases; alert on clock discontinuities.
  • Rate-limit retries and apply admission control before saturation.
  • Rehearse region failover and reconfiguration under load.
  • Make client behavior part of the system: document retry semantics.
Operational note

Keep audit and config history queryable during incidents—evidence beats intuition.

What to monitor

  • Retry/timeout rates by endpoint and client cohort.
  • Invariant violation rate (should be ~0).
  • Rollback events and the conditions that triggered them.
  • Admission-control / rate-limit rejections (by reason).
  • Authz failures and policy denials (unexpected spikes).

Rollback plan

  • Prefer backward-compatible changes; avoid “flag day” upgrades.
  • Keep dual-write / dual-verify windows where appropriate.
  • Use canaries and staged rollout; stop early when signals degrade.
  • Preserve evidence (configs, artifacts, audit logs) to reconstruct what changed.
  • Define an explicit rollback trigger (metrics + thresholds).

Evidence

  • In Search of an Understandable Consensus Algorithm (Raft) (1) — Consensus with explicit state machines and practical tradeoffs.
    • Evidence: Track term/commitIndex as explicit evidence; test leader changes and log conflicts as part of rollback behavior.
  • Jepsen (2) — Testing correctness under partitions and faults.
    • Evidence: Turn faults into test cases; prioritize partition and clock-skew scenarios that violate user-visible guarantees.

Open questions

  • How do you prevent “operator fixes” from changing safety properties?
  • Where does your protocol assume synchrony without admitting it?
  • Which invariants are violated first under overload: latency, availability, or correctness?
  • What is the worst-case recovery time after a leader + disk failure?

Checklist

  • Assumptions listed and reviewed.
  • Telemetry captures correctness signals.
  • Costs bounded (CPU/memory/bandwidth) under adversarial inputs.
  • Failure modes enumerated with mitigations.
  • Safety properties stated as invariants.
  • Rollback plan rehearsed and automated.

Further reading

1.
Ongaro D, Ousterhout J. In Search of an Understandable Consensus Algorithm (Raft). In: 2014 USENIX Annual Technical Conference (USENIX ATC 14) [Internet]. 2014. Available from: https://raft.github.io/raft.pdf
2.
Jepsen. Jepsen: Distributed Systems Safety Analysis [Internet]. Web; Available from: https://jepsen.io/