<?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>Operational-Hybrid on Tarragon</title><link>https://tarrragon.github.io/blog/tags/operational-hybrid/</link><description>Recent content in Operational-Hybrid on Tarragon</description><generator>Hugo -- gohugo.io</generator><language>zh-TW</language><copyright>Tarragon (CC BY 4.0)</copyright><lastBuildDate>Tue, 19 May 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://tarrragon.github.io/blog/tags/operational-hybrid/index.xml" rel="self" type="application/rss+xml"/><item><title>MySQL → Aurora MySQL：storage layer 轉手到 AWS、replication / HA / backup 全部 outsource</title><link>https://tarrragon.github.io/blog/backend/01-database/vendors/mysql/migrate-to-aurora/</link><pubDate>Tue, 19 May 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/backend/01-database/vendors/mysql/migrate-to-aurora/</guid><description>&lt;blockquote>
&lt;p>本文是跨 vendor &lt;a href="https://tarrragon.github.io/blog/backend/knowledge-cards/migration/" data-link-title="Migration" data-link-desc="說明系統如何把資料、流量或結構從舊狀態移到新狀態">migration&lt;/a> playbook、cross-link 到 &lt;a href="https://tarrragon.github.io/blog/backend/01-database/vendors/mysql/" data-link-title="MySQL" data-link-desc="高併發網路服務常用關聯式資料庫、Vitess / PlanetScale 分片生態、GitHub / Shopify / Facebook 規模驗證">MySQL&lt;/a> 跟 &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&lt;/a>。走 &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 methodology&lt;/a> Type C operational hybrid 結構。每階段切換用 &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> 把關。&lt;/p>&lt;/blockquote>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>Ops 責任&lt;/th>
 &lt;th>自管 MySQL&lt;/th>
 &lt;th>Aurora MySQL&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>Storage&lt;/td>
 &lt;td>EBS / local SSD、自己選 + 監控&lt;/td>
 &lt;td>Aurora distributed storage（自動 6 份跨 3 AZ）&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Replication setup&lt;/td>
 &lt;td>binlog + semi-sync 自己配&lt;/td>
 &lt;td>Storage layer 自動、無 binlog replication&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Failover&lt;/td>
 &lt;td>Orchestrator + VIP + fence script&lt;/td>
 &lt;td>Aurora 內建、&amp;lt; 30 秒 RTO&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Backup&lt;/td>
 &lt;td>mysqldump / Percona XtraBackup&lt;/td>
 &lt;td>自動 continuous backup、PITR&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Parameter tuning&lt;/td>
 &lt;td>my.cnf 自己改&lt;/td>
 &lt;td>Parameter group（部分 knob 鎖）&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Connection limit&lt;/td>
 &lt;td>max_connections 自己設&lt;/td>
 &lt;td>看 instance class、有上限&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Auto scaling&lt;/td>
 &lt;td>不適用&lt;/td>
 &lt;td>Aurora Serverless v2 + read replica auto-scaling&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Multi-region&lt;/td>
 &lt;td>自己配 chained replication&lt;/td>
 &lt;td>Aurora Global Database&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Per-month cost&lt;/td>
 &lt;td>EC2 + EBS + 自己管 ops&lt;/td>
 &lt;td>Higher per-GB / per-IOPS、但 ops headcount saving&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;p>從 &lt;em>MySQL 角度&lt;/em> 看 Aurora MySQL：wire protocol 一致、SQL 一致、ORM 不必改、application 連 endpoint 字串以外幾乎不必動。從 &lt;em>Ops 角度&lt;/em> 看 Aurora MySQL：所有 storage / replication / failover knob 都 &lt;em>看不到也改不了&lt;/em>、整個 ops 心智模型重寫。&lt;/p>
