<?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>AWS Aurora on Tarragon</title><link>https://tarrragon.github.io/blog/backend/01-database/vendors/aurora/</link><description>Recent content in AWS Aurora on Tarragon</description><generator>Hugo -- gohugo.io</generator><language>zh-TW</language><copyright>Tarragon (CC BY 4.0)</copyright><lastBuildDate>Wed, 13 May 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://tarrragon.github.io/blog/backend/01-database/vendors/aurora/index.xml" rel="self" type="application/rss+xml"/><item><title>Aurora Storage Architecture：quorum-based 分散式 log 與韌性即性能設計</title><link>https://tarrragon.github.io/blog/backend/01-database/vendors/aurora/storage-architecture/</link><pubDate>Wed, 27 May 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/backend/01-database/vendors/aurora/storage-architecture/</guid><description>&lt;p>Aurora 把 storage 從「block device + WAL on local disk」重寫成跨 AZ 分散式 log service、compute node 只負責 process query 跟 generate redo log records。這個設計直接決定 read replica、failover、backup 跟跨 AZ replication 的物理上限 — 不理解 storage layer 設計、就無法解釋為什麼 &lt;a href="https://tarrragon.github.io/blog/backend/09-performance-capacity/cases/netflix-aurora-consolidation/" data-link-title="9.C23 Netflix：把關聯式 DB 統一到 Aurora、效能 &amp;#43;75%、成本 -28%" data-link-desc="Netflix 把多套關聯式 DB 統一到 Aurora、效能提升 75%、成本下降 28%、串流數十億小時">9.C23 Netflix consolidation&lt;/a> 拿到 +75% 效能、為什麼 &lt;a href="https://tarrragon.github.io/blog/backend/09-performance-capacity/cases/draftkings-aurora-financial-ledger/" data-link-title="9.C4 DraftKings：Aurora 撐 100 萬 ops/min 的體育博彩金融帳本" data-link-desc="DraftKings 用 Aurora MySQL 跑體育博彩金融帳本、Super Bowl 流量 &amp;#43;50% 不影響延遲">9.C4 DraftKings&lt;/a> replication lag 從 30 秒降到 10-30ms、為什麼 &lt;a href="https://tarrragon.github.io/blog/backend/09-performance-capacity/cases/standard-chartered-aurora-banking/" data-link-title="9.C14 Standard Chartered：受監管銀行的 Aurora 4000 TPS 容量提升" data-link-desc="Standard Chartered 銀行遷移到 Aurora 後吞吐量提升 10 倍至 4000 TPS、跨 7 個受監管市場">9.C14 Standard Chartered&lt;/a> 能同時把韌性跟性能當成單一目標。&lt;/p>
&lt;p>本文不是 Aurora overview（請看 &lt;a href="https://tarrragon.github.io/blog/backend/01-database/vendors/aurora/" data-link-title="AWS Aurora" data-link-desc="AWS managed PostgreSQL / MySQL、storage / compute 分離、&amp;#43;75% 效能改善的 production 證據">Aurora vendor 頁&lt;/a>）— 而是 storage-level 設計的實作層教學。覆蓋 quorum-based replication 的工程含義、「韌性即性能」frame 為什麼成立、OLTP workload 在 storage 設計下的讀寫雙峰錯位、跟容量規劃的判讀槓桿。&lt;/p>
&lt;h2 id="問題情境">問題情境&lt;/h2>
&lt;p>典型觸發場景：團隊從 RDS PostgreSQL / 自管 PostgreSQL 遷到 Aurora、看到「跨 AZ replication lag 從秒級降到毫秒級」、但讀文件「quorum」「4-of-6」「分散式 storage」訊息密集、不知道哪些設計決策要相信、哪些是 marketing 詞。&lt;/p>
&lt;p>讀者常見的具體疑問：&lt;/p>
&lt;ul>
&lt;li>「為什麼 Aurora 寫入比 RDS 還低、不是該因為跨 AZ network round-trip 而變慢？」&lt;/li>
&lt;li>「Storage layer 跟 compute layer 分離具體怎麼影響 backup、failover 跟 read replica？」&lt;/li>
&lt;li>「6 個 storage node 失去 2 個還能寫嗎？失去 3 個呢？」&lt;/li>
&lt;li>「Aurora 文件講『韌性』跟『性能』都用 storage 設計解釋、是同一件事還是兩件事？」&lt;/li>
&lt;/ul>
&lt;p>進一步問題：傳統工程文化把可靠性跟性能視為對立 — HA 投資（跨 AZ replication、failover 演練）通常被當成性能成本、不被視為性能來源。Aurora 設計反這個直覺、但讀者需要看到具體機制才能信。Standard Chartered case 揭露這個 frame 在受監管銀行業務（要求兩者同時達標）的價值；DraftKings 揭露具體數字（讀 &amp;lt; 1ms、寫 6ms）。&lt;/p>
&lt;h2 id="核心機制quorum-based-分散式-log">核心機制：quorum-based 分散式 log&lt;/h2>
&lt;p>Aurora storage 的 first-class concept 是 &lt;em>quorum 寫入 + 6-way 跨 AZ replication&lt;/em>。傳統 PostgreSQL primary 把 storage 跟 CPU / RAM 綁定、storage 擴容要換 instance、replication 在 compute 層做（streaming replication、logical replication）。Aurora 把 storage 拉到分散式 log service、6 個 storage node 各自獨立、application 看到的仍是 single primary SQL。&lt;/p></description><content:encoded><![CDATA[<p>Aurora 把 storage 從「block device + WAL on local disk」重寫成跨 AZ 分散式 log service、compute node 只負責 process query 跟 generate redo log records。這個設計直接決定 read replica、failover、backup 跟跨 AZ replication 的物理上限 — 不理解 storage layer 設計、就無法解釋為什麼 <a href="/blog/backend/09-performance-capacity/cases/netflix-aurora-consolidation/" data-link-title="9.C23 Netflix：把關聯式 DB 統一到 Aurora、效能 &#43;75%、成本 -28%" data-link-desc="Netflix 把多套關聯式 DB 統一到 Aurora、效能提升 75%、成本下降 28%、串流數十億小時">9.C23 Netflix consolidation</a> 拿到 +75% 效能、為什麼 <a href="/blog/backend/09-performance-capacity/cases/draftkings-aurora-financial-ledger/" data-link-title="9.C4 DraftKings：Aurora 撐 100 萬 ops/min 的體育博彩金融帳本" data-link-desc="DraftKings 用 Aurora MySQL 跑體育博彩金融帳本、Super Bowl 流量 &#43;50% 不影響延遲">9.C4 DraftKings</a> replication lag 從 30 秒降到 10-30ms、為什麼 <a href="/blog/backend/09-performance-capacity/cases/standard-chartered-aurora-banking/" data-link-title="9.C14 Standard Chartered：受監管銀行的 Aurora 4000 TPS 容量提升" data-link-desc="Standard Chartered 銀行遷移到 Aurora 後吞吐量提升 10 倍至 4000 TPS、跨 7 個受監管市場">9.C14 Standard Chartered</a> 能同時把韌性跟性能當成單一目標。</p>
<p>本文不是 Aurora overview（請看 <a href="/blog/backend/01-database/vendors/aurora/" data-link-title="AWS Aurora" data-link-desc="AWS managed PostgreSQL / MySQL、storage / compute 分離、&#43;75% 效能改善的 production 證據">Aurora vendor 頁</a>）— 而是 storage-level 設計的實作層教學。覆蓋 quorum-based replication 的工程含義、「韌性即性能」frame 為什麼成立、OLTP workload 在 storage 設計下的讀寫雙峰錯位、跟容量規劃的判讀槓桿。</p>
<h2 id="問題情境">問題情境</h2>
<p>典型觸發場景：團隊從 RDS PostgreSQL / 自管 PostgreSQL 遷到 Aurora、看到「跨 AZ replication lag 從秒級降到毫秒級」、但讀文件「quorum」「4-of-6」「分散式 storage」訊息密集、不知道哪些設計決策要相信、哪些是 marketing 詞。</p>
<p>讀者常見的具體疑問：</p>
<ul>
<li>「為什麼 Aurora 寫入比 RDS 還低、不是該因為跨 AZ network round-trip 而變慢？」</li>
<li>「Storage layer 跟 compute layer 分離具體怎麼影響 backup、failover 跟 read replica？」</li>
<li>「6 個 storage node 失去 2 個還能寫嗎？失去 3 個呢？」</li>
<li>「Aurora 文件講『韌性』跟『性能』都用 storage 設計解釋、是同一件事還是兩件事？」</li>
</ul>
<p>進一步問題：傳統工程文化把可靠性跟性能視為對立 — HA 投資（跨 AZ replication、failover 演練）通常被當成性能成本、不被視為性能來源。Aurora 設計反這個直覺、但讀者需要看到具體機制才能信。Standard Chartered case 揭露這個 frame 在受監管銀行業務（要求兩者同時達標）的價值；DraftKings 揭露具體數字（讀 &lt; 1ms、寫 6ms）。</p>
<h2 id="核心機制quorum-based-分散式-log">核心機制：quorum-based 分散式 log</h2>
<p>Aurora storage 的 first-class concept 是 <em>quorum 寫入 + 6-way 跨 AZ replication</em>。傳統 PostgreSQL primary 把 storage 跟 CPU / RAM 綁定、storage 擴容要換 instance、replication 在 compute 層做（streaming replication、logical replication）。Aurora 把 storage 拉到分散式 log service、6 個 storage node 各自獨立、application 看到的仍是 single primary SQL。</p>
<p><strong>Storage layout</strong>：每個 storage segment 跨 3 AZ × 2 node、共 6 個 storage node。一個 cluster 的 storage 被切成多個 10GB segment、每個 segment 6-way 複製。</p>
<p><strong>Quorum 設定</strong>：</p>
<ul>
<li>Write quorum：4-of-6（4 個 storage node 確認寫入才算 commit）— 容忍 1 AZ 失效 + 1 node 失效仍能寫</li>
<li>Read quorum：3-of-6（讀 3 個 node 取最新版本）— 比 write 小、降低 read latency</li>
<li>算術不對稱：寫嚴讀鬆是設計選擇、不是 marketing — durability 由寫端保證、讀端可以放寬</li>
</ul>
<p><strong>Write path 跟傳統 PostgreSQL 的差異</strong>：</p>
<ul>
<li>PostgreSQL primary：寫 WAL 到 local disk + dirty page flush + 透過 streaming replication 推到 replica</li>
<li>Aurora compute node：只送 <em>redo log records</em> 到 storage、不送整個 page；storage node 自己 apply redo log 重建 page、自己 checkpoint、自己 backup</li>
<li>工程含義：compute node 寫量小、CPU 不被 dirty page flush 佔用、寫入路徑變短</li>
</ul>
<p><strong>「韌性即性能」frame</strong>（<a href="/blog/backend/09-performance-capacity/cases/standard-chartered-aurora-banking/" data-link-title="9.C14 Standard Chartered：受監管銀行的 Aurora 4000 TPS 容量提升" data-link-desc="Standard Chartered 銀行遷移到 Aurora 後吞吐量提升 10 倍至 4000 TPS、跨 7 個受監管市場">9.C14 Standard Chartered</a> 揭露）：</p>
<p>Aurora 把 HA 從 application-level（Patroni promotion + WAL catch-up）下推到 storage-level。設計含義是：storage 投資（6-way 跨 AZ replication）自動成為 read replica 的容量基底 — read replica 不需要 catch-up WAL、直接從共享 storage 讀、HA 預算同步轉成讀分流預算。</p>
<p>對 Standard Chartered 受監管銀行業務這代表：合規要求的 RPO / RTO 不能放棄、但業務也要求每秒 4000 TPS、兩者必須同時達成。傳統路徑要分別投資 HA（複雜的 streaming replication topology）跟性能（read replica catch-up tuning）、且兩個投資互相干擾。Aurora 讓 <em>同一份 storage 投資</em> 同時提供兩件事 — case「判讀」段第 2 點原話：「Aurora 的多 AZ storage + replica 同時提供性能（讀分流）跟韌性（故障切換）、達成 <em>韌性即性能</em> 的目標」。</p>
<p>對應 knowledge card：<a href="/blog/backend/knowledge-cards/quorum/" data-link-title="Quorum" data-link-desc="分散式系統以多數節點同意作為提交或讀取有效性的門檻">quorum</a>、<a href="/blog/backend/knowledge-cards/replication-lag/" data-link-title="Replication Lag" data-link-desc="說明資料副本落後正式來源多久，以及它如何影響讀取正確性">replication-lag</a>。</p>
<p><strong>跟通用 quorum 概念差在哪</strong>：Aurora quorum 是 <em>storage-level</em>（不是 application-level Cassandra 風格）、application 看到 single primary SQL、不用感知 quorum；vs Cassandra application 要選 consistency level（ONE / QUORUM / ALL）。</p>
<h2 id="oltp-workload-shape讀寫雙峰錯位">OLTP workload shape：讀寫雙峰錯位</h2>
<p>Aurora 設計的工程含義在 application 層落地時、要看 workload 形狀。<a href="/blog/backend/09-performance-capacity/cases/draftkings-aurora-financial-ledger/" data-link-title="9.C4 DraftKings：Aurora 撐 100 萬 ops/min 的體育博彩金融帳本" data-link-desc="DraftKings 用 Aurora MySQL 跑體育博彩金融帳本、Super Bowl 流量 &#43;50% 不影響延遲">9.C4 DraftKings</a> 揭露一個 OLTP 容量規劃的典型 pattern。</p>
<p><strong>DraftKings 揭露的雙峰錯位</strong>（case「觀察」段最後一行原文）：「write workloads spike up significantly around payout events, but opening the app during the game also activates a lot of balance queries」— 比賽進行時是讀爆量（balance query）、payout event 時是寫爆量（ledger write）、兩個峰不在同一時刻。</p>
<p><strong>工程含義</strong>：</p>
<ul>
<li>讀寫資源規劃要分開、不能用「峰值總 TPS」單一數字規劃容量</li>
<li>讀峰拉 read replica 容量、寫峰靠 primary instance class 跟 commit batching、兩條路徑獨立預配</li>
<li>預估 headroom 也要分開：讀的 headroom 可以靠 auto-scale replica 接、寫的 headroom 要靠 primary 提前升 instance class（不能 auto-scale）</li>
</ul>
<p><strong>Application-level boundary</strong>：雙峰錯位是 <em>application 層</em> 拆讀寫 datasource 的決策訊號、storage layer 本身不解。Aurora 共享 storage 提供 lag 上限可預測（10-30ms）— 這是 read replica 變成「production-grade 可用」的前提、但讀寫分流要 application 端拆 read / write data source 才能落地。Storage 設計給的是「可預測的 lag 上限」、不是「自動讀寫分離」。</p>
<p><strong>跨 case 對照</strong>：</p>
<p><a href="/blog/backend/09-performance-capacity/cases/fanduel-dual-peak-betting-streaming/" data-link-title="9.C28 FanDuel：體育直播 &#43; 投注的雙重峰值" data-link-desc="FanDuel 3.5M MAU、Super Bowl 期間擴容 5-10 倍、用 AWS Local Zones &#43; Wavelength &#43; Outposts 處理 20&#43; 州的雙重峰值">9.C28 FanDuel</a> 揭露另一種雙峰 — 直播 + 投注 <em>兩種服務</em> 同時峰、不是同服務讀寫錯位。這兩種雙峰類型要分清楚：</p>
<ul>
<li>同服務讀寫錯位（DraftKings）：解法是 read / write data source 拆分、共享 Aurora cluster</li>
<li>跨服務雙峰（FanDuel）：解法是不同服務各自獨立擴容、betting 走 Aurora、streaming 走 CDN</li>
</ul>
<p>雙峰類型不同、容量規劃策略不同。</p>
<h2 id="step-by-step-配置--觀測">Step-by-step 配置 / 觀測</h2>
<p>Aurora storage 是 cluster-level、不暴露 segment-level config。讀者能影響的維度是 instance class、storage type、backup retention 跟 monitoring。</p>
<p><strong>Cluster 建立</strong>：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl">aws rds create-db-cluster <span class="se">\
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="se"></span>  --db-cluster-identifier my-cluster <span class="se">\
</span></span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="se"></span>  --engine aurora-postgresql <span class="se">\
</span></span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="se"></span>  --engine-version 15.5 <span class="se">\
</span></span></span><span class="line"><span class="ln">5</span><span class="cl"><span class="se"></span>  --master-username admin <span class="se">\
</span></span></span><span class="line"><span class="ln">6</span><span class="cl"><span class="se"></span>  --master-user-password <span class="s2">&#34;</span><span class="k">$(</span>aws secretsmanager get-secret-value --secret-id db-password --query SecretString --output text<span class="k">)</span><span class="s2">&#34;</span> <span class="se">\
</span></span></span><span class="line"><span class="ln">7</span><span class="cl"><span class="se"></span>  --storage-type aurora-iopt1 <span class="se">\
</span></span></span><span class="line"><span class="ln">8</span><span class="cl"><span class="se"></span>  --backup-retention-period <span class="m">7</span></span></span></code></pre></div><p>關鍵欄位：</p>
<ul>
<li><code>--storage-type aurora-iopt1</code>：Aurora I/O-Optimized、月費高 30% 但無 I/O 收費；write-heavy + scan-heavy workload 才划算</li>
<li><code>--storage-type aurora</code>（預設）：Standard storage、按 I/O 計費；read-light workload 划算</li>
<li><code>--backup-retention-period 7</code>：1-35 天、影響 PITR 範圍</li>
</ul>
<p><strong>觀測 storage 狀態</strong>：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl">aws rds describe-db-clusters <span class="se">\
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="se"></span>  --db-cluster-identifier my-cluster <span class="se">\
</span></span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="se"></span>  --query <span class="s1">&#39;DBClusters[0].{StorageType:StorageType,AllocatedStorage:AllocatedStorage,Status:Status}&#39;</span></span></span></code></pre></div><p><strong>CloudWatch metric</strong>（cluster-level）：</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">VolumeBytesUsed           # 當前 storage 用量、接近 128 TB 上限要警告
</span></span><span class="line"><span class="ln">2</span><span class="cl">VolumeReadIOPs            # storage 層讀 IOPS、判斷 I/O-Optimized ROI
</span></span><span class="line"><span class="ln">3</span><span class="cl">VolumeWriteIOPs           # storage 層寫 IOPS、跟 compute 層 WriteIOPS 對照
</span></span><span class="line"><span class="ln">4</span><span class="cl">AuroraVolumeBytesLeftTotal # 剩餘可用 storage</span></span></code></pre></div><p><strong>Performance Insights wait event</strong>：</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">db.IO.aurora_redo_log_flush   # quorum write 等待訊號、p99 &gt; 10ms 要看
</span></span><span class="line"><span class="ln">2</span><span class="cl">db.IO.aurora_storage_xx       # storage layer I/O 細節</span></span></code></pre></div><p><strong>驗證點</strong>：</p>
<ul>
<li>寫入 latency p99：PostgreSQL primary 1-3ms vs Aurora 3-6ms、跨 AZ network round-trip 是物理下界</li>
<li>Read latency p99：Aurora &lt; 1ms（從共享 storage 讀、不跨 AZ）</li>
<li>Storage autoscale event：128 TB 上限前自動 grow per 10GB</li>
</ul>
<p><strong>Rollback boundary</strong>：Aurora storage 是 cluster-level、無法回滾 storage 設計；唯一 rollback 是切回 RDS / 自管（走 migration playbook、不是配置層 rollback）。</p>
<h2 id="故障模式--邊界-case">故障模式 / 邊界 case</h2>
<h3 id="case-1誤以為-aurora-寫入一定比-postgresql-primary-快">Case 1：誤以為 Aurora 寫入一定比 PostgreSQL primary 快</h3>
<p>徵兆：團隊期待 Aurora 寫入比自管 PostgreSQL 快、實測 p99 寫入 latency 沒明顯改善、甚至小 row + 單筆 commit 場景 Aurora 反而慢。</p>
<p>原因：跨 AZ network round-trip 是 3-5ms 物理下界、4-of-6 quorum 至少要等 4 個 storage node ack、單筆小寫場景 local SSD primary 仍有 latency 優勢。Aurora 的寫入優勢在 <em>壓力下</em> 才顯現 — write throughput 高峰時 PostgreSQL primary 受限於 dirty page flush + WAL fsync + replica catch-up、Aurora 的 storage layer 各自獨立處理 redo log apply。</p>
<blockquote>
<p><strong>數字口徑</strong>：「跨 AZ round-trip 3-5ms」屬通用工程估算（光速下界 + AWS 區內 AZ 物理距離）、case 未直接量化、實際值依 region / AZ pair / instance 類型而異、要看 AWS 官方 latency table 或自家 benchmark 校正。下方 DraftKings 6ms 寫入是 case 揭露的 production reference、可作為對照基線。</p></blockquote>
<p>修：</p>
<ul>
<li>benchmark 要跑壓力測試、不能只測單筆 latency</li>
<li>寫入 latency 不是 Aurora 的核心賣點、是 <em>可預測的 read replica lag + 韌性</em> 才是</li>
<li>DraftKings 6ms 寫入是 production reference：跨 AZ quorum 的物理下界、不是 Aurora 慢</li>
</ul>
<h3 id="case-2az-level-outage-期間寫入-latency-spike">Case 2：AZ-level outage 期間寫入 latency spike</h3>
<p>徵兆：1 個 AZ 失效後、寫入 p99 從 6ms spike 到 30-50ms、application timeout 增加。</p>
<p>原因：失去 1 AZ 後 quorum 仍成立（4-of-6 → 用剩 4 個 node 寫）、但 storage node fault 期間需要等 timeout 才確認；單一 storage node 額外 fault 會把寫推到 timeout。Aurora 在 AZ outage 期間 <em>能寫</em>、但不是 <em>性能不變</em>。</p>
<p>修：</p>
<ul>
<li>監測 <code>AuroraVolumeBytesLeftTotal</code> 跟 storage IOPS 分布、AZ outage 期間自動切到剩餘 AZ</li>
<li>application 端做 retry + circuit breaker、不要假設寫入永遠 6ms</li>
<li>確認 cluster 至少跨 3 AZ deploy、單 AZ outage 才有 quorum 餘地</li>
</ul>
<h3 id="case-3io-optimized-費用誤判">Case 3：I/O-Optimized 費用誤判</h3>
<p>徵兆：team 看 Aurora I/O-Optimized「無 I/O 收費」直接切過去、月帳變高 25%、沒看到 ROI。</p>
<p>原因：Standard storage 按 I/O 收費、I/O-Optimized 月費比 Standard 高 30%。只有 <em>write-heavy + scan-heavy</em> workload（I/O 月費接近 instance 費用）才划算；read-light + write-light workload 反而吃虧。</p>
<p>修：</p>
<ul>
<li>先量測 baseline I/O：<code>VolumeReadIOPs + VolumeWriteIOPs × $0.20 per million I/O</code> vs Standard 月費</li>
<li>I/O 費用 &gt; instance 費用 30% 才切 I/O-Optimized</li>
<li>DraftKings 用 I/O-Optimized 是因為金融帳本 write-heavy + balance query scan-heavy、ROI 明顯</li>
</ul>
<h3 id="case-4storage-autoscale-假設">Case 4：Storage autoscale 假設</h3>
<p>徵兆：TRUNCATE / DROP 大表釋放 50% storage、但下月帳單沒回落。</p>
<p>原因：Aurora storage 自動 grow、但 <em>不自動 shrink</em>。已分配的 storage 持續計費、TRUNCATE / DROP 只釋放 logical space、physical storage 仍占用。要 shrink 必須走 logical migration（dump / restore 到新 cluster）。</p>
<p>修：</p>
<ul>
<li>大量 DROP 操作前先評估是否值得做 logical migration</li>
<li>用 partition + DETACH 而非 DROP TABLE、partition 可以單獨 archive</li>
<li>接受 storage 用量是 <em>peak watermark</em> 而非 <em>current usage</em></li>
</ul>
<h3 id="case-5replication-lag-誤解">Case 5：Replication lag 誤解</h3>
<p>徵兆：read replica lag 10-30ms 看起來夠快、application 假設 read-after-write consistency、用戶下注後立刻查 balance 偶發看到舊資料。</p>
<p>原因：10-30ms 是 <em>typical</em>、heavy write + slow query 期間可能秒級。Aurora 共享 storage 設計讓 lag <em>可預測</em>（不會像 PostgreSQL streaming replication unbounded）、但 <em>可預測</em> 不等於 <em>zero</em>。Read-after-write 場景仍需要 application 端處理。</p>
<p>修：</p>
<ul>
<li>用戶寫操作後 N 秒內走 primary（N 由 lag p99 決定、典型 100ms）</li>
<li>Aurora 提供 session pinning：寫完同 session 短期內走 primary</li>
<li>不能假設「Aurora replication lag 小到可以忽略」、要看 application 容忍度</li>
</ul>
<h2 id="容量與觀測">容量與觀測</h2>
<p><strong>核心 metric</strong>：</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">VolumeBytesUsed           # storage 用量、128 TB 上限預警
</span></span><span class="line"><span class="ln">2</span><span class="cl">AuroraReplicaLag          # replica lag、判斷讀寫分流可行性
</span></span><span class="line"><span class="ln">3</span><span class="cl">db.IO.aurora_redo_log_flush # quorum write 等待、storage 瓶頸訊號</span></span></code></pre></div><p><strong>Production reference number</strong>（<a href="/blog/backend/09-performance-capacity/cases/draftkings-aurora-financial-ledger/" data-link-title="9.C4 DraftKings：Aurora 撐 100 萬 ops/min 的體育博彩金融帳本" data-link-desc="DraftKings 用 Aurora MySQL 跑體育博彩金融帳本、Super Bowl 流量 &#43;50% 不影響延遲">9.C4 DraftKings</a> 揭露、case「觀察」段表格）：</p>
<table>
  <thead>
      <tr>
          <th>指標</th>
          <th>DraftKings 在 Aurora MySQL 的數字</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>讀延遲</td>
          <td>&lt; 1 ms</td>
      </tr>
      <tr>
          <td>寫延遲</td>
          <td>6 ms</td>
      </tr>
      <tr>
          <td>Replication lag</td>
          <td>從 30 秒降到 10-30 ms</td>
      </tr>
  </tbody>
</table>
<p>這個 production reference 取代用「typical 3-5ms」籠統說法。讀寫 6x 差距是 OLTP 容量規劃槓桿 baseline — 寫延遲是 quorum 4-of-6 + 跨 AZ network round-trip 的物理下界、不是 storage 設計能再壓低。引用時要明示是 DraftKings production reference、不是 Aurora marketing。</p>
<p><strong>容量上限</strong>：</p>
<ul>
<li>128 TB / cluster（超過要拆 cluster、見 <a href="../read-replica-scaling/">Aurora read replica scaling</a> fleet 治理 SSoT）</li>
<li>15 read replica / region（<a href="../read-replica-scaling/">Aurora read replica scaling</a> 展開）</li>
<li>Storage 自動 grow per 10GB</li>
</ul>
<p><strong>跨 region replication</strong>：<a href="../global-database-multi-region/">Aurora Global Database</a> 用 <code>AuroraGlobalDBReplicationLag</code> 監測、&lt; 1 秒 typical。</p>
<p><strong>回路徑</strong>：<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> 抽 CloudWatch evidence、<a href="/blog/backend/09-performance-capacity/bottleneck-localization/" data-link-title="9.5 瓶頸定位流程" data-link-desc="從 app 到 DB / cache / broker / 第三方 quota 的逐層瓶頸定位">9.5 瓶頸定位流程</a> 判斷 storage-bound vs compute-bound。</p>
<h2 id="netflix-75-效能改善的根因">Netflix +75% 效能改善的根因</h2>
<p><a href="/blog/backend/09-performance-capacity/cases/netflix-aurora-consolidation/" data-link-title="9.C23 Netflix：把關聯式 DB 統一到 Aurora、效能 &#43;75%、成本 -28%" data-link-desc="Netflix 把多套關聯式 DB 統一到 Aurora、效能提升 75%、成本下降 28%、串流數十億小時">9.C23 Netflix consolidation</a> 案例揭露 storage 設計的具體效能含義。Netflix 把多套 RDBMS（PostgreSQL / MySQL / Oracle）統一到 Aurora、拿到 <em>up to 75%</em> 效能改善、-28% 成本。</p>
<p><strong>+75% 的根因</strong>：</p>
<ul>
<li>傳統 PostgreSQL primary 寫 WAL + dirty page flush + 透過 streaming replication 推到 replica</li>
<li>Compute 大量 CPU 用在 dirty page flush + replication encoding、不是用在 query processing</li>
<li>Aurora compute 只送 redo log records、storage 自己 apply page、自己 checkpoint</li>
<li>→ 同樣 instance class 下、Aurora compute 能處理更多 query</li>
</ul>
<p>這不是 marketing 的「分散式儲存讓效能提升」籠統說法、而是具體的 <em>compute 不再 flush dirty page</em>。</p>
<p><strong>scope warning（必明示、case 自帶警示原話）</strong>：</p>
<p>「effective 75% improvement 是跨多 workload 的最大改善幅度、不是『每個 workload 都 +75%』。實際每個 workload 改善幅度從 10% 到 75% 不等」（case「需要警惕」段第 1 點）。</p>
<p>引用 Netflix 時不能把 75% 套到單一 workload — 容量規劃要看自家 workload 形狀（write-heavy / read-heavy / scan-heavy）、預估改善幅度範圍而非單一數字。</p>
<h2 id="fleet-治理cross-link不展開">Fleet 治理（cross-link、不展開）</h2>
<p>Production scale 不是「單一巨型 Aurora cluster」而是 <em>fleet of clusters</em> — 5 case 揭露同一 frame：</p>
<ul>
<li>DraftKings 200 個獨立 cluster（按業務切分）</li>
<li>Netflix 多 cluster（微服務私有 store）</li>
<li>Standard Chartered 7 個 cluster（受監管市場 boundary）</li>
</ul>
<p>跨 case 合成的 fleet 拓樸 3 條 driver（business sharding / microservice ownership / 合規市場 boundary）跟「何時拆 cluster vs 加 replica」的判讀順序、SSoT 在 <a href="../read-replica-scaling/">Aurora read replica scaling</a> 邊界段。Storage 設計本身不解 fleet 邊界決策 — Aurora 解 single-cluster scaling（quorum / 共享 storage / 共享 backup）、但「拆幾個 cluster」是業務拓樸決策。</p>
<h2 id="邊界與整合--下一步">邊界與整合 / 下一步</h2>
<p><strong>Sibling deep articles</strong>：</p>
<ul>
<li><a href="../cross-az-failover-rto/">Aurora cross-AZ failover RTO</a> — storage 設計如何加速 failover（replica 不需要 catch-up）</li>
<li><a href="../read-replica-scaling/">Aurora read replica scaling</a> — 共享 storage 為什麼能養 15 replica + fleet 治理 SSoT</li>
<li><a href="../global-database-multi-region/">Aurora Global Database</a> — 跨 region storage replication 設計</li>
</ul>
<p><strong>Migration playbook</strong>：</p>
<ul>
<li><a href="../migrate-from-self-managed-pg-mysql/">PostgreSQL / MySQL → Aurora</a> — storage 設計差是 operational redesign 的核心 driver</li>
</ul>
<p><strong>1.x 章節互引</strong>：</p>
<ul>
<li><a href="/blog/backend/01-database/transaction-boundary/" data-link-title="1.3 Transaction 與一致性邊界" data-link-desc="交易邊界、isolation level、retry 策略、distributed transaction（2PC、Saga）與跨 region 強一致取捨">1.3 Transaction Boundary</a> — quorum 寫入 vs single-primary transaction 邊界</li>
<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> — Aurora storage 是 single-region scaling、不是 distributed SQL</li>
</ul>
<p><strong>何時不用本文</strong>：single-region OLTP 用 RDS 仍足夠、storage architecture 細節不影響容量規劃時可跳過、看 <a href="/blog/backend/01-database/vendors/aurora/" data-link-title="AWS Aurora" data-link-desc="AWS managed PostgreSQL / MySQL、storage / compute 分離、&#43;75% 效能改善的 production 證據">Aurora vendor overview</a> 即可。</p>
<h2 id="相關連結">相關連結</h2>
<ul>
<li><a href="/blog/backend/01-database/vendors/aurora/" data-link-title="AWS Aurora" data-link-desc="AWS managed PostgreSQL / MySQL、storage / compute 分離、&#43;75% 效能改善的 production 證據">Aurora vendor overview</a> — 服務定位、適用 / 不適用場景</li>
<li><a href="/blog/backend/knowledge-cards/quorum/" data-link-title="Quorum" data-link-desc="分散式系統以多數節點同意作為提交或讀取有效性的門檻">Quorum 卡片</a> — 概念基底</li>
<li><a href="/blog/backend/knowledge-cards/replication-lag/" data-link-title="Replication Lag" data-link-desc="說明資料副本落後正式來源多久，以及它如何影響讀取正確性">Replication Lag 卡片</a> — 對照通用 replication lag 模型</li>
<li><a href="/blog/posts/vendor-%E6%B7%B1%E5%BA%A6%E6%8A%80%E8%A1%93%E6%96%87%E7%AB%A0%E6%96%B9%E6%B3%95%E8%AB%96%E7%9A%84%E6%BC%94%E5%8C%96%E7%B4%80%E9%8C%84%E5%90%8C-vendor-%E7%B3%BB%E5%88%97%E7%9A%84%E9%96%8B%E5%A0%B4%E8%BC%AA%E6%9B%BF%E9%A9%97%E8%AD%89/" data-link-title="Vendor 深度技術文章方法論的演化紀錄：同 vendor 系列的開場輪替驗證" data-link-desc="vendor overview 飽和後要寫單一功能深度文章、需要選題與結構依據時回來。這套方法論的驗證來源與 cadence variant 在高風險場景（同 vendor sub-tool 系列）的實證。">Vendor 深度技術文章方法論</a> — 本文遵循的 6 規格面寫作模板</li>
<li>官方：<a href="https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/Aurora.Overview.StorageReliability.html">Aurora storage architecture</a></li>
</ul>
]]></content:encoded></item><item><title>Aurora Serverless v2 適用判斷：ACU 自動擴縮、混合 cluster 與何時不該用</title><link>https://tarrragon.github.io/blog/backend/01-database/vendors/aurora/serverless-v2-scaling/</link><pubDate>Tue, 02 Jun 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/backend/01-database/vendors/aurora/serverless-v2-scaling/</guid><description>&lt;p>Aurora Serverless v2 把 instance 的容量從「開機時固定的 instance class」改成「按負載秒級伸縮的 ACU」。它解的問題很具體：固定 provisioned cluster 在離峰時段付滿整台機器的錢、卻只用一小部分；尖峰來時又被 instance class 上限卡住。但 serverless v2 不是「比較便宜的 Aurora」——穩定高負載下它反而比同等 provisioned 貴。要不要用，取決於 workload 的負載形狀是否間歇、是否難預測。&lt;/p>
&lt;p>本文不是 Aurora overview（請看 &lt;a href="https://tarrragon.github.io/blog/backend/01-database/vendors/aurora/" data-link-title="AWS Aurora" data-link-desc="AWS managed PostgreSQL / MySQL、storage / compute 分離、&amp;#43;75% 效能改善的 production 證據">Aurora vendor 頁&lt;/a>）— 而是 Serverless v2 的容量機制、設定與適用邊界的實作層教學。&lt;/p>
&lt;h2 id="核心機制acu-與秒級擴縮">核心機制：ACU 與秒級擴縮&lt;/h2>
&lt;p>Serverless v2 的容量單位是 ACU（Aurora Capacity Unit），一個 ACU 對應一組固定比例的記憶體與運算資源。cluster 不再綁定一個 instance class，而是設一個 ACU 區間（min / max），Aurora 依即時負載在區間內伸縮：&lt;/p>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>屬性&lt;/th>
 &lt;th>Provisioned&lt;/th>
 &lt;th>Serverless v2&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>容量設定&lt;/td>
 &lt;td>固定 instance class（如 db.r6g.xlarge）&lt;/td>
 &lt;td>min / max ACU 區間&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>計費&lt;/td>
 &lt;td>按 instance 開機時數&lt;/td>
 &lt;td>按實際消耗的 ACU-秒&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>擴縮&lt;/td>
 &lt;td>手動改 instance class（有中斷）&lt;/td>
 &lt;td>秒級自動伸縮、無中斷&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>離峰成本&lt;/td>
 &lt;td>付滿整台&lt;/td>
 &lt;td>縮到 min ACU、只付低水位&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>適用負載&lt;/td>
 &lt;td>穩定、可預測&lt;/td>
 &lt;td>間歇、突發、難預測&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;p>&lt;strong>擴縮行為&lt;/strong>：&lt;/p>
