Google Spanner and TrueTime
How Google Spanner uses TrueTime — GPS and atomic clock-synchronized timestamps — to provide globally consistent distributed transactions, solving the.
Company Context
Google runs some of the most demanding transactional workloads on the planet: advertising billing (processing hundreds of billions of dollars annually), Google Play purchases, and internal financial systems. These workloads require ACID transactions across data centers on different continents, with strong consistency guarantees and high availability.
Before Spanner, Google used a patchwork of systems: Bigtable for high-throughput semi-structured data, Megastore for cross-datacenter transactions (but with limited throughput), and MySQL for smaller transactional workloads. None of these provided both global distribution and strong consistency with acceptable performance.
The Problem at Scale
The fundamental challenge of a globally distributed database is ordering transactions. When two transactions execute simultaneously in data centers 10,000 miles apart, how do you determine which happened first? Network latency between continents is 50-150ms, so you cannot simply send a message to coordinate.
Every other distributed database solves this by weakening the guarantee: Cassandra uses eventual consistency, DynamoDB offers configurable consistency per request, and CockroachDB uses hybrid logical clocks that provide ordering but not real-time guarantees.
Google asked a different question: what if the clocks were accurate enough to use as a global ordering mechanism?
Architecture Solution
TrueTime: The Key Innovation
TrueTime is a globally distributed clock service that provides a bounded uncertainty interval for the current time. Instead of returning a single timestamp, TrueTime returns an interval [earliest, latest] that is guaranteed to contain the true current time.
Each Google data center has TrueTime servers equipped with GPS receivers and atomic clocks. GPS provides absolute time accuracy to within nanoseconds. Atomic clocks provide stability between GPS synchronization events. By combining both (GPS corrects the atomic clock's drift, atomic clocks bridge GPS outages), TrueTime achieves uncertainty bounds of typically 1-7 milliseconds.
The API is deliberately simple:
TT.now()returns an interval[earliest, latest]TT.after(t)returns true iftis definitely in the pastTT.before(t)returns true iftis definitely in the future
How Spanner Uses TrueTime
Spanner assigns each transaction a commit timestamp. The critical property: if transaction T1 commits before transaction T2 starts (in real time), then T1's timestamp is less than T2's timestamp. This is called external consistency — the timestamp order respects the real-time order.
To achieve this, Spanner uses a technique called commit wait: after a transaction is prepared (all locks acquired, all participants ready), the coordinator waits until TrueTime guarantees that the commit timestamp is in the past. This wait is equal to the TrueTime uncertainty interval — typically 1-7ms.
Without TrueTime, this wait would need to be hundreds of milliseconds (the maximum possible clock skew between servers). With TrueTime's bounded uncertainty, the wait is short enough to be practical.
Data Model and Storage
Spanner stores data in a semi-relational model: tables with typed columns, primary keys, and support for interleaving (co-locating child rows with parent rows for locality). Under the hood, data is stored in a modified version of Bigtable's SSTable format.
Data is range-sharded by primary key across splits. Each split is a Paxos group — replicated across data centers using the Paxos consensus algorithm. The Paxos leader for each split handles reads and writes, with followers in other data centers providing read replicas.
Read-write transactions use two-phase locking within a Paxos group and two-phase commit across groups. The TrueTime-based commit wait ensures global ordering.
Read-only transactions are served at a snapshot timestamp without acquiring locks. Spanner can serve reads from any replica that has caught up to the requested snapshot timestamp, providing both consistency and low latency for read-heavy workloads.
Key Technical Decisions
Hardware-based time synchronization. Most distributed systems treat clock synchronization as unreliable and design around it. Google invested in physical infrastructure (GPS receivers, atomic clocks in every data center) to make clocks reliable enough to use as a coordination mechanism. This hardware investment reduces software complexity dramatically.
Paxos per split. Each data split (row range) is an independent Paxos group. This allows different splits to be led by different data centers, placing leadership close to the data's primary users. A European customer's data can have its Paxos leader in Europe, minimizing write latency.
Schema changes without downtime. Spanner supports online schema changes that propagate across the entire database without blocking reads or writes. The schema change is applied split-by-split, with a coordination protocol ensuring that all splits have applied the change before it takes effect globally.
Strengths
- Globally consistent transactions without sacrificing availability (in practice, Google achieves 99.999% availability)
- External consistency — the strongest consistency guarantee in any production database
- Automatic sharding and rebalancing
- SQL query support with a rich query optimizer
- Snapshot reads for low-latency read-only workloads
Weaknesses
- TrueTime requires specialized hardware (GPS receivers, atomic clocks) — not reproducible outside Google's infrastructure
- Commit wait adds latency to every write transaction (typically 5-10ms)
- Higher write latency than AP systems (Cassandra, DynamoDB) for workloads that can tolerate eventual consistency
- Cloud Spanner (the managed version) is expensive compared to self-managed databases
Cloud Spanner: The External Version
Google Cloud Spanner makes Spanner available as a managed service. Cloud Spanner uses the same TrueTime infrastructure within Google's data centers. Users get globally consistent transactions without managing any infrastructure. The pricing is significant ($0.90/node/hour plus storage and network), making it practical primarily for workloads where global consistency is a hard requirement.
Companies using Cloud Spanner include financial services firms, gaming companies with global leaderboards, and enterprises requiring cross-region disaster recovery with zero data loss.
Interview Relevance
Spanner and TrueTime demonstrate that infrastructure investment can simplify software design. When discussing consistency in distributed systems during interviews, Spanner is the proof that strong consistency at global scale is possible — it just requires solving the clock synchronization problem. This contrasts with the common assumption that distributed systems must choose between consistency and availability.
Practical Implementation for .NET Developers
In a .NET application, you would typically implement this pattern using the following approach:
ASP.NET Core setup: Create a service class that encapsulates the logic, register it with dependency injection, and inject it into your controllers or minimal API endpoints. The built-in DI container handles lifecycle management.
Entity Framework Core: For database interactions, EF Core provides the ORM layer. Use migrations for schema management and raw SQL for performance-critical queries. Consider Dapper for read-heavy paths where EF Core's overhead matters.
Azure integration: If deploying to Azure, leverage managed services — Azure Cache for Redis, Azure SQL, Azure Service Bus, Azure Cosmos DB. These eliminate operational overhead and provide built-in monitoring through Application Insights.
Testing: Use xUnit with Testcontainers for integration tests that spin up real databases in Docker. Mock external dependencies with NSubstitute. The WebApplicationFactory class lets you test your entire HTTP pipeline in-process.
Monitoring: Add Application Insights telemetry to track request latency, dependency calls, and custom metrics. Use structured logging with Serilog to make production debugging possible:
Log.Information("Processing order {OrderId} for {CustomerId}", orderId, customerId);
This gives you searchable, structured logs in Azure Monitor or Seq.
Key Takeaways for Interviews
- TrueTime API provides a bounded time uncertainty interval [earliest, latest] using GPS and atomic clocks. Spanner waits out the uncertainty before committing, guaranteeing that transaction T1 committed before T2 has a lower timestamp.
- Externally consistent transactions without traditional distributed locking — Spanner uses timestamp ordering combined with TrueTime to achieve linearizability across globally distributed data.
- "Effectively CP": Spanner is technically CP (chooses consistency over availability during partitions), but Google's private network makes partitions so rare that Spanner is "effectively CA" in practice.
- Schematized semi-relational data model: Spanner supports SQL, schemas, and secondary indexes on top of a globally distributed, strongly consistent database. This was unprecedented when the paper was published.
- Interleaved tables: Parent-child relationships stored physically adjacent on disk for efficient joins within a partition.
How This Applies to Modern .NET Systems
Cloud Spanner .NET Client: Use Google.Cloud.Spanner.Data for ADO.NET integration or Google.Cloud.Spanner.V1 for the gRPC client. Spanner supports standard SQL, making it accessible to .NET developers familiar with relational databases.
Azure Cosmos DB comparison: Azure Cosmos DB offers similar global distribution with tunable consistency levels (strong, bounded staleness, session, consistent prefix, eventual). For .NET developers on Azure, Cosmos DB provides a more integrated experience with the Azure ecosystem, though it uses a different consistency model than Spanner's TrueTime approach.
When to use Spanner patterns: If your .NET application needs global distribution with strong consistency (financial systems, inventory management across regions), Spanner or Cosmos DB with strong consistency is the right choice. For most applications, a single-region PostgreSQL with read replicas provides sufficient consistency at much lower cost and complexity.