Skip to main content

Command Palette

Search for a command to run...

Distributed Consensus: Raft and Paxos Algorithms

Published
8 min readView as Markdown
T

Welcome to TopperBlog! 👋

I'm a tech content creator passionate about helping developers level up their careers and master cutting-edge technologies.

🎯 What I Write About: • AI/ML Engineering & LLMs • Web3 & Blockchain Development
• System Design & Architecture • Interview Preparation (FAANG) • Freelancing & Remote Work • Modern Tech Stacks (Next.js, React, Rust, TypeScript) • Performance Optimization & Best Practices

💼 Mission: Sharing practical, actionable insights that accelerate your tech career and maximize your earning potential.

📚 15+ In-Depth Guides covering everything from earning $10k/month as a freelancer to cracking FAANG interviews.

🌐 Let's connect and grow together in this amazing tech journey!

#TechBlogger #SoftwareEngineering #CareerGrowth #WebDevelopment #AIEngineering

Distributed Consensus: Raft and Paxos Algorithms

In distributed systems, achieving consensus—getting multiple nodes to agree on a single value or state—remains one of the most challenging problems developers face. Whether you're building a distributed database, coordinating microservices, or implementing leader election in a cloud-native application, understanding consensus algorithms is essential. This article explores Paxos and Raft, the two dominant consensus algorithms, and demonstrates how to implement consensus patterns in modern TypeScript applications.

The Distributed Consensus Problem in 2026

Modern applications are inherently distributed. Your authentication service runs across three availability zones, your database replicates data across continents, and your Kubernetes cluster needs to elect a master node. In each scenario, multiple independent processes must agree on critical decisions despite network partitions, node failures, and message delays.

The fundamental challenge is the CAP theorem: in the presence of network partitions, you must choose between consistency and availability. Consensus algorithms help you make this choice explicit and handle it gracefully.

Consider a distributed key-value store where three replicas must agree on the order of write operations. If Client A writes user:123 = "Alice" and Client B simultaneously writes user:123 = "Bob", all replicas must process these operations in the same order. Without consensus, your system experiences split-brain scenarios where different nodes hold conflicting data.

In 2026, with edge computing, multi-cloud deployments, and increasingly complex microservice architectures, consensus problems have only intensified. The latency between edge nodes and cloud regions, combined with the expectation of real-time consistency, makes robust consensus mechanisms non-negotiable.

Why Traditional Approaches Fall Short

Early distributed systems attempted simpler solutions that proved inadequate:

Two-Phase Commit (2PC) requires all participants to agree before committing a transaction. However, if the coordinator fails after the prepare phase, participants remain blocked indefinitely. This blocking nature makes 2PC unsuitable for high-availability systems.

Master-Slave Replication without proper consensus allows split-brain scenarios. If the master fails and two slaves both promote themselves, you have two masters accepting conflicting writes.

Timestamp-based ordering fails when clocks drift. Even with NTP synchronization, clock skew between nodes can cause incorrect ordering of operations.

These approaches share a common flaw: they don't handle the fundamental challenges of distributed systems—network partitions, arbitrary message delays, and node failures—in a provably correct manner.

Understanding Paxos and Raft

Paxos: The Theoretical Foundation

Proposed by Leslie Lamport in 1998, Paxos is notoriously difficult to understand but mathematically elegant. It operates in phases:

  1. Prepare Phase: A proposer selects a proposal number and sends prepare requests to acceptors
  2. Promise Phase: Acceptors promise not to accept proposals with lower numbers
  3. Accept Phase: If a majority promises, the proposer sends accept requests
  4. Accepted Phase: Acceptors accept the proposal if they haven't promised a higher number

Paxos guarantees safety (never returning incorrect results) but requires careful implementation to ensure liveness (eventually making progress).

Raft: Understandability as a Design Goal

Developed in 2014 by Diego Ongaro and John Ousterhout, Raft was explicitly designed to be understandable. It decomposes consensus into three subproblems:

  1. Leader Election: Nodes elect a single leader using randomized timeouts
  2. Log Replication: The leader accepts client requests and replicates log entries to followers
  3. Safety: Ensuring elected leaders have all committed entries

Raft's key insight is that strong leadership simplifies the protocol. Only the leader accepts client requests, eliminating the competing proposers problem in Paxos.

Modern TypeScript Implementation

Let's implement a simplified Raft-inspired consensus system in TypeScript. This example demonstrates leader election and basic log replication:

enum NodeState {
  FOLLOWER = 'FOLLOWER',
  CANDIDATE = 'CANDIDATE',
  LEADER = 'LEADER'
}

