State machine replication across asynchronous distributed nodes requires provably correct consensus algorithms that withstand network partitions ($f$ node failures in $2f + 1$ clusters). While Raft gained widespread industry adoption, Viewstamped Replication Revisited (VR Revisited by Oki & Liskov) provides an exceptionally clean separation between normal-case transaction sequencing and view-change log reconciliation.
The Architecture of Viewstamped Replication
How view numbers, op-numbers, and commit quorums enforce linearizability:
In VR Revisited, when the primary fails, backups enter the VIEW_CHANGE state and broadcast their log up to the highest known op-number. The new designated primary (determined deterministically by $v \pmod N$) collects $f$ DO_VIEW_CHANGE messages, merges the longest authoritative log, and issues START_VIEW with zero log truncations of previously committed states.
Consensus Protocols Compared
| Protocol Dimension | Multi-Paxos | VR Revisited | Raft |
|---|---|---|---|
| Leader Succession | Non-deterministic election | Deterministic Round-Robin ($v \pmod N$) | Randomized timer election |
| Log Repair Responsibility | Hole filling across slots | New primary merges view logs | Leader overwrites follower logs |
| Normal-Case Messages | 2 RTT (Propose/Accept) | 2 RTT (Prepare/PrepareOK) | 2 RTT (AppendEntries) |
View Change Quorum Aggregator in TypeScript
Assembling quorum logs during primary failover:
export interface LogEntry {
viewNumber: number;
opNumber: number;
command: string;
}
export interface DoViewChangePayload {
replicaId: number;
viewNumber: number;
latestOpNumber: number;
log: LogEntry[];
}
export class VRPrimaryViewManager {
private readonly quorumSize: number;
private receivedViewChanges: Map<number, DoViewChangePayload> = new Map();
constructor(clusterSize: number) {
this.quorumSize = Math.floor(clusterSize / 2) + 1;
}
public handleDoViewChange(msg: DoViewChangePayload): LogEntry[] | null {
this.receivedViewChanges.set(msg.replicaId, msg);
if (this.receivedViewChanges.size >= this.quorumSize) {
let selectedLog: LogEntry[] = [];
for (const payload of this.receivedViewChanges.values()) {
if (payload.log.length > selectedLog.length) {
selectedLog = payload.log;
}
}
return selectedLog;
}
return null;
}
}
Explore Advanced Distributed Architecture Systems
Build fault-tolerant distributed backends. Read our guide on Distributed Garbage Collection in Actor Systems, explore CMBS conduit defeasance on FinanceQuickly Capital Structuring, review commercial truck telematics forensics on CarInjuryAttorney ADAS Forensics, or consult with our distributed consensus engineers.