&lt;p>這是 Type C operational hybrid 的典型 signature — &lt;em>schema / paradigm 接近、operational 完全不同&lt;/em>。&lt;/p></description><content:encoded><![CDATA[<blockquote>
<p>本文是跨 vendor <a href="/blog/backend/knowledge-cards/migration/" data-link-title="Migration" data-link-desc="說明系統如何把資料、流量或結構從舊狀態移到新狀態">migration</a> playbook、cross-link 到 <a href="/blog/backend/01-database/vendors/mysql/" data-link-title="MySQL" data-link-desc="高併發網路服務常用關聯式資料庫、Vitess / PlanetScale 分片生態、GitHub / Shopify / Facebook 規模驗證">MySQL</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>。走 <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 methodology</a> Type C operational hybrid 結構。每階段切換用 <a href="/blog/backend/knowledge-cards/migration-gate/" data-link-title="Migration Gate" data-link-desc="說明遷移流程何時可以進入下一階段或正式切換">migration gate</a> 把關。</p></blockquote>
<table>
  <thead>
      <tr>
          <th>Ops 責任</th>
          <th>自管 MySQL</th>
          <th>Aurora MySQL</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Storage</td>
          <td>EBS / local SSD、自己選 + 監控</td>
          <td>Aurora distributed storage（自動 6 份跨 3 AZ）</td>
      </tr>
      <tr>
          <td>Replication setup</td>
          <td>binlog + semi-sync 自己配</td>
          <td>Storage layer 自動、無 binlog replication</td>
      </tr>
      <tr>
          <td>Failover</td>
          <td>Orchestrator + VIP + fence script</td>
          <td>Aurora 內建、&lt; 30 秒 RTO</td>
      </tr>
      <tr>
          <td>Backup</td>
          <td>mysqldump / Percona XtraBackup</td>
          <td>自動 continuous backup、PITR</td>
      </tr>
      <tr>
          <td>Parameter tuning</td>
          <td>my.cnf 自己改</td>
          <td>Parameter group（部分 knob 鎖）</td>
      </tr>
      <tr>
          <td>Connection limit</td>
          <td>max_connections 自己設</td>
          <td>看 instance class、有上限</td>
      </tr>
      <tr>
          <td>Auto scaling</td>
          <td>不適用</td>
          <td>Aurora Serverless v2 + read replica auto-scaling</td>
      </tr>
      <tr>
          <td>Multi-region</td>
          <td>自己配 chained replication</td>
          <td>Aurora Global Database</td>
      </tr>
      <tr>
          <td>Per-month cost</td>
          <td>EC2 + EBS + 自己管 ops</td>
          <td>Higher per-GB / per-IOPS、但 ops headcount saving</td>
      </tr>
  </tbody>
</table>
<p>從 <em>MySQL 角度</em> 看 Aurora MySQL：wire protocol 一致、SQL 一致、ORM 不必改、application 連 endpoint 字串以外幾乎不必動。從 <em>Ops 角度</em> 看 Aurora MySQL：所有 storage / replication / failover knob 都 <em>看不到也改不了</em>、整個 ops 心智模型重寫。</p>
<p>這是 Type C operational hybrid 的典型 signature — <em>schema / paradigm 接近、operational 完全不同</em>。</p>
<h2 id="為什麼是-type-coperational-為主">為什麼是 Type C（operational 為主）</h2>
<p>跑 <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/#%e5%af%ab%e5%89%8d%e7%9a%84-diff-dimension-audit" data-link-title="Migration Playbook 方法論的演化紀錄：Stage 0 variant 規劃把 collapse 率從 60% 降到 0%" data-link-desc="跨 vendor migration playbook 需要獨立寫作方法論的依據，以及這套方法論從三輪 batch dogfood 中演化出來的驗證證據。">6 維 diff dimension audit</a>：</p>
<table>
  <thead>
      <tr>
          <th>維度</th>
          <th>評</th>
          <th>說明</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Schema</td>
          <td>Low</td>
          <td>MySQL wire protocol + SQL 完全一致</td>
      </tr>
      <tr>
          <td>Operational</td>
          <td>High</td>
          <td>storage / replication / failover / backup ops 全部轉到 AWS</td>
      </tr>
      <tr>
          <td>Paradigm</td>
          <td>Low</td>
          <td>同 OLTP relational paradigm</td>
      </tr>
      <tr>
          <td>Components</td>
          <td>Medium</td>
          <td>Aurora 加 storage layer / cluster endpoint / reader endpoint</td>
      </tr>
      <tr>
          <td>App change</td>
          <td>Low</td>
          <td>主要 connection string + connection pool 設定</td>
      </tr>
      <tr>
          <td>Topology</td>
          <td>Low-Medium</td>
          <td>single-region scaling、跨 region 走 Global Database</td>
      </tr>
  </tbody>
</table>
<p>Operational = High（其他 Low） → <strong>Type C operational hybrid</strong>。Migration 路徑用 <em>4-phase drop-in cutover</em> + <em>operational re-onboarding</em>。</p>
<h2 id="drivertco--multi-az-ha--aws-integration">Driver：TCO + Multi-AZ HA + AWS integration</h2>
<p>從自管 MySQL 遷到 Aurora MySQL 的核心 driver：</p>
<ul>
<li><strong>TCO</strong>：自管 MySQL 真實 cost = EC2 + EBS + ops headcount（1-3 個 FTE 撐大 MySQL deployment）。Aurora per-GB / per-IOPS 比 EC2+EBS 貴 30-50%、但省 ops headcount、總帳通常 break-even 或更便宜</li>
<li><strong>Multi-AZ HA</strong>：Aurora storage 自動 6 份跨 3 AZ、failover &lt; 30 秒、不需要自管 Orchestrator + VIP + fence script</li>
<li><strong>AWS ecosystem integration</strong>：跟 Lambda / SAM / CloudFormation / IAM / Secrets Manager 整合、給 cloud-native architecture 加分</li>
<li><strong>Read scaling</strong>：Aurora 最多 15 個 read replica、storage layer 共享（不 replicate data、僅 replicate page cache）、read latency &lt; 10ms inter-replica</li>
</ul>
<p>不適合 <em>已用 Percona Server fork</em> 或 <em>需要 cross-cloud portability</em> 的 org — Aurora MySQL 是 AWS-only、且 fork 自 MySQL 5.7/8.0、跟 Percona 特性不完全一致。</p>
<h2 id="4-phase-migration">4-phase migration</h2>
<h3 id="phase-1aurora-cluster-起來作為-read-replica">Phase 1：Aurora cluster 起來作為 read replica</h3>
<p>最低風險入口：建 Aurora cluster、用 MySQL binlog 把 production 資料 stream 進 Aurora。Application 仍寫自管 MySQL primary、Aurora 作為 <em>external read replica</em>。</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"># 1. 在 AWS 建 Aurora MySQL cluster</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 prod-aurora <span class="se">\
</span></span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="se"></span>  --engine aurora-mysql <span class="se">\
</span></span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="se"></span>  --engine-version 8.0.mysql_aurora.3.04.0 <span class="se">\
</span></span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="se"></span>  --master-username admin <span class="se">\
</span></span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="se"></span>  --master-user-password ... <span class="se">\
</span></span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="se"></span>  --database-name production <span class="se">\
</span></span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="se"></span>  --vpc-security-group-ids sg-xxx <span class="se">\
</span></span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="se"></span>  --db-subnet-group-name prod-subnet
</span></span><span class="line"><span class="ln">11</span><span class="cl">
</span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="c1"># 2. 用 mysqldump 或 Percona XtraBackup 拿 baseline</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl">mysqldump --single-transaction --master-data<span class="o">=</span><span class="m">2</span> --triggers --routines --events <span class="se">\
</span></span></span><span class="line"><span class="ln">14</span><span class="cl"><span class="se"></span>  --all-databases &gt; baseline.sql
</span></span><span class="line"><span class="ln">15</span><span class="cl">
</span></span><span class="line"><span class="ln">16</span><span class="cl"><span class="c1"># 3. Restore 到 Aurora</span>
</span></span><span class="line"><span class="ln">17</span><span class="cl">mysql -h prod-aurora.cluster-xxx.us-east-1.rds.amazonaws.com -u admin -p &lt; baseline.sql
</span></span><span class="line"><span class="ln">18</span><span class="cl">
</span></span><span class="line"><span class="ln">19</span><span class="cl"><span class="c1"># 4. 設定 Aurora 從自管 MySQL 接 binlog</span>
</span></span><span class="line"><span class="ln">20</span><span class="cl">CALL mysql.rds_set_external_master<span class="o">(</span>
</span></span><span class="line"><span class="ln">21</span><span class="cl">  <span class="s1">&#39;self-managed-primary.example.com&#39;</span>, 3306,
</span></span><span class="line"><span class="ln">22</span><span class="cl">  <span class="s1">&#39;replication_user&#39;</span>, <span class="s1">&#39;password&#39;</span>,
</span></span><span class="line"><span class="ln">23</span><span class="cl">  <span class="s1">&#39;mysql-bin.000123&#39;</span>, 12345, <span class="m">0</span>
</span></span><span class="line"><span class="ln">24</span><span class="cl"><span class="o">)</span><span class="p">;</span>
</span></span><span class="line"><span class="ln">25</span><span class="cl">CALL mysql.rds_start_replication<span class="p">;</span></span></span></code></pre></div><p>完成標準：Aurora replica lag &lt; 1 秒、跟 production primary 同步。</p>
<h3 id="phase-2application-read-切到-aurora-reader-endpoint">Phase 2：Application read 切到 Aurora reader endpoint</h3>
<p>Application 仍寫自管 primary、但讀 query 切到 Aurora reader endpoint：</p>
<ul>
<li>Aurora reader endpoint：<code>prod-aurora.cluster-ro-xxx.us-east-1.rds.amazonaws.com</code></li>
<li>自動 round-robin 多個 read replica</li>
<li>ProxySQL 或 application config 改 read connection string</li>
</ul>
<p>跑 1-2 週、確認：</p>
<ul>
<li>Aurora read latency 跟自管 replica latency 接近（通常 Aurora 略好）</li>
<li>Aurora replication lag 穩定 &lt; 1 秒</li>
<li>Aurora query 結果跟自管 primary 一致（spot-check critical query）</li>
</ul>
<p>完成標準：所有 read traffic 都進 Aurora、no application bug。</p>
<h3 id="phase-3cutover--promote-aurora-primary">Phase 3：Cutover — promote Aurora primary</h3>
<p>Cutover window 內：</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"># 1. 停 application 寫入（feature flag / scheduled maintenance）</span>
</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"><span class="c1"># 2. 等自管 primary 跟 Aurora 同步完成（檢查 Aurora replica lag = 0）</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">
</span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="c1"># 3. 把 Aurora 從 external replica 提升為獨立 primary</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">CALL mysql.rds_stop_replication<span class="p">;</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">CALL mysql.rds_reset_external_master<span class="p">;</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">
</span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="c1"># 4. Application 寫 connection string 切到 Aurora writer endpoint</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="c1"># prod-aurora.cluster-xxx.us-east-1.rds.amazonaws.com</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">
</span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="c1"># 5. 開始 application traffic</span></span></span></code></pre></div><p>完成標準：寫入流量 100% 進 Aurora、自管 primary 變 idle。Cutover 通常需要 30-60 分鐘 maintenance window。</p>
<h3 id="phase-4decommission-自管-mysql">Phase 4：Decommission 自管 MySQL</h3>
<p>跑 1-2 週確認 Aurora 穩定後 <em>慢慢退役自管</em>：</p>
<ul>
<li>自管 primary 保留作 <em>cold backup</em>（1-3 個月）、不接 traffic、可隨時 rollback</li>
<li>Replica 一個一個關掉</li>
<li>監控 Aurora cost vs 預估、確認 break-even</li>
</ul>
<p>完成標準：自管 EC2 instance terminate、EBS volume snapshot 後 delete、cost 對比驗證符合預期。</p>
<h2 id="5-個-production-踩雷">5 個 Production 踩雷</h2>
<h3 id="1-parameter-group-沒對齊--innodb_flush_log_at_trx_commit-等行為差">1. Parameter group 沒對齊 — <code>innodb_flush_log_at_trx_commit</code> 等行為差</h3>
<p>Aurora 的 <em>parameter group</em> 取代 my.cnf。預設 parameter group 不一定跟自管 MySQL 一致：</p>
<ul>
<li><code>innodb_flush_log_at_trx_commit</code>：自管常設 1（zero loss）、Aurora 預設仍 1 但走 <em>Aurora storage durability</em>（行為等價但不同 mechanism）</li>
<li><code>sync_binlog</code>：自管 1、Aurora <em>沒有 binlog 寫 disk</em> 概念（Aurora 不用 binlog 做 replication、binlog 是 <em>optional output</em>）</li>
<li><code>time_zone</code>：Aurora 預設 UTC、自管常設 local time、TIMESTAMP query 行為可能不同</li>
<li><code>character_set_*</code>：自管常設 utf8mb4、Aurora 預設可能是 latin1（看 cluster create 命令）</li>
</ul>
<p>修法：</p>
<ul>
<li>
<p>Phase 1 完成後 <em>逐 row 對比 parameter group</em>：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="ln">1</span><span class="cl"><span class="k">SELECT</span><span class="w"> </span><span class="o">@@</span><span class="k">global</span><span class="p">.</span><span class="n">variable_name</span><span class="w"> </span><span class="k">FROM</span><span class="w"> </span><span class="p">...</span></span></span></code></pre></div></li>
<li>
<p>建 <em>custom DB cluster parameter group</em>、匹配自管設定</p>
</li>
<li>
<p>重啟 Aurora primary 套 parameter group 改變（部分 parameter 需要重啟）</p>
</li>
</ul>
<h3 id="2-iam-authentication--application-沒準備">2. IAM authentication — application 沒準備</h3>
<p>Aurora 提供 <em>IAM authentication</em>（不用 password、用 AWS IAM role + temporary token）。Application 用 IAM auth 不必管 password rotation、但程式碼必須 <em>call AWS SDK 取 token、放 connection 設定</em>。</p>
<p>如果 Phase 2-3 期間沒 reverse engineer application connection logic、cutover 後 application 仍試用 password auth、Aurora 拒絕、production down。</p>
<p>修法：</p>
<ul>
<li>評估是否啟用 IAM auth — <em>簡單情況保留 password</em>、整合 AWS Secrets Manager 自動 rotation</li>
<li>啟用 IAM 必須 application code 改：
<ul>
<li>Java：<code>com.amazonaws.services.rds.auth.RdsIamAuthTokenGenerator</code></li>
<li>Python：<code>boto3.client('rds').generate_db_auth_token(...)</code></li>
<li>Go：<code>aws-sdk-go-v2/feature/rds/auth</code></li>
</ul>
</li>
<li>Phase 2 期間 application 對 Aurora 用 IAM token、self-managed 仍 password — 雙 path code</li>
</ul>
<h3 id="3-aurora-only-feature-寫進-applicationrollback-成本升高">3. Aurora-only feature 寫進 application、rollback 成本升高</h3>
<p>Migration 過程開發發現 Aurora 有 <em>Aurora-only feature</em>（Backtrack、Performance Insights、Aurora Global Database）、誘惑使用。一旦 application 用了 Aurora-only feature、要 rollback 自管 MySQL 變不可能（feature 不存在、query 失敗）。</p>
<p>常見 Aurora-only feature：</p>
<ul>
<li><em>Backtrack</em>：72 小時內 in-place rollback 整個 DB（不同於 PITR）</li>
<li><em>Aurora ML</em>：SQL function 內接 SageMaker / Comprehend</li>
<li><em>Aurora Parallel Query</em>：analytical query 跨 storage node 並行</li>
<li><em>Aurora Auto Scaling</em>：read replica 數量按 CPU 自動加減</li>
</ul>
<p>修法：</p>
<ul>
<li><em>Phase 1-3 期間禁用 Aurora-only feature</em>、保留 rollback option</li>
<li><em>Phase 4 完成後</em> 才開始 evaluate Aurora-only feature、加進來時 <em>明確記錄不可 rollback decision</em></li>
<li>把 Aurora-only feature 跟 <em>Aurora 特定 cluster</em> 綁定，避免 application 邏輯依賴 Aurora-only</li>
</ul>
<h3 id="4-read-replica-endpoint-behavior--application-不知道-reader-endpoint-round-robin">4. Read replica endpoint behavior — Application 不知道 reader endpoint round-robin</h3>
<p>Aurora reader endpoint（<code>prod-aurora.cluster-ro-xxx</code>）是 <em>DNS-based load balancer</em>、每次 DNS query 給不同 replica IP。Application connection pool 連續開 10 個 connection、可能全部連同一個 replica（DNS cache）、不均勻。</p>
<p>修法：</p>
<ul>
<li>Application connection pool 強制 <em>DNS re-resolve</em>（避免長時間 cache）</li>
<li>或用 <em>RDS Proxy</em>（managed connection pool）放在前面、不直接連 reader endpoint</li>
<li>或用 <em>Route 53 latency-based routing</em> 配 Aurora reader endpoint per AZ、application 連最近 AZ</li>
</ul>
<h3 id="5-region-failover--aurora-global-database-vs-自管-chained-replication">5. Region failover — Aurora Global Database vs 自管 chained replication</h3>
<p>自管 cross-region replication 是 <em>chained replication</em>（primary → region2 replica → region2 cascading replica）。Aurora Global Database 是 <em>storage-level replication</em>（storage page 直接 ship，而非 binlog）、跨 region &lt; 1 秒 lag、failover &lt; 1 分鐘。</p>
<p>但 Aurora Global Database 是 <em>active-passive</em>（primary region 可寫、secondary region 只讀）。如果原本自管已經 cross-region active-active write（用 multi-master 或應用層 sharding）、Aurora Global Database 的寫入模型會成為限制。</p>
<p>修法：</p>
<ul>
<li>評估 cross-region 是 <em>DR</em> 用途還是 <em>active write</em> 用途</li>
<li>純 DR + read scaling：Aurora Global Database 直接 cover</li>
<li>Active-active write：要 <em>Aurora DSQL</em>（2024 新推出、跟 Aurora 不同 product）或 distributed SQL（CockroachDB / Spanner）</li>
</ul>
<h2 id="capability-gap自管-mysql-有但-aurora-沒有">Capability gap：自管 MySQL 有但 Aurora 沒有</h2>
<table>
  <thead>
      <tr>
          <th>能力</th>
          <th>自管 MySQL</th>
          <th>Aurora MySQL</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Plugin 自己裝</td>
          <td>任意</td>
          <td>受限（Aurora 只允許官方支援）</td>
      </tr>
      <tr>
          <td>OS-level access</td>
          <td>完整 SSH access</td>
          <td>managed service，無 SSH access</td>
      </tr>
      <tr>
          <td>MySQL 8.0 latest patch</td>
          <td>你決定</td>
          <td>跟 Aurora major version 對應、有滯後</td>
      </tr>
      <tr>
          <td>InnoDB log_file_size</td>
          <td>自己改</td>
          <td>Aurora 內建 storage path</td>
      </tr>
      <tr>
          <td>Custom storage engine</td>
          <td>可（MyRocks / TokuDB）</td>
          <td>只 InnoDB（Aurora optimized）</td>
      </tr>
      <tr>
          <td>Cross-cloud DR</td>
          <td>自配 binlog ship</td>
          <td>Aurora-only (AWS region)</td>
      </tr>
  </tbody>
</table>
<p>評估時必須確認 <em>當前自管功能</em> 沒用到 Aurora 不支援的能力。如果在用 MyRocks 等 storage engine、Aurora migration 不可行。</p>
<h2 id="容量與成本對照">容量與成本對照</h2>
<p>對 100 GB DB、5K WPS、20 個 application instance 的 deployment：</p>
<table>
  <thead>
      <tr>
          <th>項目</th>
          <th>自管 MySQL（EC2）</th>
          <th>Aurora MySQL</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Primary instance</td>
          <td>r5.2xlarge（$0.50/hr）</td>
          <td>db.r6g.2xlarge（$0.83/hr）</td>
      </tr>
      <tr>
          <td>EBS / Aurora storage</td>
          <td>io2 100 GB + 5000 IOPS = ~$70/mo</td>
          <td>Aurora storage 100 GB = ~$10/mo + I/O $0.20/M</td>
      </tr>
      <tr>
          <td>Replica × 3</td>
          <td>3 × r5.2xlarge = $1080/mo</td>
          <td>3 × db.r6g.large = $540/mo</td>
      </tr>
      <tr>
          <td>Backup storage</td>
          <td>S3 + 自己 cron mysqldump ~$50/mo</td>
          <td>Aurora backup 100 GB 免費 + 額外 $0.021/GB</td>
      </tr>
      <tr>
          <td>Ops headcount</td>
          <td>1-2 FTE × $150K = $300-500K/yr</td>
          <td>&lt; 0.5 FTE × $150K = $75K/yr</td>
      </tr>
      <tr>
          <td><strong>Total infra</strong></td>
          <td>~$1500/mo + 大 ops cost</td>
          <td>~$2000-3000/mo + 小 ops cost</td>
      </tr>
  </tbody>
</table>
<p>Pure infra cost Aurora 貴 30-50%、但 <em>ops cost 降幅大過 infra increase</em> — 200 人 eng team 養 1.5 FTE DBA 是 $300K-400K/yr、Aurora 換成 0.3 FTE 是 $60K-100K/yr、差距 $200K+ 抵 infra increase。</p>
<p>小團隊 / 小 deployment Aurora 不一定划算 — 50 人 eng team 沒有 dedicated DBA、自管 MySQL 也只佔某人 20% 時間、Aurora migration 的 ops saving 不存在。</p>
<h2 id="production-casenetflix-aurora-consolidation">Production case：Netflix Aurora consolidation</h2>
<p>MySQL → Aurora migration 的 production 責任是把自管 database operation 轉移成 managed SQL 的契約，而非只搬 schema 與資料。<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 後，效能、成本與操作責任一起改變。</p>
<p>這個案例要回收到三個操作判準。第一，migration driver 應寫成 operation transfer，例如 backup、failover、storage growth、patching 與 observability 由誰承擔。第二，效能與成本要一起看，因為 Aurora 的 storage / compute / I/O 計費會把原本藏在 DBA 操作裡的成本攤開。第三，整併多套 RDBMS 時要先做 feature inventory，確認 plugin、storage engine、charset、replication topology 與 SQL mode 都能落到 Aurora MySQL 支援範圍。</p>
<p>Netflix case 的 sibling 路由是 <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 page</a> 與 <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 對位">PostgreSQL → Aurora</a>。若 migration 目標從 managed SQL 變成 multi-region active-active write，應改接 <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>。</p>
<h2 id="何時維持原路線">何時維持原路線</h2>
<ul>
<li><strong>Cross-cloud portability 是 requirement</strong>：Aurora AWS-only、要 cross-cloud 用 PlanetScale 或 自管</li>
<li><strong>用 Percona Server fork / MyRocks 等非標準 engine</strong>：Aurora 不支援</li>
<li><strong>需要 OS-level customization</strong>：Aurora 完全 managed、無 SSH</li>
<li><strong>規模太小</strong>：&lt; 100 GB / &lt; 1K WPS、自管 MySQL EC2 spot instance 已經夠便宜</li>
<li><strong>規模太大</strong>：&gt; 50 TB single DB / &gt; 100K WPS、Aurora single-instance 仍是 ceiling、考慮 Vitess 或 Aurora DSQL</li>
</ul>
<h2 id="相關連結">相關連結</h2>
<ul>
<li>平行 batch：→ PlanetScale migration playbook（同 MySQL backlog、不同 target paradigm）</li>
<li>上游：<a href="/blog/backend/01-database/vendors/mysql/" data-link-title="MySQL" data-link-desc="高併發網路服務常用關聯式資料庫、Vitess / PlanetScale 分片生態、GitHub / Shopify / Facebook 規模驗證">MySQL vendor overview</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 vendor page</a></li>
<li>跨章節：<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> — Aurora cost forecast</li>
<li>既有 case：<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> — Netflix 從多套 RDBMS 統一到 Aurora 的 migration evidence</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 Methodology</a>（Type C operational hybrid 結構說明）</li>
<li>官方：<a href="https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/AuroraMySQL.Migrating.html">Aurora MySQL Migration Guide</a></li>
</ul>
]]></content:encoded></item><item><title>自管 Vitess → PlanetScale：Vitess component ops outsource、加 schema workflow shift</title><link>https://tarrragon.github.io/blog/backend/01-database/vendors/mysql/migrate-vitess-to-planetscale/</link><pubDate>Tue, 19 May 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/backend/01-database/vendors/mysql/migrate-vitess-to-planetscale/</guid><description>&lt;blockquote>
&lt;p>本文是跨 vendor migration playbook、cross-link 到 &lt;a href="https://tarrragon.github.io/blog/backend/01-database/vendors/mysql/vitess-sharding/" data-link-title="MySQL Vitess Sharding：VTGate / VTTablet / VReplication / VSchema 四件套協作" data-link-desc="Vitess 不只是 MySQL sharding proxy、是 4 個 component 協作的完整 sharding 系統 — VTGate（query routing layer）、VTTablet（per-MySQL agent）、VReplication（跨 shard 資料移動）、VSchema（sharding metadata）。本文走 4 件套各自責任、keyspace / shard / tablet 架構、shard key 設計（Vindex）、配置 step-by-step、5 production 踩雷（cross-shard transaction / VStream lag / Vindex 不均勻 / resharding 切流 / VReplication 卡住）、跟自管 sharding 跟 PlanetScale 的對比">Vitess sharding&lt;/a> 跟 PlanetScale。走 &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 methodology&lt;/a> Type C operational hybrid 結構。&lt;/p>&lt;/blockquote>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>元件&lt;/th>
 &lt;th>自管 Vitess&lt;/th>
 &lt;th>PlanetScale&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>VTGate&lt;/td>
 &lt;td>自己部署 + LB&lt;/td>
 &lt;td>Managed、隱藏在 PlanetScale endpoint 後&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>VTTablet&lt;/td>
 &lt;td>自己 per-MySQL deploy&lt;/td>
 &lt;td>Managed&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>VReplication&lt;/td>
 &lt;td>自己 trigger workflow&lt;/td>
 &lt;td>Managed、透過 Console / API&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>VSchema&lt;/td>
 &lt;td>自己維護（YAML / API）&lt;/td>
 &lt;td>Managed、Console UI 編輯&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>MySQL backend&lt;/td>
 &lt;td>自己 EC2 / on-prem&lt;/td>
 &lt;td>Managed (Aurora-like underlying)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Schema migration&lt;/td>
 &lt;td>gh-ost / pt-osc 或 Vitess online DDL&lt;/td>
 &lt;td>&lt;strong>Branch + Deploy Request workflow&lt;/strong>&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Failover&lt;/td>
 &lt;td>自己用 VTOrc&lt;/td>
 &lt;td>Managed&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Multi-region&lt;/td>
 &lt;td>自己配 VReplication 跨 region&lt;/td>
 &lt;td>Boost / per-region cluster&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Cost model&lt;/td>
 &lt;td>EC2 + EBS + ops headcount&lt;/td>
 &lt;td>Per-row read / write + storage&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;p>這條 migration 跟 &lt;a href="https://tarrragon.github.io/blog/backend/01-database/vendors/mysql/migrate-to-aurora/" data-link-title="MySQL → Aurora MySQL：storage layer 轉手到 AWS、replication / HA / backup 全部 outsource" data-link-desc="自管 MySQL → Aurora MySQL 是 Type C operational hybrid migration — wire protocol 一致、ops 責任轉到 AWS。本文走 6 維 audit（Operational High）、Aurora storage architecture 衝擊、4-phase migration、5 production 踩雷、何時維持原路線。">→ Aurora MySQL&lt;/a> 相似（self-managed → managed），但 &lt;em>target 是 Vitess-native managed&lt;/em>、保留 sharding 能力。同時加上 &lt;a href="https://tarrragon.github.io/blog/backend/01-database/vendors/mysql/migrate-to-planetscale/" data-link-title="MySQL → PlanetScale：managed Vitess &amp;#43; branch-based schema workflow 的 hybrid shift" data-link-desc="自管 MySQL → PlanetScale 加上 Vitess sharding 跟 branch-based schema workflow。本文走 6 維 audit（Paradigm &amp;#43; Operational &amp;#43; Schema 多軸）、4-phase migration、5 production 踩雷、何時不要遷。">→ PlanetScale from self-managed MySQL&lt;/a> 的 branch workflow paradigm。&lt;/p></description><content:encoded><![CDATA[<blockquote>
<p>本文是跨 vendor migration playbook、cross-link 到 <a href="/blog/backend/01-database/vendors/mysql/vitess-sharding/" data-link-title="MySQL Vitess Sharding：VTGate / VTTablet / VReplication / VSchema 四件套協作" data-link-desc="Vitess 不只是 MySQL sharding proxy、是 4 個 component 協作的完整 sharding 系統 — VTGate（query routing layer）、VTTablet（per-MySQL agent）、VReplication（跨 shard 資料移動）、VSchema（sharding metadata）。本文走 4 件套各自責任、keyspace / shard / tablet 架構、shard key 設計（Vindex）、配置 step-by-step、5 production 踩雷（cross-shard transaction / VStream lag / Vindex 不均勻 / resharding 切流 / VReplication 卡住）、跟自管 sharding 跟 PlanetScale 的對比">Vitess sharding</a> 跟 PlanetScale。走 <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 methodology</a> Type C operational hybrid 結構。</p></blockquote>
<table>
  <thead>
      <tr>
          <th>元件</th>
          <th>自管 Vitess</th>
          <th>PlanetScale</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>VTGate</td>
          <td>自己部署 + LB</td>
          <td>Managed、隱藏在 PlanetScale endpoint 後</td>
      </tr>
      <tr>
          <td>VTTablet</td>
          <td>自己 per-MySQL deploy</td>
          <td>Managed</td>
      </tr>
      <tr>
          <td>VReplication</td>
          <td>自己 trigger workflow</td>
          <td>Managed、透過 Console / API</td>
      </tr>
      <tr>
          <td>VSchema</td>
          <td>自己維護（YAML / API）</td>
          <td>Managed、Console UI 編輯</td>
      </tr>
      <tr>
          <td>MySQL backend</td>
          <td>自己 EC2 / on-prem</td>
          <td>Managed (Aurora-like underlying)</td>
      </tr>
      <tr>
          <td>Schema migration</td>
          <td>gh-ost / pt-osc 或 Vitess online DDL</td>
          <td><strong>Branch + Deploy Request workflow</strong></td>
      </tr>
      <tr>
          <td>Failover</td>
          <td>自己用 VTOrc</td>
          <td>Managed</td>
      </tr>
      <tr>
          <td>Multi-region</td>
          <td>自己配 VReplication 跨 region</td>
          <td>Boost / per-region cluster</td>
      </tr>
      <tr>
          <td>Cost model</td>
          <td>EC2 + EBS + ops headcount</td>
          <td>Per-row read / write + storage</td>
      </tr>
  </tbody>
</table>
<p>這條 migration 跟 <a href="/blog/backend/01-database/vendors/mysql/migrate-to-aurora/" data-link-title="MySQL → Aurora MySQL：storage layer 轉手到 AWS、replication / HA / backup 全部 outsource" data-link-desc="自管 MySQL → Aurora MySQL 是 Type C operational hybrid migration — wire protocol 一致、ops 責任轉到 AWS。本文走 6 維 audit（Operational High）、Aurora storage architecture 衝擊、4-phase migration、5 production 踩雷、何時維持原路線。">→ Aurora MySQL</a> 相似（self-managed → managed），但 <em>target 是 Vitess-native managed</em>、保留 sharding 能力。同時加上 <a href="/blog/backend/01-database/vendors/mysql/migrate-to-planetscale/" data-link-title="MySQL → PlanetScale：managed Vitess &#43; branch-based schema workflow 的 hybrid shift" data-link-desc="自管 MySQL → PlanetScale 加上 Vitess sharding 跟 branch-based schema workflow。本文走 6 維 audit（Paradigm &#43; Operational &#43; Schema 多軸）、4-phase migration、5 production 踩雷、何時不要遷。">→ PlanetScale from self-managed MySQL</a> 的 branch workflow paradigm。</p>
<p>對 <em>已花心力建 Vitess team 但 ops cost 太大</em> 的 org 來說、這條 migration 比 <em>Vitess → distributed SQL</em> 風險低、保留 sharding investment。</p>
<h2 id="為什麼是-type-c不是-type-a-或-type-e">為什麼是 Type C（不是 Type A 或 Type E）</h2>
<p>跑 <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/#%e5%af%ab%e5%89%8d%e7%9a%84-diff-dimension-audit" data-link-title="Migration Playbook 方法論的演化紀錄：Stage 0 variant 規劃把 collapse 率從 60% 降到 0%" data-link-desc="跨 vendor migration playbook 需要獨立寫作方法論的依據，以及這套方法論從三輪 batch dogfood 中演化出來的驗證證據。">6 維 diff dimension audit</a>：</p>
<table>
  <thead>
      <tr>
          <th>維度</th>
          <th>評</th>
          <th>說明</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Schema</td>
          <td>Low</td>
          <td>Vitess wire protocol + VSchema 概念一致</td>
      </tr>
      <tr>
          <td>Operational</td>
          <td>High</td>
          <td>4 個 component 的 ops 全部 outsource、branch workflow 是新 paradigm</td>
      </tr>
      <tr>
          <td>Paradigm</td>
          <td>Medium</td>
          <td>Vitess paradigm 不變、但加 branch workflow</td>
      </tr>
      <tr>
          <td>Components</td>
          <td>Low</td>
          <td>同 Vitess engine</td>
      </tr>
      <tr>
          <td>App change</td>
          <td>Low</td>
          <td>Connection string 改、無 schema rewrite</td>
      </tr>
      <tr>
          <td>Topology</td>
          <td>Low</td>
          <td>Vitess sharding 結構保留</td>
      </tr>
  </tbody>
</table>
<p>Operational = High（其他 Low / Medium） → <strong>Type C operational hybrid</strong>。Branch workflow 是 <em>Medium paradigm shift</em> 但不是 dominant — 主要工作量在 <em>operational ownership 轉移</em>。</p>
<p>跟 <a href="/blog/backend/01-database/vendors/mysql/migrate-to-planetscale/" data-link-title="MySQL → PlanetScale：managed Vitess &#43; branch-based schema workflow 的 hybrid shift" data-link-desc="自管 MySQL → PlanetScale 加上 Vitess sharding 跟 branch-based schema workflow。本文走 6 維 audit（Paradigm &#43; Operational &#43; Schema 多軸）、4-phase migration、5 production 踩雷、何時不要遷。">自管 MySQL → PlanetScale</a>（Type E paradigm shift）對比：那條 path 是 <em>no-Vitess → Vitess + branch</em>、要學 Vitess 概念 + branch；本條是 <em>已有 Vitess + 加 branch</em>、只學 branch、複雜度低很多。</p>
<h2 id="driverops-headcount--branch-workflow--vitess-feature-加速">Driver：Ops headcount + Branch workflow + Vitess feature 加速</h2>
<p>從自管 Vitess 遷 PlanetScale 的核心 driver：</p>
<p><strong>Ops headcount 削減</strong>：</p>
<ul>
<li>自管 Vitess 通常需要 <em>2-5 個 SRE/DBA 撐 production</em> —VTGate / VTTablet / VReplication / VSchema 各有議題</li>
<li>PlanetScale 把這層全部 outsource、團隊 ops headcount 可降到 &lt; 1 FTE</li>
<li>對 50-200 人 eng team、ops cost saving 是顯著 driver</li>
</ul>
<p><strong>Branch workflow paradigm</strong>：</p>
<ul>
<li>自管 Vitess 仍用 gh-ost / pt-osc 或 Vitess online DDL 跑 schema migration、是 DBA 主導</li>
<li>PlanetScale branch workflow 把 schema migration 變 <em>developer self-service</em>、開 branch / Deploy Request / merge、跟 git workflow 同節奏</li>
<li>對 <em>high-velocity engineering culture</em> 是文化升級</li>
</ul>
<p><strong>Vitess upstream feature</strong>：</p>
<ul>
<li>PlanetScale team 是 Vitess 的主要 contributor、新 feature 通常 PlanetScale 先 ship</li>
<li>自管 Vitess 升級慢、PlanetScale 用戶看到新 feature 早 3-6 個月</li>
</ul>
<p>不適合 <em>跨雲 portability priority high</em> 或 <em>strict on-prem deployment</em> 的 org — PlanetScale 是 cloud-only。</p>
<h2 id="4-phase-migration">4-phase migration</h2>
<h3 id="phase-1topology--vschema-audit">Phase 1：Topology + VSchema audit</h3>
<p>把當前自管 Vitess cluster 完整盤點：</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"># Vitess cluster topology</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">vtctldclient GetKeyspaces
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">vtctldclient GetShards &lt;keyspace&gt;
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">vtctldclient GetTablets
</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"># VSchema</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">vtctldclient GetVSchema &lt;keyspace&gt;
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">
</span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="c1"># 跨 keyspace VReplication workflow</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">vtctldclient GetWorkflows</span></span></code></pre></div><p>對每個 keyspace 檢查：</p>
<ul>
<li><em>Shard 數量</em>：PlanetScale plan 對 shard 數量有 limit（Enterprise 才能超大規模）</li>
<li><em>VSchema features</em>：自管可能用 <em>PlanetScale 不支援的 Vindex</em>（custom Vindex）</li>
<li><em>Foreign key</em>：Vitess 18+（2023 末）才支援 FK、自管 Vitess 大多 &lt; 18、cluster 內已 application-enforced；遷 PlanetScale 後可選擇啟用 native FK（同 shard 內）或繼續 application enforcement</li>
<li><em>Stored procedure / trigger</em>：PlanetScale 受限、確認是否 application 依賴</li>
</ul>
<p>完成標準：寫 <em>blocker list</em>（PlanetScale 不支援的功能）+ <em>compatibility list</em>（功能對應）。</p>
<h3 id="phase-2dual-cluster--binlog-stream">Phase 2：Dual cluster + binlog stream</h3>
<p>PlanetScale 內建 <em>Vitess Connector</em>、從外部 MySQL（包括其他 Vitess cluster）binlog stream import：</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"># 1. 用 PlanetScale CLI 建 cluster</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">pscale database create production --region us-east
</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"># 2. Import schema（從自管 Vitess export）</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl">pscale shell production main &lt; schema.sql
</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"># 3. 設 Vitess Connector 從自管 cluster import 資料</span>
</span></span><span class="line"><span class="ln">8</span><span class="cl"><span class="c1"># （透過 PlanetScale Console）</span></span></span></code></pre></div><p>Vitess Connector 從自管 VTTablet 的 MySQL primary 讀 binlog、寫進 PlanetScale。Lag 通常 &lt; 1 秒。</p>
<p>跑 1-2 週、確認：</p>
<ul>
<li>Schema 完整 migrate</li>
<li>VSchema 對應正確（Vindex 行為一致）</li>
<li>Lag 穩定</li>
</ul>
<h3 id="phase-3application-read-切-planetscale">Phase 3：Application read 切 PlanetScale</h3>
<p>跟 Aurora migration Phase 2 同概念。Application read query 切 PlanetScale endpoint：</p>
<ul>
<li>連 PlanetScale connection string（<code>xxx.connect.psdb.cloud</code>）</li>
<li>仍寫自管 Vitess、Vitess Connector 同步 PlanetScale</li>
</ul>
<p>跑 2-4 週、驗證：</p>
<ul>
<li>Query result 一致</li>
<li>PlanetScale read latency 接近自管（PlanetScale Boost cache 可能加速）</li>
<li>PlanetScale row read 計費跟預估一致</li>
</ul>
<h3 id="phase-4write-cutover--自管-vitess-退役">Phase 4：Write cutover + 自管 Vitess 退役</h3>





<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"># 1. PlanetScale 把 cluster promote 為 primary（透過 Console）</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="c1"># 透過 PlanetScale Console 啟用 production write 或用 `pscale` CLI 對應 promotion 命令</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="c1"># （CLI 命令名稱隨 pscale 版本變動、以 pscale --help 為準）</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">
</span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="c1"># 2. Application 寫 connection string 切 PlanetScale</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="c1"># 自管 Vitess → PlanetScale</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"><span class="c1"># 3. Vitess Connector 反向（PlanetScale → 自管）作為 rollback buffer</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">
</span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="c1"># 4. 跑 1-2 週確認、開始 decommission 自管 Vitess</span></span></span></code></pre></div><p>Decommission 自管 Vitess 是大工程：</p>
<ul>
<li>VTGate / VTTablet pods 一個個關</li>
<li>VReplication workflow 停掉</li>
<li>MySQL backend 保留作 cold backup 1-3 月、然後 EBS snapshot + terminate</li>
</ul>
<p>完成標準：所有 traffic 在 PlanetScale、自管 Vitess 資源全 release、ops headcount confirm 下降。</p>
<h2 id="5-個-production-踩雷">5 個 Production 踩雷</h2>
<h3 id="1-vschema-不完全兼容--custom-vindex-必須改">1. VSchema 不完全兼容 — Custom Vindex 必須改</h3>
<p>自管 Vitess 可能用了 <em>custom Vindex</em>（自寫 Go plugin）、PlanetScale 不支援 custom Vindex（只支援 built-in：hash / lookup_hash / unicode 等）。</p>
<p>修法：</p>
<ul>
<li>Phase 1 audit 出所有 custom Vindex</li>
<li>對每個 custom Vindex 評估能否用 built-in 替代</li>
<li>不能替代的、考慮 <em>application 層 logic 取代 Vindex</em>（application 自己算 shard key）</li>
<li>或 <em>暫不遷該 keyspace</em>、保留自管 Vitess 跑 custom Vindex keyspace、其他遷 PlanetScale</li>
</ul>
<h3 id="2-branch-workflow-訓練不到位--dba-仍用vitess-online-ddl心智模型">2. Branch workflow 訓練不到位 — DBA 仍用「Vitess online DDL」心智模型</h3>
<p>自管 Vitess team 習慣 <code>vtctldclient ApplySchema --strategy=vitess</code> 跑 online DDL、遷 PlanetScale 後仍想直接這樣 — 但 PlanetScale production branch 禁止 schema change、必須走 Deploy Request。</p>
<p>修法：</p>
<ul>
<li>Phase 3 <em>訓練步驟</em>：team 每個 DBA / SRE 都跑過完整 branch + Deploy Request workflow</li>
<li>寫 <em>team runbook</em>：production schema change must 走 branch</li>
<li>緊急 schema change（事故中）也走 branch、PlanetScale 可加速 Deploy</li>
</ul>
<h3 id="3-super-privilege-移除--自管-admin-tool-失效">3. SUPER privilege 移除 — 自管 admin tool 失效</h3>
<p>自管 Vitess 用 <code>SUPER</code> privilege 跑 admin script、PlanetScale 沒給 SUPER。常見失效：</p>
<ul>
<li>自寫 monitor script 跑 <code>SHOW SLAVE STATUS</code>、PlanetScale 抽象掉</li>
<li>自寫 backup script 跑 <code>FLUSH TABLES WITH READ LOCK</code>、PlanetScale 不允許</li>
<li>自寫 cleanup script 跑 <code>KILL QUERY</code>、PlanetScale 受限</li>
</ul>
<p>修法：</p>
<ul>
<li>Phase 1 audit 所有 admin script</li>
<li>改用 <em>PlanetScale Console / CLI / API</em> 等價操作</li>
<li>PlanetScale 提供的 monitoring 介面替代自管監控</li>
</ul>
<h3 id="4-connection-limit--planetscale-plan-比預期緊">4. Connection limit — PlanetScale plan 比預期緊</h3>
<p>PlanetScale Scaler Plan: 10K connection、Enterprise: 100K。自管 Vitess VTGate 通常設 50K-200K connection、遷 PlanetScale 後 hit limit。</p>
<p>修法：</p>
<ul>
<li>Phase 1 <em>connection forecast</em>：peak hour 多少 active connection</li>
<li>升 PlanetScale plan（Scaler Pro / Enterprise）</li>
<li>或在 application 端加 connection pool（HikariCP / pgBouncer 等價）降低 connection count</li>
</ul>
<h3 id="5-cost-model-翻盤--per-row-read-計費超預期">5. Cost model 翻盤 — Per-row read 計費超預期</h3>
<p>PlanetScale 計費是 <em>per row read / written</em>。自管 Vitess cost = EC2 + EBS（線性 with infrastructure scale）。遷 PlanetScale 後計費跟 <em>application access pattern</em> 直接相關。</p>
<p>常見 surprise：</p>
<ul>
<li>Heavy analytics query（COUNT *、aggregation）讀大量 row、計費高</li>
<li>N+1 query pattern（application 跑很多小 SELECT）讀很多 row、計費高</li>
<li>Read-heavy workload 沒 Boost cache、每次 query 都 hit billing</li>
</ul>
<p>修法：</p>
<ul>
<li>Phase 1 <em>cost forecast</em>：用 <code>pscale analytics</code> 預估 row read / write 量、估算月帳</li>
<li>Phase 2 期間實際對 PlanetScale 跑 traffic、看實際 billing</li>
<li>Heavy analytics 改 <em>材料化 view</em> / <em>async aggregation</em>、不是每次 query</li>
<li>高 read frequency 開 Boost cache（額外 cost、但比 row read 便宜）</li>
</ul>
<h2 id="capability-mapping">Capability mapping</h2>
<table>
  <thead>
      <tr>
          <th>自管 Vitess</th>
          <th>PlanetScale 對應</th>
          <th>兼容度</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>VTGate</td>
          <td>PlanetScale endpoint</td>
          <td>100%</td>
      </tr>
      <tr>
          <td>VTTablet</td>
          <td>PlanetScale managed</td>
          <td>100%</td>
      </tr>
      <tr>
          <td>VReplication</td>
          <td>PlanetScale Console + Deploy Request</td>
          <td>90%（內部使用更受限）</td>
      </tr>
      <tr>
          <td>VSchema</td>
          <td>PlanetScale Console / pscale CLI</td>
          <td>95%（custom Vindex 不支援）</td>
      </tr>
      <tr>
          <td>Vitess online DDL</td>
          <td>Deploy Request workflow</td>
          <td>不同 paradigm、功能等價</td>
      </tr>
      <tr>
          <td>Backup</td>
          <td>PlanetScale 自動</td>
          <td>100%（且更好）</td>
      </tr>
      <tr>
          <td>Failover</td>
          <td>PlanetScale 自動</td>
          <td>100%</td>
      </tr>
      <tr>
          <td>Multi-region</td>
          <td>PlanetScale Boost / per-region cluster</td>
          <td>90%</td>
      </tr>
      <tr>
          <td>Custom plugin</td>
          <td>不支援</td>
          <td>0%</td>
      </tr>
      <tr>
          <td>SUPER privilege</td>
          <td>不支援</td>
          <td>0%</td>
      </tr>
  </tbody>
</table>
<h2 id="容量與成本對照">容量與成本對照</h2>
<p>對 200 人 eng team 用自管 Vitess（10 shard、20 TB 資料、50K WPS）：</p>
<table>
  <thead>
      <tr>
          <th>項目</th>
          <th>自管 Vitess（自管 EC2）</th>
          <th>PlanetScale Scaler Pro</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Infrastructure</td>
          <td>~$15K-25K / mo（EC2 + EBS + LB）</td>
          <td>Variable（per row read / write）</td>
      </tr>
      <tr>
          <td>Ops headcount</td>
          <td>2-3 FTE × $150K / yr = $300K-450K / yr</td>
          <td>&lt; 0.5 FTE × $150K = $75K / yr</td>
      </tr>
      <tr>
          <td>Vitess upgrade cost</td>
          <td>每年 1-2 個 SRE × 2 週</td>
          <td>自動</td>
      </tr>
      <tr>
          <td>Per-row read</td>
          <td>不計費</td>
          <td>$1 per 1B row read</td>
      </tr>
      <tr>
          <td>Per-row written</td>
          <td>不計費</td>
          <td>$1.50 per 1M row write</td>
      </tr>
      <tr>
          <td>Storage</td>
          <td>EBS $2K-5K / mo</td>
          <td>$1.50 / GB / mo</td>
      </tr>
      <tr>
          <td><strong>總帳</strong></td>
          <td>~$400K-550K / yr</td>
          <td>~$200K-350K / yr（看 traffic）</td>
      </tr>
  </tbody>
</table>
<p>對中型規模、PlanetScale 通常 break-even 或更便宜。對極大規模（&gt; 200K WPS / &gt; 100 TB）PlanetScale Enterprise 需要 commit pricing、不一定划算。</p>
<h2 id="何時不要遷">何時不要遷</h2>
<ul>
<li><strong>跨雲 / on-prem 是 requirement</strong>：PlanetScale cloud-only</li>
<li><strong>Custom Vindex / 特殊 plugin</strong> 大量使用：兼容度低、改造工作量大</li>
<li><strong>規模極大</strong> &gt; 500K WPS / &gt; 200 TB：PlanetScale plan 對應 Enterprise commit、議價辛苦</li>
<li><strong>強合規 / 資料主權限制</strong>：金融 / 政府 / 醫療場景、PlanetScale 不一定能 cover compliance</li>
<li><strong>既有 Vitess team 強 + ops cost 低</strong>：如果 ops 已經精實、不必為 outsource 而 outsource</li>
</ul>
<h2 id="跟其他模組整合">跟其他模組整合</h2>
<h3 id="跟-vitess-sharding">跟 <a href="/blog/backend/01-database/vendors/mysql/vitess-sharding/" data-link-title="MySQL Vitess Sharding：VTGate / VTTablet / VReplication / VSchema 四件套協作" data-link-desc="Vitess 不只是 MySQL sharding proxy、是 4 個 component 協作的完整 sharding 系統 — VTGate（query routing layer）、VTTablet（per-MySQL agent）、VReplication（跨 shard 資料移動）、VSchema（sharding metadata）。本文走 4 件套各自責任、keyspace / shard / tablet 架構、shard key 設計（Vindex）、配置 step-by-step、5 production 踩雷（cross-shard transaction / VStream lag / Vindex 不均勻 / resharding 切流 / VReplication 卡住）、跟自管 sharding 跟 PlanetScale 的對比">Vitess sharding</a></h3>
<p>本 migration 保留 Vitess sharding 概念、application code 視角幾乎不變。Phase 1 audit 是 <em>Vitess concept 對應 PlanetScale concept</em>、不是 <em>拆 Vitess 換 distributed SQL</em>。</p>
<h3 id="跟--planetscale-from-self-managed-mysql">跟 <a href="/blog/backend/01-database/vendors/mysql/migrate-to-planetscale/" data-link-title="MySQL → PlanetScale：managed Vitess &#43; branch-based schema workflow 的 hybrid shift" data-link-desc="自管 MySQL → PlanetScale 加上 Vitess sharding 跟 branch-based schema workflow。本文走 6 維 audit（Paradigm &#43; Operational &#43; Schema 多軸）、4-phase migration、5 production 踩雷、何時不要遷。">→ PlanetScale (from self-managed MySQL)</a></h3>
<p>本 migration 是 <em>Vitess → PlanetScale</em>、前者是 <em>MySQL → PlanetScale</em>。差異：</p>
<ul>
<li><em>MySQL → PlanetScale</em> (Type E)：要學 Vitess 概念 + branch workflow + FK 處理</li>
<li><em>Vitess → PlanetScale</em> (Type C)：只學 branch workflow + ops outsource、保留所有 Vitess investment</li>
</ul>
<p>選哪條 path 取決於起點。</p>
<h3 id="跟-major-version-upgrade">跟 <a href="/blog/backend/01-database/vendors/mysql/major-version-upgrade/" data-link-title="MySQL 5.7 → 8.0 Major Version Upgrade：character set / authentication / atomic DDL 三條 paradigm 同時換軌" data-link-desc="MySQL 5.7 → 8.0 三條 default 同時改：charset utf8 → utf8mb4、auth plugin native_password → caching_sha2_password、DDL non-atomic → atomic。本文走 Type E paradigm shift 結構、6 維 audit、4-phase upgrade、5 production 踩雷、何時不要升級。">Major Version Upgrade</a></h3>
<p>從自管 Vitess 上 MySQL 5.7 遷 PlanetScale 也是 <em>同時跨 major version</em>（PlanetScale 跑 8.0+ Vitess）。Application 必須同時處理 5.7 → 8.0 paradigm shift（charset / auth）。</p>
<h2 id="相關連結">相關連結</h2>
<ul>
<li><a href="/blog/backend/01-database/vendors/mysql/" data-link-title="MySQL" data-link-desc="高併發網路服務常用關聯式資料庫、Vitess / PlanetScale 分片生態、GitHub / Shopify / Facebook 規模驗證">MySQL vendor overview</a></li>
<li><a href="/blog/backend/01-database/vendors/mysql/vitess-sharding/" data-link-title="MySQL Vitess Sharding：VTGate / VTTablet / VReplication / VSchema 四件套協作" data-link-desc="Vitess 不只是 MySQL sharding proxy、是 4 個 component 協作的完整 sharding 系統 — VTGate（query routing layer）、VTTablet（per-MySQL agent）、VReplication（跨 shard 資料移動）、VSchema（sharding metadata）。本文走 4 件套各自責任、keyspace / shard / tablet 架構、shard key 設計（Vindex）、配置 step-by-step、5 production 踩雷（cross-shard transaction / VStream lag / Vindex 不均勻 / resharding 切流 / VReplication 卡住）、跟自管 sharding 跟 PlanetScale 的對比">Vitess Sharding</a>（self-managed source）</li>
<li><a href="/blog/backend/01-database/vendors/mysql/migrate-to-planetscale/" data-link-title="MySQL → PlanetScale：managed Vitess &#43; branch-based schema workflow 的 hybrid shift" data-link-desc="自管 MySQL → PlanetScale 加上 Vitess sharding 跟 branch-based schema workflow。本文走 6 維 audit（Paradigm &#43; Operational &#43; Schema 多軸）、4-phase migration、5 production 踩雷、何時不要遷。">→ PlanetScale from self-managed MySQL</a>（不同起點）</li>
<li><a href="/blog/backend/01-database/vendors/mysql/migrate-to-aurora/" data-link-title="MySQL → Aurora MySQL：storage layer 轉手到 AWS、replication / HA / backup 全部 outsource" data-link-desc="自管 MySQL → Aurora MySQL 是 Type C operational hybrid migration — wire protocol 一致、ops 責任轉到 AWS。本文走 6 維 audit（Operational High）、Aurora storage architecture 衝擊、4-phase migration、5 production 踩雷、何時維持原路線。">→ Aurora MySQL</a>（另一條 self-managed → managed path）</li>
<li><a href="/blog/backend/01-database/vendors/mysql/major-version-upgrade/" data-link-title="MySQL 5.7 → 8.0 Major Version Upgrade：character set / authentication / atomic DDL 三條 paradigm 同時換軌" data-link-desc="MySQL 5.7 → 8.0 三條 default 同時改：charset utf8 → utf8mb4、auth plugin native_password → caching_sha2_password、DDL non-atomic → atomic。本文走 Type E paradigm shift 結構、6 維 audit、4-phase upgrade、5 production 踩雷、何時不要升級。">Major Version Upgrade</a>（5.7 → 8.0 同期考量）</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 Methodology</a>（Type C operational hybrid）</li>
<li>官方：<a href="https://planetscale.com/docs/imports">PlanetScale Migration Guide</a> / <a href="https://github.com/planetscale/vitess-operator">Vitess Operator</a></li>
</ul>
]]></content:encoded></item><item><title>Pyroscope → Datadog Continuous Profiler：profiling deployment lifecycle 各階段 operational ownership 轉手</title><link>https://tarrragon.github.io/blog/backend/09-performance-capacity/vendors/datadog-continuous-profiler/migrate-from-pyroscope/</link><pubDate>Tue, 19 May 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/backend/09-performance-capacity/vendors/datadog-continuous-profiler/migrate-from-pyroscope/</guid><description>&lt;p>Continuous profiling deployment 的 lifecycle 有五階段：&lt;strong>install&lt;/strong>（agent / SDK 部署） → &lt;strong>instrument&lt;/strong>（service / env / version tag 注入） → &lt;strong>ingest&lt;/strong>（profile sample 進 backend store） → &lt;strong>query&lt;/strong>（flame graph / diff / explore） → &lt;strong>cost&lt;/strong>（storage retention / billing）。Pyroscope 跟 Datadog Continuous Profiler 在這五階段的 &lt;em>ops ownership 分布完全不同&lt;/em>：&lt;/p>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>階段&lt;/th>
 &lt;th>Pyroscope（self-host）&lt;/th>
 &lt;th>Datadog Continuous Profiler&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>Install&lt;/td>
 &lt;td>Grafana Alloy / Pyroscope agent / per-language SDK、自己部署&lt;/td>
 &lt;td>Datadog Agent（多半 APM 已部署）、SDK 加 flag&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Instrument&lt;/td>
 &lt;td>tag schema 自己設計&lt;/td>
 &lt;td>用 Datadog 既有 &lt;code>service&lt;/code> / &lt;code>env&lt;/code> / &lt;code>version&lt;/code> tag&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Ingest&lt;/td>
 &lt;td>Pyroscope server（自管 storage / scaling）&lt;/td>
 &lt;td>Datadog SaaS（vendor 管）&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Query&lt;/td>
 &lt;td>Grafana datasource explore / flame graph panel&lt;/td>
 &lt;td>Datadog APM 介面、跟 trace / log / metrics deep link&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Cost&lt;/td>
 &lt;td>self-host TCO（storage + ops + on-call）&lt;/td>
 &lt;td>按 APM host 計費（profiling 是 add-on）&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;p>從 Pyroscope 遷出 Datadog Continuous Profiler 的本質是 &lt;em>operational ownership 從 self-host 轉手到 SaaS&lt;/em> — pprof data model 跟 flame graph 視覺幾乎一樣、profile diff workflow 接近、&lt;em>差異 90% 在 ops 跟 ecosystem integration&lt;/em>。schema / paradigm 差距小、operational 差距大、就是 Type C operational hybrid 的 signature。&lt;/p>
