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 CaseWhy Spanner Fits
Global financial systemsTransactions must be consistent worldwide — no double-spending
Large-scale e-commerce inventoryMillions of concurrent users updating stock counts globally
Telecommunications billingReal-time billing across regions with zero data loss
Gaming leaderboardsMillions 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 ComponentDetails
Processing units (PUs)Minimum 100 PUs (~$0.09/hour). 1 node = 1000 PUs.
Storage~$0.30 per GB/month
Network egressStandard 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.

Leave a Comment