&lt;ul>
&lt;li>負載上升時 ACU 平滑增加、不需要切換 instance、無連線中斷&lt;/li>
&lt;li>負載下降時縮回低水位、但受 min ACU 下限約束&lt;/li>
&lt;li>min ACU 決定離峰的最低成本與「保留多少暖容量」；max ACU 決定尖峰的上限與成本天花板&lt;/li>
&lt;/ul>
&lt;blockquote>
&lt;p>&lt;strong>Scope warning&lt;/strong>：「ACU 對應的記憶體比例」「serverless v2 是否能縮到 0」「最小 ACU 粒度」這些屬 AWS vendor 規格、會隨版本演進（auto-pause 等能力陸續調整）、實作時 cross-verify 官方 doc 當前值。本文不含 production case 揭露的 ACU 配置數字。&lt;/p>&lt;/blockquote>
&lt;p>對應 knowledge card：&lt;a href="https://tarrragon.github.io/blog/backend/knowledge-cards/peak-forecast/" data-link-title="Peak Forecast" data-link-desc="說明預期峰值流量的預測方法 — 容量規劃的第一個輸入">peak forecast&lt;/a>、&lt;a href="https://tarrragon.github.io/blog/backend/knowledge-cards/cost-per-request/" data-link-title="Cost Per Request" data-link-desc="把雲端成本拆到單一 API 請求的 unit economics 模型">cost per request&lt;/a>。&lt;/p>
&lt;h2 id="min--max-acu-的設定權衡">min / max ACU 的設定權衡&lt;/h2>
&lt;p>min 與 max ACU 不是隨便設，兩端各自承擔不同風險。&lt;/p>
&lt;p>&lt;strong>min ACU 太低&lt;/strong>：離峰省錢，但流量回升時從很低的水位往上爬、爬升期間可能容量不足、且 buffer cache 在低 ACU 時被壓縮、回升後 cache 重新暖機、query latency 短暫升高。對延遲敏感、又有規律日週期的 workload，min ACU 不要壓到極限。&lt;/p>
&lt;p>&lt;strong>max ACU 太低&lt;/strong>：尖峰被天花板卡住、等同 provisioned 的 instance class 上限問題又回來。max ACU 要按「預期尖峰 + 餘量」設，並把它當成成本天花板來監控——max 設太高雖然不會平時就花錢，但失控 query（如缺索引的全表掃描）可能把 ACU 一路推到 max、帳單尖峰。&lt;/p>
&lt;p>&lt;strong>暖容量考量&lt;/strong>：min ACU 同時決定「保留多少隨時可用的暖容量」。完全不可預測、且要求第一個請求就低延遲的場景，min ACU 要留足暖機水位，不能為了省錢設到最低。&lt;/p>
&lt;h2 id="混合-clusterserverless--provisioned-並存">混合 cluster：serverless + provisioned 並存&lt;/h2>
&lt;p>Serverless v2 不是「整個 cluster 要嘛全 serverless、要嘛全 provisioned」。同一個 Aurora cluster 可以混用：writer 用 provisioned 保穩定、read replica 用 serverless v2 吸收讀取尖峰；或反過來。這讓 workload 的不同部分各取所需：&lt;/p></description><content:encoded><![CDATA[<p>Aurora Serverless v2 把 instance 的容量從「開機時固定的 instance class」改成「按負載秒級伸縮的 ACU」。它解的問題很具體：固定 provisioned cluster 在離峰時段付滿整台機器的錢、卻只用一小部分；尖峰來時又被 instance class 上限卡住。但 serverless v2 不是「比較便宜的 Aurora」——穩定高負載下它反而比同等 provisioned 貴。要不要用，取決於 workload 的負載形狀是否間歇、是否難預測。</p>
<p>本文不是 Aurora overview（請看 <a href="/blog/backend/01-database/vendors/aurora/" data-link-title="AWS Aurora" data-link-desc="AWS managed PostgreSQL / MySQL、storage / compute 分離、&#43;75% 效能改善的 production 證據">Aurora vendor 頁</a>）— 而是 Serverless v2 的容量機制、設定與適用邊界的實作層教學。</p>
<h2 id="核心機制acu-與秒級擴縮">核心機制：ACU 與秒級擴縮</h2>
<p>Serverless v2 的容量單位是 ACU（Aurora Capacity Unit），一個 ACU 對應一組固定比例的記憶體與運算資源。cluster 不再綁定一個 instance class，而是設一個 ACU 區間（min / max），Aurora 依即時負載在區間內伸縮：</p>
<table>
  <thead>
      <tr>
          <th>屬性</th>
          <th>Provisioned</th>
          <th>Serverless v2</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>容量設定</td>
          <td>固定 instance class（如 db.r6g.xlarge）</td>
          <td>min / max ACU 區間</td>
      </tr>
      <tr>
          <td>計費</td>
          <td>按 instance 開機時數</td>
          <td>按實際消耗的 ACU-秒</td>
      </tr>
      <tr>
          <td>擴縮</td>
          <td>手動改 instance class（有中斷）</td>
          <td>秒級自動伸縮、無中斷</td>
      </tr>
      <tr>
          <td>離峰成本</td>
          <td>付滿整台</td>
          <td>縮到 min ACU、只付低水位</td>
      </tr>
      <tr>
          <td>適用負載</td>
          <td>穩定、可預測</td>
          <td>間歇、突發、難預測</td>
      </tr>
  </tbody>
</table>
<p><strong>擴縮行為</strong>：</p>
<ul>
<li>負載上升時 ACU 平滑增加、不需要切換 instance、無連線中斷</li>
<li>負載下降時縮回低水位、但受 min ACU 下限約束</li>
<li>min ACU 決定離峰的最低成本與「保留多少暖容量」；max ACU 決定尖峰的上限與成本天花板</li>
</ul>
<blockquote>
<p><strong>Scope warning</strong>：「ACU 對應的記憶體比例」「serverless v2 是否能縮到 0」「最小 ACU 粒度」這些屬 AWS vendor 規格、會隨版本演進（auto-pause 等能力陸續調整）、實作時 cross-verify 官方 doc 當前值。本文不含 production case 揭露的 ACU 配置數字。</p></blockquote>
<p>對應 knowledge card：<a href="/blog/backend/knowledge-cards/peak-forecast/" data-link-title="Peak Forecast" data-link-desc="說明預期峰值流量的預測方法 — 容量規劃的第一個輸入">peak forecast</a>、<a href="/blog/backend/knowledge-cards/cost-per-request/" data-link-title="Cost Per Request" data-link-desc="把雲端成本拆到單一 API 請求的 unit economics 模型">cost per request</a>。</p>
<h2 id="min--max-acu-的設定權衡">min / max ACU 的設定權衡</h2>
<p>min 與 max ACU 不是隨便設，兩端各自承擔不同風險。</p>
<p><strong>min ACU 太低</strong>：離峰省錢，但流量回升時從很低的水位往上爬、爬升期間可能容量不足、且 buffer cache 在低 ACU 時被壓縮、回升後 cache 重新暖機、query latency 短暫升高。對延遲敏感、又有規律日週期的 workload，min ACU 不要壓到極限。</p>
<p><strong>max ACU 太低</strong>：尖峰被天花板卡住、等同 provisioned 的 instance class 上限問題又回來。max ACU 要按「預期尖峰 + 餘量」設，並把它當成成本天花板來監控——max 設太高雖然不會平時就花錢，但失控 query（如缺索引的全表掃描）可能把 ACU 一路推到 max、帳單尖峰。</p>
<p><strong>暖容量考量</strong>：min ACU 同時決定「保留多少隨時可用的暖容量」。完全不可預測、且要求第一個請求就低延遲的場景，min ACU 要留足暖機水位，不能為了省錢設到最低。</p>
<h2 id="混合-clusterserverless--provisioned-並存">混合 cluster：serverless + provisioned 並存</h2>
<p>Serverless v2 不是「整個 cluster 要嘛全 serverless、要嘛全 provisioned」。同一個 Aurora cluster 可以混用：writer 用 provisioned 保穩定、read replica 用 serverless v2 吸收讀取尖峰；或反過來。這讓 workload 的不同部分各取所需：</p>
<ul>
<li>穩定的寫入路徑用 provisioned instance、成本可預測</li>
<li>間歇的讀取分析、報表副本用 serverless v2、平時縮到低水位</li>
<li>failover 目標可指定 provisioned 或 serverless，依可用性需求</li>
</ul>
<p>混合配置的判讀是把 cluster 內每個角色當獨立的負載形狀評估，而非整個 cluster 一刀切。</p>
<h2 id="操作流程">操作流程</h2>
<p>從負載形狀評估到上線的 6 步流程。</p>
<h4 id="step-1判斷負載形狀">Step 1：判斷負載形狀</h4>
<p>用 CloudWatch 過去 30 天的 CPU / connection / IOPS，看負載是穩定平緩、規律日週期、還是不規則突發：</p>
<ul>
<li>穩定高負載（平均使用率高、波動小）→ provisioned 通常更划算</li>
<li>間歇 / 突發 / 開發測試 / 多租戶各自小 DB → serverless v2 適合</li>
<li>規律日週期（白天高晚上低）→ serverless v2 或 provisioned + scheduled 都可，算成本 crossover</li>
</ul>
<h4 id="step-2估-min--max-acu">Step 2：估 min / max ACU</h4>
<p>min 依離峰最低負載 + 暖容量需求；max 依尖峰負載 + 餘量。第一次設保守一點、上線後依實際 ACU 曲線收斂。</p>
<h4 id="step-3建立或轉換">Step 3：建立或轉換</h4>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl"><span class="c1"># 新 cluster 指定 serverless v2 capacity range</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">aws rds create-db-cluster <span class="se">\
</span></span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="se"></span>  --db-cluster-identifier my-cluster <span class="se">\
</span></span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="se"></span>  --engine aurora-postgresql <span class="se">\
</span></span></span><span class="line"><span class="ln">5</span><span class="cl"><span class="se"></span>  --serverless-v2-scaling-configuration <span class="nv">MinCapacity</span><span class="o">=</span>2,MaxCapacity<span class="o">=</span><span class="m">32</span></span></span></code></pre></div><p>既有 provisioned cluster 可加 serverless v2 reader、逐步驗證再調整 writer。</p>
<h4 id="step-4觀察-acu-曲線">Step 4：觀察 ACU 曲線</h4>
<p>上線後盯 <code>ServerlessDatabaseCapacity</code>（即時 ACU）與 <code>ACUUtilization</code>，確認伸縮符合負載、min/max 設定合理。</p>
<h4 id="step-5成本對照">Step 5：成本對照</h4>
<p>把實際 ACU-秒換算的帳單，跟「同等 provisioned instance 全時段開機」對照。若 serverless 帳單接近或超過 provisioned，代表負載其實夠穩定、該回 provisioned。</p>
<h4 id="step-6驗證點">Step 6：驗證點</h4>





<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"># 驗證離峰真的縮到 min ACU（看 ServerlessDatabaseCapacity 低谷）
</span></span><span class="line"><span class="ln">2</span><span class="cl"># 驗證尖峰沒撞 max ACU 天花板（看是否長時間貼著 max）
</span></span><span class="line"><span class="ln">3</span><span class="cl"># 驗證回升期 latency 可接受（min ACU 暖容量是否足夠）</span></span></code></pre></div><p><strong>Rollback boundary</strong>：serverless v2 與 provisioned 可互轉、reader 先轉驗證再動 writer；轉換本身有短暫中斷，要排 maintenance window。</p>
<h2 id="失敗模式">失敗模式</h2>
<p>production 常見的 5 個踩雷：</p>
<h4 id="case-1穩定高負載用-serverless-反而更貴">Case 1：穩定高負載用 serverless 反而更貴</h4>
<p>把一個 7x24 高使用率的 cluster 改 serverless「以為省錢」，實際 ACU 幾乎全時段貼近高水位、按 ACU-秒計費比固定 instance 貴。修法：穩定高負載用 provisioned；serverless 的省錢前提是「有顯著的離峰可以縮」。</p>
<h4 id="case-2min-acu-設太低回升期-latency-尖刺">Case 2：min ACU 設太低、回升期 latency 尖刺</h4>
<p>離峰縮到極低、早上流量回來時 cache 冷、ACU 從低水位爬、前幾分鐘 query 變慢。修法：規律日週期的 workload，min ACU 留足暖容量；或用 provisioned + scheduled scaling 處理可預測的日週期。</p>
<h4 id="case-3max-acu-沒當成本天花板監控">Case 3：max ACU 沒當成本天花板監控</h4>
<p>缺索引的 query 觸發全表掃描、ACU 一路衝到 max、帳單尖峰才發現。修法：max ACU 設合理上限 + CloudWatch alarm 盯 ACU 長時間貼 max（那是 query 或容量問題的訊號，不是正常擴縮）。</p>
<h4 id="case-4把-serverless-當不用做容量規劃">Case 4：把 serverless 當「不用做容量規劃」</h4>
<p>以為 serverless 自動伸縮就不必估容量、min/max 隨便設。修法：serverless 改變的是「不用手動切 instance」，不是「不用理解負載形狀」；min/max 仍要基於負載曲線設定。</p>
<h4 id="case-5對延遲極敏感的-oltp-全-serverless">Case 5：對延遲極敏感的 OLTP 全 serverless</h4>
<p>核心交易路徑要求穩定低延遲、卻用會伸縮的 serverless writer、伸縮邊界期間 latency 抖動。修法：穩定低延遲的核心寫入用 provisioned writer，serverless 留給可容忍伸縮抖動的讀取 / 分析副本（混合 cluster）。</p>
<p><strong>Anti-recommendation</strong>：負載穩定、使用率長期偏高、或對延遲抖動零容忍的核心 OLTP → 用 provisioned；serverless v2 的價值在「間歇、突發、難預測、或有大量離峰」的負載，沒有離峰可縮就沒有省錢空間。</p>
<h2 id="容量與觀測">容量與觀測</h2>
<p>CloudWatch metric：</p>
<ul>
<li><code>ServerlessDatabaseCapacity</code>：即時 ACU、看伸縮曲線</li>
<li><code>ACUUtilization</code>：ACU 使用率、判斷 min/max 設定是否合理</li>
<li><code>CPUUtilization</code> / <code>DatabaseConnections</code>：底層負載、對照 ACU 是否跟得上</li>
</ul>
<p><strong>判讀</strong>：</p>
<ul>
<li>ACU 長時間貼近 max → max 設太低或有失控 query，要查</li>
<li>ACU 長時間貼近 min 且使用率低 → 負載其實很輕，min 可能可再降、或這個 cluster 適合更小配置</li>
<li>ACU 幾乎不波動且水位高 → 負載穩定，serverless 沒發揮價值，評估改 provisioned</li>
</ul>
<blockquote>
<p><strong>Scope warning</strong>：本文未引用 production case 的 ACU 數字；上述 metric 與判讀屬 vendor 規格 + 通用容量工程。</p></blockquote>
<p>接回 <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>、<a href="/blog/backend/01-database/vendors/aurora/" data-link-title="AWS Aurora" data-link-desc="AWS managed PostgreSQL / MySQL、storage / compute 分離、&#43;75% 效能改善的 production 證據">Aurora 容量規劃要點</a>。</p>
<h2 id="邊界與整合">邊界與整合</h2>
<h3 id="serverless-v2-vs-provisioned--scheduled-scaling">Serverless v2 vs provisioned + scheduled scaling</h3>
<p>兩者都能處理「負載隨時間變」，但適用場景不同：</p>
<ul>
<li><strong>scheduled scaling（provisioned）</strong>：負載 <em>可預測</em>（已知的日週期、已知大活動）→ 預先排程改容量，成本最可控</li>
<li><strong>serverless v2</strong>：負載 <em>不可預測</em>（突發、不規則）→ 自動伸縮吸收，不需預測</li>
</ul>
<p>可預測的尖峰用 scheduled、不可預測的用 serverless，這跟 <a href="/blog/backend/01-database/vendors/dynamodb/on-demand-vs-provisioned/" data-link-title="DynamoDB On-Demand vs Provisioned：6 軸決策、auto-scaling 邊界與 cost crossover" data-link-desc="capacity mode 選擇不是單軸 peak/avg ratio；本文展開 6 軸決策（peak/avg / 讀寫比 trend / surge 暫時 vs 永久 baseline / predictable-peak vs flash-sale / DBA 工時釋放 / vendor vs 自管 cost crossover），含 Zomato 50% 成本下降、Zoom 30x permanent surge、Amazon Ads sustained workload 等 case 分軸 anchor">DynamoDB capacity mode</a> 的 predictable-peak vs flash-sale 判讀同源。</p>
<h3 id="sibling-與-cross-link">Sibling 與 cross-link</h3>
<ul>
<li><a href="/blog/backend/01-database/vendors/aurora/storage-architecture/" data-link-title="Aurora Storage Architecture：quorum-based 分散式 log 與韌性即性能設計" data-link-desc="Aurora storage / compute 分離、6-way 跨 AZ replication、4-of-6 write / 3-of-6 read quorum、韌性投資自動 amortize 成 read 性能、DraftKings 6ms 寫 / &lt;1ms 讀 production reference">storage-architecture</a> — serverless 只改 compute 層容量、storage 層 quorum 設計不變</li>
<li><a href="/blog/backend/01-database/vendors/aurora/read-replica-scaling/" data-link-title="Aurora Read Replica Scaling：15 replica 上限、lag profile、headroom 預留與 fleet 治理" data-link-desc="Aurora 15 replica 上限、共享 storage 為什麼能養大量 replica、事件型容量分級表、DraftKings headroom 預留判讀、FanDuel 雙 SLO 並行、fleet 治理 3 條 driver（business sharding / microservice / 合規）">read-replica-scaling</a> — serverless reader 吸收讀取尖峰、與 fleet 治理結合</li>
<li><a href="/blog/backend/01-database/vendors/postgresql/aurora-io-optimized-cost/" data-link-title="Aurora PostgreSQL I/O-Optimized Cost" data-link-desc="Aurora PostgreSQL Standard 與 I/O-Optimized 的成本模型、I/O 壓力、workload 判斷、遷移與回退條件">Aurora I/O-Optimized cost</a> — serverless 算的是 compute（ACU）成本、I/O-Optimized 算的是 storage I/O 成本，兩個成本軸獨立、要分開評估</li>
<li><a href="/blog/backend/01-database/vendors/aurora/rds-proxy-connection-pooling/" data-link-title="Aurora RDS Proxy 與連線管理：connection multiplexing、pinning 陷阱與 failover 加速" data-link-desc="RDS Proxy 不是「連上去就自動省連線」；本文展開 connection multiplexing 機制、哪些 session 操作會觸發 pinning 讓 multiplexing 失效、failover 期間 proxy 如何保持 client 連線縮短中斷，以及 RDS Proxy 與自管 pgbouncer 的責任切分">rds-proxy-connection-pooling</a> — serverless + Lambda 場景的連線管理</li>
<li>替代路由：負載穩定且高 → provisioned；KV access pattern → <a href="/blog/backend/01-database/vendors/dynamodb/" data-link-title="DynamoDB" data-link-desc="AWS managed key-value、partition-based scaling、9000 萬 RPS sustained 實戰證據">DynamoDB</a></li>
<li>跟 <a href="/blog/backend/09-performance-capacity/cases/netflix-aurora-consolidation/" data-link-title="9.C23 Netflix：把關聯式 DB 統一到 Aurora、效能 &#43;75%、成本 -28%" data-link-desc="Netflix 把多套關聯式 DB 統一到 Aurora、效能提升 75%、成本下降 28%、串流數十億小時">Netflix 9.C23</a> 互引：polyglot 架構下不同 workload 用不同 Aurora 配置（穩定 OLTP provisioned、間歇副本 serverless）</li>
</ul>
]]></content:encoded></item><item><title>Aurora 多 cluster 按業務切分：微服務私有 store、blast radius 隔離與 fleet 治理</title><link>https://tarrragon.github.io/blog/backend/01-database/vendors/aurora/multi-cluster-business-split/</link><pubDate>Tue, 02 Jun 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/backend/01-database/vendors/aurora/multi-cluster-business-split/</guid><description>&lt;p>把所有服務的資料塞進一個大 Aurora cluster，平時運維最省事，直到某一天：報表服務跑了一個沒索引的聚合 query、佔滿 connection 與 IOPS、結帳服務跟著變慢、整個平台一起卡。問題的根源是「不相關的業務共用同一個 cluster、彼此沒有隔離」，那個 query 只是觸發點。多 cluster 按業務切分要回答的是：哪些業務該各自獨立 cluster、哪些可以共用、切分後 fleet 怎麼維持治理一致。&lt;/p>
&lt;p>本文不是 Aurora overview（請看 &lt;a href="https://tarrragon.github.io/blog/backend/01-database/vendors/aurora/" data-link-title="AWS Aurora" data-link-desc="AWS managed PostgreSQL / MySQL、storage / compute 分離、&amp;#43;75% 效能改善的 production 證據">Aurora vendor 頁&lt;/a>）— 而是 cluster 邊界劃分與多 cluster 治理的實作層教學。&lt;/p>
&lt;h2 id="共用大-cluster-的根本問題blast-radius">共用大 cluster 的根本問題：blast radius&lt;/h2>
&lt;p>單一大 cluster 把多個業務的失敗耦合在一起。一個業務的異常會透過共用資源外溢到其他業務：&lt;/p>
&lt;ul>
&lt;li>&lt;strong>資源競爭&lt;/strong>：connection pool、CPU、IOPS、buffer cache 共用，一個業務的尖峰擠壓其他業務&lt;/li>
&lt;li>&lt;strong>failure blast radius&lt;/strong>：cluster 故障 / 升級 / schema 變更鎖表，影響所有掛在上面的業務&lt;/li>
&lt;li>&lt;strong>容量規劃糾纏&lt;/strong>：要為「所有業務尖峰的總和」規劃容量，無法針對單一業務調整&lt;/li>
&lt;li>&lt;strong>schema change 互相牽制&lt;/strong>：一個業務的 migration 鎖表、其他業務跟著受影響&lt;/li>
&lt;/ul>
&lt;p>按業務切 cluster 的核心價值是把這些耦合切開——每個 cluster 的故障、容量、變更只影響自己的業務範圍。&lt;/p>
&lt;h2 id="切分判斷維度">切分判斷維度&lt;/h2>
&lt;p>不是「每個服務都該有自己的 cluster」（那會走向另一個極端：cluster 數爆炸、運維 surface 失控）。切分依以下維度判斷：&lt;/p>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>維度&lt;/th>
 &lt;th>傾向獨立 cluster&lt;/th>
 &lt;th>可共用 cluster&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>業務關鍵性&lt;/td>
 &lt;td>核心交易（結帳、帳本）需隔離保護&lt;/td>
 &lt;td>內部工具、低關鍵性服務可共用&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>負載形狀&lt;/td>
 &lt;td>負載差異大、尖峰時段錯開&lt;/td>
 &lt;td>負載相近、可一起規劃容量&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>故障容忍&lt;/td>
 &lt;td>不能被別的業務拖垮&lt;/td>
 &lt;td>可接受共命運&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>schema 變更頻率&lt;/td>
 &lt;td>高頻 migration、不想牽制別人&lt;/td>
 &lt;td>低頻、變更少&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>合規邊界&lt;/td>
 &lt;td>資料需獨立隔離（PCI / 個資分艙）&lt;/td>
 &lt;td>無特殊合規隔離需求&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;p>&lt;code>9.C23 Netflix&lt;/code> 是這個判斷的 case anchor：Netflix 把過往多套不同 &lt;em>種類&lt;/em> 的關聯式 DB（PostgreSQL / MySQL / Oracle）整合到 Aurora、效能提升最高 75%、成本下降 28%；但整合的是「DB 種類 / 運維 surface」，&lt;em>不是&lt;/em> 把所有資料塞進一個 cluster——Netflix 的微服務各自擁有自己的 Aurora cluster、彼此不共用。兩件事同時成立：減少 DB &lt;em>技術種類&lt;/em> 降低運維知識負擔、同時維持 &lt;em>per-service cluster&lt;/em> 隔離 blast radius。&lt;/p>
&lt;blockquote>
&lt;p>&lt;strong>Scope warning&lt;/strong>：Netflix 的「+75% 效能 / -28% 成本」是跨多 workload 的最大改善幅度、非每個 workload 都 +75%（case 原文已標明）；且 Netflix 數據層遠不止 Aurora（還有 Cassandra / EVCache / Iceberg），Aurora 承擔的是需要 ACID 的 OLTP。引用時不可外推成「整合到 Aurora 就 +75%」。&lt;/p>&lt;/blockquote>
&lt;h2 id="兩種切分哲學的對照">兩種切分哲學的對照&lt;/h2>
&lt;p>大規模平台的 cluster 切分沒有單一正解，光譜兩端各有代表：&lt;/p>
&lt;ul>
&lt;li>&lt;strong>per-service 私有 store（Netflix 式）&lt;/strong>：每個微服務一個 Aurora cluster、容量規劃變成「每個服務各自規劃」、跨服務 contention 變成 &lt;em>網路議題&lt;/em> 而非 &lt;em>DB lock 議題&lt;/em>&lt;/li>
&lt;li>&lt;strong>高度 consolidation&lt;/strong>：少數大 cluster 承載多業務、運維實例少、但 blast radius 大&lt;/li>
&lt;/ul>
&lt;p>實務多落在中間：核心 / 高關鍵 / 合規敏感業務各自獨立 cluster，低關鍵性的內部服務可數個共用一個 cluster。判斷的是「這群業務能不能接受共命運」。&lt;/p>
&lt;h2 id="fleet-治理切分後的一致性">Fleet 治理：切分後的一致性&lt;/h2>
&lt;p>切成多 cluster 後，運維 surface 從「一個 cluster」變成「N 個 cluster」。若沒有治理一致性，N 個 cluster 各自飄移會比一個大 cluster 更難維護。fleet 治理要把以下標準化：&lt;/p></description><content:encoded><![CDATA[<p>把所有服務的資料塞進一個大 Aurora cluster，平時運維最省事，直到某一天：報表服務跑了一個沒索引的聚合 query、佔滿 connection 與 IOPS、結帳服務跟著變慢、整個平台一起卡。問題的根源是「不相關的業務共用同一個 cluster、彼此沒有隔離」，那個 query 只是觸發點。多 cluster 按業務切分要回答的是：哪些業務該各自獨立 cluster、哪些可以共用、切分後 fleet 怎麼維持治理一致。</p>
<p>本文不是 Aurora overview（請看 <a href="/blog/backend/01-database/vendors/aurora/" data-link-title="AWS Aurora" data-link-desc="AWS managed PostgreSQL / MySQL、storage / compute 分離、&#43;75% 效能改善的 production 證據">Aurora vendor 頁</a>）— 而是 cluster 邊界劃分與多 cluster 治理的實作層教學。</p>
<h2 id="共用大-cluster-的根本問題blast-radius">共用大 cluster 的根本問題：blast radius</h2>
<p>單一大 cluster 把多個業務的失敗耦合在一起。一個業務的異常會透過共用資源外溢到其他業務：</p>
<ul>
<li><strong>資源競爭</strong>：connection pool、CPU、IOPS、buffer cache 共用，一個業務的尖峰擠壓其他業務</li>
<li><strong>failure blast radius</strong>：cluster 故障 / 升級 / schema 變更鎖表，影響所有掛在上面的業務</li>
<li><strong>容量規劃糾纏</strong>：要為「所有業務尖峰的總和」規劃容量，無法針對單一業務調整</li>
<li><strong>schema change 互相牽制</strong>：一個業務的 migration 鎖表、其他業務跟著受影響</li>
</ul>
<p>按業務切 cluster 的核心價值是把這些耦合切開——每個 cluster 的故障、容量、變更只影響自己的業務範圍。</p>
<h2 id="切分判斷維度">切分判斷維度</h2>
<p>不是「每個服務都該有自己的 cluster」（那會走向另一個極端：cluster 數爆炸、運維 surface 失控）。切分依以下維度判斷：</p>
<table>
  <thead>
      <tr>
          <th>維度</th>
          <th>傾向獨立 cluster</th>
          <th>可共用 cluster</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>業務關鍵性</td>
          <td>核心交易（結帳、帳本）需隔離保護</td>
          <td>內部工具、低關鍵性服務可共用</td>
      </tr>
      <tr>
          <td>負載形狀</td>
          <td>負載差異大、尖峰時段錯開</td>
          <td>負載相近、可一起規劃容量</td>
      </tr>
      <tr>
          <td>故障容忍</td>
          <td>不能被別的業務拖垮</td>
          <td>可接受共命運</td>
      </tr>
      <tr>
          <td>schema 變更頻率</td>
          <td>高頻 migration、不想牽制別人</td>
          <td>低頻、變更少</td>
      </tr>
      <tr>
          <td>合規邊界</td>
          <td>資料需獨立隔離（PCI / 個資分艙）</td>
          <td>無特殊合規隔離需求</td>
      </tr>
  </tbody>
</table>
<p><code>9.C23 Netflix</code> 是這個判斷的 case anchor：Netflix 把過往多套不同 <em>種類</em> 的關聯式 DB（PostgreSQL / MySQL / Oracle）整合到 Aurora、效能提升最高 75%、成本下降 28%；但整合的是「DB 種類 / 運維 surface」，<em>不是</em> 把所有資料塞進一個 cluster——Netflix 的微服務各自擁有自己的 Aurora cluster、彼此不共用。兩件事同時成立：減少 DB <em>技術種類</em> 降低運維知識負擔、同時維持 <em>per-service cluster</em> 隔離 blast radius。</p>
<blockquote>
<p><strong>Scope warning</strong>：Netflix 的「+75% 效能 / -28% 成本」是跨多 workload 的最大改善幅度、非每個 workload 都 +75%（case 原文已標明）；且 Netflix 數據層遠不止 Aurora（還有 Cassandra / EVCache / Iceberg），Aurora 承擔的是需要 ACID 的 OLTP。引用時不可外推成「整合到 Aurora 就 +75%」。</p></blockquote>
<h2 id="兩種切分哲學的對照">兩種切分哲學的對照</h2>
<p>大規模平台的 cluster 切分沒有單一正解，光譜兩端各有代表：</p>
<ul>
<li><strong>per-service 私有 store（Netflix 式）</strong>：每個微服務一個 Aurora cluster、容量規劃變成「每個服務各自規劃」、跨服務 contention 變成 <em>網路議題</em> 而非 <em>DB lock 議題</em></li>
<li><strong>高度 consolidation</strong>：少數大 cluster 承載多業務、運維實例少、但 blast radius 大</li>
</ul>
<p>實務多落在中間：核心 / 高關鍵 / 合規敏感業務各自獨立 cluster，低關鍵性的內部服務可數個共用一個 cluster。判斷的是「這群業務能不能接受共命運」。</p>
<h2 id="fleet-治理切分後的一致性">Fleet 治理：切分後的一致性</h2>
<p>切成多 cluster 後，運維 surface 從「一個 cluster」變成「N 個 cluster」。若沒有治理一致性，N 個 cluster 各自飄移會比一個大 cluster 更難維護。fleet 治理要把以下標準化：</p>
<ul>
<li><strong>配置一致</strong>：engine 版本、parameter group、backup 策略、加密設定用 IaC 統一管理，避免逐個手調漂移</li>
<li><strong>監控一致</strong>：每個 cluster 同一套 CloudWatch alarm 基線（connection / replication lag / CPU / IOPS），不是只盯總量</li>
<li><strong>升級協調</strong>：major version 升級分批跨 fleet，不是一次全升（也不是放任各 cluster 版本散落）</li>
<li><strong>成本歸屬</strong>：按 cluster / 業務 tag 切成本，讓每個業務看見自己的 DB 成本</li>
</ul>
<p>這層治理對應 <a href="/blog/backend/01-database/vendors/aurora/read-replica-scaling/" data-link-title="Aurora Read Replica Scaling：15 replica 上限、lag profile、headroom 預留與 fleet 治理" data-link-desc="Aurora 15 replica 上限、共享 storage 為什麼能養大量 replica、事件型容量分級表、DraftKings headroom 預留判讀、FanDuel 雙 SLO 並行、fleet 治理 3 條 driver（business sharding / microservice / 合規）">read-replica-scaling 的 fleet 治理段</a>——讀副本 fleet 與多 cluster fleet 共用「N 個實例如何維持治理一致」的方法。</p>
<h2 id="失敗模式">失敗模式</h2>
<p>production 常見的踩雷：</p>
<h4 id="case-1共用大-cluster報表-query-拖垮交易">Case 1：共用大 cluster、報表 query 拖垮交易</h4>
<p>分析 / 報表 workload 跟核心交易共用 cluster、一個重 query 佔滿資源、交易延遲飆高。修法：分析類 workload 切到獨立 cluster 或獨立 read replica；核心交易的 cluster 不混入不可控的分析查詢。</p>
<h4 id="case-2cluster-切太細運維-surface-爆炸">Case 2：cluster 切太細、運維 surface 爆炸</h4>
<p>矯枉過正、每個小服務都獨立 cluster、結果幾十個 cluster 各自飄移、升級與監控成本失控。修法：低關鍵性、負載相近、可共命運的服務合併共用 cluster；切分以「blast radius 需求」為準，不是「每個服務都要」。</p>
<h4 id="case-3切分了-cluster-但沒切分-fleet-治理">Case 3：切分了 cluster 但沒切分 fleet 治理</h4>
<p>多 cluster 各自手調 parameter group、版本散落、backup 策略不一、出事才發現某個 cluster 設定漂移。修法：fleet 配置用 IaC 統一、監控基線一致、升級分批協調。</p>
<h4 id="case-4跨-cluster-交易需求才發現切錯邊界">Case 4：跨 cluster 交易需求才發現切錯邊界</h4>
<p>把本該強一致綁在一起的資料切到不同 cluster、結果需要跨 cluster 交易（Aurora 不提供跨 cluster transaction）、application 層自己補償、複雜又易錯。修法：cluster 邊界要對齊 transaction boundary——必須在同一個交易內一起成功失敗的資料，放同一 cluster（對應 <a href="/blog/backend/01-database/transaction-boundary/" data-link-title="1.3 Transaction 與一致性邊界" data-link-desc="交易邊界、isolation level、retry 策略、distributed transaction（2PC、Saga）與跨 region 強一致取捨">1.3 transaction 與一致性邊界</a>）。這是切分前就要確認的邊界，切錯後重切成本高。</p>
<p><strong>Anti-recommendation</strong>：團隊規模小、服務少、無合規隔離需求、且負載總量單一 cluster 撐得住 → 不要預先切成多 cluster；多 cluster 的治理成本只在「blast radius 隔離 / 合規分艙 / 負載差異大」真正需要時才值得。從少到多容易，從多合併回少要資料遷移。</p>
<h2 id="容量與觀測">容量與觀測</h2>
<ul>
<li>每個 cluster 獨立的 CloudWatch 基線：<code>DatabaseConnections</code> / <code>CPUUtilization</code> / <code>AuroraReplicaLag</code> / IOPS</li>
<li>跨 fleet 的成本 dashboard：按 cluster / 業務 tag 歸屬，看哪個業務的 DB 成本成長最快</li>
<li>blast radius 演練：定期確認單一 cluster 故障不會外溢到其他業務（混沌測試）</li>
</ul>
<blockquote>
<p><strong>Scope warning</strong>：本文未引用 production case 的 cluster 數量 / 容量數字；切分維度與治理項屬通用平台工程 + Netflix consolidation 的架構訊號。</p></blockquote>
<p>接回 <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>、<a href="/blog/backend/05-deployment-platform/" data-link-title="模組五：部署平台與網路入口" data-link-desc="整理 Kubernetes、systemd、load balancer、container 與服務生命週期合約">05 部署平台模組</a> 的 service decomposition。</p>
<h2 id="邊界與整合">邊界與整合</h2>
<h3 id="cluster-邊界-vs-微服務邊界">cluster 邊界 vs 微服務邊界</h3>
<p>多 cluster 切分常跟微服務拆分一起發生，但兩者不必一一對應。一個微服務可以擁有一個 cluster（Netflix 式私有 store），數個低關鍵微服務也可共用一個 cluster。判斷錨點是 transaction boundary 與 blast radius，不是「服務數 = cluster 數」。當切分壓力其實來自「不同資料模型」而非「隔離需求」，可能該考慮的是 polyglot persistence（OLTP 用 Aurora、KV 用 DynamoDB、analytics 用數倉），而非切更多 Aurora cluster。</p>
<h3 id="sibling-與-cross-link">Sibling 與 cross-link</h3>
<ul>
<li><a href="/blog/backend/01-database/vendors/aurora/read-replica-scaling/" data-link-title="Aurora Read Replica Scaling：15 replica 上限、lag profile、headroom 預留與 fleet 治理" data-link-desc="Aurora 15 replica 上限、共享 storage 為什麼能養大量 replica、事件型容量分級表、DraftKings headroom 預留判讀、FanDuel 雙 SLO 並行、fleet 治理 3 條 driver（business sharding / microservice / 合規）">read-replica-scaling</a> — fleet 治理方法共用、讀副本 fleet 與多 cluster fleet 同源</li>
<li><a href="/blog/backend/01-database/vendors/aurora/cross-az-failover-rto/" data-link-title="Aurora Cross-AZ Failover：RTO 量測、endpoint routing 與 application reconnect 契約" data-link-desc="Aurora cross-AZ failover lifecycle（detection / promotion / DNS update）、&lt; 30 秒 RTO、application DNS cache 跟 connection pool 對齊、Standard Chartered 受監管場景為什麼用獨立 cluster 而非 Global Database failover">cross-az-failover-rto</a> — 每個 cluster 的 failover 行為、blast radius 隔離後各自獨立</li>
<li><a href="/blog/backend/01-database/vendors/aurora/serverless-v2-scaling/" data-link-title="Aurora Serverless v2 適用判斷：ACU 自動擴縮、混合 cluster 與何時不該用" data-link-desc="Aurora Serverless v2 不是「比較便宜的 Aurora」；本文展開 ACU 計費粒度、秒級自動擴縮機制、min/max ACU 設定、serverless 與 provisioned 同 cluster 混用，以及穩定高負載下 serverless 反而更貴的成本 crossover 邊界">serverless-v2-scaling</a> — 低關鍵 / 間歇負載的 cluster 可用 serverless 降離峰成本</li>
<li><a href="/blog/backend/01-database/state-ownership-query-boundary/" data-link-title="1.8 State Ownership 與 Query Boundary" data-link-desc="正式狀態 vs 派生狀態的責任分層、CQRS / event sourcing / materialized view、四種 query 邊界">1.8 State Ownership 與 Query Boundary</a> — cluster 邊界對齊狀態 ownership</li>
<li>替代路由：切分壓力來自資料模型差異 → polyglot persistence、回 <a href="/blog/backend/00-service-selection/" data-link-title="模組零：後端服務選型" data-link-desc="從需求類型判斷資料庫、快取、訊息佇列、觀測與部署平台的選型方向">00 服務選型模組</a></li>
<li>跟 <a href="/blog/backend/09-performance-capacity/cases/netflix-aurora-consolidation/" data-link-title="9.C23 Netflix：把關聯式 DB 統一到 Aurora、效能 &#43;75%、成本 -28%" data-link-desc="Netflix 把多套關聯式 DB 統一到 Aurora、效能提升 75%、成本下降 28%、串流數十億小時">Netflix 9.C23</a> 互引：DB 種類 consolidation + per-service cluster 隔離雙重成立的架構</li>
</ul>
]]></content:encoded></item><item><title>Aurora RDS Proxy 與連線管理：connection multiplexing、pinning 陷阱與 failover 加速</title><link>https://tarrragon.github.io/blog/backend/01-database/vendors/aurora/rds-proxy-connection-pooling/</link><pubDate>Tue, 02 Jun 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/backend/01-database/vendors/aurora/rds-proxy-connection-pooling/</guid><description>&lt;p>Lambda 函式在流量尖峰被同時拉起幾百個實例、每個各自開一條到 Aurora 的連線、Aurora 的 connection 上限瞬間被打爆、新請求拿不到連線、整批失敗。根因是 &lt;em>連線管理&lt;/em> 缺位、Aurora 容量本身夠用——serverless 與高並發短連線 workload 製造的連線數遠超過資料庫該同時維持的後端連線。RDS Proxy 在 application 與 Aurora 之間做 connection multiplexing，把大量 client 連線收斂成少量後端連線。但它不是「連上去就自動省」——某些 session 操作會讓連線被 pin 住、multiplexing 失效。&lt;/p>
&lt;p>本文不是 Aurora overview（請看 &lt;a href="https://tarrragon.github.io/blog/backend/01-database/vendors/aurora/" data-link-title="AWS Aurora" data-link-desc="AWS managed PostgreSQL / MySQL、storage / compute 分離、&amp;#43;75% 效能改善的 production 證據">Aurora vendor 頁&lt;/a>）— 而是 RDS Proxy 連線管理機制與陷阱的實作層教學。&lt;/p>
&lt;h2 id="核心機制connection-multiplexing">核心機制：connection multiplexing&lt;/h2>
&lt;p>RDS Proxy 維護一個到 Aurora 的後端連線池，多個 client 連線共享這些後端連線。當 client 連線閒置（交易之間沒有活動），proxy 可以把對應的後端連線釋放回池子給其他 client 用：&lt;/p>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>沒有 proxy&lt;/th>
 &lt;th>有 RDS Proxy&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>每個 client 連線 = 一條後端連線&lt;/td>
 &lt;td>多個 client 連線共享少量後端連線&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Lambda 並發 N → 後端 N 條連線&lt;/td>
 &lt;td>Lambda 並發 N → 後端遠少於 N 條&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>failover 時 client 連線斷、要重連&lt;/td>
 &lt;td>proxy 保持 client 連線、後端切換對 client 透明&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>連線建立開銷由 application 承擔&lt;/td>
 &lt;td>proxy 維持暖連線池、省去反覆建立&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;p>multiplexing 生效的前提是 client 連線「閒置時可以被借走」。這只在連線處於 &lt;em>交易之間&lt;/em> 的乾淨狀態時成立——一旦連線帶了交易內狀態，proxy 不能把它借給別人，這就是 pinning。&lt;/p>
