Google Spanner concept page. Globally-distributed SQL database with external consistency via TrueTime API (GPS+atomic clocks). 3 regions (us-central1 leader, europe-west1 replica, asia-northeast1 replica), each with TrueTime time service. Per-shard Paxos groups (Shard A, Shard B), 2PC across shards. Clients hit shard leaders. 4 scenarios: single-shard RW txn with Paxos+commit-wait, cross-shard 2PC, lock-free read-only at snapshot, TrueTime uncertainty spike (GPS antenna fail). 2 ADRs: (1) TrueTime as foundation for external consistency vs HLC alternative, (2) when Spanner is justified vs cheaper alternatives.
Spanner — единственная в мире широко используемая SQL-СУБД, дающая strict serializability (external consistency) глобально, без single coordinator. Это самый сильный consistency model из существующих: linearizability на multiple keys плюс глобальный ordering между независимыми клиентами в разных регионах. До Spanner такой уровень требовал либо bottleneck-sequencer, либо очень дорогих compromise. Google решил это через TrueTime API — physical clocks с bounded uncertainty (~7ms), реализованные через GPS-приёмники и atomic clocks в каждом дата-центре.
Понимать Spanner важно не потому, что вы его будете развёртывать (вы не будете — он только в GCP и стоит $$$$), а потому, что:
Возьмите обычный Postgres. Разрежьте его на шарды (tablets). Каждый шард — это Paxos group из 3-5 реплик в разных availability zones. Cross-shard транзакции — 2PC поверх Paxos. До этого момента — стандартный distributed SQL.
Spanner-специфичное начинается с TrueTime. TT.now() возвращает интервал [earliest, latest] с гарантией, что истинное время лежит внутри. ε (epsilon) = latest - earliest обычно 1-7ms.
При commit транзакция:
s = TT.now().latest (commit timestamp).TT.now().earliest > s — то есть пока реальное время гарантированно перевалило за s.Инвариант: любая транзакция, начавшаяся после возврата ACK, увидит этот commit — потому что её TT.now().earliest > s. Так получается external consistency без global coordinator: каждый узел согласовывает порядок через wall-clock time, который везде «почти одинаков».
Три региона: us-central1 (leader-регион для шардов A и B), europe-west1, asia-northeast1. В каждом регионе — TrueTime service (иконка часов): связка GPS-приёмников и atomic clocks с time-daemon'ами. Каждый шард представлен лидером в us-central и репликами в EU и Asia — это Paxos group на 3 узла.
Edge leader-a ↔ leader-b — это канал 2PC между шардами. Edges leader → replica — Paxos replication внутри одного шарда. Edges leader/replica → TT — каждый запрос commit'а вызывает TT.now(). Клиенты (US и EU) ходят в leader через write-path; для read-only сценария будут ходить в ближайшую replica со snapshot timestamp.
Single-shard read-write transaction. Лидер берёт write lock, запрашивает TT.now(), выбирает s = latest, проводит Paxos quorum, потом ждёт commit-wait (~7ms) и только после этого отпускает локи. Это «золотой путь» Spanner — типичный write занимает 10-15ms при здоровом TrueTime.
Перевод денег между двумя аккаунтами на разных шардах. Coordinator-лидер (leader-a) запускает 2PC: фаза PREPARE заставляет participant'а персистить intent через Paxos на своём шарде, потом coordinator выбирает s_commit = max(s_prepare) по всем участникам, делает commit-wait, рассылает COMMIT. Обе записи commit'ятся на одном и том же s_commit — это даёт атомарность плюс external consistency. Latency — 30-50ms intra-region, 100-150ms cross-region.
Read-only at snapshot — то место, где Spanner блестит. Координатор выбирает snapshot = TT.now().latest, делает commit-wait один раз, и дальше клиент параллельно запрашивает данные из ближайших реплик с этим snapshot'ом. Никаких локов, никакого contention. Каждая реплика проверяет: safe_time >= snapshot (то есть она применила все коммиты до этого момента) — если да, отдаёт данные. На этом паттерне строятся дашборды и аналитика. Stale reads (snapshot = now - 10s) ещё дешевле — commit-wait пропускается полностью.
GPS-антенна в DC деградировала. Time daemon переключается на atomic clocks + соседние зоны, но ε растёт с 7ms до 250ms. Spanner НЕ нарушает correctness — он просто начинает дольше ждать в commit-wait. Latency спайкает с 12ms до 260ms, пользователи видят лаг, on-call получает page. Это и есть «graceful degradation»: ε напрямую конвертируется в latency, а не в потерю consistency. Контраст с HLC-based системами (CockroachDB) — там clock skew не блокирует writes, но даёт uncertainty restarts на читателе.
На диаграмме два ADR на ноде TrueTime:
ADR-001: TrueTime API как foundation для external consistency. Объясняет, почему Google пошёл по пути физических часов вместо HLC. Корень: чтобы external consistency «just work» без single coordinator, нужно либо global sequencer (bottleneck), либо bounded uncertainty на wall clock меньше, чем round-trip. Google выбрал второе и вкатил GPS+atomic clock инфраструктуру в каждый DC. Cost: ~7ms commit-wait на каждый write. Profit: SQL semantics, которые «just work» глобально.
ADR-002: Когда Spanner оправдан. Cloud Spanner стоит на порядок дороже Cloud SQL Postgres для типового SaaS. Брать его имеет смысл только при выполнении одного из: (1) geo-distributed financial/identity данные с глобальным ordering между clients; (2) workload не помещается в single instance (>100K writes/sec) и шардить руками дороже; (3) уже на GCP и нужен strict serializability + автоматический failover + online schema change; (4) regulatory требование multi-region writes. НЕ брать для single-region apps, для аналитики (BigQuery дешевле), для latency-sensitive (<5ms p99), для cache/counters (Paxos contention).
Google internal:
Cloud Spanner (external):
Inspired-by (open-source):
READ_TIMESTAMP пропускает commit-wait и читает с любой replica — это бесплатный perf.