The most surprising truth about strong consistency is that it’s often the least efficient way to handle data, yet it’s the default for many systems because it’s the easiest to reason about.

Imagine you’ve got a bank account with $100. You open two browser tabs, and in the first, you transfer $50 to a friend. In the second tab, you try to withdraw $70. If your system is strongly consistent, the second tab will see the first transfer complete, and it will correctly reject your $70 withdrawal because you only have $50 left. This is achieved by ensuring that every read operation sees the absolute latest committed write.

Here’s how a system like this might look in practice, using a simplified example with etcd, a distributed key-value store commonly used for configuration and coordination.

Let’s say we have a shared counter.

package main

import (
	"context"
	"fmt"
	"log"
	"time"

	clientv3 "go.etcd.io/etcd/client/v3"
)

func main() {
	cli, err := clientv3.New(clientv3.Config{
		Endpoints:   []string{"localhost:2379"}, // Your etcd endpoint
		DialTimeout: 5 * time.Second,
	})
	if err != nil {
		log.Fatal(err)
	}
	defer cli.Close()

	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()

	// Read the current value
	getResp, err := cli.Get(ctx, "counter")
	if err != nil {
		log.Fatalf("Failed to get counter: %v", err)
	}

	var currentVal int64
	if len(getResp.Kvs) > 0 {
		currentVal = getResp.Kvs[0].Value[0] // Assuming a single byte for simplicity
	}

	// Increment the value
	newVal := currentVal + 1

	// Write the new value
	_, err = cli.Put(ctx, "counter", []byte{byte(newVal)})
	if err != nil {
		log.Fatalf("Failed to put counter: %v", err)
	}

	fmt.Printf("Counter incremented to: %d\n", newVal)
}

In this Go code, cli.Get followed by cli.Put is an atomic operation from the client’s perspective. However, in a distributed system, this involves multiple steps: the client asks etcd for the value, etcd finds the latest value (potentially coordinating with other nodes if it’s a cluster), the client receives it, modifies it, and then sends a new value back to etcd, which again must ensure it’s the latest and commit it. Strong consistency means that between the Get and the Put, no other client could have successfully written a new value that would invalidate your read.

The core problem strong consistency solves is preventing data races and ensuring that all clients agree on the state of the data at any given point in time. This is critical for applications where the order of operations matters immensely, like financial transactions, inventory management, or distributed locking.

Internally, achieving strong consistency often involves consensus algorithms like Raft or Paxos. When a write operation occurs, the leader node in the consensus group proposes the write to its followers. A majority of followers must acknowledge they have received and durably stored the write before the leader can confirm it to the client. Reads are also often routed through the leader to ensure they see the most up-to-date committed state. This "all roads lead to Rome" approach guarantees a single, ordered history of all changes.

The levers you control are primarily around your data access patterns and the choice of consistency model for your distributed database or service. For strongly consistent systems, you’re often dealing with configurations that prioritize durability and consensus over raw speed. This might involve setting higher replication factors, using synchronous replication, or ensuring your read operations are routed to a quorum of nodes.

Many distributed databases offer tunable consistency levels. For instance, Cassandra allows you to specify consistency levels for reads and writes on a per-operation basis (e.g., QUORUM, ONE, ALL). Choosing ALL for both reads and writes provides strong consistency but at a significant performance cost. Conversely, ONE for reads and ONE for writes offers eventual consistency, which is much faster but doesn’t guarantee you’ll see the latest data immediately.

The critical insight most people miss is that the "strong consistency" guarantee often applies to the committed state of data, not necessarily the state that any arbitrary node might be holding at a specific microsecond. When a client performs a read operation that requires strong consistency, the system doesn’t just return whatever value is in memory on a randomly chosen replica. Instead, it ensures that the read is served by a replica that has successfully participated in the consensus protocol for the latest written value, or it consults a quorum of replicas to determine the most up-to-date state. This distinction is subtle but vital for understanding why a strongly consistent read might still involve network round trips to multiple servers.

The next frontier in distributed data management is often achieving strong consistency with lower latency and higher throughput, pushing the boundaries of what’s possible with consensus algorithms.

Want structured learning?

Take the full Distributed Systems course →