Distributed Snapshot Algorithms: Chandy-Lamport Marker Passing in High-Concurrency Actor Networks

Capturing a globally consistent state across distributed actor clusters without freezing message processing is a classic challenge. The Chandy-Lamport algorithm uses discrete control markers interleaved within FIFO message channels to record process states and in-flight channel messages concurrently without global synchronization locks.

The Architecture of Marker-Passing State Capture

How control markers partition message streams into pre-snapshot and post-snapshot causal events:

💾 The Channel State Recording Invariant

When process $P_i$ receives a snapshot marker on channel $C_{ki}$ for the first time, it immediately records its local process state, emits markers across all outgoing channels, and starts recording subsequent messages arriving on all other incoming channels until a matching marker arrives, capturing in-flight network transit states perfectly.

State Checkpointing Architectures Compared

Checkpointing Protocol System Ingestion Lockout Channel State Tracking Cluster Scalability Barrier
Stop-The-World Global Barrier (2PC)Full cluster pause (450ms+)None (Requires drained buffers)< 20 Nodes (High lock contention)
Asynchronous Log Tail SnapshotsZero runtime pauseLoose / Eventual consistencyHigh replay overhead during recovery
Chandy-Lamport Marker PassingZero pause (Non-blocking)Exact in-flight channel recording1,000+ Distributed Actor Nodes

Chandy-Lamport Actor Protocol in TypeScript

Handling marker messages and channel logging in asynchronous event loops:

export interface ActorMessage {
  type: 'DATA' | 'MARKER';
  senderId: string;
  snapshotId?: string;
  payload?: unknown;
}

export class SnapshotableActor {
  private state: Record<string, unknown> = {};
  private recordedState: Record<string, unknown> | null = null;
  private channelRecordings = new Map<string, unknown[]>();
  private openChannels = new Set<string>();

  public handleMessage(msg: ActorMessage, channelId: string, peerIds: string[]): void {
    if (msg.type === 'MARKER') {
      if (this.recordedState === null) {
        // Step 1: First time receiving marker -> Record local state
        this.recordedState = { ...this.state };
        this.openChannels = new Set(peerIds.filter(id => id !== channelId));
        // Step 2: Forward marker to all peers immediately
        this.broadcastMarker(msg.snapshotId!, peerIds);
      } else {
        // Step 3: Subsequent marker on open channel -> Close channel recording
        this.openChannels.delete(channelId);
      }
    } else {
      // Regular data message
      if (this.openChannels.has(channelId)) {
        // Message was in-flight before the sender's marker arrived
        if (!this.channelRecordings.has(channelId)) this.channelRecordings.set(channelId, []);
        this.channelRecordings.get(channelId)!.push(msg.payload);
      }
      this.applyStateUpdate(msg.payload);
    }
  }

  private broadcastMarker(snapshotId: string, peerIds: string[]): void {
    for (const peer of peerIds) {
      // Send non-blocking control marker over FIFO channel
    }
  }

  private applyStateUpdate(payload: unknown): void {
    // Process regular business logic
  }
}

Explore Advanced Distributed Systems Architecture

Build fault-tolerant distributed networks. Read our guide on Viewstamped Replication vs Raft Consensus, explore commercial real estate debt yield on FinanceQuickly Underwriting Models, review commercial fleet speed governor forensics on CarInjuryAttorney Commercial Litigation, or request a custom distributed architecture consultation.