interface LogEntry {
  term: number;
  command: string;
  index: number;
}

interface VoteRequest {
  term: number;
  candidateId: string;
  lastLogIndex: number;
  lastLogTerm: number;
}

interface VoteResponse {
  term: number;
  voteGranted: boolean;
}

class RaftNode {
  private state: NodeState = NodeState.FOLLOWER;
  private currentTerm: number = 0;
  private votedFor: string | null = null;
  private log: LogEntry[] = [];
  private commitIndex: number = 0;
  private lastApplied: number = 0;
  private electionTimeout: NodeJS.Timeout | null = null;
  private heartbeatInterval: NodeJS.Timeout | null = null;

  constructor(
    private nodeId: string,
    private peers: string[],
    private rpcClient: RPCClient
  ) {
    this.resetElectionTimeout();
  }

  private resetElectionTimeout(): void {
    if (this.electionTimeout) {
      clearTimeout(this.electionTimeout);
    }

    // Randomized timeout between 150-300ms
    const timeout = 150 + Math.random() * 150;

    this.electionTimeout = setTimeout(() => {
      this.startElection();
    }, timeout);
  }

  private async startElection(): Promise<void> {
    this.state = NodeState.CANDIDATE;
    this.currentTerm++;
    this.votedFor = this.nodeId;

    let votesReceived = 1; // Vote for self
    const majority = Math.floor(this.peers.length / 2) + 1;

    const voteRequest: VoteRequest = {
      term: this.currentTerm,
      candidateId: this.nodeId,
      lastLogIndex: this.log.length - 1,
      lastLogTerm: this.log[this.log.length - 1]?.term || 0
    };

    const votePromises = this.peers.map(peer =>
      this.rpcClient.requestVote(peer, voteRequest)
    );

    const responses = await Promise.allSettled(votePromises);

    for (const response of responses) {
      if (response.status === 'fulfilled' && response.value.voteGranted) {
        votesReceived++;
      }

      if (response.status === 'fulfilled' && 
          response.value.term > this.currentTerm) {
        this.stepDown(response.value.term);
        return;
      }
    }

    if (votesReceived >= majority && this.state === NodeState.CANDIDATE) {
      this.becomeLeader();
    } else {
      this.resetElectionTimeout();
    }
  }

  private becomeLeader(): void {
    this.state = NodeState.LEADER;
    console.log(`Node ${this.nodeId} became leader for term ${this.currentTerm}`);

    if (this.electionTimeout) {
      clearTimeout(this.electionTimeout);
    }

    this.sendHeartbeats();
    this.heartbeatInterval = setInterval(() => {
      this.sendHeartbeats();
    }, 50); // Send heartbeats every 50ms
  }

  private async sendHeartbeats(): Promise<void> {
    const appendEntries = this.peers.map(peer =>
      this.rpcClient.appendEntries(peer, {
        term: this.currentTerm,
        leaderId: this.nodeId,
        entries: [],
        leaderCommit: this.commitIndex
      })
    );

    await Promise.allSettled(appendEntries);
  }

  public async handleVoteRequest(request: VoteRequest): Promise<VoteResponse> {
    if (request.term > this.currentTerm) {
      this.stepDown(request.term);
    }

    const logUpToDate = request.lastLogTerm > (this.log[this.log.length - 1]?.term || 0) ||
      (request.lastLogTerm === (this.log[this.log.length - 1]?.term || 0) &&
       request.lastLogIndex >= this.log.length - 1);

    const voteGranted = request.term >= this.currentTerm &&
      (this.votedFor === null || this.votedFor === request.candidateId) &&
      logUpToDate;

    if (voteGranted) {
      this.votedFor = request.candidateId;
      this.resetElectionTimeout();
    }

    return {
      term: this.currentTerm,
      voteGranted
    };
  }

  private stepDown(term: number): void {
    this.currentTerm = term;
    this.state = NodeState.FOLLOWER;
    this.votedFor = null;

    if (this.heartbeatInterval) {
      clearInterval(this.heartbeatInterval);
    }

    this.resetElectionTimeout();
  }

  public async appendEntry(command: string): Promise<boolean> {
    if (this.state !== NodeState.LEADER) {
      throw new Error('Only leader can append entries');
    }

    const entry: LogEntry = {
      term: this.currentTerm,
      command,
      index: this.log.length
    };

    this.log.push(entry);

    // Replicate to followers (simplified)
    const replicationPromises = this.peers.map(peer =>
      this.rpcClient.appendEntries(peer, {
        term: this.currentTerm,
        leaderId: this.nodeId,
        entries: [entry],
        leaderCommit: this.commitIndex
      })
    );

    const responses = await Promise.allSettled(replicationPromises);
    const successCount = responses.filter(r => 
      r.status === 'fulfilled' && r.value.success
    ).length + 1; // +1 for leader

    const majority = Math.floor(this.peers.length / 2) + 1;

    if (successCount >= majority) {
      this.commitIndex = entry.index;
      return true;
    }

    return false;
  }
}

