GCP Cloud Spanner
Cloud Spanner is GCP's fully managed relational database that combines the consistency and SQL capabilities of a traditional relational database with the horizontal scalability of NoSQL systems. It operates across multiple regions simultaneously, providing a single globally consistent database without the usual tradeoffs between consistency and availability.
Most databases force a choice: either get strong consistency (all users see the same data at all times) or get global scale (distribute data worldwide). Spanner eliminates that tradeoff. It delivers both — strong consistency across continents — by using Google's private global network and a technology called TrueTime.
When to Use Cloud Spanner
| Use Case | Why Spanner Fits |
|---|---|
| Global financial systems | Transactions must be consistent worldwide — no double-spending |
| Large-scale e-commerce inventory | Millions of concurrent users updating stock counts globally |
| Telecommunications billing | Real-time billing across regions with zero data loss |
| Gaming leaderboards | Millions of players, real-time rankings, global access |
Spanner vs Cloud SQL
Cloud SQL: ┌────────────────────────────────────┐ │ Single Region (e.g., us-central1) │ │ Primary + Standby (same region) │ │ Max: ~30,000 QPS │ │ Cost: Low–Medium │ └────────────────────────────────────┘ Cloud Spanner: ┌─────────────────────────────────────────────────────┐ │ Multi-Region (e.g., US + Europe + Asia) │ │ All replicas are read/write capable │ │ Scales to millions of QPS │ │ Strong global consistency via TrueTime │ │ Cost: High (enterprise workloads) │ └─────────────────────────────────────────────────────┘
Spanner Architecture
Cloud Spanner Instance
│
├── Database: "ecommerce"
│ ├── Table: Products
│ ├── Table: Orders
│ └── Table: Customers
│
Replicas distributed across zones/regions:
│
├── Replica: us-central1-a (read/write)
├── Replica: us-central1-b (read/write)
├── Replica: us-central1-c (read/write) ← Regional config
│
OR
│
├── Replica: us-central1 (read/write)
├── Replica: europe-west1 (read/write) ← Multi-region config
└── Replica: asia-east1 (read/write)
Creating a Spanner Instance
# Create a Spanner instance (regional — cheaper for learning) gcloud spanner instances create my-spanner \ --config=regional-us-central1 \ --description="My Spanner Instance" \ --nodes=1 # Create a database inside the instance gcloud spanner databases create ecommerce \ --instance=my-spanner
Defining a Schema
Spanner uses SQL DDL (Data Definition Language) similar to standard SQL, with some additions like interleaving for performance.
-- Create a Customers table CREATE TABLE Customers ( CustomerId STRING(36) NOT NULL, Name STRING(100) NOT NULL, Email STRING(200) NOT NULL, CreatedAt TIMESTAMP NOT NULL OPTIONS (allow_commit_timestamp=true) ) PRIMARY KEY (CustomerId); -- Create an Orders table interleaved inside Customers -- (Orders rows are stored physically next to their parent Customer) CREATE TABLE Orders ( CustomerId STRING(36) NOT NULL, OrderId STRING(36) NOT NULL, Product STRING(200), Amount FLOAT64, Status STRING(20) ) PRIMARY KEY (CustomerId, OrderId), INTERLEAVE IN PARENT Customers ON DELETE CASCADE;
Interleaving is a Spanner-specific optimization. It stores child table rows (Orders) physically adjacent to their parent row (Customer) on disk. Reading a customer and all their orders becomes a single disk read instead of a join across separate storage locations.
Physical Storage Layout (Interleaved): ┌──────────────────────────────────────────┐ │ Customer: C001 (Rahul Sharma) │ │ Order: C001/O-1001 (Laptop, ₹49999) │ │ Order: C001/O-1002 (Mouse, ₹999) │ │ Customer: C002 (Priya Patel) │ │ Order: C002/O-2001 (Monitor, ₹15000) │ └──────────────────────────────────────────┘
Reading and Writing Data
Using gcloud CLI
# Insert a row gcloud spanner rows insert \ --instance=my-spanner \ --database=ecommerce \ --table=Customers \ --data=CustomerId=C001,Name="Rahul Sharma",Email=rahul@example.com,CreatedAt=spanner.commit_timestamp() # Query data gcloud spanner databases execute-sql ecommerce \ --instance=my-spanner \ --sql="SELECT CustomerId, Name, Email FROM Customers LIMIT 10"
Python Client
from google.cloud import spanner
instance_id = "my-spanner"
database_id = "ecommerce"
spanner_client = spanner.Client()
instance = spanner_client.instance(instance_id)
database = instance.database(database_id)
# Read data
with database.snapshot() as snapshot:
results = snapshot.execute_sql(
"SELECT CustomerId, Name FROM Customers WHERE Name LIKE 'R%'"
)
for row in results:
print(f"ID: {row[0]}, Name: {row[1]}")
# Write data using a transaction
def insert_customer(transaction):
transaction.execute_update(
"INSERT INTO Customers (CustomerId, Name, Email, CreatedAt) "
"VALUES ('C003', 'Ali Khan', 'ali@example.com', PENDING_COMMIT_TIMESTAMP())"
)
database.run_in_transaction(insert_customer)
Transactions in Spanner
# Atomic transfer: debit from Account A, credit to Account B
def transfer_funds(transaction, from_id, to_id, amount):
# Read both balances in the same transaction snapshot
from_row = transaction.execute_sql(
f"SELECT Balance FROM Accounts WHERE AccountId='{from_id}'"
).one()
to_row = transaction.execute_sql(
f"SELECT Balance FROM Accounts WHERE AccountId='{to_id}'"
).one()
# Check and update
if from_row[0] < amount:
raise ValueError("Insufficient funds")
transaction.execute_update(
f"UPDATE Accounts SET Balance = Balance - {amount} WHERE AccountId='{from_id}'"
)
transaction.execute_update(
f"UPDATE Accounts SET Balance = Balance + {amount} WHERE AccountId='{to_id}'"
)
database.run_in_transaction(transfer_funds, "A001", "A002", 5000)
TrueTime – How Spanner Achieves Global Consistency
Traditional distributed databases struggle with clock skew — different servers have slightly different clocks, making it hard to determine the exact order of events worldwide. TrueTime is Google's globally synchronized clock system using GPS receivers and atomic clocks in every data center. It exposes time as a range (earliest, latest) with a bounded uncertainty of less than 7 milliseconds.
Spanner uses TrueTime to assign globally consistent timestamps to every transaction, guaranteeing that transactions are applied in the exact order they happened — across any region.
Spanner Pricing
| Cost Component | Details |
|---|---|
| Processing units (PUs) | Minimum 100 PUs (~$0.09/hour). 1 node = 1000 PUs. |
| Storage | ~$0.30 per GB/month |
| Network egress | Standard GCP egress pricing |
Spanner is significantly more expensive than Cloud SQL. Use it when global scale and strong consistency are non-negotiable requirements — not for typical web applications.
Key Takeaways
- Cloud Spanner delivers global scale with strong consistency — without the typical tradeoff.
- It supports standard SQL, ACID transactions, and schemas — just like Cloud SQL, but at massive scale.
- Interleaving stores child rows physically next to parent rows for high-performance joins.
- TrueTime assigns globally synchronized timestamps to all transactions.
- Spanner suits high-value, globally distributed, mission-critical workloads.
- Cost is much higher than Cloud SQL — evaluate carefully before adopting.