&lt;h2 id="為什麼是-type-coperational-為主">為什麼是 Type C（operational 為主）&lt;/h2>
&lt;p>跑 &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/#6-%e7%b6%ad-diff-dimension-audit" data-link-title="Migration Playbook 方法論的演化紀錄：Stage 0 variant 規劃把 collapse 率從 60% 降到 0%" data-link-desc="跨 vendor migration playbook 需要獨立寫作方法論的依據，以及這套方法論從三輪 batch dogfood 中演化出來的驗證證據。">6 維 diff dimension audit&lt;/a>：&lt;/p>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>維度&lt;/th>
 &lt;th>評&lt;/th>
 &lt;th>說明&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>Schema&lt;/td>
 &lt;td>Low-Medium&lt;/td>
 &lt;td>pprof 是 industry standard、profile types (CPU / heap / etc) 接近&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Operational&lt;/td>
 &lt;td>High&lt;/td>
 &lt;td>self-host backend storage / retention / scaling → SaaS 全託管&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Paradigm&lt;/td>
 &lt;td>Low&lt;/td>
 &lt;td>都是 pprof-based continuous profiling、diff workflow 接近&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Components&lt;/td>
 &lt;td>Low-Medium&lt;/td>
 &lt;td>都需要 agent + backend、元件數量接近&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>App change&lt;/td>
 &lt;td>Low&lt;/td>
 &lt;td>agent / SDK config 改、code instrumentation 接近&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Topology&lt;/td>
 &lt;td>Low&lt;/td>
 &lt;td>都是 agent → backend 單向 ingest&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;p>Operational = High（其他 Low） → &lt;strong>Type C operational hybrid&lt;/strong>。Type C 結構是 &lt;em>operational audit prefix + 4-phase drop-in cutover&lt;/em> — operational diff 集中在 ingest / cost / retention 三階段、其他階段是 schema-level drop-in。&lt;/p></description><content:encoded><![CDATA[<p>Continuous profiling deployment 的 lifecycle 有五階段：<strong>install</strong>（agent / SDK 部署） → <strong>instrument</strong>（service / env / version tag 注入） → <strong>ingest</strong>（profile sample 進 backend store） → <strong>query</strong>（flame graph / diff / explore） → <strong>cost</strong>（storage retention / billing）。Pyroscope 跟 Datadog Continuous Profiler 在這五階段的 <em>ops ownership 分布完全不同</em>：</p>
<table>
  <thead>
      <tr>
          <th>階段</th>
          <th>Pyroscope（self-host）</th>
          <th>Datadog Continuous Profiler</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Install</td>
          <td>Grafana Alloy / Pyroscope agent / per-language SDK、自己部署</td>
          <td>Datadog Agent（多半 APM 已部署）、SDK 加 flag</td>
      </tr>
      <tr>
          <td>Instrument</td>
          <td>tag schema 自己設計</td>
          <td>用 Datadog 既有 <code>service</code> / <code>env</code> / <code>version</code> tag</td>
      </tr>
      <tr>
          <td>Ingest</td>
          <td>Pyroscope server（自管 storage / scaling）</td>
          <td>Datadog SaaS（vendor 管）</td>
      </tr>
      <tr>
          <td>Query</td>
          <td>Grafana datasource explore / flame graph panel</td>
          <td>Datadog APM 介面、跟 trace / log / metrics deep link</td>
      </tr>
      <tr>
          <td>Cost</td>
          <td>self-host TCO（storage + ops + on-call）</td>
          <td>按 APM host 計費（profiling 是 add-on）</td>
      </tr>
  </tbody>
</table>
<p>從 Pyroscope 遷出 Datadog Continuous Profiler 的本質是 <em>operational ownership 從 self-host 轉手到 SaaS</em> — pprof data model 跟 flame graph 視覺幾乎一樣、profile diff workflow 接近、<em>差異 90% 在 ops 跟 ecosystem integration</em>。schema / paradigm 差距小、operational 差距大、就是 Type C operational hybrid 的 signature。</p>
<h2 id="為什麼是-type-coperational-為主">為什麼是 Type C（operational 為主）</h2>
<p>跑 <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/#6-%e7%b6%ad-diff-dimension-audit" data-link-title="Migration Playbook 方法論的演化紀錄：Stage 0 variant 規劃把 collapse 率從 60% 降到 0%" data-link-desc="跨 vendor migration playbook 需要獨立寫作方法論的依據，以及這套方法論從三輪 batch dogfood 中演化出來的驗證證據。">6 維 diff dimension audit</a>：</p>
<table>
  <thead>
      <tr>
          <th>維度</th>
          <th>評</th>
          <th>說明</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Schema</td>
          <td>Low-Medium</td>
          <td>pprof 是 industry standard、profile types (CPU / heap / etc) 接近</td>
      </tr>
      <tr>
          <td>Operational</td>
          <td>High</td>
          <td>self-host backend storage / retention / scaling → SaaS 全託管</td>
      </tr>
      <tr>
          <td>Paradigm</td>
          <td>Low</td>
          <td>都是 pprof-based continuous profiling、diff workflow 接近</td>
      </tr>
      <tr>
          <td>Components</td>
          <td>Low-Medium</td>
          <td>都需要 agent + backend、元件數量接近</td>
      </tr>
      <tr>
          <td>App change</td>
          <td>Low</td>
          <td>agent / SDK config 改、code instrumentation 接近</td>
      </tr>
      <tr>
          <td>Topology</td>
          <td>Low</td>
          <td>都是 agent → backend 單向 ingest</td>
      </tr>
  </tbody>
</table>
<p>Operational = High（其他 Low） → <strong>Type C operational hybrid</strong>。Type C 結構是 <em>operational audit prefix + 4-phase drop-in cutover</em> — operational diff 集中在 ingest / cost / retention 三階段、其他階段是 schema-level drop-in。</p>
<h2 id="drivertco--datadog-ecosystem-內-deep-linking">Driver：TCO + Datadog ecosystem 內 deep linking</h2>
<p>從 Pyroscope 遷出 Datadog Profiler 的核心 driver 有兩條：</p>
<p><strong>TCO（total cost of ownership）</strong>：self-host Pyroscope 看起來免費（Apache 2.0）、但實際 ops 成本：</p>
<ul>
<li>Storage：profile sample 大、retention 與 storage cost 需要自己估（每 service 每天可能 1-10 GB）</li>
<li>Scaling：profile ingestion 突增（deploy event / canary rollout 期間）要 storage / ingester 撐住</li>
<li>On-call：Pyroscope server 自己會壞、要 on-call 帶</li>
<li>Ops engineer time：規模成長後可能需要 0.5-1 個 FTE 維護 Grafana stack 內的 Pyroscope</li>
</ul>
<p>對 <em>已經有 Datadog APM 帳單</em> 的 org、profiling 會跟 APM / profiled host 進同一個商務談判與 usage report，不需要額外 ops headcount。這條 TCO 拉力對 50-500 人 eng 規模最強 — 小於 50 人 self-host 也撐得住、大於 500 人 self-host 的 economy of scale 可能開始 favored Pyroscope。</p>
<p><strong>Ecosystem deep linking</strong>：Datadog Profiler 跟 trace / log / metrics <em>在同一個介面</em>、profile span 直接連到 trace span、deploy marker 直接顯示在 flame graph timeline、cross-signal query 不用 wire。Pyroscope 要透過 Grafana datasource correlation 達到類似效果、但需要 Tempo / Loki 已部署 + 手動配 correlation rule、整合精度跟自動程度都不如 Datadog 內建。</p>
<p>這條 driver 對 <em>已是 Datadog-heavy org</em> 強、對 <em>Grafana-heavy org</em> 弱（後者 Pyroscope 才是自然選擇、Datadog Profiler 反而 ecosystem misfit）。</p>
<h2 id="type-c-migration4-phase">Type C migration（4-phase）</h2>
<h3 id="phase-1operational-audit">Phase 1：Operational audit</h3>
<p>確認 Datadog Continuous Profiler 能 cover Pyroscope 當前用途、且 ops ownership 轉移可接受：</p>
<ul>
<li><strong>Language coverage</strong>：當前 Pyroscope 用哪些 SDK？Datadog Profiler 支援 Go / Java / Python / Node / Ruby / .NET / PHP / Rust / C / C++，但每個語言的 profiler type 與啟用方式不同；Erlang 等較小眾語言仍要逐項驗證</li>
<li><strong>Profile type coverage</strong>：Pyroscope 抓的 profile type（CPU / heap / allocation / goroutine / lock / wall time）在 Datadog Profiler 同語言是否都支援？Java 跟 Go 兩家都全、其他語言可能 partial</li>
<li><strong>Retention requirement</strong>：Pyroscope retention 可自管；Datadog Profiler retention 依產品資料保留政策與合約設定，要確認是否滿足既有 long-term baseline / audit 查詢需求</li>
<li><strong>資料主權</strong>：profile data 包含 application function name / line number、有時帶 customer data hint（function 名字暗示 customer-specific 邏輯）— 是否能 send to SaaS？</li>
<li><strong>Cost forecast</strong>：Datadog public pricing 以 profiled host / APM tier 計費，估算時要用實際 host 數、container density、APM plan 與 commit discount 跟 Pyroscope self-host TCO 比</li>
</ul>
<p>完成標準：寫出「Datadog 能 cover、不能 cover、不確定」三欄、不確定欄全部問過 Datadog SE / 用 trial 跑過 production-like load。</p>
<h3 id="phase-2agent-parallel-runprofile-雙寫">Phase 2：Agent parallel run（profile 雙寫）</h3>
<p>Datadog Agent 多半已部署（如果在用 Datadog APM）。Phase 2 在現有 Datadog Agent 開 profiling flag、<em>不關 Pyroscope agent</em>、跑 2-4 週 parallel：</p>
<ul>
<li>設定 <code>DD_PROFILING_ENABLED=true</code>（per service env var）</li>
<li>每個 service SDK init 加對應 profiling enable call（Go: <code>profiler.Start()</code>、Python: <code>import ddtrace.profiling.auto</code>、Java: agent flag 即可）</li>
<li>Pyroscope SDK / Alloy 繼續跑、profile 雙寫到兩家</li>
<li>對比同一個 service / 同一個時間段在 Pyroscope flame graph 跟 Datadog Profiler flame graph、確認 hot path 一致</li>
</ul>
<p>Parallel run 期間的 overhead：兩邊 agent 同時跑 profiling、CPU overhead 大致 2-4%（單一 profiler 通常 1-2%、雙寫 double）、production-acceptable but not free。Phase 2 不要超過 4 週、避免長期 double overhead。</p>
<p>完成標準：每個 production service 在 Datadog Profiler 都有 4 週連續 profile data、跟 Pyroscope flame graph 對比一致。</p>
<h3 id="phase-3tag-schema-reconcile--trace-correlation">Phase 3：Tag schema reconcile + trace correlation</h3>
<p>Pyroscope tag schema（自己設計）跟 Datadog standard tag（<code>service</code> / <code>env</code> / <code>version</code> / <code>host</code>）對齊：</p>
<ul>
<li>Pyroscope tag <code>app=checkout-api</code> → Datadog <code>service:checkout-api</code></li>
<li>Pyroscope tag <code>env=prod-us</code> → Datadog <code>env:prod</code> + <code>region:us-east-1</code></li>
<li>Pyroscope tag <code>git_sha=abc123</code> → Datadog <code>version:abc123</code>（透過 <code>DD_VERSION</code>）</li>
<li>Custom tag（team / business unit）→ Datadog custom tag（透過 SDK config 或 agent label）</li>
</ul>
<p>Trace correlation：Datadog Profiler 自動跟 APM trace 關聯（透過 <code>trace_id</code> injection into profile sample）— Phase 3 要驗證這個 correlation 可用（在 Datadog APM 點 trace span、應該能跳到對應時段 profile）。</p>
<p>Deploy marker：CI 在 deploy 時打 Datadog deployment marker（<code>datadog-ci deployment mark</code> 或 API call）、讓 Profiler diff view 知道 baseline / candidate 邊界。</p>
<p>完成標準：tag schema 1:1 對應、trace → profile deep link 可用、deploy marker 自動推送。</p>
<h3 id="phase-4pyroscope-agent-關掉--server-退役">Phase 4：Pyroscope agent 關掉 + server 退役</h3>
<p>逐步關 Pyroscope agent（per service rollout）：</p>
<ul>
<li>先關低重要性 service（dev / staging / non-critical prod）</li>
<li>觀察 1-2 週、確認沒事故再關下一批</li>
<li>最後關 critical service、留 Pyroscope server 跑 1-2 週空 ingest（rollback 緩衝）</li>
<li>取消 Pyroscope server（decommission storage、release K8s resource、關 on-call rotation）</li>
</ul>
<p>Pyroscope 歷史 profile data 保留策略：</p>
<ul>
<li>多數場景：直接 archive S3 / GCS、未來查得到但不維護 query UI</li>
<li>強合規場景：export Pyroscope flame graph data 為 pprof file 保存（pprof 是長期可讀格式）</li>
</ul>
<p>完成標準：所有 production service 只走 Datadog Profiler、Pyroscope server 取消、TCO 對比驗證符合預期。</p>
<h2 id="5-個-production-踩雷">5 個 production 踩雷</h2>
<h3 id="1-兩家-agent-同時跑造成-production-overhead">1. 兩家 agent 同時跑造成 production overhead</h3>
<p>Phase 2 parallel run 期間 CPU overhead 2-4%、預期內。但有些 service 設定錯誤（例如 sampling rate 預設都拉高）變成 6-10% overhead、p99 飄升、誤判為 Datadog Profiler 自己的問題。修法是 <em>parallel run 期間 Pyroscope sampling rate 降低 50%</em>（已經有歷史 baseline、不需要全採）、且 Phase 2 不要在 peak event 期間跑。</p>
<h3 id="2-tag-schema-不一致導致-historic-baseline-對不上">2. Tag schema 不一致導致 historic baseline 對不上</h3>
<p>Pyroscope tag <code>app=checkout-api</code> 跟 Datadog <code>service:checkout-api</code> 都指同一個 service、但 Datadog 內 <em>historic profile</em> 沒有 <code>app</code> tag、所以從 Pyroscope 視角看 baseline 跟 Datadog 視角看 baseline <em>是不同的時段切片</em>。Release regression 比較時用錯 baseline、會誤判 release 沒問題（實際 baseline 不對應）。修法是 Phase 3 明確記錄 <em>Datadog Profiler 的 baseline 起算時間是 Phase 2 開始日</em>、Pyroscope 歷史不直接搬入比較。</p>
<h3 id="3-trace_id-correlation-斷phase-3-最常見">3. Trace_id correlation 斷（Phase 3 最常見）</h3>
<p>Datadog Profiler 自動關聯 trace 的前提是 <em>同一個 Datadog Agent + APM SDK 注入 trace_id</em>。如果 service 用 OpenTelemetry SDK + Datadog Agent（OTel-first 配置）、trace_id 注入方式不同、profile 跟 trace 可能無法自動 correlate。修法是 <em>確認所有 service 用 Datadog SDK 或正確配 OTel-to-Datadog converter</em>、在 Datadog APM 介面 random 抽 10 個 trace 驗證 profile correlation 是否 wire 通。</p>
<h3 id="4-cost-突增phase-4-後常見">4. Cost 突增（Phase 4 後常見）</h3>
<p>關掉 Pyroscope agent 後、Datadog Profiler 變成 sole profile source、ingest volume 上升、Datadog bill 比預估高 30-50%。原因通常是：</p>
<ul>
<li>Profile sampling rate 不小心開太高（部分 service config 沒對齊）</li>
<li>Custom tag 太多（每個 unique tag combination 增加 indexing cost）</li>
<li>Profile event 量比預估高（service count × sampling rate × profile types）</li>
</ul>
<p>修法是 Phase 1 cost forecast 要保留 30% buffer、且 Phase 4 完成後立即跑 Datadog usage report 確認 actual 跟 forecast 對比。</p>
<h3 id="5-retention--baseline-政策變動造成歷史-query-斷層">5. Retention / baseline 政策變動造成歷史 query 斷層</h3>
<p>Pyroscope 自管 retention 可以設成配合內部 storage 與 compliance policy；Datadog Profiler 的 retention 依產品資料保留政策與合約設定。真正的風險不是固定「7 天 vs 90 天」，而是 <em>既有 baseline 查詢習慣是否還成立</em>：原 Pyroscope user 可能習慣查特定 release 前後的 flame graph、Datadog 端則要看 profile tag、deployment marker 與保留政策能否支援同樣查詢。修法是 Phase 1 明確列出「要查多久前、用什麼 tag 找、誰有權限看」三個問題，超出 profile retention 的長期 trend 改用 Datadog metrics-derived signal（cumulative CPU% / memory growth rate）或保留 Pyroscope archive。</p>
<h2 id="capability-對照">Capability 對照</h2>
<table>
  <thead>
      <tr>
          <th>能力</th>
          <th>Pyroscope（self-host）</th>
          <th>Datadog Continuous Profiler</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Language SDK 覆蓋</td>
          <td>Go / Java / Python / Node / Ruby / .NET / Rust / PHP</td>
          <td>Go / Java / Python / Node / Ruby / .NET / PHP / Rust / C / C++</td>
      </tr>
      <tr>
          <td>Profile type（CPU / heap / lock / etc）</td>
          <td>全（依語言 SDK 而定）</td>
          <td>全（依語言 SDK 而定）</td>
      </tr>
      <tr>
          <td>Flame graph diff workflow</td>
          <td>Grafana panel</td>
          <td>Datadog Profile Comparison</td>
      </tr>
      <tr>
          <td>Trace correlation</td>
          <td>手動配 Grafana correlation rule</td>
          <td>自動（trace_id injection）</td>
      </tr>
      <tr>
          <td>Deploy marker</td>
          <td>手動</td>
          <td>datadog-ci 自動</td>
      </tr>
      <tr>
          <td>Retention</td>
          <td>自管（無上限、cost 自負）</td>
          <td>依 Datadog retention policy / 合約設定</td>
      </tr>
      <tr>
          <td>資料主權</td>
          <td>完全自管</td>
          <td>SaaS（profile 出境）</td>
      </tr>
      <tr>
          <td>Ops ownership</td>
          <td>自管（storage / scaling / on-call）</td>
          <td>Vendor</td>
      </tr>
      <tr>
          <td>Cost model</td>
          <td>self-host TCO</td>
          <td>profiled host / APM tier / commit discount</td>
      </tr>
      <tr>
          <td>Cross-signal query</td>
          <td>Grafana cross-datasource</td>
          <td>Datadog native（trace / log / profile / metrics 同一 query bar）</td>
      </tr>
  </tbody>
</table>
<h2 id="何時不要切保留-pyroscope">何時不要切（保留 Pyroscope）</h2>
<ul>
<li><strong>資料主權 / compliance 不允許 profile data 出境</strong>：金融 / 醫療 / 政府 / 國防、保留 Pyroscope self-host</li>
<li><strong>內網 / air-gap 部署</strong>：物理上連不到 Datadog SaaS、保留 Pyroscope</li>
<li><strong>OSS-first / vendor neutrality policy</strong>：org 政策不允許 vendor lock-in profiling、保留 Pyroscope</li>
<li><strong>規模超大（&gt; 500 APM host）</strong>：Datadog Profiler add-on cost × host 數可能超過 Pyroscope self-host TCO、計算交叉點</li>
<li><strong>Long retention / 自訂 archive 強需求</strong>：若 profile data 必須照內部 retention policy 長期保存、保留 Pyroscope 或建立 export / archive 流程</li>
<li><strong>Datadog 不支援的語言或 profiler type</strong>：Erlang、特定 runtime 或特定 profile type 若 Datadog 無法覆蓋，保留 Pyroscope 為對應 service profiling</li>
</ul>
<h2 id="下一步路由">下一步路由</h2>
<ul>
<li>平行 batch：<a href="/blog/backend/09-performance-capacity/vendors/k6/migrate-from-jmeter/" data-link-title="JMeter → k6：k6 不是 JMeter 的「script 版本」、是 VU model 取代 thread model" data-link-desc="JMeter → k6 是 Type E paradigm shift、不是把 .jmx XML 翻成 JavaScript — VU (virtual user) model 跟 thread group model 是兩種對「使用者行為」不同的建模方式。本文走 6 維 audit（Schema High / Paradigm High / Operational Medium）、釐清反向定義、4-phase partial migration（多數 org 停 Phase 2-3 hybrid）、5 production 踩雷（thread group 翻譯失真 / arrival rate vs concurrent VU 混淆 / protocol gap / 結果 schema 改 / CI integration 重做）、protocol gap（JDBC / JMS / LDAP 在 k6 沒原生對應）、何時不要切">JMeter → k6</a>（Type E paradigm shift）</li>
<li>同 batch Type C：（待補、本篇是 batch 唯一 Type C）</li>
<li>上游：<a href="/blog/backend/09-performance-capacity/performance-observability/" data-link-title="9.8 效能可觀測性" data-link-desc="saturation metric、USE / RED method、cost dashboard">9.8 Performance Observability</a> / <a href="/blog/backend/04-observability/continuous-profiling/" data-link-title="4.9 Continuous Profiling" data-link-desc="把 CPU / memory / lock profile 從一次性除錯升級為持續訊號">4.9 Continuous Profiling</a></li>
<li>下游：<a href="/blog/backend/09-performance-capacity/improvement-loop/" data-link-title="9.9 Performance Improvement Loop" data-link-desc="壓測 → profile → fix → re-test → release gate 的閉環">9.9 Performance Improvement Loop</a>（profile diff 接入 release regression workflow）</li>
<li>vendor 對照：<a href="/blog/backend/09-performance-capacity/vendors/pyroscope/" data-link-title="Pyroscope" data-link-desc="用 Grafana 生態與開源 profiling backend 建立可自管 profile diff 與 flame graph 的工具">Pyroscope</a> / <a href="/blog/backend/09-performance-capacity/vendors/datadog-continuous-profiler/" data-link-title="Datadog Continuous Profiler" data-link-desc="用 SaaS APM 整合、deployment marker 與 profile diff 支援 release regression 定位的 profiling 工具">Datadog Continuous Profiler</a> / <a href="/blog/backend/09-performance-capacity/vendors/parca/" data-link-title="Parca" data-link-desc="用 eBPF 與開源 continuous profiling 平台建立 infrastructure-wide profile evidence 的工具">Parca</a></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 Methodology</a>（Type C operational hybrid 結構說明）</li>
</ul>
]]></content:encoded></item></channel></rss>