<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Truetime on Tarragon</title><link>https://tarrragon.github.io/blog/tags/truetime/</link><description>Recent content in Truetime on Tarragon</description><generator>Hugo -- gohugo.io</generator><language>zh-TW</language><copyright>Tarragon (CC BY 4.0)</copyright><lastBuildDate>Wed, 27 May 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://tarrragon.github.io/blog/tags/truetime/index.xml" rel="self" type="application/rss+xml"/><item><title>Spanner TrueTime API 深度：GPS + 原子鐘、commit wait、為什麼 line-rate scaling 才是設計目的</title><link>https://tarrragon.github.io/blog/backend/01-database/vendors/spanner/truetime-api-depth/</link><pubDate>Wed, 27 May 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/backend/01-database/vendors/spanner/truetime-api-depth/</guid><description>&lt;blockquote>
&lt;p>本文是 &lt;a href="https://tarrragon.github.io/blog/backend/01-database/vendors/spanner/" data-link-title="Google Cloud Spanner" data-link-desc="全球分散式 strong-consistency OLTP、TrueTime API、線性擴展到 10 億 req/sec">Cloud Spanner&lt;/a> overview 的 implementation-layer deep article。Overview 已說明 Spanner 在全球 OLTP 譜系的定位、本文聚焦 &lt;em>TrueTime API&lt;/em> — Spanner 用來消滅 single coordinator bottleneck、換到 line-rate scaling 的核心機制。&lt;/p>&lt;/blockquote>
&lt;hr>
&lt;h2 id="商業邏輯先行truetime-是手段line-rate-scaling-才是目的">商業邏輯先行：TrueTime 是手段、line-rate scaling 才是目的&lt;/h2>
&lt;p>TrueTime 的設計目的是消滅 single coordinator bottleneck、讓 OLTP 拿到 line-rate scaling — external consistency 只是這條路徑上拿到的副產品。讀者若把 TrueTime 當成「一個保證 external consistency 的精巧時間 trick」、會誤把工具當目標、後續所有 commit wait / Paxos / GPS 細節都解錯方向。&lt;/p>
&lt;p>傳統 OLTP（PostgreSQL、MySQL、Cloud SQL）跨節點交易要靠一個 coordinator 決定全局順序、coordinator 本身就是 bottleneck。&lt;code>1x node = 1x throughput&lt;/code> 的線性擴展在 single-primary 模型撞牆、想 scale 只能往應用層 sharding 走、付管理 shard key / 跨 shard query / resharding 的代價。Spanner 換掉這條路徑：TrueTime 把 wall-clock 變成跨 datacenter 可比較的 &lt;em>interval&lt;/em>、Paxos 把 coordinator 變成「拓樸感知的多 leader」（每個 &lt;a href="https://tarrragon.github.io/blog/backend/knowledge-cards/range-sharding/" data-link-title="Range Sharding" data-link-desc="分散式 SQL 把 key space 切成可自動 split / merge 的 range、每個 range 自己的 consensus group、application 透明">Range Sharding&lt;/a> split 自己的 Paxos group 各自前進）、commit timestamp 用 TrueTime 對齊到 real-time 順序、不再需要一個全局 coordinator 串行所有 transaction。&lt;/p>
&lt;p>9.C10 Cloud Spanner planetary scale case 揭露的線性擴展證據：「2 nodes → 45K reads/sec、4 nodes → 90K reads/sec」是 Spanner 設計目標的直接證據、不只是 marketing 數字。這條揭露 Spanner external consistency 不是「加強版 serializable isolation」、是「coordinator 換拓樸」的 paradigm shift。寫到這裡讀者該意識到一件事：選 Spanner 不是選一個更貴更強的 SQL、是選一條 &lt;em>把 coordinator 拆掉&lt;/em> 的 scaling 路徑。&lt;/p>
&lt;p>&lt;strong>Dogfood 邊界（本文反覆強調）&lt;/strong>：9.C10 是 Google internal dogfood case、不是 customer-facing capacity 參考。「10 億 req/sec」是 Google 全使用者加總、不是單一 instance 配額；「2 nodes → 45K reads / 4 nodes → 90K reads」是 Google internal benchmark 揭露的線性擴展 &lt;em>模式&lt;/em>、不是客戶 SLA 承諾。本文後續所有 9.C10 數字引用都會明示這條邊界、避免讀者誤把 dogfood 當配額。&lt;/p></description><content:encoded><![CDATA[<blockquote>
<p>本文是 <a href="/blog/backend/01-database/vendors/spanner/" data-link-title="Google Cloud Spanner" data-link-desc="全球分散式 strong-consistency OLTP、TrueTime API、線性擴展到 10 億 req/sec">Cloud Spanner</a> overview 的 implementation-layer deep article。Overview 已說明 Spanner 在全球 OLTP 譜系的定位、本文聚焦 <em>TrueTime API</em> — Spanner 用來消滅 single coordinator bottleneck、換到 line-rate scaling 的核心機制。</p></blockquote>
<hr>
<h2 id="商業邏輯先行truetime-是手段line-rate-scaling-才是目的">商業邏輯先行：TrueTime 是手段、line-rate scaling 才是目的</h2>
<p>TrueTime 的設計目的是消滅 single coordinator bottleneck、讓 OLTP 拿到 line-rate scaling — external consistency 只是這條路徑上拿到的副產品。讀者若把 TrueTime 當成「一個保證 external consistency 的精巧時間 trick」、會誤把工具當目標、後續所有 commit wait / Paxos / GPS 細節都解錯方向。</p>
<p>傳統 OLTP（PostgreSQL、MySQL、Cloud SQL）跨節點交易要靠一個 coordinator 決定全局順序、coordinator 本身就是 bottleneck。<code>1x node = 1x throughput</code> 的線性擴展在 single-primary 模型撞牆、想 scale 只能往應用層 sharding 走、付管理 shard key / 跨 shard query / resharding 的代價。Spanner 換掉這條路徑：TrueTime 把 wall-clock 變成跨 datacenter 可比較的 <em>interval</em>、Paxos 把 coordinator 變成「拓樸感知的多 leader」（每個 <a href="/blog/backend/knowledge-cards/range-sharding/" data-link-title="Range Sharding" data-link-desc="分散式 SQL 把 key space 切成可自動 split / merge 的 range、每個 range 自己的 consensus group、application 透明">Range Sharding</a> split 自己的 Paxos group 各自前進）、commit timestamp 用 TrueTime 對齊到 real-time 順序、不再需要一個全局 coordinator 串行所有 transaction。</p>
<p>9.C10 Cloud Spanner planetary scale case 揭露的線性擴展證據：「2 nodes → 45K reads/sec、4 nodes → 90K reads/sec」是 Spanner 設計目標的直接證據、不只是 marketing 數字。這條揭露 Spanner external consistency 不是「加強版 serializable isolation」、是「coordinator 換拓樸」的 paradigm shift。寫到這裡讀者該意識到一件事：選 Spanner 不是選一個更貴更強的 SQL、是選一條 <em>把 coordinator 拆掉</em> 的 scaling 路徑。</p>
<p><strong>Dogfood 邊界（本文反覆強調）</strong>：9.C10 是 Google internal dogfood case、不是 customer-facing capacity 參考。「10 億 req/sec」是 Google 全使用者加總、不是單一 instance 配額；「2 nodes → 45K reads / 4 nodes → 90K reads」是 Google internal benchmark 揭露的線性擴展 <em>模式</em>、不是客戶 SLA 承諾。本文後續所有 9.C10 數字引用都會明示這條邊界、避免讀者誤把 dogfood 當配額。</p>
<p><strong>Fact vs derive 分層警告</strong>：本段「coordinator bottleneck → TrueTime + Paxos」frame 是跨 Spanner 2012 OSDI 論文 + 公開文件（2024-2026）+ 9.C10 case 合成的工程 frame、不是 9.C10 case 直接展開實作層細節。9.C10 案例直接揭露的 fact 是線性擴展數字跟 dogfood 邊界；本文 derive 的 frame 是「為什麼傳統 OLTP coordinator 是 bottleneck」。引用時這條分層在每段引用具體數字時都會重申。</p>
<h2 id="問題情境跨-region-oltp-的順序漏洞">問題情境：跨 region OLTP 的順序漏洞</h2>
<p>跨 region OLTP 想保證「全球用戶看到的交易順序跟 wall clock 一致」、但 NTP 同步誤差動輒 10-100ms、足夠讓 region A 已 commit 的計費事件被 region B 看到一個更新的 timestamp 卻是舊狀態。讀者徵兆通常從這幾個地方浮現：分散式系統團隊在 Cloud SQL / Aurora 多 region 上做 read replica、發現「跨 region read 順序顛倒」、audit log timestamp 不可靠、reconcile 對帳對不上、業務以為自己用了 transaction 就有「強一致」、實際只有 single-node 的 serializable isolation。</p>
<p>真實壓力場景：Google Ads 計費需要把每筆扣款事件放進可驗證的 <em>外部</em> 順序、不只是 transaction 內部 serializable。讀者若把這套需求帶回自家系統、會發現一條共同訊號 — 「兩個 transaction 都 commit 成功、用戶體感卻違反順序」這種事故、不是 isolation level 的問題、是 <em>external consistency</em> 的問題。</p>
<p>Case anchor：<a href="/blog/backend/09-performance-capacity/cases/spanner-planetary-scale-database-gcp/" data-link-title="9.C10 Cloud Spanner：每秒 10 億請求的全球一致性資料庫" data-link-desc="Google Cloud Spanner 內部峰值 10 億 req/sec、跨地區強一致 — 全球分散式 OLTP 容量參考">9.C10 Cloud Spanner planetary scale</a> — Google Ads / Play 訂閱 / Search 計費跟 TrueTime 綁定。<strong>dogfood 邊界明示</strong>：9.C10 是 Google 內部 dogfood case、不是 customer-facing capacity 參考；引用其揭露的線性 scaling 模式時要分清「設計目標證據」vs「客戶可獲得配額」。</p>
<h2 id="核心機制truetime-的-api-跟硬體基礎">核心機制：TrueTime 的 API 跟硬體基礎</h2>
<p>TrueTime 對外只有兩個 primitive — <code>TT.now()</code> 回傳一個 <em>interval</em> <code>[earliest, latest]</code>、不是單一時刻；<code>TT.after(t)</code> / <code>TT.before(t)</code> 判斷一個事件是否確定在 t 之後 / 之前。整個 external consistency 演算法都建立在「時間是一個 interval、不是一個點」這個 API 設計上。</p>
<h3 id="硬體基礎gps--原子鐘冗餘">硬體基礎：GPS + 原子鐘冗餘</h3>
<p>每個 datacenter 部署 GPS 接收器 + 原子鐘（armageddon master、用來防 GPS 全網干擾）、time master 之間互相比對排除離群值、TrueTime daemon 從多個 master 拉時間並算 worst-case bound。GPS 給 absolute time reference、原子鐘給 short-term stability（GPS 短暫失聯時仍能用 drift bound 撐過去）。雙來源是為了把 ε 的失敗模式限制在「絕大多數時間 ε ≤ 7ms、極端事件下 ε spike 但不會無限制漂移」。</p>
<h3 id="不確定性-εepsilon">不確定性 ε（epsilon）</h3>
<p>跨 datacenter 同步 + clock drift 估計、ε 目標維持在 1-7ms 區間。</p>
<p><strong>Fact source 分層警告</strong>：1-7ms 是 Google 2012 OSDI 論文 + Spanner 公開文件（2024-2026）引用的範圍、9.C10 dogfood case 未直接揭露 production ε 分布。引用時這組數字明標「來自 Spanner vendor docs / 2012 論文、不是 9.C10 case 直接揭露」、避免讀者把兩種來源混為一談。</p>
<h3 id="commit-wait-機制external-consistency-的核心">Commit wait 機制：external consistency 的核心</h3>
<p>read-write transaction 要拿 commit timestamp s 時、Spanner 設 <code>s = TT.now().latest</code>、然後 <em>等待</em> 直到 <code>TT.after(s)</code> 才回 ACK。這段「等」就是 <a href="/blog/backend/knowledge-cards/commit-wait/" data-link-title="Commit Wait" data-link-desc="Spanner external consistency 的核心機制 — read-write transaction 拿 commit timestamp s 後等到 TT.after(s) 才 ACK、wait ≈ 2ε、付 latency tax 換 commit 順序 = real-time 順序">Commit Wait</a> — Spanner 特有的物理延遲、由 TrueTime ε 主導、跟 <a href="/blog/backend/knowledge-cards/cross-region-quorum/" data-link-title="Cross-Region Quorum" data-link-desc="multi-region distributed SQL 強制 voting replica 跨 region、commit 等多 region quorum ack、跨洲 RTT 物理硬限">Cross-Region Quorum</a> 的網路 RTT 是兩個獨立的延遲來源、不能混算。</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">T1 開始 commit            T1 確定可回 ACK
</span></span><span class="line"><span class="ln">2</span><span class="cl">       |                          |
</span></span><span class="line"><span class="ln">3</span><span class="cl">       v                          v
</span></span><span class="line"><span class="ln">4</span><span class="cl">TT.now().earliest .... s = TT.now().latest .... TT.after(s)
</span></span><span class="line"><span class="ln">5</span><span class="cl">       |--------- ε --------|
</span></span><span class="line"><span class="ln">6</span><span class="cl">                            |---------- commit wait ≈ ε ----------|
</span></span><span class="line"><span class="ln">7</span><span class="cl">       |---------- total commit wait ≈ 2ε（從拿 s 那刻開始） ---------|</span></span></code></pre></div><p>commit wait ≈ 2ε 的數學保證了「下一個 transaction 拿到的 timestamp 一定 &gt; s」、external consistency 的全序性質就由這個 wait 撐住。<strong>Fact source 分層</strong>：commit wait ≈ 2ε 的推導來自 Spanner 2012 OSDI 論文 + 官方文件、不是 9.C10 case 直接展開實作層數學。引用這條數學要附「來源 vendor docs / paper」、避免讀者誤以為這是 case 揭露。</p>
<h3 id="跟通用-linearizability-卡片的差異">跟通用 linearizability 卡片的差異</h3>
<p><a href="/blog/backend/knowledge-cards/linearizability/" data-link-title="Linearizability" data-link-desc="每次操作看起來都在單一全域順序中即時生效的一致性語意">Linearizability</a> 只要求「存在某個全序」、external consistency 進一步要求「全序跟 real-time 順序一致」。TrueTime 是把後者變可實作的關鍵 — 它把跨 datacenter 的「real-time 順序」變成可機械判定的 <code>TT.after(s)</code>、不需要全局 coordinator 來決定誰先誰後。對應的概念卡：<a href="/blog/backend/knowledge-cards/external-consistency/" data-link-title="External Consistency" data-link-desc="交易可見順序與外部真實時間順序一致的強一致性語意">external-consistency</a>、<a href="/blog/backend/knowledge-cards/linearizability/" data-link-title="Linearizability" data-link-desc="每次操作看起來都在單一全域順序中即時生效的一致性語意">linearizability</a>、<a href="/blog/backend/knowledge-cards/quorum/" data-link-title="Quorum" data-link-desc="分散式系統以多數節點同意作為提交或讀取有效性的門檻">quorum</a>。</p>
<h2 id="操作流程怎麼觀測-ε-跟調用-truetime">操作流程：怎麼觀測 ε 跟調用 TrueTime</h2>
<p>TrueTime 本身不對外暴露給 application 操作、ε / commit wait 由 Spanner 內部執行。團隊能做的是 <em>觀測</em> ε 跟 <em>選擇</em> 不同強度的 read consistency。</p>
<h3 id="觀測-ε">觀測 ε</h3>
<p>Cloud Monitoring metric <code>spanner.googleapis.com/instance/clock_skew_ms</code> 是 ε 的對外指標、判讀正常 &lt; 7ms、異常 spike &gt; 50ms 代表 time master 失聯或 GPS 干擾。把這條 metric 跟 <code>commit_latencies</code> p99 配成 evidence pair：ε spike 時 commit latency heatmap 應該整層平移、若 commit latency 動但 ε 沒動、不是 TrueTime 的問題、是 quorum / network 的問題。</p>
<h3 id="跨-region-instance-配置時的-truetime-影響">跨 region instance 配置時的 TrueTime 影響</h3>
<p>voting region 越分散、ε 上限越高、commit wait 越長 → write latency 直接受 ε 影響。multi-region instance config 在做 region layout 決策時要把「voting region 散布範圍」當 latency budget 的固定支出、不是配完才補觀測。</p>
<h3 id="read-only-transaction-的-staleness-選項">read-only transaction 的 staleness 選項</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">strong              → 等 TrueTime 確認可讀最新、付完整 commit wait + quorum cost
</span></span><span class="line"><span class="ln">2</span><span class="cl">exact_staleness(t)  → 讀 t 秒前快照、避開 commit wait、適合 reporting / analytics
</span></span><span class="line"><span class="ln">3</span><span class="cl">bounded_staleness(t)→ 容忍 t 秒、可讀最近的本地 replica 副本、不跨 region quorum</span></span></code></pre></div><p>stale / bounded staleness 走的是 Spanner 版的 <a href="/blog/backend/knowledge-cards/follower-read/" data-link-title="Follower Read" data-link-desc="分散式 SQL 從 non-voting replica 讀 closed timestamp 之前的資料、不參與 Raft commit、低 latency 但 read-after-write 場景仍可能 stale">Follower Read</a> — 本地 replica serve 不參與 commit 的 read、避開跨 region quorum 把 read latency 降到 single-region 等級。</p>
<p>三者 trade-off 在 SDK 層顯式設定、不是 isolation level：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="ln">1</span><span class="cl"><span class="c1">// Spanner Go SDK 範例（time-sensitive、查最新文件確認 API）</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="nx">client</span><span class="p">.</span><span class="nf">Single</span><span class="p">().</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">    <span class="nf">WithTimestampBound</span><span class="p">(</span><span class="nx">spanner</span><span class="p">.</span><span class="nf">MaxStaleness</span><span class="p">(</span><span class="mi">10</span> <span class="o">*</span> <span class="nx">time</span><span class="p">.</span><span class="nx">Second</span><span class="p">)).</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl">    <span class="nf">Query</span><span class="p">(</span><span class="nx">ctx</span><span class="p">,</span> <span class="nx">statement</span><span class="p">)</span></span></span></code></pre></div><h3 id="驗證點跟-rollback-boundary">驗證點跟 rollback boundary</h3>
<p>跑 cross-region write + cross-region read benchmark、量 p50 / p99 write latency、確認 ≈ 2ε + quorum RTT 的數量級。TrueTime 配置不由用戶調、commit wait 由 Spanner 自動執行；應用層 rollback boundary 在「改用 stale read / bounded staleness」而不是「關掉 TrueTime」 — TrueTime 是 Spanner 內部不可關的機制、不是 feature flag。</p>
<h2 id="失敗模式ε-暴衝跟誤用-strong-read">失敗模式：ε 暴衝跟誤用 strong read</h2>
<h3 id="ε-暴衝time-master-失聯">ε 暴衝（time master 失聯）</h3>
<p>GPS 干擾、datacenter time master 雙故障、ε 從 4ms 跳到 200ms → 所有 write 的 commit wait 暴增、p99 write latency 從 50ms 變 500ms。徵兆是 Cloud Monitoring <code>commit_latencies</code> heatmap 整層平移、<code>clock_skew_ms</code> 同步上升。根因不在 application、在 datacenter 物理層、修法是等 GCP 內部 time master 恢復、應用層只能臨時降到 bounded staleness 救 read path。</p>
<h3 id="把-strong-read-用在不需要的路徑">把 strong read 用在不需要的路徑</h3>
<p>報表、analytics、user profile fetch 全用 strong read、每次 read 都付 TrueTime 對齊代價、p99 read 跟 write 同步退化。徵兆是 <code>commit_latencies</code> 沒動、但 <code>api/request_latencies</code> for <code>ExecuteSql</code> 整體上升。修法是把 read path 分類、reporting / analytics 改 bounded staleness、保留 strong read 給「讀後決策再寫」的 critical path。</p>
<h3 id="在-client-側做自己的-timestamp">在 client 側做「自己的 timestamp」</h3>
<p>application 用 <code>time.Now()</code> 當業務 key、跨 region 寫入時 client clock skew 直接破壞順序 — Spanner 內部 external consistency 對、業務層卻錯。徵兆是對帳系統發現 timestamp 順序顛倒、但 Spanner audit log 都 OK。修法是業務層 timestamp 全改用 Spanner <code>PENDING_COMMIT_TIMESTAMP</code> sentinel、commit 時由 Spanner 填、不靠 client clock。</p>
<h3 id="把-spanner-當-single-region-sql-用卻配-multi-region-instance">把 Spanner 當 single-region SQL 用、卻配 multi-region instance</h3>
<p>每筆 write 都付跨洲 quorum + commit wait、cost 跟 latency 都浪費。徵兆是 instance config 是 multi-region 但實際 read 99% 來自單一 region、write 也是。修法是降到 regional instance、把跨 region 需求改用 read-only replica 或 export 到 BigQuery。</p>
<h3 id="ε-沒監控">ε 沒監控</h3>
<p>團隊直到事故才看 clock_skew metric、被動處理而非主動告警。建議 <code>clock_skew_ms &gt; 20ms</code> warn、<code>&gt; 50ms</code> page、跟 commit_latencies p99 偏離 baseline 2x 一起當 saturation discovery 訊號（回 <a href="/blog/backend/09-performance-capacity/saturation-discovery/" data-link-title="9.4 Saturation Discovery" data-link-desc="找出 throughput plateau 與 latency knee 的方法">9.4 Saturation Discovery</a>）。</p>
<h2 id="容量與觀測truetime-ε-是-latency-budget-的固定支出">容量與觀測：TrueTime ε 是 latency budget 的固定支出</h2>
<p>必看 metric：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">commit_latencies (p50 / p95 / p99)        → commit wait + quorum RTT 的總和
</span></span><span class="line"><span class="ln">2</span><span class="cl">api/request_count by method               → strong read vs stale read 的分布
</span></span><span class="line"><span class="ln">3</span><span class="cl">instance/cpu/utilization_by_priority      → high / low priority 分流
</span></span><span class="line"><span class="ln">4</span><span class="cl">clock_skew_ms                             → TrueTime ε 的對外指標</span></span></code></pre></div><p>用 <a href="/blog/backend/04-observability/observability-evidence-package/" data-link-title="4.20 Observability Evidence Package" data-link-desc="把 log、metric、trace、audit 與資料品質限制包成可交接證據">4.20 Observability Evidence Package</a> 框架把 TrueTime ε 跟 commit latency 配成 evidence pair。Capacity 規劃路由回 <a href="/blog/backend/09-performance-capacity/capacity-planning/" data-link-title="9.6 容量規劃模型" data-link-desc="peak forecast、headroom budget、growth curve、autoscaling sizing">9.6 容量規劃模型</a>、把「ε × write rate」當 latency budget 的固定支出 — 寫越多筆、commit wait 累積成本越高、不是 free。</p>
<p>Alert 建議：</p>
<table>
  <thead>
      <tr>
          <th>Metric</th>
          <th>Warn</th>
          <th>Page</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><code>clock_skew_ms</code></td>
          <td>&gt; 20ms</td>
          <td>&gt; 50ms</td>
      </tr>
      <tr>
          <td><code>commit_latencies</code> p99</td>
          <td>baseline 1.5x</td>
          <td>baseline 2x</td>
      </tr>
      <tr>
          <td><code>low_priority_utilization</code></td>
          <td>&gt; 80%</td>
          <td>&gt; 90%</td>
      </tr>
  </tbody>
</table>
<h3 id="line-rate-scaling-驗證呼應商業邏輯先行段">Line-rate scaling 驗證（呼應商業邏輯先行段）</h3>
<p>擴 node 數時量「read throughput / node」是否維持線性 — 9.C10 揭露的 2 → 4 nodes = 45K → 90K reads/sec 是 Google internal dogfood 的線性模式、不是客戶 SLA 承諾。團隊在自己 instance 上要驗證的不是「能不能達到 90K reads」、是「擴 node 後 throughput / node 有沒有保持線性」。若曲線 sub-linear、檢查是否 hot split / hot range / Paxos group 不均、TrueTime 機制本身不解這層。</p>
<h2 id="邊界與整合何時不用-truetime或不用-spanner">邊界與整合：何時不用 TrueTime（或不用 Spanner）</h2>
<h3 id="何時改用-stale-read">何時改用 stale read</h3>
<p>reporting / analytics / dashboard 場景改用 bounded staleness 換 cost、不付 commit wait 的 latency tax。判準：若這個 read path 用 5 秒前的資料不會影響業務決策、改 stale read；若會、保留 strong read。</p>
<h3 id="何時不該升-spanner">何時不該升 Spanner</h3>
<p>單 region workload 不該為了 external consistency 升 Spanner、Cloud SQL + serializable isolation 已經夠。9.C10 dogfood 揭露的線性 scaling 是「跨 region + 大規模」場景的設計目標、單 region 用戶拿不到對應的 cost / latency benefit。詳見遷移判讀：<a href="../migrate-from-cloud-sql-pg/">Cloud SQL → Spanner Migration Playbook</a> 的 no-go condition 段。</p>
<h3 id="sibling-deep-articles-路由">Sibling deep articles 路由</h3>
<ul>
<li><a href="../consistency-models-comparison/">consistency-models-comparison</a>：為什麼 external consistency ≠ serializability ≠ linearizability、line-rate scaling 對照表、cross-region quorum 100-200ms 物理硬限</li>
<li><a href="../schema-migration-interleaved-tables/">schema-migration-interleaved-tables</a>：schema change 也用 TrueTime 保證 version 邊界、parent-child storage layout</li>
<li><a href="../migrate-from-cloud-sql-pg/">migrate-from-cloud-sql-pg</a>：cutover 階段需要把 application 對 timestamp 的假設審一遍（特別是 client 端 <code>time.Now()</code> 那條失敗模式）</li>
</ul>
<h3 id="跟-1x-章節的互引">跟 1.x 章節的互引</h3>
<ul>
<li><a href="/blog/backend/01-database/global-distributed-oltp/" data-link-title="1.11 全球分散式 OLTP" data-link-desc="Spanner / Aurora DSQL / Cosmos DB multi-region write / CockroachDB / TiDB 的全球一致性取捨">1.11 全球分散式 OLTP</a>：Spanner 是 PC 系統的代表、Cosmos DB AP 系統當對照</li>
<li><a href="/blog/backend/knowledge-cards/transaction-boundary/" data-link-title="Transaction Boundary" data-link-desc="說明哪些資料變更應在同一個交易中一起成功或一起回復">transaction boundary</a>：external consistency 是 transaction boundary 的全球延伸</li>
</ul>
<h3 id="anti-recommendation">Anti-recommendation</h3>
<p>讀者讀完本文應該能判斷：TrueTime 不是「保證強一致」的功能、是「換 scaling 路徑」的核心；若團隊只想要「強一致」、不需要「跨節點線性擴展」、PostgreSQL serializable + 應用層補上 client-side ordering 就夠、不必為 TrueTime 付 GCP lock-in 的 cost。</p>
]]></content:encoded></item></channel></rss>