&lt;blockquote>
&lt;p>&lt;strong>Scope warning&lt;/strong>：「RDS Proxy 支援的 engine / 連線數上限 / IAM 認證細節」屬 AWS vendor 規格、實作時 cross-verify 官方 doc 當前值。本文不含 production case 揭露的 proxy 配置數字。&lt;/p>&lt;/blockquote>
&lt;p>對應 knowledge card：&lt;a href="https://tarrragon.github.io/blog/backend/knowledge-cards/connection-pool/" data-link-title="Connection Pool" data-link-desc="說明連線池如何限制下游資源並影響服務容量">connection pool&lt;/a>。&lt;/p>
&lt;h2 id="pinningmultiplexing-失效的主因">Pinning：multiplexing 失效的主因&lt;/h2>
&lt;p>Pinning 是 RDS Proxy 最常被忽略、卻直接決定省連線效果的機制。當 client 在連線上做了「跨交易持續的 session 狀態」操作，proxy 無法安全地把這條後端連線借給其他 client，於是把它 &lt;em>pin&lt;/em>（綁定）到該 client 直到連線關閉——這條後端連線在 pin 期間不參與 multiplexing。&lt;/p>
&lt;p>常見觸發 pinning 的操作：&lt;/p>
&lt;ul>
&lt;li>session 層級的變數設定（&lt;code>SET&lt;/code> 某些 session variable）&lt;/li>
&lt;li>建立 temp table&lt;/li>
&lt;li>prepared statement（某些情況）&lt;/li>
&lt;li>advisory lock、保持開啟的交易&lt;/li>
&lt;li>部分 session 層級的設定語句&lt;/li>
&lt;/ul>
&lt;p>pinning 的後果是「明明裝了 RDS Proxy、後端連線數卻沒降下來」。若大量 client 都觸發 pinning，等於退化回「一個 client 一條後端連線」、proxy 白裝。&lt;/p>
&lt;p>&lt;strong>判讀與修法方向&lt;/strong>：&lt;/p>
&lt;ul>
&lt;li>監控 &lt;code>DatabaseConnectionsCurrentlySessionPinned&lt;/code>，看 pinning 比例&lt;/li>
&lt;li>application 端避免不必要的 session 狀態（少用 session variable、temp table；改用交易內可清理的方式）&lt;/li>
&lt;li>真的需要 session 狀態的 workload，接受該連線會 pin、或評估這類 workload 是否適合走 proxy&lt;/li>
&lt;/ul>
&lt;blockquote>
&lt;p>&lt;strong>Scope warning&lt;/strong>：「哪些具體語句觸發 pinning」隨 RDS Proxy 版本與 engine 演進、實作時以 AWS doc 當前清單為準；本段列舉是常見類型、非完整或固定清單。&lt;/p></description><content:encoded><![CDATA[<p>Lambda 函式在流量尖峰被同時拉起幾百個實例、每個各自開一條到 Aurora 的連線、Aurora 的 connection 上限瞬間被打爆、新請求拿不到連線、整批失敗。根因是 <em>連線管理</em> 缺位、Aurora 容量本身夠用——serverless 與高並發短連線 workload 製造的連線數遠超過資料庫該同時維持的後端連線。RDS Proxy 在 application 與 Aurora 之間做 connection multiplexing，把大量 client 連線收斂成少量後端連線。但它不是「連上去就自動省」——某些 session 操作會讓連線被 pin 住、multiplexing 失效。</p>
<p>本文不是 Aurora overview（請看 <a href="/blog/backend/01-database/vendors/aurora/" data-link-title="AWS Aurora" data-link-desc="AWS managed PostgreSQL / MySQL、storage / compute 分離、&#43;75% 效能改善的 production 證據">Aurora vendor 頁</a>）— 而是 RDS Proxy 連線管理機制與陷阱的實作層教學。</p>
<h2 id="核心機制connection-multiplexing">核心機制：connection multiplexing</h2>
<p>RDS Proxy 維護一個到 Aurora 的後端連線池，多個 client 連線共享這些後端連線。當 client 連線閒置（交易之間沒有活動），proxy 可以把對應的後端連線釋放回池子給其他 client 用：</p>
<table>
  <thead>
      <tr>
          <th>沒有 proxy</th>
          <th>有 RDS Proxy</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>每個 client 連線 = 一條後端連線</td>
          <td>多個 client 連線共享少量後端連線</td>
      </tr>
      <tr>
          <td>Lambda 並發 N → 後端 N 條連線</td>
          <td>Lambda 並發 N → 後端遠少於 N 條</td>
      </tr>
      <tr>
          <td>failover 時 client 連線斷、要重連</td>
          <td>proxy 保持 client 連線、後端切換對 client 透明</td>
      </tr>
      <tr>
          <td>連線建立開銷由 application 承擔</td>
          <td>proxy 維持暖連線池、省去反覆建立</td>
      </tr>
  </tbody>
</table>
<p>multiplexing 生效的前提是 client 連線「閒置時可以被借走」。這只在連線處於 <em>交易之間</em> 的乾淨狀態時成立——一旦連線帶了交易內狀態，proxy 不能把它借給別人，這就是 pinning。</p>
<blockquote>
<p><strong>Scope warning</strong>：「RDS Proxy 支援的 engine / 連線數上限 / IAM 認證細節」屬 AWS vendor 規格、實作時 cross-verify 官方 doc 當前值。本文不含 production case 揭露的 proxy 配置數字。</p></blockquote>
<p>對應 knowledge card：<a href="/blog/backend/knowledge-cards/connection-pool/" data-link-title="Connection Pool" data-link-desc="說明連線池如何限制下游資源並影響服務容量">connection pool</a>。</p>
<h2 id="pinningmultiplexing-失效的主因">Pinning：multiplexing 失效的主因</h2>
<p>Pinning 是 RDS Proxy 最常被忽略、卻直接決定省連線效果的機制。當 client 在連線上做了「跨交易持續的 session 狀態」操作，proxy 無法安全地把這條後端連線借給其他 client，於是把它 <em>pin</em>（綁定）到該 client 直到連線關閉——這條後端連線在 pin 期間不參與 multiplexing。</p>
<p>常見觸發 pinning 的操作：</p>
<ul>
<li>session 層級的變數設定（<code>SET</code> 某些 session variable）</li>
<li>建立 temp table</li>
<li>prepared statement（某些情況）</li>
<li>advisory lock、保持開啟的交易</li>
<li>部分 session 層級的設定語句</li>
</ul>
<p>pinning 的後果是「明明裝了 RDS Proxy、後端連線數卻沒降下來」。若大量 client 都觸發 pinning，等於退化回「一個 client 一條後端連線」、proxy 白裝。</p>
<p><strong>判讀與修法方向</strong>：</p>
<ul>
<li>監控 <code>DatabaseConnectionsCurrentlySessionPinned</code>，看 pinning 比例</li>
<li>application 端避免不必要的 session 狀態（少用 session variable、temp table；改用交易內可清理的方式）</li>
<li>真的需要 session 狀態的 workload，接受該連線會 pin、或評估這類 workload 是否適合走 proxy</li>
</ul>
<blockquote>
<p><strong>Scope warning</strong>：「哪些具體語句觸發 pinning」隨 RDS Proxy 版本與 engine 演進、實作時以 AWS doc 當前清單為準；本段列舉是常見類型、非完整或固定清單。</p></blockquote>
<h2 id="failover-加速">Failover 加速</h2>
<p>RDS Proxy 的第二個價值是縮短 failover 對 application 的中斷。沒有 proxy 時，writer failover 會讓所有 client 連線斷掉、application 要偵測、重連、重建連線池；有 proxy 時，proxy 保持與 client 的連線、在後端把流量切到新 writer，client 端感知到的中斷時間縮短。</p>
<p>這對連線建立成本高、或 failover 期間不能大量重連的 workload 特別有價值。但 proxy 不消除 failover 本身——in-flight 的交易仍會失敗、application 仍要有 retry；proxy 縮短的是「重建連線」這段，不是「交易不中斷」。</p>
<h2 id="操作流程">操作流程</h2>
<p>從連線壓力判讀到上線的 6 步流程。</p>
<h4 id="step-1確認是不是連線問題">Step 1：確認是不是連線問題</h4>
<p>先區分「Aurora 容量不夠」vs「連線管理問題」。看 <code>DatabaseConnections</code> 是否逼近上限、且 CPU/IOPS 還有餘量——後者是典型的連線數問題、proxy 能解；若是 CPU/IOPS 飽和，proxy 不解。</p>
<h4 id="step-2判斷-workload-是否適合-proxy">Step 2：判斷 workload 是否適合 proxy</h4>
<ul>
<li>serverless / Lambda / 高並發短連線 → 適合（連線爆炸是主問題）</li>
<li>少量長連線、穩定的 application server → proxy 效益有限（連線數本就可控）</li>
<li>大量 session 狀態 workload → pinning 會吃掉 multiplexing 效益、要先評估</li>
</ul>
<h4 id="step-3建立-proxy">Step 3：建立 proxy</h4>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl">aws rds create-db-proxy <span class="se">\
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="se"></span>  --db-proxy-name my-aurora-proxy <span class="se">\
</span></span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="se"></span>  --engine-family POSTGRESQL <span class="se">\
</span></span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="se"></span>  --auth ... <span class="se">\
</span></span></span><span class="line"><span class="ln">5</span><span class="cl"><span class="se"></span>  --role-arn ... <span class="se">\
</span></span></span><span class="line"><span class="ln">6</span><span class="cl"><span class="se"></span>  --vpc-subnet-ids ...</span></span></code></pre></div><p>application 連到 proxy endpoint 而非直連 cluster endpoint。</p>
<h4 id="step-4減少-pinning">Step 4：減少 pinning</h4>
<p>review application 的 session 狀態使用、移除不必要的 <code>SET</code> / temp table；連線池設定避免長時間持有閒置連線。</p>
<h4 id="step-5驗證-multiplexing-生效">Step 5：驗證 multiplexing 生效</h4>





<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"># 對照後端連線數：裝 proxy 後 Aurora 的 DatabaseConnections 應顯著低於 client 並發數
</span></span><span class="line"><span class="ln">2</span><span class="cl"># 看 DatabaseConnectionsCurrentlySessionPinned：pinning 比例高代表 multiplexing 沒發揮</span></span></code></pre></div><h4 id="step-6驗證-failover-行為">Step 6：驗證 failover 行為</h4>
<p>主動觸發一次 failover、測量 application 感知到的中斷時間、確認 retry 邏輯能吸收 in-flight 交易失敗。</p>
<p><strong>Rollback boundary</strong>：application 可在 proxy endpoint 與直連 cluster endpoint 間切換、proxy 出問題時改回直連（但直連會回到連線爆炸風險，要先確認後端撐得住）。</p>
<h2 id="失敗模式">失敗模式</h2>
<p>production 常見的 5 個踩雷：</p>
<h4 id="case-1裝了-proxy-但-pinning-比例高連線沒降">Case 1：裝了 proxy 但 pinning 比例高、連線沒降</h4>
<p>application 大量用 session variable / temp table、多數連線被 pin、後端連線數沒降、proxy 白裝。修法：監控 pinning 比例、減少 session 狀態；理解 proxy 的省連線前提是連線可被借走。</p>
<h4 id="case-2把-proxy-當aurora-容量擴充">Case 2：把 proxy 當「Aurora 容量擴充」</h4>
<p>連線數沒問題、是 CPU/IOPS 飽和、卻裝 proxy 期待變快。修法：proxy 解連線管理、不解運算容量；容量問題要擴 instance / 加 replica。</p>
<h4 id="case-3以為-proxy-讓-failover-零中斷">Case 3：以為 proxy 讓 failover 零中斷</h4>
<p>裝了 proxy 就拿掉 application 的 retry、failover 時 in-flight 交易失敗沒處理。修法：proxy 縮短重連時間、不保證交易不中斷；application 仍要 retry in-flight 交易。</p>
<h4 id="case-4少量長連線-workload-強裝-proxy">Case 4：少量長連線 workload 強裝 proxy</h4>
<p>穩定的 application server 連線數本就可控、裝 proxy 多一跳延遲、效益有限。修法：proxy 的價值在連線爆炸場景（serverless / 高並發短連線）；連線可控的 workload 不必加。</p>
<h4 id="case-5proxy-與自管-pooler-疊加未理清責任">Case 5：proxy 與自管 pooler 疊加未理清責任</h4>
<p>application 已有自管連線池（如語言層 pool）、又加 RDS Proxy、兩層 pool 互相打架、連線數行為難預測。修法：理清兩層職責——application 層 pool 管「app 到 proxy」、proxy 管「proxy 到 Aurora」；兩層設定要協調、不是各設各的。</p>
<p><strong>Anti-recommendation</strong>：連線數本就可控的少量長連線 workload、或 workload 大量依賴 session 狀態（pinning 會吃掉效益）→ 不必上 RDS Proxy；它的價值集中在 serverless / Lambda / 高並發短連線的連線爆炸場景。</p>
<h2 id="容量與觀測">容量與觀測</h2>
<p>CloudWatch metric：</p>
<ul>
<li><code>DatabaseConnections</code>（Aurora 端）：裝 proxy 後應顯著低於 client 並發數</li>
<li><code>DatabaseConnectionsCurrentlySessionPinned</code>：pinning 數、判斷 multiplexing 效益</li>
<li><code>ClientConnections</code>（proxy 端）：client 側連線數、對照後端收斂比例</li>
<li><code>QueryDatabaseResponseLatency</code>：proxy 多一跳的延遲影響</li>
</ul>
<p><strong>判讀</strong>：</p>
<ul>
<li>後端連線數沒因 proxy 下降 → pinning 比例高或 workload 不適合</li>
<li>pinning 數持續高 → application session 狀態過多、需 review</li>
<li>proxy 延遲明顯 → 評估這一跳對延遲敏感路徑是否值得</li>
</ul>
<blockquote>
<p><strong>Scope warning</strong>：本文未引用 production case 的 proxy metric 數字；上述指標與判讀屬 vendor 規格 + 通用連線管理工程。</p></blockquote>
<p>接回 <a href="/blog/backend/09-performance-capacity/bottleneck-localization/" data-link-title="9.5 瓶頸定位流程" data-link-desc="從 app 到 DB / cache / broker / 第三方 quota 的逐層瓶頸定位">9.5 瓶頸定位流程</a>、<a href="/blog/backend/01-database/high-concurrency-access/" data-link-title="1.1 高併發下的 SQL 讀寫邊界" data-link-desc="說明高併發服務如何共用資料庫 client、控制 transaction、管理 connection pool、避免資料庫成為瓶頸">1.1 高併發下的 SQL 讀寫邊界</a>。</p>
<h2 id="邊界與整合">邊界與整合</h2>
<h3 id="rds-proxy-vs-自管-pgbouncer">RDS Proxy vs 自管 pgbouncer</h3>
<p>兩者都是 connection pooler，責任切分在「managed vs 自管」：</p>
<ul>
<li><strong>RDS Proxy</strong>：AWS managed、跟 Aurora / IAM / Secrets Manager 整合、零運維、含 failover 加速；綁 AWS</li>
<li><strong>自管 pgbouncer / pgcat</strong>：自己部署運維、pooling 模式（session / transaction / statement）可細調、跨雲可攜；運維責任自負</li>
</ul>
<p>PostgreSQL 的通用連線池機制與 pgbouncer 細節主寫於 <a href="/blog/backend/01-database/vendors/postgresql/pgbouncer-config/" data-link-title="PostgreSQL pgBouncer 配置 &#43; 連線池治理" data-link-desc="pgBouncer transaction pooling 配置、跟 application connection pool 的分層、production 故障演練（pool exhaustion / stale connection / DNS failover）跟容量規劃">pgbouncer-config</a> 與 <a href="/blog/backend/01-database/vendors/postgresql/connection-pooler-comparison/" data-link-title="PostgreSQL Connection Pooler Comparison" data-link-desc="PostgreSQL PgBouncer、Odyssey、RDS Proxy、application pool 與 transaction pooling 的選型比較">connection-pooler-comparison</a>；本篇聚焦 RDS Proxy 這個 AWS managed 方案的機制與 pinning 陷阱。要細調 pooling 模式、或需要跨雲可攜 → 評估自管 pooler；要零運維 + Aurora 原生整合 + failover 加速 → RDS Proxy。</p>
<h3 id="sibling-與-cross-link">Sibling 與 cross-link</h3>
<ul>
<li><a href="/blog/backend/01-database/vendors/aurora/serverless-v2-scaling/" data-link-title="Aurora Serverless v2 適用判斷：ACU 自動擴縮、混合 cluster 與何時不該用" data-link-desc="Aurora Serverless v2 不是「比較便宜的 Aurora」；本文展開 ACU 計費粒度、秒級自動擴縮機制、min/max ACU 設定、serverless 與 provisioned 同 cluster 混用，以及穩定高負載下 serverless 反而更貴的成本 crossover 邊界">serverless-v2-scaling</a> — serverless + Lambda 場景的連線管理常與 RDS Proxy 一起出現</li>
<li><a href="/blog/backend/01-database/vendors/aurora/cross-az-failover-rto/" data-link-title="Aurora Cross-AZ Failover：RTO 量測、endpoint routing 與 application reconnect 契約" data-link-desc="Aurora cross-AZ failover lifecycle（detection / promotion / DNS update）、&lt; 30 秒 RTO、application DNS cache 跟 connection pool 對齊、Standard Chartered 受監管場景為什麼用獨立 cluster 而非 Global Database failover">cross-az-failover-rto</a> — proxy 縮短 failover 重連時間、與 RTO 目標結合</li>
<li><a href="/blog/backend/01-database/vendors/postgresql/pgbouncer-config/" data-link-title="PostgreSQL pgBouncer 配置 &#43; 連線池治理" data-link-desc="pgBouncer transaction pooling 配置、跟 application connection pool 的分層、production 故障演練（pool exhaustion / stale connection / DNS failover）跟容量規劃">pgbouncer-config</a> / <a href="/blog/backend/01-database/vendors/postgresql/connection-pooler-comparison/" data-link-title="PostgreSQL Connection Pooler Comparison" data-link-desc="PostgreSQL PgBouncer、Odyssey、RDS Proxy、application pool 與 transaction pooling 的選型比較">connection-pooler-comparison</a> — 通用連線池 SSoT、自管方案對照</li>
<li><a href="/blog/backend/01-database/high-concurrency-access/" data-link-title="1.1 高併發下的 SQL 讀寫邊界" data-link-desc="說明高併發服務如何共用資料庫 client、控制 transaction、管理 connection pool、避免資料庫成為瓶頸">1.1 高併發下的 SQL 讀寫邊界</a> — 連線池與 transaction 範圍控制</li>
<li>替代路由：需要細調 pooling 模式 / 跨雲 → 自管 pgbouncer</li>
</ul>
]]></content:encoded></item><item><title>Aurora PG/MySQL vs Aurora DSQL 取捨：何時 single-region managed 夠用、何時跨到 distributed</title><link>https://tarrragon.github.io/blog/backend/01-database/vendors/aurora/aurora-vs-dsql-tradeoff/</link><pubDate>Tue, 02 Jun 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/backend/01-database/vendors/aurora/aurora-vs-dsql-tradeoff/</guid><description>&lt;blockquote>
&lt;p>本文是 Aurora family 內的決策取捨文章。聚焦 &lt;em>standard Aurora（Aurora PostgreSQL / MySQL，single-region managed SQL）&lt;/em> 跟 &lt;em>Aurora DSQL（active-active distributed SQL）&lt;/em> 之間的升級門檻判斷。兩個既有 SSoT 不在本篇重複：「PG → DSQL 怎麼遷」見 &lt;a href="https://tarrragon.github.io/blog/backend/01-database/vendors/postgresql/migrate-to-aurora-dsql/" data-link-title="PostgreSQL → Aurora DSQL Migration：PG wire-compatible Distributed SQL 的 Paradigm Shift" data-link-desc="Aurora DSQL（2024-12 re:Invent preview / 2025-05 GA）是 AWS 推的 PG wire-compatible *active-active distributed SQL*、跟 self-managed PG / Aurora PG 不同 paradigm（OCC &amp;#43; snapshot isolation &amp;#43; multi-region strong consistency）。Migration 結構是 *protocol drop-in &amp;#43; paradigm shift*：app SQL 不太改、但 transaction retry / extension 缺位 / 多 region 一致性需重設計。本文走 DSQL vs Aurora PG vs self-managed PG 三軸對比、為什麼遷的三條 driver（global write / operational zero-touch / region resiliency）、Type E phased plan、5 production 踩雷（transaction retry 沒處理 / extension 缺位 / sequence throughput 限制 / Aurora PG 直升 DSQL 不可行 / region failover semantic）、跟 PG → Aurora 跟 PG → CockroachDB 對比">migrate-to-aurora-dsql&lt;/a>；「DSQL vs Spanner vs CockroachDB 三方 distributed SQL 選型」見 &lt;a href="https://tarrragon.github.io/blog/backend/01-database/vendors/cockroachdb/aurora-dsql-spanner-decision-tree/" data-link-title="CockroachDB vs Aurora DSQL vs Spanner：撞牆訊號分型 &amp;#43; 七問題決策樹" data-link-desc="Distributed SQL 三選一決策樹。先用撞牆訊號分型識別 driver path（DoorDash 單主寫入撞牆 / Netflix Cassandra 缺口 / Hard Rock 合規驅動）、再走七問題（跨雲 / 雲商生態 / 風險預算 / PG 相容 / 管理負擔 / team size / vendor sizing barrier）。PostgreSQL 相容性 audit checklist 4 項、Spanner 100 pu sizing barrier、Hard Rock 「省 10-20 工程師」機會成本警示、Netflix Database Platform Team 規模">aurora-dsql-spanner-decision-tree&lt;/a>。本篇只回答「standard Aurora 夠不夠、要不要跨過去」。&lt;/p>&lt;/blockquote>
&lt;p>多數團隊不需要 Aurora DSQL。Aurora PostgreSQL / MySQL 已經是 managed SQL、storage / compute 分離、跨 AZ 高可用、read replica 擴讀——絕大多數 OLTP workload 在這層就解決了。Aurora DSQL 是 2024-12 re:Invent preview、2025-05 GA 的 &lt;em>不同 paradigm&lt;/em> 產品：PG wire-compatible 但底層是 active-active distributed、OCC + snapshot isolation、multi-region strong consistency。它解的是 standard Aurora &lt;em>解不了&lt;/em> 的特定問題，代價是放棄一部分 PostgreSQL 相容性與交易自由度。要不要跨過去，看 workload 是否真的撞到 standard Aurora 的結構上限。&lt;/p></description><content:encoded><![CDATA[<blockquote>
<p>本文是 Aurora family 內的決策取捨文章。聚焦 <em>standard Aurora（Aurora PostgreSQL / MySQL，single-region managed SQL）</em> 跟 <em>Aurora DSQL（active-active distributed SQL）</em> 之間的升級門檻判斷。兩個既有 SSoT 不在本篇重複：「PG → DSQL 怎麼遷」見 <a href="/blog/backend/01-database/vendors/postgresql/migrate-to-aurora-dsql/" data-link-title="PostgreSQL → Aurora DSQL Migration：PG wire-compatible Distributed SQL 的 Paradigm Shift" data-link-desc="Aurora DSQL（2024-12 re:Invent preview / 2025-05 GA）是 AWS 推的 PG wire-compatible *active-active distributed SQL*、跟 self-managed PG / Aurora PG 不同 paradigm（OCC &#43; snapshot isolation &#43; multi-region strong consistency）。Migration 結構是 *protocol drop-in &#43; paradigm shift*：app SQL 不太改、但 transaction retry / extension 缺位 / 多 region 一致性需重設計。本文走 DSQL vs Aurora PG vs self-managed PG 三軸對比、為什麼遷的三條 driver（global write / operational zero-touch / region resiliency）、Type E phased plan、5 production 踩雷（transaction retry 沒處理 / extension 缺位 / sequence throughput 限制 / Aurora PG 直升 DSQL 不可行 / region failover semantic）、跟 PG → Aurora 跟 PG → CockroachDB 對比">migrate-to-aurora-dsql</a>；「DSQL vs Spanner vs CockroachDB 三方 distributed SQL 選型」見 <a href="/blog/backend/01-database/vendors/cockroachdb/aurora-dsql-spanner-decision-tree/" data-link-title="CockroachDB vs Aurora DSQL vs Spanner：撞牆訊號分型 &#43; 七問題決策樹" data-link-desc="Distributed SQL 三選一決策樹。先用撞牆訊號分型識別 driver path（DoorDash 單主寫入撞牆 / Netflix Cassandra 缺口 / Hard Rock 合規驅動）、再走七問題（跨雲 / 雲商生態 / 風險預算 / PG 相容 / 管理負擔 / team size / vendor sizing barrier）。PostgreSQL 相容性 audit checklist 4 項、Spanner 100 pu sizing barrier、Hard Rock 「省 10-20 工程師」機會成本警示、Netflix Database Platform Team 規模">aurora-dsql-spanner-decision-tree</a>。本篇只回答「standard Aurora 夠不夠、要不要跨過去」。</p></blockquote>
<p>多數團隊不需要 Aurora DSQL。Aurora PostgreSQL / MySQL 已經是 managed SQL、storage / compute 分離、跨 AZ 高可用、read replica 擴讀——絕大多數 OLTP workload 在這層就解決了。Aurora DSQL 是 2024-12 re:Invent preview、2025-05 GA 的 <em>不同 paradigm</em> 產品：PG wire-compatible 但底層是 active-active distributed、OCC + snapshot isolation、multi-region strong consistency。它解的是 standard Aurora <em>解不了</em> 的特定問題，代價是放棄一部分 PostgreSQL 相容性與交易自由度。要不要跨過去，看 workload 是否真的撞到 standard Aurora 的結構上限。</p>
<blockquote>
<p><strong>時間錨點</strong>：Aurora DSQL 2024-12 preview、2025-05 GA。vendor 能力持續演進、實際決策前以 AWS docs 當前狀態為準。</p></blockquote>
<h2 id="核心差異single-writer-vs-active-active">核心差異：single-writer vs active-active</h2>
<p>兩者的根本差異在寫入架構：</p>
<table>
  <thead>
      <tr>
          <th>維度</th>
          <th>Aurora PG / MySQL（standard）</th>
          <th>Aurora DSQL</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>寫入架構</td>
          <td>single writer（一個 region 一個 writer）</td>
          <td>active-active（多 region 同時可寫）</td>
      </tr>
      <tr>
          <td>一致性</td>
          <td>單 region 強一致、跨 region 非同步</td>
          <td>multi-region strong consistency</td>
      </tr>
      <tr>
          <td>SQL 相容</td>
          <td>完整 PostgreSQL / MySQL</td>
          <td>PG wire-compatible <em>子集</em>、無多數 extension</td>
      </tr>
      <tr>
          <td>交易模型</td>
          <td>標準 PG/MySQL transaction、長交易</td>
          <td>OCC + snapshot isolation、需處理 retry</td>
      </tr>
      <tr>
          <td>寫入擴展</td>
          <td>受 single writer instance 上限約束</td>
          <td>水平擴展、無 single writer 瓶頸</td>
      </tr>
      <tr>
          <td>運維</td>
          <td>managed、但仍要管 instance / failover</td>
          <td>serverless、zero-touch、無 instance 概念</td>
      </tr>
  </tbody>
</table>
<p>standard Aurora 的 storage 層雖然分散，<em>compute 寫入仍是 single writer</em>——這是它的結構上限。DSQL 把寫入也分散，代價是 SQL 相容性縮窄（PG 子集、extension 缺位）與交易語意改變（OCC，衝突要 application retry）。</p>
<h2 id="該跨到-dsql-的訊號">該跨到 DSQL 的訊號</h2>
<p>只有撞到 standard Aurora 結構上限的特定需求，才值得跨 paradigm：</p>
<ul>
<li><strong>global write（多 region 都要低延遲寫入）</strong>：standard Aurora 跨 region 只有非同步副本、寫入要回到單一 writer region；真正需要多 region active-active 寫入 → DSQL</li>
<li><strong>single-writer 寫入上限撞牆</strong>：寫入量大到單一 writer instance（即使最大 instance class）撐不住、且無法用 sharding 簡單解 → DSQL 的水平寫入擴展</li>
<li><strong>region resiliency（單 region 失效仍要可寫）</strong>：standard Aurora 的跨 region failover 有 RPO/RTO 與寫入中斷；要求單 region 失效時其他 region 仍持續接受寫入 → DSQL active-active</li>
<li><strong>operational zero-touch</strong>：不想管 instance / failover / 容量 → DSQL serverless 模型（但這單項不足以跨 paradigm、要搭配上面的結構需求）</li>
</ul>
<h2 id="不該跨的訊號standard-aurora-夠用">不該跨的訊號（standard Aurora 夠用）</h2>
<p>以下情況跨 DSQL 是過度工程、且會付出相容性代價：</p>
<ul>
<li><strong>single-region 夠用</strong>：寫入集中在一個 region、跨 region 只需要讀副本或 DR → standard Aurora</li>
<li><strong>需要 PostgreSQL extension</strong>：依賴 PostGIS / pgvector / 特定 extension → DSQL 子集不支援、留 standard Aurora</li>
<li><strong>複雜 / 長交易</strong>：依賴長交易、複雜多語句交易、特定 isolation 行為 → standard Aurora 的完整交易模型</li>
<li><strong>寫入量 standard Aurora 撐得住</strong>：single writer 還有餘量 → 不必為「未來可能」預先跨 paradigm</li>
</ul>
<p><code>9.C14 Standard Chartered</code> 與 <code>9.C4 DraftKings</code> 是反向佐證：金融帳本 / 博彩這類高一致性、高關鍵 OLTP workload，在 <em>standard Aurora</em> 上就能同時拿到韌性與性能（DraftKings replication lag 降到 10-30ms 級、Standard Chartered 把韌性與性能當單一目標）。它們沒有跨到 distributed SQL——因為 single-region 強一致 + 跨 AZ 高可用已滿足需求。多數金融 OLTP 不需要 active-active multi-region write。</p>
<blockquote>
<p><strong>Scope warning</strong>：Standard Chartered / DraftKings 的 case 揭露其用 standard Aurora 達成韌性 + 性能（見 <a href="/blog/backend/01-database/vendors/aurora/storage-architecture/" data-link-title="Aurora Storage Architecture：quorum-based 分散式 log 與韌性即性能設計" data-link-desc="Aurora storage / compute 分離、6-way 跨 AZ replication、4-of-6 write / 3-of-6 read quorum、韌性投資自動 amortize 成 read 性能、DraftKings 6ms 寫 / &lt;1ms 讀 production reference">storage-architecture</a>）；「它們不需要 DSQL」是本文基於其 single-region 強一致需求的推論、非 case 明文比較 DSQL。引用為「standard Aurora 已足夠多數高一致 OLTP」的訊號、不當 DSQL 對比的 case fact。</p></blockquote>
<h2 id="升級門檻決策流程">升級門檻決策流程</h2>
<p>從需求判讀到路徑選擇的流程：</p>
<h4 id="step-1確認是不是-global-write-需求">Step 1：確認是不是 global write 需求</h4>
<p>寫入是否真的需要多 region 同時低延遲？還是只需要多 region 讀 + 單 region 寫？後者 standard Aurora（+ Global Database 讀副本）就解。</p>
<h4 id="step-2確認-single-writer-是否真的撞牆">Step 2：確認 single-writer 是否真的撞牆</h4>
<p>當前寫入量 vs 最大 instance class 上限、是否已嘗試過 read/write 分離、是否能用 application 層 sharding。撞牆才考慮 DSQL；沒撞牆是過早優化。</p>
<h4 id="step-3檢查相容性代價">Step 3：檢查相容性代價</h4>
<p>清點對 PG extension、長交易、特定 SQL 功能的依賴。依賴重 → DSQL 相容性子集會擋路、留 standard Aurora。</p>
<h4 id="step-4若決定跨走既有-ssot">Step 4：若決定跨，走既有 SSoT</h4>
<ul>
<li>「PG → DSQL 怎麼遷」（protocol drop-in + paradigm shift、transaction retry 處理、extension 缺位）→ <a href="/blog/backend/01-database/vendors/postgresql/migrate-to-aurora-dsql/" data-link-title="PostgreSQL → Aurora DSQL Migration：PG wire-compatible Distributed SQL 的 Paradigm Shift" data-link-desc="Aurora DSQL（2024-12 re:Invent preview / 2025-05 GA）是 AWS 推的 PG wire-compatible *active-active distributed SQL*、跟 self-managed PG / Aurora PG 不同 paradigm（OCC &#43; snapshot isolation &#43; multi-region strong consistency）。Migration 結構是 *protocol drop-in &#43; paradigm shift*：app SQL 不太改、但 transaction retry / extension 缺位 / 多 region 一致性需重設計。本文走 DSQL vs Aurora PG vs self-managed PG 三軸對比、為什麼遷的三條 driver（global write / operational zero-touch / region resiliency）、Type E phased plan、5 production 踩雷（transaction retry 沒處理 / extension 缺位 / sequence throughput 限制 / Aurora PG 直升 DSQL 不可行 / region failover semantic）、跟 PG → Aurora 跟 PG → CockroachDB 對比">migrate-to-aurora-dsql</a></li>
<li>「DSQL vs Spanner vs CockroachDB 哪個 distributed SQL」→ <a href="/blog/backend/01-database/vendors/cockroachdb/aurora-dsql-spanner-decision-tree/" data-link-title="CockroachDB vs Aurora DSQL vs Spanner：撞牆訊號分型 &#43; 七問題決策樹" data-link-desc="Distributed SQL 三選一決策樹。先用撞牆訊號分型識別 driver path（DoorDash 單主寫入撞牆 / Netflix Cassandra 缺口 / Hard Rock 合規驅動）、再走七問題（跨雲 / 雲商生態 / 風險預算 / PG 相容 / 管理負擔 / team size / vendor sizing barrier）。PostgreSQL 相容性 audit checklist 4 項、Spanner 100 pu sizing barrier、Hard Rock 「省 10-20 工程師」機會成本警示、Netflix Database Platform Team 規模">aurora-dsql-spanner-decision-tree</a></li>
</ul>
<p><strong>Rollback boundary</strong>：跨 paradigm 是高成本決策——DSQL 子集相容性與 OCC 交易模型改變了 application 契約，回退到 standard Aurora 不是改 connection string 就好。決策前用一個非關鍵 workload 試點、確認相容性與 retry 行為，再擴大。</p>
<h2 id="邊界與整合">邊界與整合</h2>
<h3 id="為什麼這是升級門檻而非遷移">為什麼這是「升級門檻」而非「遷移」</h3>
<p>standard Aurora → DSQL 不是版本升級、是 paradigm 切換。Aurora PG/MySQL 用得好好的，不代表「升級到 DSQL 會更好」——多數情況會更差（失去 extension、交易要改、相容性縮窄）。只有 workload 真的需要 active-active multi-region write 或撞到 single-writer 上限，跨過去才划算。這跟「PostgreSQL major version upgrade」（同 paradigm、向後相容）是完全不同性質的決策。</p>
<h3 id="sibling-與-cross-link">Sibling 與 cross-link</h3>
<ul>
<li><a href="/blog/backend/01-database/vendors/aurora/storage-architecture/" data-link-title="Aurora Storage Architecture：quorum-based 分散式 log 與韌性即性能設計" data-link-desc="Aurora storage / compute 分離、6-way 跨 AZ replication、4-of-6 write / 3-of-6 read quorum、韌性投資自動 amortize 成 read 性能、DraftKings 6ms 寫 / &lt;1ms 讀 production reference">storage-architecture</a> — standard Aurora 的 storage 分散但 compute single-writer 的結構上限根源</li>
<li><a href="/blog/backend/01-database/vendors/aurora/global-database-multi-region/" data-link-title="Aurora Global Database：跨 region async replication、&lt; 1 秒 lag 與合規 anti-recommendation" data-link-desc="Aurora Global Database 跨 region storage-level async replication、&lt; 1 秒 typical lag、planned vs unplanned failover RTO 數量級對比、Standard Chartered 合規禁止跨境複製為什麼讓 Global Database 變反指標">global-database-multi-region</a> — standard Aurora 的多 region 方案（非同步副本）、global write 需求前先確認這層夠不夠</li>
<li><a href="/blog/backend/01-database/vendors/postgresql/migrate-to-aurora-dsql/" data-link-title="PostgreSQL → Aurora DSQL Migration：PG wire-compatible Distributed SQL 的 Paradigm Shift" data-link-desc="Aurora DSQL（2024-12 re:Invent preview / 2025-05 GA）是 AWS 推的 PG wire-compatible *active-active distributed SQL*、跟 self-managed PG / Aurora PG 不同 paradigm（OCC &#43; snapshot isolation &#43; multi-region strong consistency）。Migration 結構是 *protocol drop-in &#43; paradigm shift*：app SQL 不太改、但 transaction retry / extension 缺位 / 多 region 一致性需重設計。本文走 DSQL vs Aurora PG vs self-managed PG 三軸對比、為什麼遷的三條 driver（global write / operational zero-touch / region resiliency）、Type E phased plan、5 production 踩雷（transaction retry 沒處理 / extension 缺位 / sequence throughput 限制 / Aurora PG 直升 DSQL 不可行 / region failover semantic）、跟 PG → Aurora 跟 PG → CockroachDB 對比">migrate-to-aurora-dsql</a> — 決定跨之後的遷移 playbook（SSoT）</li>
<li><a href="/blog/backend/01-database/vendors/cockroachdb/aurora-dsql-spanner-decision-tree/" data-link-title="CockroachDB vs Aurora DSQL vs Spanner：撞牆訊號分型 &#43; 七問題決策樹" data-link-desc="Distributed SQL 三選一決策樹。先用撞牆訊號分型識別 driver path（DoorDash 單主寫入撞牆 / Netflix Cassandra 缺口 / Hard Rock 合規驅動）、再走七問題（跨雲 / 雲商生態 / 風險預算 / PG 相容 / 管理負擔 / team size / vendor sizing barrier）。PostgreSQL 相容性 audit checklist 4 項、Spanner 100 pu sizing barrier、Hard Rock 「省 10-20 工程師」機會成本警示、Netflix Database Platform Team 規模">aurora-dsql-spanner-decision-tree</a> — 三方 distributed SQL 選型（SSoT）</li>
<li>替代路由：single-region 夠 → 留 standard Aurora；KV access pattern → <a href="/blog/backend/01-database/vendors/dynamodb/" data-link-title="DynamoDB" data-link-desc="AWS managed key-value、partition-based scaling、9000 萬 RPS sustained 實戰證據">DynamoDB</a></li>
<li>跟 <a href="/blog/backend/09-performance-capacity/cases/standard-chartered-aurora-banking/" data-link-title="9.C14 Standard Chartered：受監管銀行的 Aurora 4000 TPS 容量提升" data-link-desc="Standard Chartered 銀行遷移到 Aurora 後吞吐量提升 10 倍至 4000 TPS、跨 7 個受監管市場">Standard Chartered 9.C14</a> / <a href="/blog/backend/09-performance-capacity/cases/draftkings-aurora-financial-ledger/" data-link-title="9.C4 DraftKings：Aurora 撐 100 萬 ops/min 的體育博彩金融帳本" data-link-desc="DraftKings 用 Aurora MySQL 跑體育博彩金融帳本、Super Bowl 流量 &#43;50% 不影響延遲">DraftKings 9.C4</a> 互引：高一致 OLTP 在 standard Aurora 已足夠的訊號</li>
</ul>
]]></content:encoded></item><item><title>Aurora Cross-AZ Failover：RTO 量測、endpoint routing 與 application reconnect 契約</title><link>https://tarrragon.github.io/blog/backend/01-database/vendors/aurora/cross-az-failover-rto/</link><pubDate>Wed, 27 May 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/backend/01-database/vendors/aurora/cross-az-failover-rto/</guid><description>&lt;p>Aurora cross-AZ failover 的 RTO 文件數字是「&amp;lt; 30 秒」、但 application 端實測常常看到 60-120 秒 — 這個落差不是 Aurora 慢、是 &lt;em>DNS cache + connection pool + retry policy&lt;/em> 的對齊問題。本文展開 failover lifecycle 三段（detection / promotion / DNS update）、application 端 reconnect 契約、量測真實 RTO 的流程、跟 &lt;a href="https://tarrragon.github.io/blog/backend/09-performance-capacity/cases/standard-chartered-aurora-banking/" data-link-title="9.C14 Standard Chartered：受監管銀行的 Aurora 4000 TPS 容量提升" data-link-desc="Standard Chartered 銀行遷移到 Aurora 後吞吐量提升 10 倍至 4000 TPS、跨 7 個受監管市場">9.C14 Standard Chartered&lt;/a> 受監管銀行業務為什麼選獨立 cluster 而非 Global Database failover 的合規 driver。&lt;/p>
&lt;p>本文不是 Aurora overview（請看 &lt;a href="https://tarrragon.github.io/blog/backend/01-database/vendors/aurora/" data-link-title="AWS Aurora" data-link-desc="AWS managed PostgreSQL / MySQL、storage / compute 分離、&amp;#43;75% 效能改善的 production 證據">Aurora vendor 頁&lt;/a>）— 而是 failover 流程的實作層教學。前置閱讀建議 &lt;a href="../storage-architecture/">Aurora storage architecture&lt;/a>（理解為什麼 Aurora failover 不需要 data catch-up）。&lt;/p>
&lt;h2 id="問題情境">問題情境&lt;/h2>
&lt;p>典型觸發場景：DraftKings / Standard Chartered 等級的金融交易服務、AZ-level outage 期間用戶操作不能斷、RTO 預算 &amp;lt; 60 秒、但 application 端看到的 reconnect 行為跟 AWS 文件不一致。&lt;/p>
&lt;p>讀者常見的具體疑問：&lt;/p>
&lt;ul>
&lt;li>「Failover trigger 後新 connection 還連到舊 primary、為什麼？」&lt;/li>
&lt;li>「Writer endpoint DNS 切換了、application 還沒重連、什麼時候會切？」&lt;/li>
&lt;li>「Failover 期間 in-flight transaction 是全 abort 還是部分 commit？」&lt;/li>
&lt;li>「我手動測 failover RTO 量出 90 秒、AWS 文件講 &amp;lt; 30 秒、誰錯？」&lt;/li>
&lt;/ul>
&lt;p>進一步問題：失敗模式分布在 &lt;em>application 端的 connection state&lt;/em>、不只是 Aurora 端的 promotion 流程。Aurora 端的 promotion 在 storage 共享下確實 &amp;lt; 30 秒（不需要等 data catch-up）、但 application reconnect 受 JVM DNS cache、connection pool validation、retry policy 影響、容易把總體 RTO 拉長到 2-3 倍。&lt;/p>
&lt;p>對 Standard Chartered 這種受監管銀行業務、failover 還有合規維度：受監管市場資料 &lt;em>不能跨境複製&lt;/em>、Global Database 在這種場景違反合規、必須用每市場獨立 cluster 的 cross-AZ failover 吸收 RTO 預算。這個 driver 跟一般工程「跨 region failover 更好」的直覺相反。&lt;/p>
&lt;h2 id="核心機制failover-lifecycle-三段">核心機制：failover lifecycle 三段&lt;/h2>
&lt;p>Aurora cross-AZ failover 的 first-class concept 是 &lt;em>failover lifecycle 三段&lt;/em>：detection → promotion → DNS update。每一段有自己的 SLA 跟可調維度。&lt;/p></description><content:encoded><![CDATA[<p>Aurora cross-AZ failover 的 RTO 文件數字是「&lt; 30 秒」、但 application 端實測常常看到 60-120 秒 — 這個落差不是 Aurora 慢、是 <em>DNS cache + connection pool + retry policy</em> 的對齊問題。本文展開 failover lifecycle 三段（detection / promotion / DNS update）、application 端 reconnect 契約、量測真實 RTO 的流程、跟 <a href="/blog/backend/09-performance-capacity/cases/standard-chartered-aurora-banking/" data-link-title="9.C14 Standard Chartered：受監管銀行的 Aurora 4000 TPS 容量提升" data-link-desc="Standard Chartered 銀行遷移到 Aurora 後吞吐量提升 10 倍至 4000 TPS、跨 7 個受監管市場">9.C14 Standard Chartered</a> 受監管銀行業務為什麼選獨立 cluster 而非 Global Database failover 的合規 driver。</p>
<p>本文不是 Aurora overview（請看 <a href="/blog/backend/01-database/vendors/aurora/" data-link-title="AWS Aurora" data-link-desc="AWS managed PostgreSQL / MySQL、storage / compute 分離、&#43;75% 效能改善的 production 證據">Aurora vendor 頁</a>）— 而是 failover 流程的實作層教學。前置閱讀建議 <a href="../storage-architecture/">Aurora storage architecture</a>（理解為什麼 Aurora failover 不需要 data catch-up）。</p>
<h2 id="問題情境">問題情境</h2>
<p>典型觸發場景：DraftKings / Standard Chartered 等級的金融交易服務、AZ-level outage 期間用戶操作不能斷、RTO 預算 &lt; 60 秒、但 application 端看到的 reconnect 行為跟 AWS 文件不一致。</p>
<p>讀者常見的具體疑問：</p>
<ul>
<li>「Failover trigger 後新 connection 還連到舊 primary、為什麼？」</li>
<li>「Writer endpoint DNS 切換了、application 還沒重連、什麼時候會切？」</li>
<li>「Failover 期間 in-flight transaction 是全 abort 還是部分 commit？」</li>
<li>「我手動測 failover RTO 量出 90 秒、AWS 文件講 &lt; 30 秒、誰錯？」</li>
</ul>
<p>進一步問題：失敗模式分布在 <em>application 端的 connection state</em>、不只是 Aurora 端的 promotion 流程。Aurora 端的 promotion 在 storage 共享下確實 &lt; 30 秒（不需要等 data catch-up）、但 application reconnect 受 JVM DNS cache、connection pool validation、retry policy 影響、容易把總體 RTO 拉長到 2-3 倍。</p>
<p>對 Standard Chartered 這種受監管銀行業務、failover 還有合規維度：受監管市場資料 <em>不能跨境複製</em>、Global Database 在這種場景違反合規、必須用每市場獨立 cluster 的 cross-AZ failover 吸收 RTO 預算。這個 driver 跟一般工程「跨 region failover 更好」的直覺相反。</p>
<h2 id="核心機制failover-lifecycle-三段">核心機制：failover lifecycle 三段</h2>
<p>Aurora cross-AZ failover 的 first-class concept 是 <em>failover lifecycle 三段</em>：detection → promotion → DNS update。每一段有自己的 SLA 跟可調維度。</p>
<p><strong>Detection（10-15 秒）</strong>：</p>
<ul>
<li>AWS 內部 health check 每幾秒檢查 primary writer health</li>
<li>連續失敗到一定閾值才 trigger failover（避免 false positive）</li>
<li>讀者無法直接調 detection 閾值、是 AWS managed</li>
</ul>
<p><strong>Promotion（&lt; 5 秒）</strong>：</p>
<ul>
<li>選 PromotionTier 最低的 read replica 升 primary</li>
<li>Storage 跨 AZ 共享、replica 升 primary <em>不需要 data catch-up</em>（vs 傳統 PostgreSQL streaming replication 要等 WAL apply）</li>
<li>Promotion 本身極快、是 Aurora storage 設計的直接受益</li>
</ul>
<p><strong>DNS update（5-15 秒）</strong>：</p>
<ul>
<li>Cluster endpoint / writer endpoint DNS 切到新 primary</li>
<li>Aurora endpoint DNS TTL 是 5 秒、AWS DNS infrastructure 通常 5-15 秒 propagate 完</li>
<li>但 application 端的 DNS cache 可能 cache 更久 — JVM <code>networkaddress.cache.ttl</code> 預設 -1（cache forever）就會卡在這層</li>
</ul>
<p><strong>Endpoint 類型跟 failover 行為</strong>：</p>
<ul>
<li><strong>Writer endpoint</strong>：跟著 failover 走、DNS 切到新 primary、application 寫操作用這個</li>
<li><strong>Reader endpoint</strong>：load-balance 到所有 replica；failover 期間短暫包含 promoted replica（已升 primary）、reader query 可能打到 primary、引起寫鎖競爭</li>
<li><strong>Custom endpoint</strong>：用戶自定 routing rule、failover 期間行為要驗證、不能假設自動跟隨</li>
</ul>
<p><strong>跟通用 failover 差在哪</strong>：Aurora 不需要 data catch-up phase、failover 主要瓶頸是 DNS propagation + application reconnect、不是 promotion 本身。傳統 PostgreSQL streaming replication failover 要等 replica WAL catch-up（heavy write 期間可能秒級延遲）、Aurora 在 storage 設計下消除這段等待。</p>
<p>對應 knowledge card：<a href="/blog/backend/knowledge-cards/failover/" data-link-title="Failover" data-link-desc="說明主要服務或節點失效時如何切換到備援能力">failover</a>、<a href="/blog/backend/knowledge-cards/rto/" data-link-title="RTO" data-link-desc="說明恢復時間目標如何約束事故回復策略">rto</a>、<a href="/blog/backend/knowledge-cards/rpo/" data-link-title="RPO" data-link-desc="說明恢復點目標如何定義可接受資料損失範圍">rpo</a>。</p>
<h2 id="step-by-step-配置--量測">Step-by-step 配置 / 量測</h2>
<p><strong>Cluster failover 配置</strong>：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="c1"># 確認 cluster 至少有一個跨 AZ replica</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">aws rds describe-db-clusters <span class="se">\
</span></span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="se"></span>  --db-cluster-identifier my-cluster <span class="se">\
</span></span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="se"></span>  --query <span class="s1">&#39;DBClusters[0].DBClusterMembers&#39;</span>
</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"><span class="c1"># 設定 PromotionTier（0 最優先、15 最不優先）</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">aws rds modify-db-instance <span class="se">\
</span></span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="se"></span>  --db-instance-identifier my-replica-az-b <span class="se">\
</span></span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="se"></span>  --promotion-tier <span class="m">0</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">
</span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="c1"># 跨 region replica 預設 tier 15（不優先升、避免 failover 跨 region）</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl">aws rds modify-db-instance <span class="se">\
</span></span></span><span class="line"><span class="ln">13</span><span class="cl"><span class="se"></span>  --db-instance-identifier my-cross-region-replica <span class="se">\
</span></span></span><span class="line"><span class="ln">14</span><span class="cl"><span class="se"></span>  --promotion-tier <span class="m">15</span></span></span></code></pre></div><p><strong>Application 端 JVM 設定</strong>（最常踩雷的點）：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-properties" data-lang="properties"><span class="line"><span class="ln">1</span><span class="cl"><span class="c1"># JVM 系統 property、預設 -1 = cache forever、必改</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="na">networkaddress.cache.ttl</span><span class="o">=</span><span class="s">5</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="na">networkaddress.cache.negative.ttl</span><span class="o">=</span><span class="s">0</span></span></span></code></pre></div><p><strong>Connection pool 設定</strong>（HikariCP 範例）：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="ln">1</span><span class="cl"><span class="nt">spring.datasource.hikari</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="w">  </span><span class="nt">maximum-pool-size</span><span class="p">:</span><span class="w"> </span><span class="m">30</span><span class="w">
</span></span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="w">  </span><span class="nt">connection-test-query</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;SELECT 1&#34;</span><span class="w">
</span></span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="w">  </span><span class="nt">validation-timeout</span><span class="p">:</span><span class="w"> </span><span class="m">5000</span><span class="w">
</span></span></span><span class="line"><span class="ln">5</span><span class="cl"><span class="w">  </span><span class="nt">max-lifetime</span><span class="p">:</span><span class="w"> </span><span class="m">1800000</span><span class="w">      </span><span class="c"># 30 分鐘、強制 recycle connection</span><span class="w">
</span></span></span><span class="line"><span class="ln">6</span><span class="cl"><span class="w">  </span><span class="nt">keepalive-time</span><span class="p">:</span><span class="w"> </span><span class="m">30000</span><span class="w">      </span><span class="c"># 30 秒檢查 idle connection</span><span class="w">
</span></span></span><span class="line"><span class="ln">7</span><span class="cl"><span class="w">  </span><span class="nt">connection-timeout</span><span class="p">:</span><span class="w"> </span><span class="m">30000</span></span></span></code></pre></div><p><strong>Retry policy</strong>：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-java" data-lang="java"><span class="line"><span class="ln">1</span><span class="cl"><span class="c1">// 簡化範例、實際用 Resilience4j 或 Failsafe</span><span class="w">
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="w"></span><span class="n">RetryPolicy</span><span class="o">&lt;</span><span class="n">Object</span><span class="o">&gt;</span><span class="w"> </span><span class="n">retryPolicy</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">RetryPolicy</span><span class="p">.</span><span class="na">builder</span><span class="p">()</span><span class="w">
</span></span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="w">    </span><span class="p">.</span><span class="na">handle</span><span class="p">(</span><span class="n">SQLTransientConnectionException</span><span class="p">.</span><span class="na">class</span><span class="p">,</span><span class="w"> </span><span class="n">SQLNonTransientConnectionException</span><span class="p">.</span><span class="na">class</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="w">    </span><span class="p">.</span><span class="na">withBackoff</span><span class="p">(</span><span class="n">Duration</span><span class="p">.</span><span class="na">ofSeconds</span><span class="p">(</span><span class="n">1</span><span class="p">),</span><span class="w"> </span><span class="n">Duration</span><span class="p">.</span><span class="na">ofSeconds</span><span class="p">(</span><span class="n">30</span><span class="p">))</span><span class="w">
</span></span></span><span class="line"><span class="ln">5</span><span class="cl"><span class="w">    </span><span class="p">.</span><span class="na">withMaxAttempts</span><span class="p">(</span><span class="n">5</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="ln">6</span><span class="cl"><span class="w">    </span><span class="p">.</span><span class="na">build</span><span class="p">();</span></span></span></code></pre></div><p><strong>手動觸發 failover 量測 RTO</strong>：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl"><span class="c1"># 觸發 failover、記錄時間</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="nv">START</span><span class="o">=</span><span class="k">$(</span>date +%s%3N<span class="k">)</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">aws rds failover-db-cluster --db-cluster-identifier my-cluster
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="nb">echo</span> <span class="s2">&#34;Failover triggered at </span><span class="nv">$START</span><span class="s2"> ms&#34;</span>
</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"><span class="c1"># 用 application heartbeat 寫入時間戳</span>
</span></span><span class="line"><span class="ln">7</span><span class="cl"><span class="c1"># application 端跑 every-second insert、failover 後第一個成功 insert 的時間 - START = RTO</span></span></span></code></pre></div><p><strong>驗證點</strong>：</p>
<ul>
<li>CloudWatch <code>FailoverEvent</code> counter &gt; 0（failover 觸發訊號）</li>
<li><code>DatabaseConnections</code> 在 failover 期間 drop &gt; 50%、之後 spike（reconnect 風暴）</li>
<li>Application metric「first successful write after failover trigger」&lt; 30 秒</li>
</ul>
<p><strong>Rollback boundary</strong>：promotion 不可逆 — 原 primary 變 replica、不會自動 fallback。要切回原 AZ 必須再做一次 failover。</p>
<h2 id="故障模式--邊界-case">故障模式 / 邊界 case</h2>
<h3 id="case-1dns-cache-把-rto-從-30-秒拉到-120-秒">Case 1：DNS cache 把 RTO 從 30 秒拉到 120 秒</h3>
<p>徵兆：手動 failover 後、CloudWatch <code>FailoverEvent</code> 1 秒內出現、但 application log 顯示寫操作 120 秒後才恢復。</p>
<p>原因：JVM <code>networkaddress.cache.ttl</code> 預設 <code>-1</code>（cache forever）、application JVM 把 writer endpoint DNS 永久 cache 到舊 primary IP；只有 connection pool eviction 或 application restart 才會重新 resolve。</p>
<p>修：</p>
<ul>
<li>JVM startup 加 <code>-Dnetworkaddress.cache.ttl=5</code></li>
<li>或在 <code>$JAVA_HOME/lib/security/java.security</code> 改 <code>networkaddress.cache.ttl=5</code></li>
<li>Python application 通常沒這問題（DNS resolve per connection）、但要確認 SQLAlchemy 用 <code>pool_pre_ping=True</code></li>
</ul>
<h3 id="case-2connection-pool-cached-connection-全-stale">Case 2：Connection pool cached connection 全 stale</h3>
<p>徵兆：DNS 切換 OK、但 application 寫操作 timeout 10-30 秒後才觸發 reconnect、p99 latency spike。</p>
<p>原因：connection pool 的 cached connection 還指向舊 primary IP、validation 沒開或 timeout 太長、application 拿到 stale connection 才發現 backend gone。</p>
<p>修：</p>
<ul>
<li>HikariCP：<code>connection-test-query: &quot;SELECT 1&quot;</code> + <code>validation-timeout: 5000</code> + <code>keepalive-time: 30000</code></li>
<li>SQLAlchemy：<code>pool_pre_ping=True</code> + <code>pool_recycle=1800</code></li>
<li>failover 演練後驗證 connection pool 在 30 秒內 evict 完所有 stale connection</li>
</ul>
<h3 id="case-3reader-endpoint-failover-期間打到新-primary">Case 3：Reader endpoint failover 期間打到新 primary</h3>
<p>徵兆：failover 期間 application read query 偶發出現 <code>cannot execute SELECT in a read-only transaction</code> 或寫鎖競爭、用戶看到 inconsistent state。</p>
<p>原因：reader endpoint 是 DNS-based load balance 到所有 replica、failover 期間 <em>短暫</em> 包含已升 primary 的 replica（DNS propagation 期間 reader 跟 writer endpoint 都指向同一台）。Read query 打到 primary 後、跟正在寫的 transaction 競爭。</p>
<p>修：</p>
<ul>
<li>Application 端 read 跟 write data source 拆分、不要假設 reader endpoint 永遠 read-only</li>
<li>Failover 期間 application 端做 SQL error type 偵測、<code>read-only transaction</code> 錯誤觸發 retry</li>
<li>用 custom endpoint group 特定 replica、failover 期間 custom endpoint 行為更可控</li>
</ul>
<h3 id="case-4in-flight-transaction-全-abort">Case 4：In-flight transaction 全 abort</h3>
<p>徵兆：failover 期間正在執行的 transaction <em>全部 abort</em>、application 看到 <code>connection reset</code> 或 <code>server closed connection</code>、commit 沒成功。</p>
<p>原因：Aurora failover 不保留 transaction 狀態、所有 in-flight transaction（包括已執行 BEGIN 但還沒 COMMIT 的）全 abort。Application 沒做 idempotent retry 就會丟失 commit。</p>
<p>修：</p>
<ul>
<li>寫操作必須 idempotent（用 idempotency key、application 端做 deduplication）</li>
<li>在 application 層做 transaction-level retry、不在 connection 層 retry</li>
<li>重要寫入做 <em>write-then-verify</em> 模式：commit 後立刻 SELECT 確認、失敗才 retry</li>
</ul>
<h3 id="case-5promotiontier-配置忽略">Case 5：PromotionTier 配置忽略</h3>
<p>徵兆：failover 後 application latency 暴漲、發現升 primary 的是 cross-region replica。</p>
<p>原因：cross-region replica 預設 PromotionTier 是 1（或忘記改）、failover 時優先升、application 跟新 primary 跨 region、latency 從 5ms 變 100ms+。</p>
<p>修：</p>
<ul>
<li>cross-region replica <code>--promotion-tier 15</code>（不優先升）</li>
<li>同 region 跨 AZ replica <code>--promotion-tier 0</code> 或 <code>1</code></li>
<li>Multi-AZ deployment 至少配 2 個 same-region replica、避免 cross-region 被升</li>
</ul>
<h2 id="standard-chartered-為什麼選獨立-cluster-而非-global-database">Standard Chartered 為什麼選獨立 cluster 而非 Global Database</h2>
<p><a href="/blog/backend/09-performance-capacity/cases/standard-chartered-aurora-banking/" data-link-title="9.C14 Standard Chartered：受監管銀行的 Aurora 4000 TPS 容量提升" data-link-desc="Standard Chartered 銀行遷移到 Aurora 後吞吐量提升 10 倍至 4000 TPS、跨 7 個受監管市場">9.C14 Standard Chartered</a> 揭露受監管產業的 failover 設計選擇 — 案例「判讀」段第 1 點：「7 個受監管市場代表 7 個獨立 cluster（資料不能跨境）、容量規劃變成『7 個獨立規劃 × 各自合規門檻』」。</p>
<p><strong>合規 driver</strong>：</p>
<ul>
<li>受監管市場資料 <em>不能跨境複製</em></li>
<li>Aurora Global Database 是跨 region async replication、會把資料推到其他 region</li>
<li>→ Global Database 在這種場景 <em>違反合規</em>、不是 DR 選項</li>
<li>必須用每市場獨立 cluster、各自做 cross-AZ failover、各自吸收 RTO 預算</li>
</ul>
<p><strong>工程含義</strong>：</p>
<ul>
<li>每市場 cross-AZ failover RTO &lt; 30 秒、滿足當地監管 RTO 要求</li>
<li>跨市場 DR 不靠 Global Database、靠應用層的 <em>市場切換</em>（用戶從 A 市場切到 B 市場是業務決策、不是技術 failover）</li>
<li>7 個 cluster 各自獨立、operational surface area × 7（parameter group / backup / IAM / observability fan-out）、但合規要求壓倒運維成本</li>
</ul>
<p><strong>Fleet 拓樸</strong>：合規驅動的 fleet 設計（7 個受監管市場 = 7 個獨立 cluster）詳見 <a href="../read-replica-scaling/">Aurora read replica scaling</a> fleet 治理 SSoT 邊界段。本篇只展開 <em>單 cluster cross-AZ failover</em> 流程、不展開跨 cluster 拓樸決策。</p>
<p><strong>scope warning（必明示、case 自承）</strong>：Standard Chartered case 未公開是 PostgreSQL 還是 MySQL、未公開具體 cost 數字、屬「相關 case study」匿名對照。引用時不能擴寫具體 engine。</p>
<h2 id="容量與觀測">容量與觀測</h2>
<p><strong>核心 metric</strong>：</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">FailoverEvent           # failover 觸發 counter、&gt; 0 立即通知
</span></span><span class="line"><span class="ln">2</span><span class="cl">DatabaseConnections     # failover 期間 drop、之後 spike
</span></span><span class="line"><span class="ln">3</span><span class="cl">AuroraReplicaLag        # failover 前 replica 是否 caught up</span></span></code></pre></div><p><strong>Application 端 metric</strong>：</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">first_successful_write_after_failover  # 真實 RTO
</span></span><span class="line"><span class="ln">2</span><span class="cl">connection_pool_error_rate              # stale connection 訊號
</span></span><span class="line"><span class="ln">3</span><span class="cl">db_retry_count                          # retry policy 觸發頻率</span></span></code></pre></div><p><strong>量測 RTO 流程</strong>：</p>
<ol>
<li>跑 application 端 every-second heartbeat insert</li>
<li>手動觸發 failover、記錄 trigger 時間戳</li>
<li>從 heartbeat insert log 找 failover 後第一個成功 insert 的時間戳</li>
<li>差值 = 真實 RTO（包含 detection + promotion + DNS + reconnect）</li>
</ol>
<p><strong>Alert</strong>：</p>
<ul>
<li><code>FailoverEvent &gt; 0</code> 立即通知 on-call</li>
<li><code>DatabaseConnections</code> 5 分鐘內 drop &gt; 50% 警告 stale connection</li>
<li><code>db_retry_count</code> 短期內 spike 警告 reconnect 風暴</li>
</ul>
<p><strong>Failover 演練頻率</strong>：</p>
<ul>
<li>Non-critical workload：每季一次 planned failover drill</li>
<li>受監管產業（Standard Chartered 類）：每月一次、有合規 sign-off 記錄</li>
<li>重大版本升級前必跑一次</li>
</ul>
<p><strong>回路徑</strong>：<a href="/blog/backend/08-incident-response/" data-link-title="模組八：事故處理與復盤" data-link-desc="用 IR 領域詞彙建問題節點、以服務級案例庫累積事故脈絡，先建概念與案例庫再進實作交接">8.x incident response</a> failover playbook、<a href="/blog/backend/09-performance-capacity/bottleneck-localization/" data-link-title="9.5 瓶頸定位流程" data-link-desc="從 app 到 DB / cache / broker / 第三方 quota 的逐層瓶頸定位">9.5 瓶頸定位流程</a> 判斷 reconnect-bound vs query-bound。</p>
<h2 id="邊界與整合--下一步">邊界與整合 / 下一步</h2>
<p><strong>Sibling deep articles</strong>：</p>
<ul>
<li><a href="../storage-architecture/">Aurora storage architecture</a> — 理解為什麼 Aurora failover 不需要 data catch-up（storage 跨 AZ 共享）</li>
<li><a href="../read-replica-scaling/">Aurora read replica scaling</a> — replica 升 primary 流程跟 fleet 治理 SSoT</li>
<li><a href="../global-database-multi-region/">Aurora Global Database</a> — 跨 region failover RTO 不同數量級（2-15 分鐘 vs cross-AZ &lt; 30 秒）</li>
</ul>
<p><strong>Migration playbook</strong>：</p>
<ul>
<li><a href="../migrate-from-self-managed-pg-mysql/">PostgreSQL / MySQL → Aurora</a> — HA redesign 是 operational redesign 主項、從 Patroni / Orchestrator 切到 Aurora cluster endpoint</li>
</ul>
<p><strong>1.x 章節互引</strong>：</p>
<ul>
<li><a href="/blog/backend/01-database/transaction-boundary/" data-link-title="1.3 Transaction 與一致性邊界" data-link-desc="交易邊界、isolation level、retry 策略、distributed transaction（2PC、Saga）與跨 region 強一致取捨">1.3 Transaction Boundary</a> — failover 期間 in-flight transaction abort 對 application 契約的影響</li>
<li><a href="/blog/backend/08-incident-response/" data-link-title="模組八：事故處理與復盤" data-link-desc="用 IR 領域詞彙建問題節點、以服務級案例庫累積事故脈絡，先建概念與案例庫再進實作交接">8.x incident response</a> — failover decision log</li>
</ul>
<p><strong>何時不用本文</strong>：non-critical workload、RTO 預算 &gt; 5 分鐘、Multi-AZ 預設配置足夠時可跳過、看 <a href="/blog/backend/01-database/vendors/aurora/" data-link-title="AWS Aurora" data-link-desc="AWS managed PostgreSQL / MySQL、storage / compute 分離、&#43;75% 效能改善的 production 證據">Aurora vendor overview</a> 即可。</p>
<h2 id="相關連結">相關連結</h2>
<ul>
<li><a href="/blog/backend/01-database/vendors/aurora/" data-link-title="AWS Aurora" data-link-desc="AWS managed PostgreSQL / MySQL、storage / compute 分離、&#43;75% 效能改善的 production 證據">Aurora vendor overview</a> — 服務定位、適用 / 不適用場景</li>
<li><a href="/blog/backend/knowledge-cards/failover/" data-link-title="Failover" data-link-desc="說明主要服務或節點失效時如何切換到備援能力">Failover 卡片</a> — 概念基底</li>
<li><a href="/blog/backend/knowledge-cards/rto/" data-link-title="RTO" data-link-desc="說明恢復時間目標如何約束事故回復策略">RTO 卡片</a> — RTO 量測判讀</li>
<li><a href="/blog/posts/vendor-%E6%B7%B1%E5%BA%A6%E6%8A%80%E8%A1%93%E6%96%87%E7%AB%A0%E6%96%B9%E6%B3%95%E8%AB%96%E7%9A%84%E6%BC%94%E5%8C%96%E7%B4%80%E9%8C%84%E5%90%8C-vendor-%E7%B3%BB%E5%88%97%E7%9A%84%E9%96%8B%E5%A0%B4%E8%BC%AA%E6%9B%BF%E9%A9%97%E8%AD%89/" data-link-title="Vendor 深度技術文章方法論的演化紀錄：同 vendor 系列的開場輪替驗證" data-link-desc="vendor overview 飽和後要寫單一功能深度文章、需要選題與結構依據時回來。這套方法論的驗證來源與 cadence variant 在高風險場景（同 vendor sub-tool 系列）的實證。">Vendor 深度技術文章方法論</a> — 本文遵循的 6 規格面寫作模板</li>
<li>官方：<a href="https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/Concepts.AuroraHighAvailability.html">Aurora high availability</a></li>
</ul>
]]></content:encoded></item><item><title>Aurora Read Replica Scaling：15 replica 上限、lag profile、headroom 預留與 fleet 治理</title><link>https://tarrragon.github.io/blog/backend/01-database/vendors/aurora/read-replica-scaling/</link><pubDate>Wed, 27 May 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/backend/01-database/vendors/aurora/read-replica-scaling/</guid><description>&lt;p>Aurora 「最多 15 read replica」是文件數字、實際 production 部署常常更早遇到拆 cluster 的決策點 — 不是 15 replica 不夠用、是 &lt;a href="https://tarrragon.github.io/blog/backend/knowledge-cards/blast-radius/" data-link-title="Blast Radius" data-link-desc="說明事故影響面如何估算與隔離">blast radius&lt;/a>、業務 sharding、微服務 ownership、合規 boundary 早在 15 replica 之前就推動拆 cluster。本文同時展開兩個議題：(1) 單 cluster 內 read replica 怎麼用、容量怎麼規劃、lag 怎麼管；(2) Aurora fleet 治理的 3 條 driver、什麼條件下拆 cluster vs 加 replica。後者是 Aurora 系列的 &lt;em>fleet 治理 SSoT&lt;/em> — &lt;a href="../storage-architecture/">Aurora storage architecture&lt;/a> / &lt;a href="../cross-az-failover-rto/">Aurora cross-AZ failover RTO&lt;/a> / &lt;a href="../global-database-multi-region/">Aurora Global Database&lt;/a> / &lt;a href="../migrate-from-self-managed-pg-mysql/">Aurora migration playbook&lt;/a> 都 cross-link 到本篇、不重複展開。&lt;/p>
&lt;p>本文不是 Aurora overview（請看 &lt;a href="https://tarrragon.github.io/blog/backend/01-database/vendors/aurora/" data-link-title="AWS Aurora" data-link-desc="AWS managed PostgreSQL / MySQL、storage / compute 分離、&amp;#43;75% 效能改善的 production 證據">Aurora vendor 頁&lt;/a>）— 而是 read replica 跟 fleet 拓樸的實作層教學。前置閱讀建議 &lt;a href="../storage-architecture/">Aurora storage architecture&lt;/a>（理解共享 storage 為什麼能養大量 replica）。&lt;/p>
&lt;h2 id="問題情境">問題情境&lt;/h2>
&lt;p>典型觸發場景：FanDuel Super Bowl / DraftKings 比賽日、流量 5-10 倍尖峰、read query（用戶查 balance、投注紀錄、odds）打爆 primary、需要快速擴 read replica 但又怕 lag 把 stale read 推到 user-facing。&lt;/p>
&lt;p>讀者常見的具體疑問：&lt;/p>
&lt;ul>
&lt;li>「加 read replica 後 primary CPU 沒降、為什麼？」&lt;/li>
&lt;li>「Auto-scaling 加 replica 要幾分鐘、來不及接尖峰怎麼辦？」&lt;/li>
&lt;li>「Reader endpoint round-robin 把 query 打到 lag 大的 replica、用戶看到舊 balance」&lt;/li>
&lt;li>「業務跨 200 個 cluster、單個 cluster 才 5-10 個 replica、為什麼不集中？」&lt;/li>
&lt;/ul>
&lt;p>進一步問題：讀寫雙峰錯位是 Aurora 讀寫分流的核心 driver。&lt;a href="https://tarrragon.github.io/blog/backend/09-performance-capacity/cases/draftkings-aurora-financial-ledger/" data-link-title="9.C4 DraftKings：Aurora 撐 100 萬 ops/min 的體育博彩金融帳本" data-link-desc="DraftKings 用 Aurora MySQL 跑體育博彩金融帳本、Super Bowl 流量 &amp;#43;50% 不影響延遲">9.C4 DraftKings&lt;/a> 揭露「write workloads spike up significantly around payout events, but opening the app during the game also activates a lot of balance queries」— 比賽進行時讀爆量、payout event 時寫爆量、兩個峰不在同一時刻。這代表 read replica 容量規劃不是「分散負載」、而是「為讀峰專門配置 capacity」。&lt;/p>
&lt;p>&lt;a href="https://tarrragon.github.io/blog/backend/09-performance-capacity/cases/fanduel-dual-peak-betting-streaming/" data-link-title="9.C28 FanDuel：體育直播 &amp;#43; 投注的雙重峰值" data-link-desc="FanDuel 3.5M MAU、Super Bowl 期間擴容 5-10 倍、用 AWS Local Zones &amp;#43; Wavelength &amp;#43; Outposts 處理 20&amp;#43; 州的雙重峰值">9.C28 FanDuel&lt;/a> 揭露事件型容量分級：平日 baseline → 季後賽 2-3x → 季冠軍賽 4-5x → Super Bowl 5-10x。容量規劃要按事件級別分段、不是一律 10x。&lt;/p></description><content:encoded><![CDATA[<p>Aurora 「最多 15 read replica」是文件數字、實際 production 部署常常更早遇到拆 cluster 的決策點 — 不是 15 replica 不夠用、是 <a href="/blog/backend/knowledge-cards/blast-radius/" data-link-title="Blast Radius" data-link-desc="說明事故影響面如何估算與隔離">blast radius</a>、業務 sharding、微服務 ownership、合規 boundary 早在 15 replica 之前就推動拆 cluster。本文同時展開兩個議題：(1) 單 cluster 內 read replica 怎麼用、容量怎麼規劃、lag 怎麼管；(2) Aurora fleet 治理的 3 條 driver、什麼條件下拆 cluster vs 加 replica。後者是 Aurora 系列的 <em>fleet 治理 SSoT</em> — <a href="../storage-architecture/">Aurora storage architecture</a> / <a href="../cross-az-failover-rto/">Aurora cross-AZ failover RTO</a> / <a href="../global-database-multi-region/">Aurora Global Database</a> / <a href="../migrate-from-self-managed-pg-mysql/">Aurora migration playbook</a> 都 cross-link 到本篇、不重複展開。</p>
<p>本文不是 Aurora overview（請看 <a href="/blog/backend/01-database/vendors/aurora/" data-link-title="AWS Aurora" data-link-desc="AWS managed PostgreSQL / MySQL、storage / compute 分離、&#43;75% 效能改善的 production 證據">Aurora vendor 頁</a>）— 而是 read replica 跟 fleet 拓樸的實作層教學。前置閱讀建議 <a href="../storage-architecture/">Aurora storage architecture</a>（理解共享 storage 為什麼能養大量 replica）。</p>
<h2 id="問題情境">問題情境</h2>
<p>典型觸發場景：FanDuel Super Bowl / DraftKings 比賽日、流量 5-10 倍尖峰、read query（用戶查 balance、投注紀錄、odds）打爆 primary、需要快速擴 read replica 但又怕 lag 把 stale read 推到 user-facing。</p>
<p>讀者常見的具體疑問：</p>
<ul>
<li>「加 read replica 後 primary CPU 沒降、為什麼？」</li>
<li>「Auto-scaling 加 replica 要幾分鐘、來不及接尖峰怎麼辦？」</li>
<li>「Reader endpoint round-robin 把 query 打到 lag 大的 replica、用戶看到舊 balance」</li>
<li>「業務跨 200 個 cluster、單個 cluster 才 5-10 個 replica、為什麼不集中？」</li>
</ul>
<p>進一步問題：讀寫雙峰錯位是 Aurora 讀寫分流的核心 driver。<a href="/blog/backend/09-performance-capacity/cases/draftkings-aurora-financial-ledger/" data-link-title="9.C4 DraftKings：Aurora 撐 100 萬 ops/min 的體育博彩金融帳本" data-link-desc="DraftKings 用 Aurora MySQL 跑體育博彩金融帳本、Super Bowl 流量 &#43;50% 不影響延遲">9.C4 DraftKings</a> 揭露「write workloads spike up significantly around payout events, but opening the app during the game also activates a lot of balance queries」— 比賽進行時讀爆量、payout event 時寫爆量、兩個峰不在同一時刻。這代表 read replica 容量規劃不是「分散負載」、而是「為讀峰專門配置 capacity」。</p>
<p><a href="/blog/backend/09-performance-capacity/cases/fanduel-dual-peak-betting-streaming/" data-link-title="9.C28 FanDuel：體育直播 &#43; 投注的雙重峰值" data-link-desc="FanDuel 3.5M MAU、Super Bowl 期間擴容 5-10 倍、用 AWS Local Zones &#43; Wavelength &#43; Outposts 處理 20&#43; 州的雙重峰值">9.C28 FanDuel</a> 揭露事件型容量分級：平日 baseline → 季後賽 2-3x → 季冠軍賽 4-5x → Super Bowl 5-10x。容量規劃要按事件級別分段、不是一律 10x。</p>
<p>對 <a href="/blog/backend/09-performance-capacity/cases/standard-chartered-aurora-banking/" data-link-title="9.C14 Standard Chartered：受監管銀行的 Aurora 4000 TPS 容量提升" data-link-desc="Standard Chartered 銀行遷移到 Aurora 後吞吐量提升 10 倍至 4000 TPS、跨 7 個受監管市場">9.C14 Standard Chartered</a> 這種受監管金融、不能用單一巨型 cluster — 7 個受監管市場 = 7 個獨立 cluster、合規 boundary 比運維成本優先。</p>
<h2 id="核心機制15-replica-上限共享-storagereader-endpoint">核心機制：15 replica 上限、共享 storage、reader endpoint</h2>
<p>Aurora read replica 的 first-class concept 是 <em>共享 storage + DNS-based reader endpoint</em>。傳統 PostgreSQL streaming replication 靠 primary push WAL 給 replica、replica 自己 apply；Aurora replica 直接從共享 storage 讀已 apply 的 page、不需要 catch-up。</p>
<p><strong>15 replica 上限</strong>：</p>
<ul>
<li>每個 Aurora cluster 最多 15 個 read replica（跨 AZ）</li>
<li>跨 region replica 走 <a href="../global-database-multi-region/">Aurora Global Database</a>（不算這 15 個）</li>
<li>文件上限不是 production 真實上限 — 多數 production 部署在 5-10 replica 之間遇到拆 cluster 訊號</li>
</ul>
<p><strong>共享 storage 對 lag 的影響</strong>：</p>
<ul>
<li>Replica 不靠 logical replication catch-up、直接從共享 storage 讀</li>
<li>Lag 來源是 <em>compute node 的 buffer cache 同步</em>、不是 WAL replay</li>
<li>Typical 10-30ms、heavy write 期間可能 100ms+、但 <em>不會像 PostgreSQL 那樣 unbounded</em></li>
</ul>
<p><strong>DraftKings 揭露的「lag 可預測」frame</strong>（<a href="/blog/backend/09-performance-capacity/cases/draftkings-aurora-financial-ledger/" data-link-title="9.C4 DraftKings：Aurora 撐 100 萬 ops/min 的體育博彩金融帳本" data-link-desc="DraftKings 用 Aurora MySQL 跑體育博彩金融帳本、Super Bowl 流量 &#43;50% 不影響延遲">case「判讀」段第 2 點</a>）：</p>
<p>「30 秒降到 10-30 ms」的工程意義不只是「快」、而是「讓 read-after-write 變得可預測」。30 秒 lag 的世界裡、application 端做 read-after-write 要 cache 用戶最後寫入 30 秒以上、實務上做不到；10-30ms lag 的世界裡、application 可以做「寫操作後 100ms 內走 primary、之後可走 replica」的可規劃策略。</p>
<p><strong>Reader endpoint 行為</strong>：</p>
<ul>
<li>DNS-based round-robin、不感知 replica 健康狀態</li>
<li>Application 想要 lag-aware routing 要自己實作或用 RDS Proxy</li>
<li>Failover 期間短暫包含 promoted replica（已升 primary）、見 <a href="../cross-az-failover-rto/">Aurora cross-AZ failover RTO</a></li>
</ul>
<p><strong>Auto-scaling policy</strong>：</p>
<ul>
<li>CloudWatch metric（CPU / connection）trigger</li>
<li>Replica creation 2-5 分鐘</li>
<li><em>無法用於秒級尖峰</em> — 是 DraftKings「+50% no sweat」誤讀的關鍵點</li>
</ul>
<p><strong>跟通用 read replica 差在哪</strong>：Aurora replica 不用 catch-up WAL、lag 上限可預測；vs PostgreSQL streaming replication lag 是 unbounded（取決於 primary 寫速度）。可預測 lag 是 read-after-write 場景變得可規劃的前提。</p>
<p>對應 knowledge card：<a href="/blog/backend/knowledge-cards/replication-lag/" data-link-title="Replication Lag" data-link-desc="說明資料副本落後正式來源多久，以及它如何影響讀取正確性">replication-lag</a>、<a href="/blog/backend/knowledge-cards/stale-read/" data-link-title="Stale Read" data-link-desc="讀取到落後於最新寫入版本的舊資料">stale-read</a>。</p>
<h2 id="step-by-step-配置--reader-endpoint-設計">Step-by-step 配置 / Reader endpoint 設計</h2>
<p><strong>建 read replica</strong>：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl">aws rds create-db-instance <span class="se">\
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="se"></span>  --db-cluster-identifier my-cluster <span class="se">\
</span></span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="se"></span>  --db-instance-identifier my-replica-01 <span class="se">\
</span></span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="se"></span>  --db-instance-class db.r6g.4xlarge <span class="se">\
</span></span></span><span class="line"><span class="ln">5</span><span class="cl"><span class="se"></span>  --engine aurora-postgresql <span class="se">\
</span></span></span><span class="line"><span class="ln">6</span><span class="cl"><span class="se"></span>  --availability-zone us-east-1b <span class="se">\
</span></span></span><span class="line"><span class="ln">7</span><span class="cl"><span class="se"></span>  --promotion-tier <span class="m">1</span></span></span></code></pre></div><p><strong>Reader endpoint vs Custom endpoint</strong>：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl"><span class="c1"># 預設 reader endpoint：所有 replica round-robin</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="c1"># 訪問 url: my-cluster.cluster-ro-xxx.us-east-1.rds.amazonaws.com</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="c1"># Custom endpoint：group 特定 replica</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl">aws rds create-db-cluster-endpoint <span class="se">\
</span></span></span><span class="line"><span class="ln">6</span><span class="cl"><span class="se"></span>  --db-cluster-identifier my-cluster <span class="se">\
</span></span></span><span class="line"><span class="ln">7</span><span class="cl"><span class="se"></span>  --db-cluster-endpoint-identifier my-cluster-analytics <span class="se">\
</span></span></span><span class="line"><span class="ln">8</span><span class="cl"><span class="se"></span>  --endpoint-type READER <span class="se">\
</span></span></span><span class="line"><span class="ln">9</span><span class="cl"><span class="se"></span>  --static-members my-replica-analytics-01 my-replica-analytics-02</span></span></code></pre></div><p>Custom endpoint 適用場景：</p>
<ul>
<li>分析 query 走獨立 endpoint、不影響 OLTP read replica</li>
<li>Read-after-write session 走 primary endpoint、其他 read 走 reader endpoint</li>
<li>不同 SLO 的 read traffic 分流（high-priority vs batch）</li>
</ul>
<p><strong>Auto-scaling policy</strong>：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln"> 1</span><span class="cl">aws application-autoscaling register-scalable-target <span class="se">\
</span></span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="se"></span>  --service-namespace rds <span class="se">\
</span></span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="se"></span>  --resource-id cluster:my-cluster <span class="se">\
</span></span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="se"></span>  --scalable-dimension rds:cluster:ReadReplicaCount <span class="se">\
</span></span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="se"></span>  --min-capacity <span class="m">2</span> <span class="se">\
</span></span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="se"></span>  --max-capacity <span class="m">10</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">aws application-autoscaling put-scaling-policy <span class="se">\
</span></span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="se"></span>  --service-namespace rds <span class="se">\
</span></span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="se"></span>  --resource-id cluster:my-cluster <span class="se">\
</span></span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="se"></span>  --scalable-dimension rds:cluster:ReadReplicaCount <span class="se">\
</span></span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="se"></span>  --policy-name my-cluster-cpu-scaling <span class="se">\
</span></span></span><span class="line"><span class="ln">13</span><span class="cl"><span class="se"></span>  --policy-type TargetTrackingScaling <span class="se">\
</span></span></span><span class="line"><span class="ln">14</span><span class="cl"><span class="se"></span>  --target-tracking-scaling-policy-configuration file://scaling-config.json</span></span></code></pre></div><p><strong>預配 vs auto-scale</strong>：</p>
<ul>
<li>Peak workload 預知（賽事、促銷、季節事件）→ 提前 1 小時預配</li>
<li>Unpredictable burst → auto-scale（接受 2-5 分鐘 lead time）</li>
<li>兩者混合：baseline 預配 + auto-scale 處理 baseline 之上的浮動</li>
</ul>
<p><strong>驗證點</strong>：</p>
<ul>
<li><code>AuroraReplicaLag</code> &lt; 100ms（per replica）</li>
<li>Reader endpoint CPU 分布均勻（不是某 replica 過熱）</li>
<li>Application stale-read error rate &lt; 0.1%</li>
</ul>
<p><strong>Rollback boundary</strong>：移除 replica 即時生效、無 data loss；但 reader endpoint DNS cache 仍可能短暫 routing 到已移除 replica（5-30 秒）。</p>
<h2 id="故障模式--邊界-case">故障模式 / 邊界 case</h2>
<h3 id="case-1加-replica-後-primary-cpu-沒降">Case 1：加 replica 後 primary CPU 沒降</h3>
<p>徵兆：明明加了 3 個 read replica、primary CPU 仍然 90%、reader endpoint CPU 才 10%。</p>
<p>原因：application 沒把 read query routing 到 reader endpoint、所有 query 仍打 primary。Aurora reader endpoint 不會自動分流 — 必須 application 端拆 read / write data source。</p>
<p>修：</p>
<ul>
<li>Application 端 ORM / data source layer 拆 read / write connection pool</li>
<li>寫操作用 writer endpoint、純讀走 reader endpoint</li>
<li>雙峰錯位是這層拆分的 driver（<a href="/blog/backend/09-performance-capacity/cases/draftkings-aurora-financial-ledger/" data-link-title="9.C4 DraftKings：Aurora 撐 100 萬 ops/min 的體育博彩金融帳本" data-link-desc="DraftKings 用 Aurora MySQL 跑體育博彩金融帳本、Super Bowl 流量 &#43;50% 不影響延遲">DraftKings case 揭露</a> 讀寫資源規劃要分開）</li>
</ul>
<h3 id="case-2reader-endpoint-round-robin-推-stale-read">Case 2：Reader endpoint round-robin 推 stale read</h3>
<p>徵兆：read-after-write 場景（用戶下注後立刻查 balance）打到 lagging replica、看到舊 balance、客訴。</p>
<p>原因：reader endpoint DNS-based round-robin、不感知 lag。Application 假設 read 永遠 fresh、但 typical 10-30ms lag 期間用戶操作就會踩到。</p>
<p>修：</p>
<ul>
<li>Sticky session：寫操作後 N 秒內同 session 走 primary（N = lag p99、typical 100ms）</li>
<li>Application 端做「下注後 N 秒走 primary」邏輯（DraftKings「可預測 lag」frame 讓 N 秒可規劃）</li>
<li>或用 RDS Proxy 提供 lag-aware routing（managed alternative）</li>
</ul>
<h3 id="case-3auto-scaling-來不及接秒級尖峰--headroom-預留判讀">Case 3：Auto-scaling 來不及接秒級尖峰 — headroom 預留判讀</h3>
<p>徵兆：賽事開賽 30 秒內流量 +50%、auto-scaling 觸發但 2-5 分鐘後才有新 replica、開賽尖峰已過、用戶在最關鍵時段看到 timeout。</p>
<p>機制限制：replica creation 2-5 分鐘、秒級尖峰過去了 replica 才上線。</p>
<p><strong>DraftKings「Super Bowl +50% no sweat」的工程意義</strong>（<a href="/blog/backend/09-performance-capacity/cases/draftkings-aurora-financial-ledger/" data-link-title="9.C4 DraftKings：Aurora 撐 100 萬 ops/min 的體育博彩金融帳本" data-link-desc="DraftKings 用 Aurora MySQL 跑體育博彩金融帳本、Super Bowl 流量 &#43;50% 不影響延遲">case「判讀」段第 3 點原文</a>）：「這句話的工程意義是 <em>提前做好容量規劃</em>、不是『Aurora 神奇』。寫 workload 預期可能 +50%、整個 system headroom 預留至少 50%、加上 read replica 動態加減、才能讓 50% 增幅變成『不流汗』」。</p>
<p>工程含義：</p>
<ul>
<li>Peak workload 預知（賽事 / 促銷）用 <em>headroom 預留 + <a href="/blog/backend/knowledge-cards/scheduled-scaling/" data-link-title="Scheduled Scaling" data-link-desc="說明按已知時間表預先擴容的 autoscaler 模式">scheduled scaling</a> 提前預配</em>、不靠 auto-scale 接秒級</li>
<li>Auto-scale 是 unpredictable burst 才用（突發新聞、KOL 推廣、未預期事件）</li>
<li>DraftKings 的「不流汗」是 <em>系統設計</em> 結果、不是 Aurora 特殊能力</li>
</ul>
<p>修：</p>
<ul>
<li>賽事日曆建模：賽前 1 小時自動加 replica、賽後 2 小時減</li>
<li>Primary instance class 升級提前一週、不是賽前升（升級期間 failover 風險）</li>
<li>Headroom 預算：read replica 預留 50%、primary CPU baseline &lt; 50%</li>
</ul>
<h3 id="case-415-replica-上限--拆-cluster-訊號">Case 4：15 replica 上限 — 拆 cluster 訊號</h3>
<p>徵兆：read traffic 持續成長、加到 15 replica 仍接近 CPU 瓶頸、想加第 16 個被 API 拒絕。</p>
<p>原因：Aurora 硬上限 15 replica / cluster、超過要拆 cluster。但實務上更常在 5-10 replica 就遇到其他拆 cluster 訊號（blast radius、ownership boundary、業務 sharding）。</p>
<p>修：見下方「邊界與整合：fleet 治理 SSoT」段、按 3 條 driver 判讀拆 cluster vs 加 replica。</p>
<h3 id="case-5heavy-write-期間-replica-lag-spike">Case 5：Heavy write 期間 replica lag spike</h3>
<p>徵兆：bulk insert / DDL 期間 replica lag 從 10-30ms 跳到 100-500ms、application 假設 typical lag 永遠成立、stale read 比例大幅上升。</p>
<p>原因：heavy write 期間 replica buffer cache invalidate 速度跟不上、lag 暫時拉大。Aurora 的「可預測 lag」不等於「lag 永遠 10-30ms」。</p>
<p>修：</p>
<ul>
<li>bulk insert / DDL 期間 application 端切到全 primary 模式（避開 stale read 風險）</li>
<li>重要 DDL 用 <a href="https://github.com/reorg/pg_repack">pg_repack</a> 或 logical migration、避免長時間 table lock</li>
<li>監測 <code>AuroraReplicaLagMaximum</code>、spike 超過 p99 threshold trigger application 端 fallback</li>
</ul>
<h3 id="case-6fanduel-雙-slo-並行--不要壓成單一數字">Case 6：FanDuel 雙 SLO 並行 — 不要壓成單一數字</h3>
<p>徵兆：team 看 FanDuel「5-10x peak」直接套到自家 streaming workload、結果 Aurora 撐不住、發現 FanDuel streaming 根本不走 Aurora。</p>
<p><a href="/blog/backend/09-performance-capacity/cases/fanduel-dual-peak-betting-streaming/" data-link-title="9.C28 FanDuel：體育直播 &#43; 投注的雙重峰值" data-link-desc="FanDuel 3.5M MAU、Super Bowl 期間擴容 5-10 倍、用 AWS Local Zones &#43; Wavelength &#43; Outposts 處理 20&#43; 州的雙重峰值">9.C28 FanDuel</a> case「判讀」段第 1 點原文：「直播跟投注是兩種完全不同 SLO：直播容忍秒級延遲（用 CDN + ABR 串流）、投注必須毫秒級成交。兩個服務必須各自獨立擴容、各自獨立 SLO」。</p>
<p><strong>scope warning（必明示）</strong>：</p>
<ul>
<li>FanDuel 5-10x 是 <em>betting 服務的 Aurora 擴容倍數</em>、不是 streaming</li>
<li>Streaming 走 CDN、不走 Aurora</li>
<li>不能把兩種 SLO 壓縮成「Aurora 撐 5-10x」單一數字</li>
</ul>
<p><strong>case 自承的進一步 scope warning</strong>：「AWS 案例 <em>沒有</em> 提具體 betting transaction TPS、concurrent streams、延遲分布」（case「需要警惕」段）。引用 FanDuel 時不能寫「Aurora 在 betting 路徑撐 X TPS」這類細節 — case 沒提的數字不能擴寫。</p>
<p>修：</p>
<ul>
<li>不同 SLO workload 拆獨立 cluster 或拆 read / write data source</li>
<li>容量規劃看自家 workload TPS、不要套用未公開的 case 數字</li>
</ul>
<h2 id="事件型容量分級表">事件型容量分級表</h2>
<p><a href="/blog/backend/09-performance-capacity/cases/fanduel-dual-peak-betting-streaming/" data-link-title="9.C28 FanDuel：體育直播 &#43; 投注的雙重峰值" data-link-desc="FanDuel 3.5M MAU、Super Bowl 期間擴容 5-10 倍、用 AWS Local Zones &#43; Wavelength &#43; Outposts 處理 20&#43; 州的雙重峰值">9.C28 FanDuel</a> 揭露事件型 scaling 不是一律 10x — <em>事件級別</em> 是容量分級單位：</p>
<table>
  <thead>
      <tr>
          <th>事件級別</th>
          <th>倍數</th>
          <th>來源</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>平日 baseline</td>
          <td>1x</td>
          <td>FanDuel case「判讀」段第 3 點</td>
      </tr>
      <tr>
          <td>季後賽 playoff</td>
          <td>2-3x</td>
          <td>FanDuel case 揭露事件分級</td>
      </tr>
      <tr>
          <td>季冠軍賽 championship</td>
          <td>4-5x</td>
          <td>FanDuel case 揭露事件分級</td>
      </tr>
      <tr>
          <td>Super Bowl</td>
          <td>5-10x</td>
          <td>FanDuel case 揭露事件分級</td>
      </tr>
  </tbody>
</table>
<p><strong>Frame 8 event-driven scaling 5 模式（跨 vendor 共寫）</strong>：本表是 Aurora 端從讀峰視角切入的事件分級、跟 <a href="/blog/backend/01-database/vendors/dynamodb/on-demand-vs-provisioned/" data-link-title="DynamoDB On-Demand vs Provisioned：6 軸決策、auto-scaling 邊界與 cost crossover" data-link-desc="capacity mode 選擇不是單軸 peak/avg ratio；本文展開 6 軸決策（peak/avg / 讀寫比 trend / surge 暫時 vs 永久 baseline / predictable-peak vs flash-sale / DBA 工時釋放 / vendor vs 自管 cost crossover），含 Zomato 50% 成本下降、Zoom 30x permanent surge、Amazon Ads sustained workload 等 case 分軸 anchor">DynamoDB on-demand-vs-provisioned</a> 的 5 模式分類（flash-sale spike / predictable peak / sustained growth / surge baseline permanent shift / B2B sustained + 高可用）共軸。Aurora 端的 FanDuel 季賽 cycle 在 5 模式分類中對應 <em>predictable peak</em> 的時間序列展開 — 事件 tier 已知（賽季 → 季後賽 → 季冠軍賽 → Super Bowl）、按 tier 預配 read replica 數量、本質是「峰值已知 + 重複出現」的 predictable peak 在多 tier 結構下的延伸。</p>
<p><strong>KV 層 vs SQL 層的 mode 決策差異</strong>：DynamoDB 端的 on-demand vs provisioned mode 是 KV vendor 的容量抽象（軸 1 peak/avg ratio / 軸 4 predictable-peak vs flash-sale）、詳見 <a href="/blog/backend/01-database/vendors/dynamodb/on-demand-vs-provisioned/" data-link-title="DynamoDB On-Demand vs Provisioned：6 軸決策、auto-scaling 邊界與 cost crossover" data-link-desc="capacity mode 選擇不是單軸 peak/avg ratio；本文展開 6 軸決策（peak/avg / 讀寫比 trend / surge 暫時 vs 永久 baseline / predictable-peak vs flash-sale / DBA 工時釋放 / vendor vs 自管 cost crossover），含 Zomato 50% 成本下降、Zoom 30x permanent surge、Amazon Ads sustained workload 等 case 分軸 anchor">DynamoDB on-demand-vs-provisioned 6 軸決策</a>、本篇不展開。Aurora 端對應的決策是 <em>read replica 數量 + auto-scaling vs scheduled scaling vs headroom 預留</em>、靠的是 replica fleet size 而非 mode 切換。</p>
<p>兩 vendor 在 Frame 8 各自承擔：</p>
<ul>
<li><strong>DynamoDB on-demand-vs-provisioned</strong>：5 模式分類 SSoT、mode × 事件型分類的合成判讀</li>
<li><strong>Aurora read-replica-scaling（本篇）</strong>：read 峰值的 headroom 預留 + 雙 SLO 並行（FanDuel 分級 + DraftKings 讀寫雙峰錯位）+ fleet 治理</li>
</ul>
<p><strong>case 自帶警示（scope warning 必保留）</strong>：</p>
<ul>
<li>「5-10x」是 <em>峰值倍數</em>、不是 <em>peak 持續時間</em>。Super Bowl 的關鍵 30 分鐘可能 8-10x、其他 3 小時可能 3-5x（case「需要警惕」段）</li>
<li>分級 driver 是「同類事件中的最高倍率」、不是恆定數字 — 引用時要保留事件 tier 對應、不是一律「Super Bowl = 10x」單一閾值</li>
<li>跨業務 transfer 判讀：本表 <em>只代表體育博彩賽季 cycle</em>、不能直接套到 e-commerce flash-sale（後者倍數結構是「秒級數千倍」、跟事件 tier 結構不同）</li>
</ul>
<p><strong>容量規劃做法</strong>：</p>
<ul>
<li>建立 event tier 體系、每 tier 對應不同 pre-scale 倍數跟 lead time（賽前 N 小時預配）</li>
<li>事件型分級的關鍵是「峰值是已知的」、不是「峰值多大」</li>
<li>對應 <a href="/blog/backend/09-performance-capacity/" data-link-title="模組九：效能工程與容量規劃" data-link-desc="把『目前配置能撐多少、要加多少機器』變成可量化、可驗證、可改進的工程流程">9.11 高峰事件準備</a> 的容量分級</li>
</ul>
<h2 id="邊界與整合fleet-治理-ssot--何時拆-cluster-vs-加-replica">邊界與整合：Fleet 治理 SSoT — 何時拆 cluster vs 加 replica</h2>
<p>本段是 Aurora fleet 治理軸 SSoT — <a href="../storage-architecture/">Aurora storage architecture</a> / <a href="../cross-az-failover-rto/">Aurora cross-AZ failover RTO</a> / <a href="../global-database-multi-region/">Aurora Global Database</a> / <a href="../migrate-from-self-managed-pg-mysql/">Aurora migration playbook</a> cross-link 不重複展開。</p>
<p><strong>跨 case 合成 frame</strong>：production scale 不是「單一巨型 cluster」而是 <em>fleet of clusters</em>、但 <em>driver 各異</em>。</p>
<table>
  <thead>
      <tr>
          <th>Driver</th>
          <th>Case anchor</th>
          <th>Fleet 規模</th>
          <th>拆分判讀</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Business sharding</td>
          <td><a href="/blog/backend/09-performance-capacity/cases/draftkings-aurora-financial-ledger/" data-link-title="9.C4 DraftKings：Aurora 撐 100 萬 ops/min 的體育博彩金融帳本" data-link-desc="DraftKings 用 Aurora MySQL 跑體育博彩金融帳本、Super Bowl 流量 &#43;50% 不影響延遲">9.C4 DraftKings</a></td>
          <td>200 cluster</td>
          <td>業務本身可切分（每體育類別 / 每地理 / 每產品線各自 cluster）、blast radius 隔離</td>
      </tr>
      <tr>
          <td>Microservice ownership</td>
          <td><a href="/blog/backend/09-performance-capacity/cases/netflix-aurora-consolidation/" data-link-title="9.C23 Netflix：把關聯式 DB 統一到 Aurora、效能 &#43;75%、成本 -28%" data-link-desc="Netflix 把多套關聯式 DB 統一到 Aurora、效能提升 75%、成本下降 28%、串流數十億小時">9.C23 Netflix</a></td>
          <td>多 cluster</td>
          <td>每微服務私有 store、不共用 cluster — 容量規劃分散到 service owner</td>
      </tr>
      <tr>
          <td>合規市場 boundary</td>
          <td><a href="/blog/backend/09-performance-capacity/cases/standard-chartered-aurora-banking/" data-link-title="9.C14 Standard Chartered：受監管銀行的 Aurora 4000 TPS 容量提升" data-link-desc="Standard Chartered 銀行遷移到 Aurora 後吞吐量提升 10 倍至 4000 TPS、跨 7 個受監管市場">9.C14 Standard Chartered</a></td>
          <td>7 cluster</td>
          <td>受監管市場資料 <em>不能跨境複製</em>、每市場獨立 cluster — Global Database 在合規場景反指標</td>
      </tr>
  </tbody>
</table>
<h3 id="driver-1business-shardingdraftkings-200-cluster">Driver 1：Business sharding（DraftKings 200 cluster）</h3>
<p>DraftKings 不用一個巨型 cluster 撐 100 萬 ops/min、而是 <em>按業務切 200 cluster</em>。每體育類別、每地理、每產品線各自 cluster、blast radius 自然隔離。</p>
<p>工程含義：</p>
<ul>
<li>業務本身就有 sharding key（sport type / region / product line）— 拆 cluster 不需要 schema redesign</li>
<li>單 cluster 故障只影響該業務、不影響全平台</li>
<li>容量規劃變成「每 cluster 的容量規劃」、單機極限不重要</li>
</ul>
<p><strong>容易誤判的邊界</strong>：<a href="/blog/backend/09-performance-capacity/cases/draftkings-aurora-financial-ledger/" data-link-title="9.C4 DraftKings：Aurora 撐 100 萬 ops/min 的體育博彩金融帳本" data-link-desc="DraftKings 用 Aurora MySQL 跑體育博彩金融帳本、Super Bowl 流量 &#43;50% 不影響延遲">DraftKings 100 萬 ops/min ≈ 17K ops/sec</a> 是 <em>200 cluster 加總</em>、平均每 cluster 約 80 ops/sec（case「需要警惕」段）— 不是「單一 cluster 撐 100 萬 ops」、案例對照不能擴寫成單 cluster 容量。</p>
<h3 id="driver-2microservice-ownershipnetflix">Driver 2：Microservice ownership（Netflix）</h3>
<p>Netflix 每微服務各自有 private Aurora cluster、不共用 — 跟 monolith「一個大 DB 撐全部」相反。</p>
<p>工程含義：</p>
<ul>
<li>DB 容量規劃變成「每微服務的容量規劃」、複雜度分散到 service owner</li>
<li>跨服務 contention 變成 <em>network 議題</em> 而非 <em>DB lock 議題</em></li>
<li>每多一個微服務就多一個 cluster、operational surface area × N</li>
</ul>
<p><strong>case 自帶 scope 警示</strong>：<a href="/blog/backend/09-performance-capacity/cases/netflix-aurora-consolidation/" data-link-title="9.C23 Netflix：把關聯式 DB 統一到 Aurora、效能 &#43;75%、成本 -28%" data-link-desc="Netflix 把多套關聯式 DB 統一到 Aurora、效能提升 75%、成本下降 28%、串流數十億小時">Netflix 數據層遠不止 Aurora</a> — 還有 Cassandra（playback metadata）、EVCache（cache layer）、Iceberg（data warehouse）。Aurora 主要是「需要 ACID 的 OLTP 工作負載」、不是「all-purpose store」（case「需要警惕」段第 2 點）。讀者引用 Netflix consolidation 時、不能誤推論「Aurora 可以替所有 store」。</p>
<h3 id="driver-3合規市場-boundarystandard-chartered-7-cluster">Driver 3：合規市場 boundary（Standard Chartered 7 cluster）</h3>
<p>Standard Chartered 7 個受監管市場 = 7 個獨立 cluster。<a href="/blog/backend/knowledge-cards/data-residency/" data-link-title="Data Residency" data-link-desc="合規要求資料留在特定地理邊界內、跨境複製違反合規、推動 fleet 拓樸決策">Data Residency</a> 規範資料 <em>不能跨境複製</em>、<a href="../global-database-multi-region/">Aurora Global Database</a> 在這種場景違反合規。</p>
<p>工程含義：</p>
<ul>
<li>容量規劃變成「7 個獨立規劃 × 各自合規門檻」</li>
<li>跨市場 DR 不靠 Global Database、靠應用層市場切換</li>
<li>合規 lead time 是時程主項（見 <a href="../migrate-from-self-managed-pg-mysql/">migration playbook</a> 合規時程段）</li>
</ul>
<p><strong>case 自承 scope 警示</strong>：Standard Chartered case 未公開是 PostgreSQL 還是 MySQL、未公開具體 cost 數字、屬「相關 case study」匿名對照。</p>
<h3 id="何時拆-vs-加-replica-的判讀順序">何時拆 vs 加 replica 的判讀順序</h3>
<p>按以下順序判斷、第一個成立的就是拆 cluster 的訊號：</p>
<ol>
<li><strong>&gt; 15 replica 需求</strong> → 拆 cluster（Aurora 硬上限）</li>
<li><strong>Blast radius 隔離需求</strong> → 拆 cluster（單 cluster 故障影響範圍太大、業務不能接受）</li>
<li><strong>業務本身可切分</strong>（user shard / 產品線 / 地理）→ 拆 cluster（DraftKings 拓樸）</li>
<li><strong>微服務私有 store 拓樸</strong> → 拆 cluster（Netflix 拓樸、跟服務生命週期綁定）</li>
<li><strong>合規禁止跨境複製</strong> → 拆 cluster（Standard Chartered 拓樸、Global Database 反指標）</li>
<li><strong>以上都不成立</strong> → 加 replica（最便宜的容量槓桿）</li>
</ol>
<p><strong>容易誤判的邊界</strong>：</p>
<ul>
<li>Fleet 治理本身有 ops surface area 成本（parameter group / backup / IAM / observability fan-out × N cluster）— 不是免費；driver 不夠強時不該拆</li>
<li>「fleet 看起來大」不是 driver — driver 是業務本身有 boundary、不是運維美觀</li>
<li>拆 cluster 後再合併比拆更難（資料遷移成本高）— driver 不確定時先加 replica</li>
</ul>
<h2 id="容量與觀測">容量與觀測</h2>
<p><strong>核心 metric</strong>：</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">AuroraReplicaLag           # per replica lag
</span></span><span class="line"><span class="ln">2</span><span class="cl">AuroraReplicaLagMaximum    # cluster max lag
</span></span><span class="line"><span class="ln">3</span><span class="cl">CPUUtilization             # per replica CPU
</span></span><span class="line"><span class="ln">4</span><span class="cl">DatabaseConnections        # per replica connection</span></span></code></pre></div><p><strong>Application 端 metric</strong>：</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">read_query_latency_p99       # per endpoint (writer vs reader)
</span></span><span class="line"><span class="ln">2</span><span class="cl">stale_read_error_count       # read-after-write 失敗訊號
</span></span><span class="line"><span class="ln">3</span><span class="cl">read_replica_routing_ratio   # writer vs reader 流量比例</span></span></code></pre></div><p><strong>容量上限</strong>：</p>
<ul>
<li>15 replica / cluster（硬上限）</li>
<li>Cross-region replica 走 <a href="../global-database-multi-region/">Aurora Global Database</a>（不算 15）</li>
</ul>
<p><strong>容量公式</strong>：</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">read replica count = (read QPS / replica throughput) × (1 + lag buffer) × (1 + event tier headroom)
</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">lag buffer        = 30%（典型）
</span></span><span class="line"><span class="ln">4</span><span class="cl">event tier headroom = 0% (平日) / 50% (playoff) / 100% (championship) / 200% (Super Bowl)</span></span></code></pre></div><p><strong>回路徑</strong>：<a href="/blog/backend/09-performance-capacity/bottleneck-localization/" data-link-title="9.5 瓶頸定位流程" data-link-desc="從 app 到 DB / cache / broker / 第三方 quota 的逐層瓶頸定位">9.5 瓶頸定位流程</a> 判斷 read-bound vs write-bound、<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> peak workload 預配 vs auto-scale 決策。</p>
<h2 id="邊界與整合--下一步">邊界與整合 / 下一步</h2>
<p><strong>Sibling deep articles</strong>：</p>
<ul>
<li><a href="../storage-architecture/">Aurora storage architecture</a> — 共享 storage 為什麼能養 15 replica + 雙峰錯位 application 邊界</li>
<li><a href="../cross-az-failover-rto/">Aurora cross-AZ failover RTO</a> — replica 升 primary 流程</li>
<li><a href="../global-database-multi-region/">Aurora Global Database</a> — 跨 region replica 配置 + 合規 anti-pattern</li>
</ul>
<p><strong>Migration playbook</strong>：</p>
<ul>
<li><a href="../migrate-from-self-managed-pg-mysql/">PostgreSQL / MySQL → Aurora</a> — fleet 拓樸是 migration 規劃的維度之一</li>
</ul>
<p><strong>1.x 章節互引</strong>：</p>
<ul>
<li><a href="/blog/backend/01-database/high-concurrency-access/" data-link-title="1.1 高併發下的 SQL 讀寫邊界" data-link-desc="說明高併發服務如何共用資料庫 client、控制 transaction、管理 connection pool、避免資料庫成為瓶頸">1.1 高併發資料存取</a> — read replica 是 OLTP 擴容的基本槓桿</li>
</ul>
<p><strong>RDS Proxy 整合</strong>：lag-aware routing、connection pool 共享、Lambda 場景；managed alternative。</p>
<p><strong>何時不用本文</strong>：single replica + cross-AZ failover 已滿足、read traffic 不是 bottleneck 時可跳過、看 <a href="/blog/backend/01-database/vendors/aurora/" data-link-title="AWS Aurora" data-link-desc="AWS managed PostgreSQL / MySQL、storage / compute 分離、&#43;75% 效能改善的 production 證據">Aurora vendor overview</a> 即可。</p>
<h2 id="相關連結">相關連結</h2>
<ul>
<li><a href="/blog/backend/01-database/vendors/aurora/" data-link-title="AWS Aurora" data-link-desc="AWS managed PostgreSQL / MySQL、storage / compute 分離、&#43;75% 效能改善的 production 證據">Aurora vendor overview</a> — 服務定位、適用 / 不適用場景</li>
<li><a href="/blog/backend/knowledge-cards/replication-lag/" data-link-title="Replication Lag" data-link-desc="說明資料副本落後正式來源多久，以及它如何影響讀取正確性">Replication Lag 卡片</a> — 概念基底</li>
<li><a href="/blog/backend/knowledge-cards/stale-read/" data-link-title="Stale Read" data-link-desc="讀取到落後於最新寫入版本的舊資料">Stale Read 卡片</a> — read-after-write 容忍度</li>
<li><a href="/blog/backend/09-performance-capacity/cases/draftkings-aurora-financial-ledger/" data-link-title="9.C4 DraftKings：Aurora 撐 100 萬 ops/min 的體育博彩金融帳本" data-link-desc="DraftKings 用 Aurora MySQL 跑體育博彩金融帳本、Super Bowl 流量 &#43;50% 不影響延遲">9.C4 DraftKings</a> — 200 cluster business sharding 跟 headroom 預留</li>
<li><a href="/blog/backend/09-performance-capacity/cases/netflix-aurora-consolidation/" data-link-title="9.C23 Netflix：把關聯式 DB 統一到 Aurora、效能 &#43;75%、成本 -28%" data-link-desc="Netflix 把多套關聯式 DB 統一到 Aurora、效能提升 75%、成本下降 28%、串流數十億小時">9.C23 Netflix</a> — 微服務私有 store + Aurora 非 all-purpose store 邊界</li>
<li><a href="/blog/backend/09-performance-capacity/cases/standard-chartered-aurora-banking/" data-link-title="9.C14 Standard Chartered：受監管銀行的 Aurora 4000 TPS 容量提升" data-link-desc="Standard Chartered 銀行遷移到 Aurora 後吞吐量提升 10 倍至 4000 TPS、跨 7 個受監管市場">9.C14 Standard Chartered</a> — 合規驅動 fleet 拓樸</li>
<li><a href="/blog/backend/09-performance-capacity/cases/fanduel-dual-peak-betting-streaming/" data-link-title="9.C28 FanDuel：體育直播 &#43; 投注的雙重峰值" data-link-desc="FanDuel 3.5M MAU、Super Bowl 期間擴容 5-10 倍、用 AWS Local Zones &#43; Wavelength &#43; Outposts 處理 20&#43; 州的雙重峰值">9.C28 FanDuel</a> — 雙 SLO 並行 + 事件型容量分級</li>
<li><a href="/blog/posts/vendor-%E6%B7%B1%E5%BA%A6%E6%8A%80%E8%A1%93%E6%96%87%E7%AB%A0%E6%96%B9%E6%B3%95%E8%AB%96%E7%9A%84%E6%BC%94%E5%8C%96%E7%B4%80%E9%8C%84%E5%90%8C-vendor-%E7%B3%BB%E5%88%97%E7%9A%84%E9%96%8B%E5%A0%B4%E8%BC%AA%E6%9B%BF%E9%A9%97%E8%AD%89/" data-link-title="Vendor 深度技術文章方法論的演化紀錄：同 vendor 系列的開場輪替驗證" data-link-desc="vendor overview 飽和後要寫單一功能深度文章、需要選題與結構依據時回來。這套方法論的驗證來源與 cadence variant 在高風險場景（同 vendor sub-tool 系列）的實證。">Vendor 深度技術文章方法論</a> — 本文遵循的 6 規格面寫作模板</li>
<li>官方：<a href="https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/Aurora.Replication.html">Aurora replication</a></li>
</ul>
]]></content:encoded></item><item><title>Aurora Global Database：跨 region async replication、&lt; 1 秒 lag 與合規 anti-recommendation</title><link>https://tarrragon.github.io/blog/backend/01-database/vendors/aurora/global-database-multi-region/</link><pubDate>Wed, 27 May 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/backend/01-database/vendors/aurora/global-database-multi-region/</guid><description>&lt;p>Aurora Global Database 是 &lt;em>跨 region async replication&lt;/em>、&amp;lt; 1 秒 typical lag、最多 5 個 secondary region — 看起來是 multi-region OLTP 的標準解、但 &lt;a href="https://tarrragon.github.io/blog/backend/09-performance-capacity/cases/standard-chartered-aurora-banking/" data-link-title="9.C14 Standard Chartered：受監管銀行的 Aurora 4000 TPS 容量提升" data-link-desc="Standard Chartered 銀行遷移到 Aurora 後吞吐量提升 10 倍至 4000 TPS、跨 7 個受監管市場">9.C14 Standard Chartered&lt;/a> 揭露一個受監管產業的 anti-recommendation：合規禁止跨境複製場景下、Global Database &lt;em>違反合規&lt;/em>、要改用每市場獨立 cluster + 應用層市場切換。本文展開 Global Database 適用條件、跟 cross-AZ failover 的 RTO 數量級差、合規邊界、跟 Aurora DSQL / Spanner / CockroachDB 的決策樹。&lt;/p>
&lt;p>本文不是 Aurora overview（請看 &lt;a href="https://tarrragon.github.io/blog/backend/01-database/vendors/aurora/" data-link-title="AWS Aurora" data-link-desc="AWS managed PostgreSQL / MySQL、storage / compute 分離、&amp;#43;75% 效能改善的 production 證據">Aurora vendor 頁&lt;/a>）— 而是 Global Database 的實作層教學。前置閱讀建議 &lt;a href="../storage-architecture/">Aurora storage architecture&lt;/a>（理解 storage-level replication）、&lt;a href="../cross-az-failover-rto/">Aurora cross-AZ failover RTO&lt;/a>（對照單 region failover）。&lt;/p>
&lt;h2 id="問題情境">問題情境&lt;/h2>
&lt;p>典型觸發場景：global SaaS / 跨地理金融服務、需要 region-level DR（us-east-1 整 region 失效時 &amp;lt; 5 分鐘恢復寫入）、或跨地理 read（歐洲用戶查美國 primary 延遲 100ms+ 不可接受）、但又不到「multi-region active-active write」需求。&lt;/p>
&lt;p>讀者常見的具體疑問：&lt;/p>
&lt;ul>
&lt;li>「Global Database 是 sync 還是 async？lag 多少？」&lt;/li>
&lt;li>「Secondary region 可以寫嗎？」&lt;/li>
&lt;li>「Region failover 流程跟 cross-AZ 一樣嗎？」&lt;/li>
&lt;li>「跟 Aurora DSQL / Spanner / CockroachDB 怎麼選？」&lt;/li>
&lt;li>「合規場景一定要用 Global Database 嗎？」&lt;/li>
&lt;/ul>
&lt;p>進一步問題：Global Database 對一般 SaaS 是合理的 DR + 跨地理 read 工具、但對 &lt;em>受監管產業&lt;/em> 是反指標。&lt;a href="https://tarrragon.github.io/blog/backend/09-performance-capacity/cases/standard-chartered-aurora-banking/" data-link-title="9.C14 Standard Chartered：受監管銀行的 Aurora 4000 TPS 容量提升" data-link-desc="Standard Chartered 銀行遷移到 Aurora 後吞吐量提升 10 倍至 4000 TPS、跨 7 個受監管市場">9.C14 Standard Chartered&lt;/a> 7 個受監管市場、各自獨立 Aurora cluster、不用 Global Database — 不是技術不夠、是合規要求「資料不能跨境複製」。讀者規劃 multi-region 架構時、合規維度要在技術維度之前判斷。&lt;/p>
&lt;h2 id="核心機制跨-region-async-storage-replication">核心機制：跨 region async storage replication&lt;/h2>
&lt;p>Aurora Global Database 的 first-class concept 是 &lt;em>跨 region storage-level async replication&lt;/em>。跟 logical replication / streaming replication 不同、Global Database 在 storage layer 複製、lag 上限相對穩定。&lt;/p></description><content:encoded><![CDATA[<p>Aurora Global Database 是 <em>跨 region async replication</em>、&lt; 1 秒 typical lag、最多 5 個 secondary region — 看起來是 multi-region OLTP 的標準解、但 <a href="/blog/backend/09-performance-capacity/cases/standard-chartered-aurora-banking/" data-link-title="9.C14 Standard Chartered：受監管銀行的 Aurora 4000 TPS 容量提升" data-link-desc="Standard Chartered 銀行遷移到 Aurora 後吞吐量提升 10 倍至 4000 TPS、跨 7 個受監管市場">9.C14 Standard Chartered</a> 揭露一個受監管產業的 anti-recommendation：合規禁止跨境複製場景下、Global Database <em>違反合規</em>、要改用每市場獨立 cluster + 應用層市場切換。本文展開 Global Database 適用條件、跟 cross-AZ failover 的 RTO 數量級差、合規邊界、跟 Aurora DSQL / Spanner / CockroachDB 的決策樹。</p>
<p>本文不是 Aurora overview（請看 <a href="/blog/backend/01-database/vendors/aurora/" data-link-title="AWS Aurora" data-link-desc="AWS managed PostgreSQL / MySQL、storage / compute 分離、&#43;75% 效能改善的 production 證據">Aurora vendor 頁</a>）— 而是 Global Database 的實作層教學。前置閱讀建議 <a href="../storage-architecture/">Aurora storage architecture</a>（理解 storage-level replication）、<a href="../cross-az-failover-rto/">Aurora cross-AZ failover RTO</a>（對照單 region failover）。</p>
<h2 id="問題情境">問題情境</h2>
<p>典型觸發場景：global SaaS / 跨地理金融服務、需要 region-level DR（us-east-1 整 region 失效時 &lt; 5 分鐘恢復寫入）、或跨地理 read（歐洲用戶查美國 primary 延遲 100ms+ 不可接受）、但又不到「multi-region active-active write」需求。</p>
<p>讀者常見的具體疑問：</p>
<ul>
<li>「Global Database 是 sync 還是 async？lag 多少？」</li>
<li>「Secondary region 可以寫嗎？」</li>
<li>「Region failover 流程跟 cross-AZ 一樣嗎？」</li>
<li>「跟 Aurora DSQL / Spanner / CockroachDB 怎麼選？」</li>
<li>「合規場景一定要用 Global Database 嗎？」</li>
</ul>
<p>進一步問題：Global Database 對一般 SaaS 是合理的 DR + 跨地理 read 工具、但對 <em>受監管產業</em> 是反指標。<a href="/blog/backend/09-performance-capacity/cases/standard-chartered-aurora-banking/" data-link-title="9.C14 Standard Chartered：受監管銀行的 Aurora 4000 TPS 容量提升" data-link-desc="Standard Chartered 銀行遷移到 Aurora 後吞吐量提升 10 倍至 4000 TPS、跨 7 個受監管市場">9.C14 Standard Chartered</a> 7 個受監管市場、各自獨立 Aurora cluster、不用 Global Database — 不是技術不夠、是合規要求「資料不能跨境複製」。讀者規劃 multi-region 架構時、合規維度要在技術維度之前判斷。</p>
<h2 id="核心機制跨-region-async-storage-replication">核心機制：跨 region async storage replication</h2>
<p>Aurora Global Database 的 first-class concept 是 <em>跨 region storage-level async replication</em>。跟 logical replication / streaming replication 不同、Global Database 在 storage layer 複製、lag 上限相對穩定。</p>
<p><strong>Architecture</strong>：</p>
<ul>
<li>Primary region：1 個 writer cluster + N read replica</li>
<li>Secondary region：最多 5 個 secondary region、每 region N 個 reader-only cluster（最多 16 個 reader 含 1 個 headless）</li>
<li>Storage replication：primary region 寫 storage 後 <em>async</em> push 到 secondary region storage、不等 ack</li>
</ul>
<p><strong>Write path</strong>：</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">Application
</span></span><span class="line"><span class="ln">2</span><span class="cl">    ↓ writer endpoint (primary region only)
</span></span><span class="line"><span class="ln">3</span><span class="cl">Primary region compute
</span></span><span class="line"><span class="ln">4</span><span class="cl">    ↓ redo log
</span></span><span class="line"><span class="ln">5</span><span class="cl">Primary region storage (4-of-6 quorum)
</span></span><span class="line"><span class="ln">6</span><span class="cl">    ↓ async replication (typical &lt; 1 秒)
</span></span><span class="line"><span class="ln">7</span><span class="cl">Secondary region storage</span></span></code></pre></div><p><strong>Read path</strong>：</p>
<ul>
<li>Secondary region 直接從 local storage 讀、不需要跨 region 拉</li>
<li>Read latency 是 secondary region local latency、不是跨 region</li>
</ul>
<p><strong>DR 切換 RTO 跟 cross-AZ 對比</strong>：</p>
<table>
  <thead>
      <tr>
          <th>場景</th>
          <th>RTO</th>
          <th>機制</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Cross-AZ failover</td>
          <td>&lt; 30 秒</td>
          <td>storage 跨 AZ 共享、replica 升 primary 即可</td>
      </tr>
      <tr>
          <td>Planned failover</td>
          <td>&lt; 2 分鐘</td>
          <td>managed graceful failover、無資料丟失</td>
      </tr>
      <tr>
          <td>Unplanned failover</td>
          <td>5-15 分鐘</td>
          <td>整 region 失效、手動 promote secondary</td>
      </tr>
  </tbody>
</table>
<p>數量級不同 — cross-AZ 是 <em>seconds</em>、cross-region planned 是 <em>minutes</em>、unplanned 是 <em>tens of minutes</em>。</p>
<p><strong>對應 knowledge card</strong>：<a href="/blog/backend/knowledge-cards/stale-read/" data-link-title="Stale Read" data-link-desc="讀取到落後於最新寫入版本的舊資料">stale-read</a>、<a href="/blog/backend/knowledge-cards/rpo/" data-link-title="RPO" data-link-desc="說明恢復點目標如何定義可接受資料損失範圍">rpo</a>、<a href="/blog/backend/knowledge-cards/rto/" data-link-title="RTO" data-link-desc="說明恢復時間目標如何約束事故回復策略">rto</a>。</p>
<p><strong>跟通用 cross-region replication 差在哪</strong>：Aurora 在 storage layer 複製、lag 上限更穩定；vs PostgreSQL logical replication lag 受寫速度影響大、heavy write 期間可能秒級到分鐘級。</p>
<h2 id="step-by-step-配置">Step-by-step 配置</h2>
<p><strong>建 global cluster</strong>：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="c1"># Step 1：在 primary region 建 global cluster</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">aws rds create-global-cluster <span class="se">\
</span></span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="se"></span>  --global-cluster-identifier myglobal <span class="se">\
</span></span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="se"></span>  --source-db-cluster-identifier arn:aws:rds:us-east-1:123:cluster:primary-cluster <span class="se">\
</span></span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="se"></span>  --region us-east-1
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">
</span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="c1"># Step 2：在 secondary region 加 reader cluster</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">aws rds create-db-cluster <span class="se">\
</span></span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="se"></span>  --db-cluster-identifier secondary-cluster <span class="se">\
</span></span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="se"></span>  --global-cluster-identifier myglobal <span class="se">\
</span></span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="se"></span>  --engine aurora-postgresql <span class="se">\
</span></span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="se"></span>  --source-region us-east-1 <span class="se">\
</span></span></span><span class="line"><span class="ln">13</span><span class="cl"><span class="se"></span>  --region eu-west-1
</span></span><span class="line"><span class="ln">14</span><span class="cl">
</span></span><span class="line"><span class="ln">15</span><span class="cl"><span class="c1"># Step 3：在 secondary region 建 db instance</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl">aws rds create-db-instance <span class="se">\
</span></span></span><span class="line"><span class="ln">17</span><span class="cl"><span class="se"></span>  --db-cluster-identifier secondary-cluster <span class="se">\
</span></span></span><span class="line"><span class="ln">18</span><span class="cl"><span class="se"></span>  --db-instance-identifier secondary-reader-01 <span class="se">\
</span></span></span><span class="line"><span class="ln">19</span><span class="cl"><span class="se"></span>  --db-instance-class db.r6g.4xlarge <span class="se">\
</span></span></span><span class="line"><span class="ln">20</span><span class="cl"><span class="se"></span>  --engine aurora-postgresql <span class="se">\
</span></span></span><span class="line"><span class="ln">21</span><span class="cl"><span class="se"></span>  --region eu-west-1</span></span></code></pre></div><p><strong>Application routing</strong>：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="ln">1</span><span class="cl"><span class="c"># 寫永遠去 primary region writer endpoint</span><span class="w">
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="w"></span><span class="nt">primary</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="w">  </span><span class="nt">url</span><span class="p">:</span><span class="w"> </span><span class="l">jdbc:postgresql://primary-cluster.cluster-xxx.us-east-1.rds.amazonaws.com/mydb</span><span class="w">
</span></span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">5</span><span class="cl"><span class="w"></span><span class="c"># read 可走 secondary region reader endpoint（靠近用戶的 region）</span><span class="w">
</span></span></span><span class="line"><span class="ln">6</span><span class="cl"><span class="w"></span><span class="nt">secondary-eu</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln">7</span><span class="cl"><span class="w">  </span><span class="nt">url</span><span class="p">:</span><span class="w"> </span><span class="l">jdbc:postgresql://secondary-cluster.cluster-ro-xxx.eu-west-1.rds.amazonaws.com/mydb</span></span></span></code></pre></div><p><strong>DR 切換（planned failover）</strong>：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl">aws rds failover-global-cluster <span class="se">\
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="se"></span>  --global-cluster-identifier myglobal <span class="se">\
</span></span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="se"></span>  --target-db-cluster-identifier arn:aws:rds:eu-west-1:123:cluster:secondary-cluster</span></span></code></pre></div><p>切換後 application 端要 <em>reconfigure connection string</em> — DNS 不自動切跨 region（vs cross-AZ failover writer endpoint 自動跟）。</p>
<p><strong>Application reconfiguration 模式</strong>：</p>
<ul>
<li>Connection string 用 service discovery（Consul / Route53 health check）動態解析</li>
<li>或在 application config 加入 region-aware logic、failover 後切換 active region</li>
<li>不能假設 application 自動 reconnect 到新 primary region</li>
</ul>
<p><strong>驗證點</strong>：</p>
<ul>
<li><code>AuroraGlobalDBReplicationLag</code> &lt; 1 秒</li>
<li>Planned failover RTO 量測（手動 trigger + heartbeat timestamp diff）</li>
<li>Application 跨 region read 路徑 latency 符合預期</li>
</ul>
<p><strong>Rollback boundary</strong>：promote secondary 後原 primary 變 secondary、不會自動 fallback；rollback 要再做一次 failover。</p>
<h2 id="故障模式--邊界-case">故障模式 / 邊界 case</h2>
<h3 id="case-1期待-multi-region-active-active-write">Case 1：期待 multi-region active-active write</h3>
<p>徵兆：team 在 secondary region application 直連 secondary cluster 寫資料、收到 <code>cannot execute INSERT in a read-only transaction</code> 錯誤。</p>
<p>原因：Global Database secondary 是 <em>reader-only</em>、寫只能去 primary region。要 active-active write 必須改用其他服務（Aurora DSQL / Spanner / CockroachDB）。</p>
<p>修：</p>
<ul>
<li>Application 設計時明確區分 read region vs write region</li>
<li>寫操作永遠路由到 primary region、容忍跨 region write latency</li>
<li>真的需要 active-active write 才考慮 Aurora DSQL（2024-12 preview / 2025-05 GA）</li>
</ul>
<h3 id="case-2dns-不跨-region-自動切">Case 2：DNS 不跨 region 自動切</h3>
<p>徵兆：手動 failover trigger 後、application 端 connection string 仍指向舊 primary region、寫操作全失敗。</p>
<p>原因：cross-AZ failover writer endpoint DNS 自動跟、cross-region 不會 — Global Database 切換要 application 端管 region-specific connection string。</p>
<p>修：</p>
<ul>
<li>Application 用 service discovery（Route53 / Consul / etcd）解析 active primary region</li>
<li>部署 region-aware DNS（Route53 latency-based routing + health check）</li>
<li>Failover 演練要包含 application reconfiguration step、不只是 DB layer</li>
</ul>
<h3 id="case-3跨-region-read-假設-strong-consistency">Case 3：跨 region read 假設 strong consistency</h3>
<p>徵兆：用戶在 primary region 寫資料、隨即在 secondary region read、看到舊資料、客訴 inconsistency。</p>
<p>原因：Global Database 是 async replication、&lt; 1 秒 lag 不是 zero、read-after-write 場景仍會看到 stale data。</p>
<p>修：</p>
<ul>
<li>用戶寫操作後短期內 read 走 primary region（read-after-write window）</li>
<li>接受最終一致性、application 端做 versioning / timestamp 比對</li>
<li>強一致性需求改 Aurora DSQL / Spanner</li>
</ul>
<h3 id="case-4lag-spike-during-bulk-operation">Case 4：Lag spike during bulk operation</h3>
<p>徵兆：DDL 或 bulk insert 期間 cross-region lag 從 &lt; 1 秒跳到秒級到分鐘級、secondary region read 大量 stale。</p>
<p>原因：Global Database 「&lt; 1 秒」是 typical、heavy write 期間 lag 拉大。Storage-level replication 比 logical 穩定、但 <em>不是 zero variance</em>。</p>
<p>修：</p>
<ul>
<li>DDL 跟 bulk insert 在低峰期跑、避開跨 region read traffic</li>
<li>監測 <code>AuroraGlobalDBReplicationLag</code>、spike 超過閾值 trigger application 端 fallback（read 切回 primary region）</li>
<li>重要 DDL 用 <a href="https://github.com/reorg/pg_repack">pg_repack</a> 避免長時間 lag</li>
</ul>
<h3 id="case-5合規邊界誤用-global-database--standard-chartered-anti-pattern">Case 5：合規邊界誤用 Global Database — Standard Chartered anti-pattern</h3>
<p>徵兆：team 以為 Global Database 是受監管金融的標準 DR 解、配置完才發現監管機構不接受跨境資料複製、被迫拆掉 Global Database 重建獨立 cluster。</p>
<p><a href="/blog/backend/09-performance-capacity/cases/standard-chartered-aurora-banking/" data-link-title="9.C14 Standard Chartered：受監管銀行的 Aurora 4000 TPS 容量提升" data-link-desc="Standard Chartered 銀行遷移到 Aurora 後吞吐量提升 10 倍至 4000 TPS、跨 7 個受監管市場">9.C14 Standard Chartered case</a> 「判讀」段第 1 點原文：「7 個受監管市場代表 7 個獨立 cluster（資料不能跨境）、容量規劃變成『7 個獨立規劃 × 各自合規門檻』」。</p>
<p>原因：受監管市場資料 <em>不能跨境複製</em>（<a href="/blog/backend/knowledge-cards/data-residency/" data-link-title="Data Residency" data-link-desc="合規要求資料留在特定地理邊界內、跨境複製違反合規、推動 fleet 拓樸決策">Data Residency</a> 硬約束）、Global Database 本質上就是跨 region storage replication、配置了就違反合規。Standard Chartered 的選擇是 <em>每市場獨立 cluster</em>、跨市場 DR 走應用層市場切換、不靠 Global Database。</p>
<p>修：</p>
<ul>
<li>規劃 multi-region 前先確認合規要求（資料駐留、跨境複製禁令、稽核要求）</li>
<li>合規禁止跨境複製場景：每市場獨立 cluster + cross-AZ failover 吸收 RTO（見 <a href="../cross-az-failover-rto/">cross-az-failover-rto</a>）</li>
<li>跨市場 DR 設計成 <em>市場切換</em>（用戶從 A 市場切到 B 市場）、不是 <em>資料切換</em></li>
<li>Fleet 拓樸（多市場 → 多 cluster）詳見 <a href="../read-replica-scaling/">Aurora read replica scaling</a> fleet 治理 SSoT</li>
</ul>
<p><strong>scope warning（必明示）</strong>：Standard Chartered case 未公開是 PostgreSQL 還是 MySQL、未公開具體 cost 數字、屬「相關 case study」匿名對照。引用時不能擴寫具體 engine。</p>
<h3 id="case-6cost-trap--cross-region-data-transfer">Case 6：Cost trap — cross-region data transfer</h3>
<p>徵兆：開了 Global Database 後月帳變高 50%、發現 cross-region data transfer 是主要費用、不是 instance。</p>
<p>原因：Aurora 跨 region replication 走 AWS 內部網路、但 <em>cross-region data transfer 仍計費</em>。Heavy write workload 月費可能 doubled。</p>
<p>修：</p>
<ul>
<li>用 <code>AuroraGlobalDBReplicatedWriteIO</code> × per-region transfer rate 估月費</li>
<li>Write-heavy workload 評估 Global Database ROI（保險、低費用版本是用 cross-region snapshot 做冷備）</li>
<li>Cost 跟 RTO 一起看 — 如果接受 hours RTO、cross-region snapshot 更便宜</li>
</ul>
<h3 id="case-7fanduel-雙峰-case-對照避免-over-extrapolate">Case 7：FanDuel 雙峰 case 對照（避免 over-extrapolate）</h3>
<p>如果 team 引用 <a href="/blog/backend/09-performance-capacity/cases/fanduel-dual-peak-betting-streaming/" data-link-title="9.C28 FanDuel：體育直播 &#43; 投注的雙重峰值" data-link-desc="FanDuel 3.5M MAU、Super Bowl 期間擴容 5-10 倍、用 AWS Local Zones &#43; Wavelength &#43; Outposts 處理 20&#43; 州的雙重峰值">9.C28 FanDuel</a> 規劃 multi-region 部署、要明示 scope warning。</p>
<p><strong>case「判讀」段第 1 點原文</strong>：「直播跟投注是兩種完全不同 SLO：直播容忍秒級延遲（用 CDN + ABR 串流）、投注必須毫秒級成交。兩個服務必須各自獨立擴容、各自獨立 SLO」。</p>
<p><strong>scope warning（必明示）</strong>：</p>
<ul>
<li>FanDuel 5-10x 是 <em>betting 服務的 Aurora 擴容倍數</em>、不是 streaming（streaming 走 CDN、不走 Aurora）</li>
<li>不能壓成「Aurora 撐 5-10x」單一數字</li>
<li>案例自承：betting transaction TPS 跟 concurrent streams 未公開、不能 over-extrapolate</li>
</ul>
<p>引用 FanDuel 規劃自家 multi-region betting workload 時、看 <em>策略</em>（事件型分級 + 雙 SLO 拆分 + 多層 edge）、不套用 <em>具體數字</em>。</p>
<h2 id="跟-aurora-dsql--spanner--cockroachdb-的決策樹">跟 Aurora DSQL / Spanner / CockroachDB 的決策樹</h2>
<p>Global Database 是 <em>async + reader-only secondary</em>、不是 multi-region active-active。當 active-active write 是核心需求時、要看 distributed SQL 方案。</p>
<table>
  <thead>
      <tr>
          <th>維度</th>
          <th>Aurora Global Database</th>
          <th>Aurora DSQL</th>
          <th>Spanner</th>
          <th>CockroachDB</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Replication</td>
          <td>Async storage-level</td>
          <td>Sync distributed</td>
          <td>Sync TrueTime</td>
          <td>Sync Raft consensus</td>
      </tr>
      <tr>
          <td>Secondary</td>
          <td>Reader-only</td>
          <td>Active-active</td>
          <td>Active-active</td>
          <td>Active-active</td>
      </tr>
      <tr>
          <td>Lag</td>
          <td>&lt; 1 秒 typical</td>
          <td>None (sync)</td>
          <td>None (sync)</td>
          <td>None (sync)</td>
      </tr>
      <tr>
          <td>Write</td>
          <td>Primary region only</td>
          <td>Multi-region</td>
          <td>Multi-region</td>
          <td>Multi-region</td>
      </tr>
      <tr>
          <td>Strong consistency cross-region</td>
          <td>No</td>
          <td>Yes</td>
          <td>Yes</td>
          <td>Yes</td>
      </tr>
      <tr>
          <td>適用</td>
          <td>DR + 跨地理 read</td>
          <td>Multi-region OLTP</td>
          <td>Global scale OLTP</td>
          <td>Cross-cloud OLTP</td>
      </tr>
      <tr>
          <td>邊界</td>
          <td>active-active 不支援、合規 反指標</td>
          <td>AWS-only、新服務</td>
          <td>GCP-only、學習曲線</td>
          <td>跨雲、operational 複雜</td>
      </tr>
  </tbody>
</table>
<p><strong>何時選 Global Database</strong>：</p>
<ul>
<li>DR + 跨地理 read 是主要需求</li>
<li>寫流量集中在一個 region（單 region write 撐得住）</li>
<li>合規允許跨境複製（一般 SaaS、非受監管）</li>
<li>從 single-region Aurora 升級、不想換 engine</li>
</ul>
<p><strong>何時改 Aurora DSQL / Spanner / CockroachDB</strong>：</p>
<ul>
<li>Multi-region active-active write</li>
<li>跨 region strong consistency 是業務需求</li>
<li>跨雲 / on-prem 需求（CockroachDB）</li>
</ul>
<p><strong>何時不用 Global Database</strong>：</p>
<ul>
<li>合規禁止跨境複製（Standard Chartered case）→ 每市場獨立 cluster</li>
<li>Single-region 已滿足 DR / read 需求</li>
<li>跨 region cost 不划算（write-heavy workload）</li>
</ul>
<h2 id="容量與觀測">容量與觀測</h2>
<p><strong>核心 metric</strong>：</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">AuroraGlobalDBReplicationLag       # secondary lag、&lt; 1 秒 typical
</span></span><span class="line"><span class="ln">2</span><span class="cl">AuroraGlobalDBReplicatedWriteIO    # cross-region data transfer 量
</span></span><span class="line"><span class="ln">3</span><span class="cl">AuroraGlobalDBProgressLag          # storage replication progress</span></span></code></pre></div><p><strong>容量上限</strong>：</p>
<ul>
<li>1 primary region + 5 secondary region</li>
<li>每 secondary region 16 個 reader 含 1 個 headless（可升 writer）</li>
</ul>
<p><strong>Cost signal</strong>：</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">月費 ≈ AuroraGlobalDBReplicatedWriteIO × per-region transfer rate
</span></span><span class="line"><span class="ln">2</span><span class="cl">     + secondary region instance + storage
</span></span><span class="line"><span class="ln">3</span><span class="cl">     + cross-region snapshot (optional)</span></span></code></pre></div><p>Write 量大的 workload 月費可能 doubled（primary region + secondary region 都計費）、要在規劃時估準。</p>
<p><strong>驗證 DR</strong>：</p>
<ul>
<li>Planned failover drill 每季一次、量測 RTO / RPO</li>
<li>受監管產業：每月一次、有合規 sign-off 記錄</li>
<li>重大版本升級前必跑一次</li>
</ul>
<p><strong>回路徑</strong>：<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> cross-region cost、<a href="/blog/backend/08-incident-response/" data-link-title="模組八：事故處理與復盤" data-link-desc="用 IR 領域詞彙建問題節點、以服務級案例庫累積事故脈絡，先建概念與案例庫再進實作交接">8.x DR playbook</a> region-level failover decision。</p>
<h2 id="邊界與整合--下一步">邊界與整合 / 下一步</h2>
<p><strong>Sibling deep articles</strong>：</p>
<ul>
<li><a href="../storage-architecture/">Aurora storage architecture</a> — cross-region replication 是 storage-level 延伸</li>
<li><a href="../cross-az-failover-rto/">Aurora cross-AZ failover RTO</a> — cross-AZ 跟 cross-region failover RTO 數量級對比</li>
<li><a href="../read-replica-scaling/">Aurora read replica scaling</a> — fleet 治理 SSoT、合規驅動 fleet 拓樸的展開</li>
</ul>
<p><strong>Migration playbook</strong>：</p>
<ul>
<li><a href="../migrate-from-self-managed-pg-mysql/">PostgreSQL / MySQL → Aurora</a> — 從 PostgreSQL streaming replication 跨 region 升級的差異</li>
</ul>
<p><strong>1.x 章節互引</strong>：</p>
<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> — Global Database vs distributed SQL 對比</li>
</ul>
<p><strong>何時不用本文</strong>：single-region OLTP、無跨 region DR / read 需求時可跳過、看 <a href="/blog/backend/01-database/vendors/aurora/" data-link-title="AWS Aurora" data-link-desc="AWS managed PostgreSQL / MySQL、storage / compute 分離、&#43;75% 效能改善的 production 證據">Aurora vendor overview</a> 即可。</p>
<h2 id="相關連結">相關連結</h2>
<ul>
<li><a href="/blog/backend/01-database/vendors/aurora/" data-link-title="AWS Aurora" data-link-desc="AWS managed PostgreSQL / MySQL、storage / compute 分離、&#43;75% 效能改善的 production 證據">Aurora vendor overview</a> — 服務定位、適用 / 不適用場景</li>
<li><a href="/blog/backend/knowledge-cards/stale-read/" data-link-title="Stale Read" data-link-desc="讀取到落後於最新寫入版本的舊資料">Stale Read 卡片</a> — read-after-write 容忍度</li>
<li><a href="/blog/backend/knowledge-cards/rpo/" data-link-title="RPO" data-link-desc="說明恢復點目標如何定義可接受資料損失範圍">RPO 卡片</a> — DR RPO 判讀</li>
<li><a href="/blog/backend/09-performance-capacity/cases/standard-chartered-aurora-banking/" data-link-title="9.C14 Standard Chartered：受監管銀行的 Aurora 4000 TPS 容量提升" data-link-desc="Standard Chartered 銀行遷移到 Aurora 後吞吐量提升 10 倍至 4000 TPS、跨 7 個受監管市場">9.C14 Standard Chartered</a> — 合規驅動的 Global Database anti-pattern</li>
<li><a href="/blog/backend/09-performance-capacity/cases/fanduel-dual-peak-betting-streaming/" data-link-title="9.C28 FanDuel：體育直播 &#43; 投注的雙重峰值" data-link-desc="FanDuel 3.5M MAU、Super Bowl 期間擴容 5-10 倍、用 AWS Local Zones &#43; Wavelength &#43; Outposts 處理 20&#43; 州的雙重峰值">9.C28 FanDuel</a> — 雙 SLO 並行的 multi-region 策略對照</li>
<li><a href="/blog/posts/vendor-%E6%B7%B1%E5%BA%A6%E6%8A%80%E8%A1%93%E6%96%87%E7%AB%A0%E6%96%B9%E6%B3%95%E8%AB%96%E7%9A%84%E6%BC%94%E5%8C%96%E7%B4%80%E9%8C%84%E5%90%8C-vendor-%E7%B3%BB%E5%88%97%E7%9A%84%E9%96%8B%E5%A0%B4%E8%BC%AA%E6%9B%BF%E9%A9%97%E8%AD%89/" data-link-title="Vendor 深度技術文章方法論的演化紀錄：同 vendor 系列的開場輪替驗證" data-link-desc="vendor overview 飽和後要寫單一功能深度文章、需要選題與結構依據時回來。這套方法論的驗證來源與 cadence variant 在高風險場景（同 vendor sub-tool 系列）的實證。">Vendor 深度技術文章方法論</a> — 本文遵循的 6 規格面寫作模板</li>
<li>官方：<a href="https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/aurora-global-database.html">Aurora Global Database</a></li>
</ul>
]]></content:encoded></item><item><title>從自管 PostgreSQL / MySQL 遷到 Aurora：operational redesign migration playbook</title><link>https://tarrragon.github.io/blog/backend/01-database/vendors/aurora/migrate-from-self-managed-pg-mysql/</link><pubDate>Wed, 27 May 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/backend/01-database/vendors/aurora/migrate-from-self-managed-pg-mysql/</guid><description>&lt;p>從自管 PostgreSQL / MySQL 遷到 Aurora 是 &lt;em>operational redesign hybrid&lt;/em>（Type C &lt;a href="https://tarrragon.github.io/blog/backend/knowledge-cards/migration/" data-link-title="Migration" data-link-desc="說明系統如何把資料、流量或結構從舊狀態移到新狀態">migration&lt;/a>）— wire protocol 相容、application 不改、但 HA / backup / monitoring / capacity 模型完全不同。本 playbook 走 &lt;a href="https://tarrragon.github.io/blog/posts/migration-playbook-%E6%96%B9%E6%B3%95%E8%AB%96%E7%9A%84%E6%BC%94%E5%8C%96%E7%B4%80%E9%8C%84stage-0-variant-%E8%A6%8F%E5%8A%83%E6%8A%8A-collapse-%E7%8E%87%E5%BE%9E-60-%E9%99%8D%E5%88%B0-0/" data-link-title="Migration Playbook 方法論的演化紀錄：Stage 0 variant 規劃把 collapse 率從 60% 降到 0%" data-link-desc="跨 vendor migration playbook 需要獨立寫作方法論的依據，以及這套方法論從三輪 batch dogfood 中演化出來的驗證證據。">migration playbook 6 規格面&lt;/a>（Driver / Diff audit / Phase plan / Evidence / Cutover / Cleanup）、補三個 Aurora-specific 議題：(1) 合規禁止跨境複製的 no-go condition、(2) 合規驅動遷移的時程模型（市場數 × 平均審查月份）、(3) Aurora 不是 all-purpose store 邊界。每階段進入下一步前都要過 &lt;a href="https://tarrragon.github.io/blog/backend/knowledge-cards/migration-gate/" data-link-title="Migration Gate" data-link-desc="說明遷移流程何時可以進入下一階段或正式切換">migration gate&lt;/a> — Evidence 段列出的證據是 gate 條件、不是 nice-to-have。&lt;/p>
&lt;p>本 playbook 不重複 Aurora overview（請看 &lt;a href="https://tarrragon.github.io/blog/backend/01-database/vendors/aurora/" data-link-title="AWS Aurora" data-link-desc="AWS managed PostgreSQL / MySQL、storage / compute 分離、&amp;#43;75% 效能改善的 production 證據">Aurora vendor 頁&lt;/a>）— 前置閱讀建議 &lt;a href="../storage-architecture/">Aurora storage architecture&lt;/a>（理解為什麼 operational redesign）、&lt;a href="../cross-az-failover-rto/">Aurora cross-AZ failover RTO&lt;/a>（HA redesign 主項）、&lt;a href="../read-replica-scaling/">Aurora read replica scaling&lt;/a>（fleet 治理 SSoT、含合規 driver）。&lt;/p>
&lt;h2 id="migration-type-判定">Migration type 判定&lt;/h2>
&lt;p>本 playbook 是 &lt;em>Type C：Operational redesign hybrid&lt;/em>：&lt;/p>
&lt;ul>
&lt;li>PostgreSQL / MySQL → Aurora wire protocol 相容、application 多數不改&lt;/li>
&lt;li>但 operational model（HA / backup / monitoring / capacity）完全不同、需要 redesign&lt;/li>
&lt;li>跟 Type A schema translation 差：不需要翻譯 application SQL&lt;/li>
&lt;li>跟 Type B drop-in 差：HA / backup / monitoring / capacity 模型需要 redesign&lt;/li>
&lt;li>跟 Type E paradigm shift 差：保留 single-primary SQL 跟 ACID transaction 語意&lt;/li>
&lt;/ul>
&lt;p>對照其他 Aurora-related migration playbook：&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/backend/01-database/vendors/postgresql/migrate-to-aurora-dsql/" data-link-title="PostgreSQL → Aurora DSQL Migration：PG wire-compatible Distributed SQL 的 Paradigm Shift" data-link-desc="Aurora DSQL（2024-12 re:Invent preview / 2025-05 GA）是 AWS 推的 PG wire-compatible *active-active distributed SQL*、跟 self-managed PG / Aurora PG 不同 paradigm（OCC &amp;#43; snapshot isolation &amp;#43; multi-region strong consistency）。Migration 結構是 *protocol drop-in &amp;#43; paradigm shift*：app SQL 不太改、但 transaction retry / extension 缺位 / 多 region 一致性需重設計。本文走 DSQL vs Aurora PG vs self-managed PG 三軸對比、為什麼遷的三條 driver（global write / operational zero-touch / region resiliency）、Type E phased plan、5 production 踩雷（transaction retry 沒處理 / extension 缺位 / sequence throughput 限制 / Aurora PG 直升 DSQL 不可行 / region failover semantic）、跟 PG → Aurora 跟 PG → CockroachDB 對比">PG → Aurora DSQL&lt;/a> 是 Type E paradigm shift（distributed SQL、multi-region active-active）&lt;/li>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/backend/01-database/vendors/postgresql/migrate-to-cockroachdb/" data-link-title="PostgreSQL → CockroachDB：三維皆 High 的多重歸類 migration" data-link-desc="PostgreSQL → CockroachDB 是 Schema / Operational / Paradigm 三維皆 High 的 multi-axis migration、實證 [#127](/report/content-structure-by-max-diff-dimension/) 的「多重歸類跟 tie-breaking」規則；主結構走 Type E paradigm shift、Schema 差 &amp;#43; Operational redesign 抽出獨立段；涵蓋 transaction model 重設計、SQL dialect gap、5 個 production 踩雷">PG → CockroachDB&lt;/a> 是 Type E paradigm shift + cross-cloud&lt;/li>
&lt;/ul>
&lt;h2 id="driver為什麼遷">Driver：為什麼遷&lt;/h2>
&lt;h3 id="主要-driver">主要 driver&lt;/h3>
&lt;ul>
&lt;li>團隊規模成長、DBA bandwidth 飽和、backup / failover / patch 操作負擔超過產品價值&lt;/li>
&lt;li>Read replica scaling 需求（傳統 streaming replication lag 秒級、Aurora 10-30ms — 詳見 &lt;a href="../read-replica-scaling/">Aurora read replica scaling&lt;/a>）&lt;/li>
&lt;li>Storage growth 痛點（local SSD 上限、resize 要 downtime、Aurora 自動 grow 到 128 TB）&lt;/li>
&lt;/ul>
&lt;h3 id="次要-driver">次要 driver&lt;/h3>
&lt;ul>
&lt;li>HA model 簡化（Patroni / Orchestrator → Aurora cluster endpoint、見 &lt;a href="../cross-az-failover-rto/">cross-AZ failover RTO&lt;/a>）&lt;/li>
&lt;li>Backup 自動化（pgBackRest / xtrabackup → Aurora automated backup + PITR）&lt;/li>
&lt;li>Multi-region DR 需求（&lt;a href="../global-database-multi-region/">Aurora Global Database&lt;/a>、但合規場景例外）&lt;/li>
&lt;/ul>
&lt;h3 id="no-go-condition嚴格遵守">No-go condition（嚴格遵守）&lt;/h3>
&lt;p>跨雲 / on-prem 需求觸動 &lt;a href="https://tarrragon.github.io/blog/backend/knowledge-cards/vendor-lock-in/" data-link-title="Vendor Lock-In" data-link-desc="說明採用供應商產品後，其 API 與格式滲入程式碼造成的退出成本">vendor lock-in&lt;/a> — Aurora storage layer 是 AWS 專屬、wire protocol 相容不代表退出成本低、long-term 跨雲策略未定時 self-managed PG / MySQL 反而保留路徑。&lt;/p></description><content:encoded><![CDATA[<p>從自管 PostgreSQL / MySQL 遷到 Aurora 是 <em>operational redesign hybrid</em>（Type C <a href="/blog/backend/knowledge-cards/migration/" data-link-title="Migration" data-link-desc="說明系統如何把資料、流量或結構從舊狀態移到新狀態">migration</a>）— wire protocol 相容、application 不改、但 HA / backup / monitoring / capacity 模型完全不同。本 playbook 走 <a href="/blog/posts/migration-playbook-%E6%96%B9%E6%B3%95%E8%AB%96%E7%9A%84%E6%BC%94%E5%8C%96%E7%B4%80%E9%8C%84stage-0-variant-%E8%A6%8F%E5%8A%83%E6%8A%8A-collapse-%E7%8E%87%E5%BE%9E-60-%E9%99%8D%E5%88%B0-0/" data-link-title="Migration Playbook 方法論的演化紀錄：Stage 0 variant 規劃把 collapse 率從 60% 降到 0%" data-link-desc="跨 vendor migration playbook 需要獨立寫作方法論的依據，以及這套方法論從三輪 batch dogfood 中演化出來的驗證證據。">migration playbook 6 規格面</a>（Driver / Diff audit / Phase plan / Evidence / Cutover / Cleanup）、補三個 Aurora-specific 議題：(1) 合規禁止跨境複製的 no-go condition、(2) 合規驅動遷移的時程模型（市場數 × 平均審查月份）、(3) Aurora 不是 all-purpose store 邊界。每階段進入下一步前都要過 <a href="/blog/backend/knowledge-cards/migration-gate/" data-link-title="Migration Gate" data-link-desc="說明遷移流程何時可以進入下一階段或正式切換">migration gate</a> — Evidence 段列出的證據是 gate 條件、不是 nice-to-have。</p>
<p>本 playbook 不重複 Aurora overview（請看 <a href="/blog/backend/01-database/vendors/aurora/" data-link-title="AWS Aurora" data-link-desc="AWS managed PostgreSQL / MySQL、storage / compute 分離、&#43;75% 效能改善的 production 證據">Aurora vendor 頁</a>）— 前置閱讀建議 <a href="../storage-architecture/">Aurora storage architecture</a>（理解為什麼 operational redesign）、<a href="../cross-az-failover-rto/">Aurora cross-AZ failover RTO</a>（HA redesign 主項）、<a href="../read-replica-scaling/">Aurora read replica scaling</a>（fleet 治理 SSoT、含合規 driver）。</p>
<h2 id="migration-type-判定">Migration type 判定</h2>
<p>本 playbook 是 <em>Type C：Operational redesign hybrid</em>：</p>
<ul>
<li>PostgreSQL / MySQL → Aurora wire protocol 相容、application 多數不改</li>
<li>但 operational model（HA / backup / monitoring / capacity）完全不同、需要 redesign</li>
<li>跟 Type A schema translation 差：不需要翻譯 application SQL</li>
<li>跟 Type B drop-in 差：HA / backup / monitoring / capacity 模型需要 redesign</li>
<li>跟 Type E paradigm shift 差：保留 single-primary SQL 跟 ACID transaction 語意</li>
</ul>
<p>對照其他 Aurora-related migration playbook：</p>
<ul>
<li><a href="/blog/backend/01-database/vendors/postgresql/migrate-to-aurora-dsql/" data-link-title="PostgreSQL → Aurora DSQL Migration：PG wire-compatible Distributed SQL 的 Paradigm Shift" data-link-desc="Aurora DSQL（2024-12 re:Invent preview / 2025-05 GA）是 AWS 推的 PG wire-compatible *active-active distributed SQL*、跟 self-managed PG / Aurora PG 不同 paradigm（OCC &#43; snapshot isolation &#43; multi-region strong consistency）。Migration 結構是 *protocol drop-in &#43; paradigm shift*：app SQL 不太改、但 transaction retry / extension 缺位 / 多 region 一致性需重設計。本文走 DSQL vs Aurora PG vs self-managed PG 三軸對比、為什麼遷的三條 driver（global write / operational zero-touch / region resiliency）、Type E phased plan、5 production 踩雷（transaction retry 沒處理 / extension 缺位 / sequence throughput 限制 / Aurora PG 直升 DSQL 不可行 / region failover semantic）、跟 PG → Aurora 跟 PG → CockroachDB 對比">PG → Aurora DSQL</a> 是 Type E paradigm shift（distributed SQL、multi-region active-active）</li>
<li><a href="/blog/backend/01-database/vendors/postgresql/migrate-to-cockroachdb/" data-link-title="PostgreSQL → CockroachDB：三維皆 High 的多重歸類 migration" data-link-desc="PostgreSQL → CockroachDB 是 Schema / Operational / Paradigm 三維皆 High 的 multi-axis migration、實證 [#127](/report/content-structure-by-max-diff-dimension/) 的「多重歸類跟 tie-breaking」規則；主結構走 Type E paradigm shift、Schema 差 &#43; Operational redesign 抽出獨立段；涵蓋 transaction model 重設計、SQL dialect gap、5 個 production 踩雷">PG → CockroachDB</a> 是 Type E paradigm shift + cross-cloud</li>
</ul>
<h2 id="driver為什麼遷">Driver：為什麼遷</h2>
<h3 id="主要-driver">主要 driver</h3>
<ul>
<li>團隊規模成長、DBA bandwidth 飽和、backup / failover / patch 操作負擔超過產品價值</li>
<li>Read replica scaling 需求（傳統 streaming replication lag 秒級、Aurora 10-30ms — 詳見 <a href="../read-replica-scaling/">Aurora read replica scaling</a>）</li>
<li>Storage growth 痛點（local SSD 上限、resize 要 downtime、Aurora 自動 grow 到 128 TB）</li>
</ul>
<h3 id="次要-driver">次要 driver</h3>
<ul>
<li>HA model 簡化（Patroni / Orchestrator → Aurora cluster endpoint、見 <a href="../cross-az-failover-rto/">cross-AZ failover RTO</a>）</li>
<li>Backup 自動化（pgBackRest / xtrabackup → Aurora automated backup + PITR）</li>
<li>Multi-region DR 需求（<a href="../global-database-multi-region/">Aurora Global Database</a>、但合規場景例外）</li>
</ul>
<h3 id="no-go-condition嚴格遵守">No-go condition（嚴格遵守）</h3>
<p>跨雲 / on-prem 需求觸動 <a href="/blog/backend/knowledge-cards/vendor-lock-in/" data-link-title="Vendor Lock-In" data-link-desc="說明採用供應商產品後，其 API 與格式滲入程式碼造成的退出成本">vendor lock-in</a> — Aurora storage layer 是 AWS 專屬、wire protocol 相容不代表退出成本低、long-term 跨雲策略未定時 self-managed PG / MySQL 反而保留路徑。</p>
<table>
  <thead>
      <tr>
          <th>條件</th>
          <th>為什麼是 no-go</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>跨雲 / on-prem 需求</td>
          <td>Aurora AWS-only、wire protocol 相容但 storage 是 AWS 專屬</td>
      </tr>
      <tr>
          <td>需要 latest upstream 特性</td>
          <td>Aurora 通常落後 upstream PostgreSQL / MySQL 1-2 major version</td>
      </tr>
      <tr>
          <td>預算極敏感</td>
          <td>Aurora 比 self-managed PostgreSQL / MySQL 貴 20-30%</td>
      </tr>
      <tr>
          <td>合規禁止跨境複製</td>
          <td>受監管市場 <a href="/blog/backend/knowledge-cards/data-residency/" data-link-title="Data Residency" data-link-desc="合規要求資料留在特定地理邊界內、跨境複製違反合規、推動 fleet 拓樸決策">Data Residency</a> <em>禁止跨境複製</em>、Aurora Global Database 在這種場景 <em>違反合規</em> — 要改用每市場獨立 cluster</td>
      </tr>
      <tr>
          <td>客製化 storage / I/O</td>
          <td>Aurora storage 是 AWS managed、不能客製化（vs self-managed 可以做 cgroup / quota / 自訂 storage 配置）</td>
      </tr>
  </tbody>
</table>
<p><strong>合規禁止跨境複製 no-go</strong>（<a href="/blog/backend/09-performance-capacity/cases/standard-chartered-aurora-banking/" data-link-title="9.C14 Standard Chartered：受監管銀行的 Aurora 4000 TPS 容量提升" data-link-desc="Standard Chartered 銀行遷移到 Aurora 後吞吐量提升 10 倍至 4000 TPS、跨 7 個受監管市場">9.C14 Standard Chartered 揭露</a>）：</p>
<p>受監管市場資料不能跨境複製、Aurora Global Database 在這種場景違反合規。讀者規劃 Aurora migration 時不能假設「Aurora 一定有 Global Database 選項」— 要改用每市場獨立 cluster（fleet 拓樸吸收合規邊界、見 <a href="../read-replica-scaling/">Aurora read replica scaling</a> fleet SSoT）。</p>
<h3 id="替代方案">替代方案</h3>
<ul>
<li><strong>RDS PostgreSQL / MySQL</strong>：更接近 upstream、單 AZ 便宜、不重寫 storage</li>
<li><strong>自管 + Patroni HA + pgBackRest</strong>：保留控制、跨雲可用</li>
<li><strong>CockroachDB / Aurora DSQL</strong>：multi-region active-active write 需求</li>
</ul>
<h3 id="case-anchor">Case anchor</h3>
<ul>
<li><a href="/blog/backend/09-performance-capacity/cases/netflix-aurora-consolidation/" data-link-title="9.C23 Netflix：把關聯式 DB 統一到 Aurora、效能 &#43;75%、成本 -28%" data-link-desc="Netflix 把多套關聯式 DB 統一到 Aurora、效能提升 75%、成本下降 28%、串流數十億小時">9.C23 Netflix Aurora consolidation</a>：多套 RDBMS 統一到 Aurora、driver 是 <em>operational consolidation</em>、不是純效能</li>
<li><a href="/blog/backend/09-performance-capacity/cases/draftkings-aurora-financial-ledger/" data-link-title="9.C4 DraftKings：Aurora 撐 100 萬 ops/min 的體育博彩金融帳本" data-link-desc="DraftKings 用 Aurora MySQL 跑體育博彩金融帳本、Super Bowl 流量 &#43;50% 不影響延遲">9.C4 DraftKings</a>：200 個 cluster、按業務切分（不是一個大 cluster + 200 schema）</li>
<li><a href="/blog/backend/09-performance-capacity/cases/standard-chartered-aurora-banking/" data-link-title="9.C14 Standard Chartered：受監管銀行的 Aurora 4000 TPS 容量提升" data-link-desc="Standard Chartered 銀行遷移到 Aurora 後吞吐量提升 10 倍至 4000 TPS、跨 7 個受監管市場">9.C14 Standard Chartered</a>：受監管場景、合規 lead time 是時程主項</li>
</ul>
<p><strong>Netflix scope warning（必引用）</strong>：</p>
<ul>
<li><a href="/blog/backend/09-performance-capacity/cases/netflix-aurora-consolidation/" data-link-title="9.C23 Netflix：把關聯式 DB 統一到 Aurora、效能 &#43;75%、成本 -28%" data-link-desc="Netflix 把多套關聯式 DB 統一到 Aurora、效能提升 75%、成本下降 28%、串流數十億小時">case「需要警惕」段第 2 點原文</a>：「Netflix 數據層遠不止 Aurora — 還有 Cassandra（playback metadata）、EVCache（cache layer）、Iceberg（data warehouse）。Aurora 主要是『需要 ACID 的 OLTP 工作負載』、不是『all-purpose store』」</li>
<li>工程含義：consolidation 是 <em>ACID OLTP 整合到 Aurora</em>、不是 <em>所有 store 整合到 Aurora</em></li>
<li>讀者規劃整合範圍時要明示什麼 workload 不在範圍（cache、analytics、time-series、search、KV 高峰）</li>
<li>「+75% performance improvement 是跨多 workload 的最大改善幅度、不是『每個 workload 都 +75%』。實際每個 workload 改善幅度從 10% 到 75% 不等」（case「需要警惕」段第 1 點）</li>
</ul>
<h2 id="diff-audit6-維-source--target-差異盤點">Diff audit：6 維 source / target 差異盤點</h2>
<table>
  <thead>
      <tr>
          <th>維度</th>
          <th>差異</th>
          <th>主導程度</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Schema</td>
          <td>PostgreSQL extension 相容性（pg_cron 改 Lambda / Step Functions、pg_partman 改 manual / native partitioning、TimescaleDB 不支援、PostGIS 支援）；MySQL plugin（HandlerSocket 不支援、audit plugin 改 CloudTrail）</td>
          <td>中</td>
      </tr>
      <tr>
          <td>Operational</td>
          <td>HA model、backup、monitoring、parameter management（postgresql.conf → DB parameter group / cluster parameter group）</td>
          <td>高（主導）</td>
      </tr>
      <tr>
          <td>Paradigm</td>
          <td>保留（single-primary SQL、ACID transaction、wire protocol）</td>
          <td>無變動</td>
      </tr>
      <tr>
          <td>Components</td>
          <td>connection pool（PgBouncer → RDS Proxy 或保留 PgBouncer in front of Aurora）、logical replication（pglogical / Debezium → Aurora 原生支援、但有版本限制）</td>
          <td>中</td>
      </tr>
      <tr>
          <td>Application</td>
          <td>保留（connection string 改 endpoint、SSL config 改 RDS CA、driver 不改）</td>
          <td>低</td>
      </tr>
      <tr>
          <td>Topology</td>
          <td>保留（single-region scaling、若要 multi-region 走另一條 playbook to DSQL）；fleet 拓樸決策（拆幾個 cluster）詳見 <a href="../read-replica-scaling/">read replica scaling</a> fleet SSoT</td>
          <td>中-高</td>
      </tr>
  </tbody>
</table>
<p><strong>主導差異</strong>：Operational layer（HA / backup / monitoring）、不是 schema 或 application。</p>
<h3 id="schema-diff-細節">Schema diff 細節</h3>
<p><strong>PostgreSQL → Aurora PostgreSQL</strong>：</p>
<table>
  <thead>
      <tr>
          <th>Extension</th>
          <th>Aurora 支援</th>
          <th>Migration 策略</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>pg_cron</td>
          <td>不支援</td>
          <td>改 Lambda 排程 + RDS event 或 Step Functions</td>
      </tr>
      <tr>
          <td>pg_partman</td>
          <td>不支援</td>
          <td>改 native declarative partitioning（PostgreSQL 11+）</td>
      </tr>
      <tr>
          <td>TimescaleDB</td>
          <td>不支援</td>
          <td>改 native partition + materialized view、或保留 self-managed</td>
      </tr>
      <tr>
          <td>PostGIS</td>
          <td>支援</td>
          <td>直接遷</td>
      </tr>
      <tr>
          <td>pgvector</td>
          <td>支援（新版）</td>
          <td>確認 Aurora PostgreSQL version、可能需要升級</td>
      </tr>
      <tr>
          <td>pglogical</td>
          <td>不支援</td>
          <td>改 Aurora 原生 logical replication（有版本限制）</td>
      </tr>
  </tbody>
</table>
<p><strong>MySQL → Aurora MySQL</strong>：</p>
<table>
  <thead>
      <tr>
          <th>Plugin</th>
          <th>Aurora 支援</th>
          <th>Migration 策略</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>HandlerSocket</td>
          <td>不支援</td>
          <td>改 SQL access 或 Aurora-specific KV cache</td>
      </tr>
      <tr>
          <td>Vault audit</td>
          <td>不支援</td>
          <td>改 AWS CloudTrail + RDS audit log</td>
      </tr>
      <tr>
          <td>MyRocks engine</td>
          <td>不支援</td>
          <td>改 InnoDB（Aurora 預設）、評估 storage 成本</td>
      </tr>
      <tr>
          <td>MaxScale</td>
          <td>不支援</td>
          <td>改 Aurora reader endpoint 或 RDS Proxy</td>
      </tr>
  </tbody>
</table>
<h3 id="operational-diff-細節">Operational diff 細節</h3>
<table>
  <thead>
      <tr>
          <th>元素</th>
          <th>Self-managed</th>
          <th>Aurora</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>HA</td>
          <td>Patroni / Orchestrator + etcd / ZooKeeper</td>
          <td>Cluster endpoint + 自動 cross-AZ failover</td>
      </tr>
      <tr>
          <td>Backup</td>
          <td>pgBackRest / xtrabackup + S3 lifecycle</td>
          <td>Automated backup + manual snapshot + PITR</td>
      </tr>
      <tr>
          <td>Monitoring</td>
          <td>Prometheus exporter + Grafana</td>
          <td>CloudWatch + Performance Insights</td>
      </tr>
      <tr>
          <td>Parameter</td>
          <td>postgresql.conf / my.cnf</td>
          <td>DB parameter group / cluster parameter group</td>
      </tr>
      <tr>
          <td>Failover testing</td>
          <td>Patroni <code>patronictl failover</code></td>
          <td><code>aws rds failover-db-cluster</code></td>
      </tr>
      <tr>
          <td>WAL / binlog 觀測</td>
          <td><code>pg_stat_wal</code> / <code>SHOW MASTER STATUS</code></td>
          <td>CloudWatch + Performance Insights wait events</td>
      </tr>
  </tbody>
</table>
<h3 id="application-diff-細節">Application diff 細節</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"># Self-managed PostgreSQL
</span></span><span class="line"><span class="ln">2</span><span class="cl">jdbc:postgresql://primary.internal:5432/mydb?ssl=true&amp;sslmode=verify-full&amp;sslrootcert=/etc/ssl/postgresql.crt
</span></span><span class="line"><span class="ln">3</span><span class="cl">
</span></span><span class="line"><span class="ln">4</span><span class="cl"># Aurora PostgreSQL
</span></span><span class="line"><span class="ln">5</span><span class="cl">jdbc:postgresql://my-cluster.cluster-xxx.us-east-1.rds.amazonaws.com:5432/mydb?ssl=true&amp;sslmode=verify-full&amp;sslrootcert=rds-ca.pem</span></span></code></pre></div><p>Application 改動量小：connection string 換 endpoint、SSL CA 換 RDS CA、driver 不變。</p>
<p>對應 knowledge card：<a href="/blog/backend/knowledge-cards/failover/" data-link-title="Failover" data-link-desc="說明主要服務或節點失效時如何切換到備援能力">failover</a>、<a href="/blog/backend/knowledge-cards/replication-lag/" data-link-title="Replication Lag" data-link-desc="說明資料副本落後正式來源多久，以及它如何影響讀取正確性">replication-lag</a>。</p>
<h2 id="phase-plan階段切換">Phase plan：階段切換</h2>
<h3 id="phase-0pre-migration-audit2-4-週">Phase 0：Pre-migration audit（2-4 週）</h3>
<p>工作：</p>
<ul>
<li>Extension audit：<code>SELECT * FROM pg_extension</code> / <code>SHOW PLUGINS</code>、列出 source 使用的 extension</li>
<li>Parameter audit：postgresql.conf vs Aurora parameter group、列差異</li>
<li>Application connection string audit：所有服務的 DB connection 點位</li>
<li>Benchmark baseline：write QPS / read QPS / p99 latency</li>
<li>Cost baseline：current self-managed monthly cost vs Aurora estimate</li>
</ul>
<p>Output：</p>
<ul>
<li>Migration feasibility report（含 no-go condition check）</li>
<li>Aurora cluster sizing 估算</li>
<li>Extension migration plan（each extension 對應的策略）</li>
</ul>
<h3 id="phase-1aurora-infra-準備1-2-週">Phase 1：Aurora infra 準備（1-2 週）</h3>
<p>工作：</p>
<ul>
<li>Aurora cluster 開設（dev / staging / prod）</li>
<li>Parameter group 對位（從 source postgresql.conf / my.cnf 翻譯到 Aurora parameter group）</li>
<li>SG / subnet / IAM 設定</li>
<li>RDS Proxy 配置（如需要）</li>
<li>CloudWatch dashboard + Performance Insights baseline</li>
<li>Backup retention 設定（1-35 天）</li>
</ul>
<p>Output：</p>
<ul>
<li>Aurora cluster 待 data load</li>
<li>Monitoring 已 ready、能對照 source 跟 target</li>
</ul>
<h3 id="phase-2data-migration2-8-週依資料量">Phase 2：Data migration（2-8 週、依資料量）</h3>
<p>三條 path、依場景選：</p>
<h4 id="path-aaws-dms-full-load--cdc">Path A：AWS DMS full load + CDC</h4>
<ul>
<li>適合：&lt; 1 TB、可接受 read-only 短窗口</li>
<li>流程：DMS full load → DMS CDC → application cutover</li>
<li>優點：managed、validation 工具齊全</li>
<li>缺點：CDC lag 受 DMS task config 影響、bulk DDL 不友善</li>
</ul>
<h4 id="path-bpg_dump--mysqldump--logical-replication-catch-up">Path B：pg_dump / mysqldump + logical replication catch-up</h4>
<ul>
<li>適合：&gt; 1 TB、要長 CDC 期、預算敏感</li>
<li>流程：snapshot → pg_dump / mysqldump → restore to Aurora → logical replication catch-up → application cutover</li>
<li>優點：成本低、可控性高</li>
<li>缺點：手動步驟多、要自己管 CDC lag</li>
</ul>
<h4 id="path-csnapshot-restore">Path C：Snapshot restore</h4>
<ul>
<li>適合：已在 RDS PostgreSQL / MySQL</li>
<li>流程：RDS snapshot → Aurora restore-from-snapshot → catch-up → application cutover</li>
<li>優點：最快、AWS-internal 操作</li>
<li>缺點：只適用 RDS source、不適用 self-managed</li>
</ul>
<h3 id="phase-3dual-read-validation1-2-週">Phase 3：Dual-read validation（1-2 週）</h3>
<p>工作：</p>
<ul>
<li>Application read 50/50 split source / target</li>
<li>比對 query 結果（per-table checksum + sampling）</li>
<li>量測 latency（Aurora p99 ≤ source × 1.2）</li>
<li>確認 stale read 比例 &lt; 0.01%</li>
</ul>
<p>Output：</p>
<ul>
<li>Validation report：query 結果差異、latency 對照</li>
<li>Go/no-go decision for cutover</li>
</ul>
<h3 id="phase-4cutover-1-小時-window">Phase 4：Cutover（&lt; 1 小時 window）</h3>
<p>工作：</p>
<ul>
<li>Source set read-only</li>
<li>CDC catch-up final（lag → 0）</li>
<li>Application switch endpoint（DNS / service discovery / config flag）</li>
<li>Smoke test（critical path query + write）</li>
<li>Monitor error rate + latency 1 小時</li>
</ul>
<p>Output：</p>
<ul>
<li>Cutover complete</li>
<li>Source 切到 read-only、保留作為 rollback 餘地</li>
</ul>
<h3 id="phase-5cleanup4-8-週">Phase 5：Cleanup（4-8 週）</h3>
<p>工作：</p>
<ul>
<li>Source 保留 1 個月 read-only（rollback window）</li>
<li>確認穩定後 snapshot → S3 archive → decommission</li>
<li>舊 monitoring / backup / runbook archive</li>
</ul>
<p>Output：</p>
<ul>
<li>Source decommissioned</li>
<li>新 runbook + monitoring 為 SSoT</li>
</ul>
<h3 id="本-phase-plan-適用範圍">本 phase plan 適用範圍</h3>
<p><strong>Non-regulated workload</strong>（一般 SaaS / e-commerce / 內部系統）。受監管場景（銀行 / 保險 / 醫療）請見下方「合規驅動遷移的時程模型」段、技術 phase 不變但 lead time 完全不同。</p>
<h2 id="合規驅動遷移的時程模型">合規驅動遷移的時程模型</h2>
<p>受監管產業遷移的關鍵時程是 <em>合規審查 lead time</em>、不是技術遷移時間 — 本段是補充給銀行 / 保險 / 醫療讀者、避免照本 playbook 走嚴重低估時程。</p>
<h3 id="standard-chartered-揭露的時程模型">Standard Chartered 揭露的時程模型</h3>
<p><a href="/blog/backend/09-performance-capacity/cases/standard-chartered-aurora-banking/" data-link-title="9.C14 Standard Chartered：受監管銀行的 Aurora 4000 TPS 容量提升" data-link-desc="Standard Chartered 銀行遷移到 Aurora 後吞吐量提升 10 倍至 4000 TPS、跨 7 個受監管市場">9.C14 Standard Chartered case</a> 「判讀」段第 3 點 + 「策略」段第 3 點原文：「每個受監管市場的審查可能 3-12 個月、合計遷移時程是『市場數 × 平均審查月份』、不是『技術遷移月份』」。</p>
<p>工程含義：</p>
<ul>
<li>技術 phase plan 假設 2-8 週 data migration + &lt; 1 小時 cutover</li>
<li>合規 lead time 是 <em>獨立軸</em>、可能比技術時程長一個數量級</li>
<li>不同市場合規進度不同步、可能要分批上線</li>
</ul>
<h3 id="合規時程組合">合規時程組合</h3>
<table>
  <thead>
      <tr>
          <th>軸</th>
          <th>時程估算</th>
          <th>不可壓縮原因</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>技術遷移</td>
          <td>2-8 週 data migration + &lt; 1 小時 cutover</td>
          <td>工程可控</td>
      </tr>
      <tr>
          <td>單市場合規審查</td>
          <td>3-12 個月（Standard Chartered case 揭露）</td>
          <td>監管機構 lead time、不是技術問題</td>
      </tr>
      <tr>
          <td>多市場合規 lead time</td>
          <td>市場數 × 平均審查月份（7 市場 × 6 個月 ≈ 3.5 年最壞情況）</td>
          <td>各市場各自審、平行度受監管機構文化影響</td>
      </tr>
      <tr>
          <td>跨境複製禁令審查</td>
          <td>包含在合規審查內、可能讓 Global Database 從候選變反指標</td>
          <td>監管要求 data residency、無 cross-region replication option</td>
      </tr>
  </tbody>
</table>
<h3 id="讀者判讀">讀者判讀</h3>
<ul>
<li>受監管場景 <em>不能</em> 用本 playbook 的「2-8 週 data migration + &lt; 1 小時 cutover」估時程交付給管理層 — 合規 lead time 是時程主項</li>
<li>受監管場景 <em>不能</em> 假設 Aurora Global Database 是 multi-region DR 選項 — 合規禁止跨境複製場景下 Global Database 違反合規（見 <a href="../global-database-multi-region/">global-database-multi-region</a>），要改用每市場獨立 cluster</li>
<li>合規場景的 phase plan 要把每市場當成獨立 mini-migration、用 <em>市場批次</em> 推進、不是一次 big bang</li>
</ul>
<p><strong>scope warning（必明示、case 自承）</strong>：Standard Chartered case 未公開是 PostgreSQL 還是 MySQL、未公開具體 cost 數字 — 引用時不能擴寫「Standard Chartered 用 Aurora PostgreSQL」這類細節（case 用「相關 case study」匿名標明）。</p>
<p><strong>合規時程 scope 警示</strong>：「3-12 個月、7 市場 × 6 個月 ≈ 3.5 年」是 Standard Chartered case 揭露範圍。實際合規 lead time 隨產業（銀行 / 保險 / 醫療）跟國家（東南亞 / 歐盟 / 北美 / 中東）差異大、不是恆定數字。讀者要把自家對應監管框架的實際 lead time 算進來、不是直接套 Standard Chartered 數字。</p>
<h2 id="evidence每階段驗證資料">Evidence：每階段驗證資料</h2>
<table>
  <thead>
      <tr>
          <th>Phase</th>
          <th>Evidence</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Phase 0</td>
          <td>extension list、parameter diff、application SQL 抽樣 test on Aurora dev cluster</td>
      </tr>
      <tr>
          <td>Phase 1</td>
          <td>Aurora cluster ready、monitoring dashboard 跟 source 對照</td>
      </tr>
      <tr>
          <td>Phase 2</td>
          <td>DMS row count match、checksum（per-table MD5）、CDC replication lag &lt; 5 秒</td>
      </tr>
      <tr>
          <td>Phase 3</td>
          <td>query result diff &lt; 0.01%、p99 latency Aurora ≤ source × 1.2、application error rate baseline</td>
      </tr>
      <tr>
          <td>Phase 4</td>
          <td>cutover 完成後 1 小時內 error rate &lt; baseline × 2、write success rate 100%</td>
      </tr>
      <tr>
          <td>Phase 5</td>
          <td>30 天無 rollback trigger、cost 月帳對齊預估</td>
      </tr>
  </tbody>
</table>
<p><strong>受監管追加 evidence</strong>：</p>
<ul>
<li>每市場合規 sign-off 文件（central bank / 金融監管機關）</li>
<li>跨境複製禁令審查記錄</li>
<li>Data residency 驗證測試（資料未流出受監管市場 boundary）</li>
<li>Audit log 連續性驗證（source / target audit log 銜接）</li>
</ul>
<p><strong>回路徑</strong>：<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> 抽 CDC / latency evidence。</p>
<h2 id="cutover切流決策">Cutover：切流決策</h2>
<p><strong>Cutover window</strong>：</p>
<ul>
<li>建議 4 AM local time（lowest traffic）</li>
<li>預留 4 小時 buffer</li>
<li>受監管場景可能要在合規規定的 maintenance window（例如某些央行規定週日凌晨）</li>
</ul>
<p><strong>Rollback condition</strong>：</p>
<ul>
<li>error rate &gt; baseline × 5</li>
<li>write latency p99 &gt; baseline × 3 持續 10 分鐘</li>
<li>data corruption signal（checksum mismatch、unexpected row count drop）</li>
</ul>
<p><strong>Rollback path</strong>：</p>
<ul>
<li>Application connection string 切回 source</li>
<li>Source 仍 read-write（cutover 前留 read-write 路徑、若已 read-only 要先解凍）</li>
<li>CDC 反向同步（Aurora → source）catch-up</li>
</ul>
<p><strong>Decision owner</strong>：</p>
<ul>
<li>DBA lead + service owner + on-call SRE 三方 sign-off</li>
<li>受監管場景追加 compliance officer sign-off</li>
<li>Cutover decision log 記錄（<a href="/blog/backend/knowledge-cards/rollback-window/" data-link-title="Rollback Window" data-link-desc="說明變更進入 production 後還能用哪種方式回退或改路線的時間與條件">rollback window</a> / <a href="/blog/backend/knowledge-cards/rollback-condition/" data-link-title="Rollback Condition" data-link-desc="說明決策執行後出現哪些訊號時要撤回、回退或改路線">rollback condition</a> 文件化）</li>
</ul>
<p>對應 knowledge card：<a href="/blog/backend/knowledge-cards/rollback-window/" data-link-title="Rollback Window" data-link-desc="說明變更進入 production 後還能用哪種方式回退或改路線的時間與條件">rollback-window</a>、<a href="/blog/backend/knowledge-cards/rollback-condition/" data-link-title="Rollback Condition" data-link-desc="說明決策執行後出現哪些訊號時要撤回、回退或改路線">rollback-condition</a>。</p>
<h2 id="cleanup雙軌退役">Cleanup：雙軌退役</h2>
<table>
  <thead>
      <tr>
          <th>元素</th>
          <th>Cleanup 策略</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Source database</td>
          <td>read-only 1 個月、確認穩定後 snapshot → S3 archive → decommission</td>
      </tr>
      <tr>
          <td>舊 monitoring</td>
          <td>Prometheus exporter 拆、Grafana dashboard archive、CloudWatch dashboard 為 SSoT</td>
      </tr>
      <tr>
          <td>舊 backup chain</td>
          <td>pgBackRest / xtrabackup retention 保留至合規邊界（金融 7 年、一般 90 天）</td>
      </tr>
      <tr>
          <td>舊 runbook</td>
          <td>Patroni / Orchestrator runbook archive、新 runbook 對 Aurora cluster endpoint</td>
      </tr>
      <tr>
          <td>舊 CDC connector</td>
          <td>DMS task 留 7 天觀察期 → delete；自管 Debezium / pglogical 在 source decommission 同時退役</td>
      </tr>
  </tbody>
</table>
<p><strong>不可逆 cleanup 邊界</strong>：</p>
<ul>
<li>Source decommission 後資料只能從 backup restore</li>
<li>確保 backup 可用性測試通過再 decommission</li>
<li>受監管場景要保留 source backup 到合規 retention（金融 7 年、可能更長）</li>
</ul>
<h2 id="案例對照">案例對照</h2>
<h3 id="netflix-aurora-consolidationoperational-consolidation-的價值">Netflix Aurora consolidation：operational consolidation 的價值</h3>
<p><a href="/blog/backend/09-performance-capacity/cases/netflix-aurora-consolidation/" data-link-title="9.C23 Netflix：把關聯式 DB 統一到 Aurora、效能 &#43;75%、成本 -28%" data-link-desc="Netflix 把多套關聯式 DB 統一到 Aurora、效能提升 75%、成本下降 28%、串流數十億小時">9.C23 Netflix</a> 多套 RDBMS（PostgreSQL / MySQL / Oracle）→ Aurora、+75% 效能 / -28% 成本。</p>
<p><strong>驗證的 driver</strong>：</p>
<ul>
<li>DB 種類太多本身是規模化的成本（每多一種 DB 多一套 DBA 知識 / backup / monitoring）</li>
<li>整合到 Aurora 釋放工程資源、不是純效能改善</li>
</ul>
<p><strong>case 自帶警示（必引用）</strong>：</p>
<ul>
<li>「+75% 是跨多 workload 最大改善幅度、不是每 workload 都 +75%」（case「需要警惕」段第 1 點）</li>
<li><strong>Aurora 非 all-purpose store 邊界</strong>：「Netflix 數據層遠不止 Aurora — 還有 Cassandra（playback metadata）、EVCache（cache layer）、Iceberg（data warehouse）。Aurora 主要是『需要 ACID 的 OLTP 工作負載』」（case「需要警惕」段第 2 點）</li>
</ul>
<p>工程含義：consolidation 是「ACID OLTP 整合到 Aurora」、不是「所有 store 整合到 Aurora」。讀者規劃整合範圍時要明示什麼 workload 不在範圍：</p>
<table>
  <thead>
      <tr>
          <th>Workload</th>
          <th>是否在 Aurora consolidation 範圍</th>
          <th>替代</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>ACID OLTP</td>
          <td>是</td>
          <td>-</td>
      </tr>
      <tr>
          <td>Playback metadata</td>
          <td>否（Netflix 用 Cassandra）</td>
          <td>Cassandra / ScyllaDB</td>
      </tr>
      <tr>
          <td>Cache layer</td>
          <td>否（Netflix 用 EVCache）</td>
          <td>EVCache / Redis / Memcached</td>
      </tr>
      <tr>
          <td>Data warehouse</td>
          <td>否（Netflix 用 Iceberg）</td>
          <td>Iceberg / Snowflake / Redshift</td>
      </tr>
      <tr>
          <td>Time-series</td>
          <td>否（性能不適合）</td>
          <td>InfluxDB / TimescaleDB self-managed</td>
      </tr>
      <tr>
          <td>Search</td>
          <td>否（無 inverted index 優化）</td>
          <td>Elasticsearch / OpenSearch</td>
      </tr>
  </tbody>
</table>
<h3 id="draftkingsfleet-拓樸-redesign">DraftKings：fleet 拓樸 redesign</h3>
<p><a href="/blog/backend/09-performance-capacity/cases/draftkings-aurora-financial-ledger/" data-link-title="9.C4 DraftKings：Aurora 撐 100 萬 ops/min 的體育博彩金融帳本" data-link-desc="DraftKings 用 Aurora MySQL 跑體育博彩金融帳本、Super Bowl 流量 &#43;50% 不影響延遲">9.C4 DraftKings</a> 200 個獨立 Aurora cluster、按業務切分（不是一個大 cluster + 200 schema）。</p>
<p><strong>驗證的 driver</strong>：</p>
<ul>
<li>Migration 不只是技術切換、也是 cluster 拓樸 redesign</li>
<li>業務本身可切分（每體育類別 / 每地理 / 每產品線）就在 migration 時順便拆 cluster</li>
<li>Blast radius 隔離跟容量規劃分散一起獲得</li>
</ul>
<p><strong>Fleet 拓樸決策</strong>：詳見 <a href="../read-replica-scaling/">Aurora read replica scaling</a> 邊界段 SSoT。本 playbook 提醒 <em>migration 是拆 cluster 的好時機</em>、不展開拓樸決策本身。</p>
<h3 id="standard-chartered合規-lead-time--跨境複製禁令">Standard Chartered：合規 lead time + 跨境複製禁令</h3>
<p><a href="/blog/backend/09-performance-capacity/cases/standard-chartered-aurora-banking/" data-link-title="9.C14 Standard Chartered：受監管銀行的 Aurora 4000 TPS 容量提升" data-link-desc="Standard Chartered 銀行遷移到 Aurora 後吞吐量提升 10 倍至 4000 TPS、跨 7 個受監管市場">9.C14 Standard Chartered</a> 受監管場景揭露：</p>
<ul>
<li>合規 lead time 是時程主項（3-12 個月 / 市場）</li>
<li>跨境複製禁止讓 Global Database 變反指標</li>
<li>每市場獨立 cluster + cross-AZ failover 是合規場景的標準解</li>
</ul>
<h3 id="反例aurora-不適合的場景">反例：Aurora 不適合的場景</h3>
<ul>
<li>Multi-region active-active write：見 <a href="/blog/backend/01-database/vendors/postgresql/migrate-to-aurora-dsql/" data-link-title="PostgreSQL → Aurora DSQL Migration：PG wire-compatible Distributed SQL 的 Paradigm Shift" data-link-desc="Aurora DSQL（2024-12 re:Invent preview / 2025-05 GA）是 AWS 推的 PG wire-compatible *active-active distributed SQL*、跟 self-managed PG / Aurora PG 不同 paradigm（OCC &#43; snapshot isolation &#43; multi-region strong consistency）。Migration 結構是 *protocol drop-in &#43; paradigm shift*：app SQL 不太改、但 transaction retry / extension 缺位 / 多 region 一致性需重設計。本文走 DSQL vs Aurora PG vs self-managed PG 三軸對比、為什麼遷的三條 driver（global write / operational zero-touch / region resiliency）、Type E phased plan、5 production 踩雷（transaction retry 沒處理 / extension 缺位 / sequence throughput 限制 / Aurora PG 直升 DSQL 不可行 / region failover semantic）、跟 PG → Aurora 跟 PG → CockroachDB 對比">PG → Aurora DSQL Migration</a></li>
<li>跨雲：見 <a href="/blog/backend/01-database/vendors/postgresql/migrate-to-cockroachdb/" data-link-title="PostgreSQL → CockroachDB：三維皆 High 的多重歸類 migration" data-link-desc="PostgreSQL → CockroachDB 是 Schema / Operational / Paradigm 三維皆 High 的 multi-axis migration、實證 [#127](/report/content-structure-by-max-diff-dimension/) 的「多重歸類跟 tie-breaking」規則；主結構走 Type E paradigm shift、Schema 差 &#43; Operational redesign 抽出獨立段；涵蓋 transaction model 重設計、SQL dialect gap、5 個 production 踩雷">PG → CockroachDB Migration</a></li>
<li>極端寫入吞吐（&gt; 100K WPS）：考慮 sharding、CockroachDB、或 DynamoDB</li>
</ul>
<h2 id="邊界與整合--下一步">邊界與整合 / 下一步</h2>
<p><strong>Sibling playbook</strong>：</p>
<ul>
<li><a href="/blog/backend/01-database/vendors/postgresql/migrate-to-aurora-dsql/" data-link-title="PostgreSQL → Aurora DSQL Migration：PG wire-compatible Distributed SQL 的 Paradigm Shift" data-link-desc="Aurora DSQL（2024-12 re:Invent preview / 2025-05 GA）是 AWS 推的 PG wire-compatible *active-active distributed SQL*、跟 self-managed PG / Aurora PG 不同 paradigm（OCC &#43; snapshot isolation &#43; multi-region strong consistency）。Migration 結構是 *protocol drop-in &#43; paradigm shift*：app SQL 不太改、但 transaction retry / extension 缺位 / 多 region 一致性需重設計。本文走 DSQL vs Aurora PG vs self-managed PG 三軸對比、為什麼遷的三條 driver（global write / operational zero-touch / region resiliency）、Type E phased plan、5 production 踩雷（transaction retry 沒處理 / extension 缺位 / sequence throughput 限制 / Aurora PG 直升 DSQL 不可行 / region failover semantic）、跟 PG → Aurora 跟 PG → CockroachDB 對比">PG → Aurora DSQL</a> — paradigm shift、Type E、multi-region active-active</li>
<li><a href="/blog/backend/01-database/vendors/postgresql/migrate-to-cockroachdb/" data-link-title="PostgreSQL → CockroachDB：三維皆 High 的多重歸類 migration" data-link-desc="PostgreSQL → CockroachDB 是 Schema / Operational / Paradigm 三維皆 High 的 multi-axis migration、實證 [#127](/report/content-structure-by-max-diff-dimension/) 的「多重歸類跟 tie-breaking」規則；主結構走 Type E paradigm shift、Schema 差 &#43; Operational redesign 抽出獨立段；涵蓋 transaction model 重設計、SQL dialect gap、5 個 production 踩雷">PG → CockroachDB</a> — cross-cloud、paradigm shift</li>
<li><a href="/blog/backend/01-database/vendors/postgresql/migrate-to-aurora/" data-link-title="PostgreSQL → Aurora Migration：protocol 相容、operational 重設計" data-link-desc="Aurora 號稱 PostgreSQL-compatible 但 operational model 不同（storage decouple / cluster endpoint / instance class / 自家備份）；遷移流程是混合（protocol drop-in &#43; operational phased）、5 個 production 踩雷（extension 不支援 / replication slot 不直通 / autovacuum 行為差 / IAM 認證強制 / cost model 換算）、跟 Patroni / read replica / DR 對位">PG → Aurora</a> — 既有 PG-specific playbook、可對照本 playbook 的 vendor-neutral 版本</li>
</ul>
<p><strong>Sibling deep article</strong>：</p>
<ul>
<li><a href="../storage-architecture/">Aurora storage architecture</a> — 理解 storage 設計才知道為什麼 operational redesign</li>
<li><a href="../cross-az-failover-rto/">Aurora cross-AZ failover RTO</a> — HA redesign 主項</li>
<li><a href="../read-replica-scaling/">Aurora read replica scaling</a> — fleet 治理 SSoT、含合規 driver</li>
<li><a href="../global-database-multi-region/">Aurora Global Database</a> — 合規禁止跨境複製的 anti-recommendation</li>
</ul>
<p><strong>1.x 章節互引</strong>：</p>
<ul>
<li><a href="/blog/backend/01-database/large-scale-db-migration/" data-link-title="1.12 大規模 DB 遷移實戰" data-link-desc="跨 DB 遷移的 dual-write、[shadow read](/backend/knowledge-cards/shadow-read/)、cutover、rollback 流程 — 從實戰案例提煉的工程做法">1.12 大規模 DB 遷移實戰</a> — migration 上游 framework</li>
</ul>
<p><strong>何時不用本 playbook</strong>：</p>
<ul>
<li>從 Aurora 遷到別處（反向、走對應的反向 playbook）</li>
<li>從 RDS PostgreSQL 升 Aurora PostgreSQL 是 in-place upgrade、用 RDS console「Convert to Aurora」即可、不需要這套 playbook</li>
<li>跨雲遷移：本 playbook 不涵蓋 GCP / Azure SQL → Aurora 流程</li>
</ul>
<h2 id="相關連結">相關連結</h2>
<ul>
<li><a href="/blog/backend/01-database/vendors/aurora/" data-link-title="AWS Aurora" data-link-desc="AWS managed PostgreSQL / MySQL、storage / compute 分離、&#43;75% 效能改善的 production 證據">Aurora vendor overview</a> — 服務定位、適用 / 不適用場景</li>
<li><a href="/blog/backend/knowledge-cards/failover/" data-link-title="Failover" data-link-desc="說明主要服務或節點失效時如何切換到備援能力">Failover 卡片</a> — 概念基底</li>
<li><a href="/blog/backend/knowledge-cards/replication-lag/" data-link-title="Replication Lag" data-link-desc="說明資料副本落後正式來源多久，以及它如何影響讀取正確性">Replication Lag 卡片</a> — operational diff 主軸</li>
<li><a href="/blog/backend/knowledge-cards/rollback-window/" data-link-title="Rollback Window" data-link-desc="說明變更進入 production 後還能用哪種方式回退或改路線的時間與條件">Rollback Window 卡片</a> — cutover decision</li>
<li><a href="/blog/backend/knowledge-cards/rollback-condition/" data-link-title="Rollback Condition" data-link-desc="說明決策執行後出現哪些訊號時要撤回、回退或改路線">Rollback Condition 卡片</a> — rollback trigger</li>
<li><a href="/blog/backend/09-performance-capacity/cases/netflix-aurora-consolidation/" data-link-title="9.C23 Netflix：把關聯式 DB 統一到 Aurora、效能 &#43;75%、成本 -28%" data-link-desc="Netflix 把多套關聯式 DB 統一到 Aurora、效能提升 75%、成本下降 28%、串流數十億小時">9.C23 Netflix</a> — operational consolidation 跟 Aurora 非 all-purpose store 邊界</li>
<li><a href="/blog/backend/09-performance-capacity/cases/draftkings-aurora-financial-ledger/" data-link-title="9.C4 DraftKings：Aurora 撐 100 萬 ops/min 的體育博彩金融帳本" data-link-desc="DraftKings 用 Aurora MySQL 跑體育博彩金融帳本、Super Bowl 流量 &#43;50% 不影響延遲">9.C4 DraftKings</a> — fleet 拓樸 redesign</li>
<li><a href="/blog/backend/09-performance-capacity/cases/standard-chartered-aurora-banking/" data-link-title="9.C14 Standard Chartered：受監管銀行的 Aurora 4000 TPS 容量提升" data-link-desc="Standard Chartered 銀行遷移到 Aurora 後吞吐量提升 10 倍至 4000 TPS、跨 7 個受監管市場">9.C14 Standard Chartered</a> — 合規 lead time + 跨境複製禁令</li>
<li><a href="/blog/posts/migration-playbook-%E6%96%B9%E6%B3%95%E8%AB%96%E7%9A%84%E6%BC%94%E5%8C%96%E7%B4%80%E9%8C%84stage-0-variant-%E8%A6%8F%E5%8A%83%E6%8A%8A-collapse-%E7%8E%87%E5%BE%9E-60-%E9%99%8D%E5%88%B0-0/" data-link-title="Migration Playbook 方法論的演化紀錄：Stage 0 variant 規劃把 collapse 率從 60% 降到 0%" data-link-desc="跨 vendor migration playbook 需要獨立寫作方法論的依據，以及這套方法論從三輪 batch dogfood 中演化出來的驗證證據。">Migration Playbook 寫作方法論</a> — 本文遵循的 6 規格面寫作模板</li>
<li>官方：<a href="https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/AuroraMySQL.Migrating.html">Aurora migration documentation</a></li>
</ul>
]]></content:encoded></item></channel></rss>