// RPC Client interface
interface RPCClient {
  requestVote(peer: string, request: VoteRequest): Promise<VoteResponse>;
  appendEntries(peer: string, request: any): Promise<any>;
}

Common Pitfalls and How to Avoid Them

1. Ignoring Network Partitions Always test your consensus implementation with network partition scenarios. Use tools like Jepsen or implement chaos engineering practices.

2. Incorrect Timeout Configuration Election timeouts must be significantly larger than network round-trip times. In 2026's multi-cloud environments, account for cross-region latencies (100-300ms).

3. Not Persisting State Critical state (current term, voted for, log entries) must survive crashes. Use durable storage with fsync guarantees.

4. Ignoring Log Compaction Logs grow indefinitely without compaction. Implement snapshotting to bound memory usage.

5. Blocking on Consensus Never block user-facing operations on consensus completion. Use async patterns and eventual consistency where appropriate.

Best Practices for Production Systems

Use Proven Libraries: Implement consensus from scratch only for learning. Production systems should use battle-tested libraries like etcd (Raft), Consul (Raft), or Apache ZooKeeper (ZAB, similar to Paxos).

Monitor Consensus Health: Track metrics like election frequency, log replication lag, and commit latency. Frequent elections indicate network or configuration issues.

Implement Proper Backpressure: When the leader can't replicate fast enough, implement backpressure to prevent log divergence.

Test Extensively: Use property-based testing and simulation frameworks. The TLA+ specification language can formally verify your consensus implementation.

Plan for Reconfiguration: Cluster membership changes require special handling. Raft uses joint consensus; ensure your implementation supports safe reconfiguration.

Frequently Asked Questions

Q: Should I use Paxos or Raft? A: For new implementations, choose Raft. It's easier to understand, implement, and debug. Paxos is primarily of historical and theoretical interest unless you're maintaining legacy systems.

Q: How many nodes do I need? A: Consensus requires 2f+1 nodes to tolerate f failures. Three nodes tolerate one failure, five nodes tolerate two. More nodes increase latency without proportional reliability gains.

Q: Can consensus work across continents? A: Yes, but with high latency. Consider using multiple consensus groups (one per region) with asynchronous replication between regions for better performance.

Q: What's the performance overhead? A: Consensus requires at least one network round-trip per operation. Modern implementations achieve 10,000-100,000 operations/second depending on network conditions and payload size.

Q: How does consensus relate to blockchain? A: Blockchain consensus (Proof of Work, Proof of Stake) solves Byzantine fault tolerance in adversarial environments. Raft and Paxos assume non-Byzantine failures and are more efficient for trusted environments.

Q: Can I use consensus for real-time systems? A: Consensus has unbounded latency in worst cases. For hard real-time requirements, use specialized protocols or accept eventual consistency.

Q: What happens during a network partition? A: The partition with a majority continues operating. The minority partition cannot commit new entries, ensuring consistency at the cost of availability (CP in CAP theorem).

Conclusion

Distributed consensus is no longer an academic curiosity—it's a practical necessity for modern distributed systems. While Paxos laid the theoretical groundwork, Raft's understandability has made consensus accessible to practicing engineers.

When building distributed systems in 2026, leverage proven consensus implementations rather than rolling your own. Use etcd for Kubernetes-style workloads, Consul for service mesh coordination, or managed services like Google Cloud Spanner that handle consensus internally.

Understanding these algorithms helps you make informed architectural decisions, debug distributed systems issues, and appreciate the complexity that managed services abstract away. Whether you're implementing leader election, distributed locking, or replicated state machines, consensus algorithms provide the foundation for building reliable distributed systems.


Metadata

```json { "seo_title": "Distributed Consensus: Raft and Paxos Algorithms Explained", "meta_description": "Learn how Raft and Paxos consensus algorithms solve distributed systems challenges. Includes TypeScript implementation, best practices, and production guidance for developers.", "primary_keyword": "distributed consensus algorithms", "secondary_keywords": [ "Raft algorithm", "Paxos algorithm", "leader election", "distributed systems", "consensus protocol", "log replication", "TypeScript distributed systems", "CAP theorem" ], "tags": [ "distributed-systems", "consensus", "raft", "paxos", "typescript", "architecture", "backend" ] }