<?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>Mimir on Tarragon</title><link>https://tarrragon.github.io/blog/tags/mimir/</link><description>Recent content in Mimir on Tarragon</description><generator>Hugo -- gohugo.io</generator><language>zh-TW</language><copyright>Tarragon (CC BY 4.0)</copyright><lastBuildDate>Mon, 22 Jun 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://tarrragon.github.io/blog/tags/mimir/index.xml" rel="self" type="application/rss+xml"/><item><title>LGTM Stack 組合運維：Loki + Grafana + Tempo + Mimir</title><link>https://tarrragon.github.io/blog/backend/04-observability/vendors/grafana-stack/lgtm-stack-operations/</link><pubDate>Mon, 22 Jun 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/backend/04-observability/vendors/grafana-stack/lgtm-stack-operations/</guid><description>&lt;blockquote>
&lt;p>本文是 &lt;a href="https://tarrragon.github.io/blog/backend/04-observability/vendors/grafana-stack/" data-link-title="Grafana Stack" data-link-desc="Grafana / Loki / Tempo / Mimir / Pyroscope 全棧">Grafana Stack&lt;/a> 的 vendor deep article，深化 overview 的元件組合段。初次接觸 Grafana Stack 的讀者建議先讀 &lt;a href="https://tarrragon.github.io/blog/backend/04-observability/vendors/grafana-stack/" data-link-title="Grafana Stack" data-link-desc="Grafana / Loki / Tempo / Mimir / Pyroscope 全棧">Grafana Stack 服務頁&lt;/a>。&lt;/p>&lt;/blockquote>
&lt;h2 id="定位">定位&lt;/h2>
&lt;p>Grafana Stack（LGTM = Loki + Grafana + Tempo + Mimir）是自架觀測平台的完整選項，四個元件各自承擔一類訊號的儲存跟查詢。理解每個元件的責任邊界、部署模式跟故障特性，才能避免「裝了四個元件但不知道哪個壞了」的黑盒問題。&lt;/p>
&lt;h2 id="四元件的責任分工">四元件的責任分工&lt;/h2>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>元件&lt;/th>
 &lt;th>訊號類型&lt;/th>
 &lt;th>查詢語言&lt;/th>
 &lt;th>儲存後端&lt;/th>
 &lt;th>角色&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>Loki&lt;/td>
 &lt;td>Log&lt;/td>
 &lt;td>LogQL&lt;/td>
 &lt;td>Object storage + BoltDB&lt;/td>
 &lt;td>Log aggregation、grep 替代品&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Mimir&lt;/td>
 &lt;td>Metric&lt;/td>
 &lt;td>PromQL&lt;/td>
 &lt;td>Object storage&lt;/td>
 &lt;td>Prometheus 的可擴展長期儲存&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Tempo&lt;/td>
 &lt;td>Trace&lt;/td>
 &lt;td>TraceQL&lt;/td>
 &lt;td>Object storage&lt;/td>
 &lt;td>Trace 儲存、span 搜尋&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Grafana&lt;/td>
 &lt;td>視覺化&lt;/td>
 &lt;td>—&lt;/td>
 &lt;td>—&lt;/td>
 &lt;td>Dashboard、alert、data source&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;p>Grafana 是查詢 / 視覺化層，Loki / Mimir / Tempo 是儲存 / 查詢層。Grafana 本身不存觀測資料，它連接 data source（Loki / Mimir / Tempo / Prometheus / Elasticsearch）做查詢跟渲染。&lt;/p>
&lt;p>四個元件獨立部署、獨立擴展、各自有健康指標。一個元件故障不影響其他元件 — Loki 掛了時 Grafana 的 metric dashboard 跟 trace 查詢仍然正常，只有 log panel 會報錯。&lt;/p>
&lt;h2 id="部署模式">部署模式&lt;/h2>
&lt;h3 id="monolithic-mode">Monolithic mode&lt;/h3>
&lt;p>四個元件（或其中幾個）跑在同一個 process / container。適合小規模（每天數 GB log、數十萬 metric series、少量 trace）。部署最簡單 — 一個 docker-compose 或 Helm chart 起全套。&lt;/p>
&lt;p>限制是沒辦法獨立擴展 — log 量大但 metric 量小時，monolithic mode 不能只加 Loki 的資源。&lt;/p>
&lt;h3 id="microservices-mode">Microservices mode&lt;/h3>
&lt;p>每個元件拆成獨立的 deployment、各自 autoscaling。Loki 拆成 distributor / ingester / querier / compactor；Mimir 拆成類似的元件；Tempo 也有對應的分層。&lt;/p>
&lt;p>適合中到大規模。部署跟維運複雜度顯著上升 — 每個元件的每個子服務都需要獨立的 health check、autoscaling 設定、persistent volume。&lt;/p>
&lt;h3 id="選擇判準">選擇判準&lt;/h3>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>條件&lt;/th>
 &lt;th>建議模式&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>團隊 &amp;lt; 5 人、日 log &amp;lt; 10 GB&lt;/td>
 &lt;td>Monolithic&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>需要獨立擴展某一類訊號&lt;/td>
 &lt;td>Microservices&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>不想自管、預算足夠&lt;/td>
 &lt;td>Grafana Cloud&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>已有 Prometheus、只需要加 log / trace&lt;/td>
 &lt;td>漸進式加 Loki + Tempo&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;h2 id="常見故障模式">常見故障模式&lt;/h2>
&lt;h3 id="lokiingester-oom">Loki：ingester OOM&lt;/h3>
&lt;p>Loki ingester 把 log chunks 保存在記憶體，高流量時容易 OOM。觸發條件是突然的 log 量爆增（部署後 error storm、某服務開了 debug log level）。&lt;/p></description><content:encoded><![CDATA[<blockquote>
<p>本文是 <a href="/blog/backend/04-observability/vendors/grafana-stack/" data-link-title="Grafana Stack" data-link-desc="Grafana / Loki / Tempo / Mimir / Pyroscope 全棧">Grafana Stack</a> 的 vendor deep article，深化 overview 的元件組合段。初次接觸 Grafana Stack 的讀者建議先讀 <a href="/blog/backend/04-observability/vendors/grafana-stack/" data-link-title="Grafana Stack" data-link-desc="Grafana / Loki / Tempo / Mimir / Pyroscope 全棧">Grafana Stack 服務頁</a>。</p></blockquote>
<h2 id="定位">定位</h2>
<p>Grafana Stack（LGTM = Loki + Grafana + Tempo + Mimir）是自架觀測平台的完整選項，四個元件各自承擔一類訊號的儲存跟查詢。理解每個元件的責任邊界、部署模式跟故障特性，才能避免「裝了四個元件但不知道哪個壞了」的黑盒問題。</p>
<h2 id="四元件的責任分工">四元件的責任分工</h2>
<table>
  <thead>
      <tr>
          <th>元件</th>
          <th>訊號類型</th>
          <th>查詢語言</th>
          <th>儲存後端</th>
          <th>角色</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Loki</td>
          <td>Log</td>
          <td>LogQL</td>
          <td>Object storage + BoltDB</td>
          <td>Log aggregation、grep 替代品</td>
      </tr>
      <tr>
          <td>Mimir</td>
          <td>Metric</td>
          <td>PromQL</td>
          <td>Object storage</td>
          <td>Prometheus 的可擴展長期儲存</td>
      </tr>
      <tr>
          <td>Tempo</td>
          <td>Trace</td>
          <td>TraceQL</td>
          <td>Object storage</td>
          <td>Trace 儲存、span 搜尋</td>
      </tr>
      <tr>
          <td>Grafana</td>
          <td>視覺化</td>
          <td>—</td>
          <td>—</td>
          <td>Dashboard、alert、data source</td>
      </tr>
  </tbody>
</table>
<p>Grafana 是查詢 / 視覺化層，Loki / Mimir / Tempo 是儲存 / 查詢層。Grafana 本身不存觀測資料，它連接 data source（Loki / Mimir / Tempo / Prometheus / Elasticsearch）做查詢跟渲染。</p>
<p>四個元件獨立部署、獨立擴展、各自有健康指標。一個元件故障不影響其他元件 — Loki 掛了時 Grafana 的 metric dashboard 跟 trace 查詢仍然正常，只有 log panel 會報錯。</p>
<h2 id="部署模式">部署模式</h2>
<h3 id="monolithic-mode">Monolithic mode</h3>
<p>四個元件（或其中幾個）跑在同一個 process / container。適合小規模（每天數 GB log、數十萬 metric series、少量 trace）。部署最簡單 — 一個 docker-compose 或 Helm chart 起全套。</p>
<p>限制是沒辦法獨立擴展 — log 量大但 metric 量小時，monolithic mode 不能只加 Loki 的資源。</p>
<h3 id="microservices-mode">Microservices mode</h3>
<p>每個元件拆成獨立的 deployment、各自 autoscaling。Loki 拆成 distributor / ingester / querier / compactor；Mimir 拆成類似的元件；Tempo 也有對應的分層。</p>
<p>適合中到大規模。部署跟維運複雜度顯著上升 — 每個元件的每個子服務都需要獨立的 health check、autoscaling 設定、persistent volume。</p>
<h3 id="選擇判準">選擇判準</h3>
<table>
  <thead>
      <tr>
          <th>條件</th>
          <th>建議模式</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>團隊 &lt; 5 人、日 log &lt; 10 GB</td>
          <td>Monolithic</td>
      </tr>
      <tr>
          <td>需要獨立擴展某一類訊號</td>
          <td>Microservices</td>
      </tr>
      <tr>
          <td>不想自管、預算足夠</td>
          <td>Grafana Cloud</td>
      </tr>
      <tr>
          <td>已有 Prometheus、只需要加 log / trace</td>
          <td>漸進式加 Loki + Tempo</td>
      </tr>
  </tbody>
</table>
<h2 id="常見故障模式">常見故障模式</h2>
<h3 id="lokiingester-oom">Loki：ingester OOM</h3>
<p>Loki ingester 把 log chunks 保存在記憶體，高流量時容易 OOM。觸發條件是突然的 log 量爆增（部署後 error storm、某服務開了 debug log level）。</p>
<p>判讀指標：<code>loki_ingester_memory_chunks</code>、<code>process_resident_memory_bytes</code>。修復方向：調整 chunk flush interval（更頻繁寫入 object storage、降低記憶體壓力）、加 ingester replica、或在 pipeline 層（OTel Collector）做 log volume rate limit。</p>
<h3 id="mimircompactor-卡住">Mimir：compactor 卡住</h3>
<p>Mimir compactor 負責合併 ingester 寫入的 block。Compactor 卡住時，block 數量持續增長、query 需要掃描更多 block、延遲上升。</p>
<p>判讀指標：<code>cortex_compactor_runs_completed_total</code> 停滯、<code>cortex_bucket_blocks_count</code> 持續增長。修復方向：檢查 object storage 的寫入權限跟延遲、增加 compactor 資源（CPU / memory）、或暫時停止 ingestion 讓 compactor 追上。</p>
<h3 id="tempotrace-not-found">Tempo：trace not found</h3>
<p>使用者用 trace ID 查詢時回 &ldquo;trace not found&rdquo;，但 trace 確實存在。常見原因是 Tempo 的 bloom filter / compacted block index 還沒包含該 trace（ingestion 到可查詢有延遲），或 trace 被 retention policy 刪除。</p>
<p>判讀方式：查 trace 的 timestamp 是否在 retention 範圍內、查 <code>tempo_ingester_traces_created_total</code> 確認 ingestion 正常、查 compactor 是否正常運行。</p>
<h3 id="grafanadashboard-provisioning-漂移">Grafana：dashboard provisioning 漂移</h3>
<p>用 provisioning（YAML / JSON 檔案）管理 dashboard 時，手動在 UI 修改的 dashboard 會在下次 provisioning 同步時被覆蓋。團隊成員在 UI 調整了 panel、下次重啟 Grafana 後修改消失。</p>
<p>修復方向：dashboard 修改統一透過 git → provisioning pipeline（GitOps），UI 只用於臨時調整跟探索。把 provisioning 的 <code>allowUiUpdates</code> 設為 false、強制所有變更走 git。</p>
<h2 id="dashboard-provisioning">Dashboard Provisioning</h2>
<p>Dashboard 的管理方式影響長期維護成本。手動在 UI 建立 dashboard 的起步最快，但隨 dashboard 數量增長會出現版本不一致、無法 rollback、owner 不明的問題。</p>
<h3 id="infrastructure-as-code">Infrastructure as Code</h3>
<p>Dashboard JSON 存在 git repo、透過 provisioning 同步到 Grafana。變更走 PR review、有版本歷史、可以 rollback。</p>
<p>Grafana 的 provisioning 機制讀 YAML config，指定 dashboard JSON 的來源（local file / HTTP / API）。Helm chart 部署時把 dashboard JSON 放在 ConfigMap 或 persistent volume。</p>
<h3 id="grafonnet--jsonnet">Grafonnet / Jsonnet</h3>
<p>用 Jsonnet（Grafana 的 dashboard-as-code library）產生 dashboard JSON。適合大量相似 dashboard 的場景 — 每個服務一個 dashboard，結構相同但 data source 跟 label 不同。</p>
<p>Grafonnet 的學習曲線比直接寫 JSON 高，但在 dashboard 數量 &gt; 20 個時開始有維護效率的回報。</p>
<h2 id="下一步路由">下一步路由</h2>
<ul>
<li><a href="/blog/backend/04-observability/vendors/grafana-stack/" data-link-title="Grafana Stack" data-link-desc="Grafana / Loki / Tempo / Mimir / Pyroscope 全棧">Grafana Stack 服務頁</a>：overview 跟日常操作</li>
<li><a href="/blog/backend/04-observability/vendors/prometheus/" data-link-title="Prometheus" data-link-desc="Pull-based metrics 主流 OSS、PromQL 與 alerting">Prometheus 服務頁</a>：Mimir 的上游 metric 來源</li>
<li><a href="/blog/backend/04-observability/vendors/opentelemetry/collector-deployment-patterns/" data-link-title="OTel Collector 部署模式：agent / gateway / sidecar 與 pipeline 設計" data-link-desc="說明 OpenTelemetry Collector 三種部署位置的責任分工、receivers/processors/exporters pipeline 設計，以及 collector 失效、記憶體壓力與 backpressure 的故障演練與容量邊界">OTel Collector 部署模式</a>：LGTM 的 ingestion 入口</li>
<li><a href="/blog/backend/04-observability/telemetry-pipeline/" data-link-title="4.11 Telemetry Pipeline 架構" data-link-desc="把 log / metric / trace 的 agent → collector → ingest → storage → query 分層治理">4.11 telemetry pipeline</a>：pipeline 各層的治理</li>
<li><a href="/blog/backend/04-observability/observability-operating-model/" data-link-title="4.18 Observability Operating Model" data-link-desc="定義 platform / service team / on-call 對訊號、dashboard、alert 與成本的 ownership">4.18 operating model</a>：dashboard / alert 的 ownership</li>
</ul>
]]></content:encoded></item><item><title>Self-managed Prometheus → Grafana Cloud Metrics：feature × ops × cost 對照</title><link>https://tarrragon.github.io/blog/backend/04-observability/vendors/grafana-stack/migrate-prometheus-to-cloud-metrics/</link><pubDate>Tue, 19 May 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/backend/04-observability/vendors/grafana-stack/migrate-prometheus-to-cloud-metrics/</guid><description>&lt;blockquote>
&lt;p>本文是跨 vendor migration playbook、cross-link &lt;a href="https://tarrragon.github.io/blog/backend/04-observability/vendors/prometheus/" data-link-title="Prometheus" data-link-desc="Pull-based metrics 主流 OSS、PromQL 與 alerting">Prometheus&lt;/a> 跟 &lt;a href="https://tarrragon.github.io/blog/backend/04-observability/vendors/grafana-stack/" data-link-title="Grafana Stack" data-link-desc="Grafana / Loki / Tempo / Mimir / Pyroscope 全棧">Grafana Stack&lt;/a>（Grafana Cloud Metrics、Mimir-backed）。跑 &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 6 維 audit&lt;/a> 後對映 &lt;em>Operational = High → Type C operational redesign hybrid&lt;/em>。&lt;/p>&lt;/blockquote>
&lt;h2 id="feature--ops--cost-三維對照">Feature / ops / cost 三維對照&lt;/h2>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>維度&lt;/th>
 &lt;th>Self-managed Prometheus&lt;/th>
 &lt;th>Grafana Cloud Metrics&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>Storage backend&lt;/td>
 &lt;td>Local disk + remote_write (optional)&lt;/td>
 &lt;td>Mimir + S3 (auto cold tier)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Retention&lt;/td>
 &lt;td>TSDB local 15 天 default&lt;/td>
 &lt;td>13 個月 default、可延長&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>HA&lt;/td>
 &lt;td>Two Prometheus + sidecar&lt;/td>
 &lt;td>Built-in multi-AZ&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Cardinality limit&lt;/td>
 &lt;td>自管 limit + recording rule&lt;/td>
 &lt;td>1.5M active series / tier、scale-up 配額&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Query API&lt;/td>
 &lt;td>PromQL + Prometheus HTTP API&lt;/td>
 &lt;td>完全相容&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Alert&lt;/td>
 &lt;td>Alertmanager self-managed&lt;/td>
 &lt;td>Grafana Cloud Alerting&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Dashboard&lt;/td>
 &lt;td>Grafana self-managed&lt;/td>
 &lt;td>Grafana Cloud (included)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Long-term storage&lt;/td>
 &lt;td>Thanos / Cortex / Mimir 自管&lt;/td>
 &lt;td>Mimir 內建&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Cost (mid-tier)&lt;/td>
 &lt;td>$500-2000 / mo + ops FTE&lt;/td>
 &lt;td>$300-1500 / mo (按 series)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Operational FTE&lt;/td>
 &lt;td>0.3-0.8&lt;/td>
 &lt;td>0.05-0.15&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&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/" 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;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>Schema / API&lt;/td>
 &lt;td>Low（PromQL + API 完全相容）&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Operational&lt;/td>
 &lt;td>&lt;strong>High&lt;/strong>（HA / retention / scaling 全託管）&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Paradigm&lt;/td>
 &lt;td>Low（同 Prometheus metric paradigm）&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Components&lt;/td>
 &lt;td>Low&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Application change&lt;/td>
 &lt;td>Low（remote_write endpoint 改）&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Data topology&lt;/td>
 &lt;td>Low&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;p>Operational = High → Type C standard。&lt;/p></description><content:encoded><![CDATA[<blockquote>
<p>本文是跨 vendor migration playbook、cross-link <a href="/blog/backend/04-observability/vendors/prometheus/" data-link-title="Prometheus" data-link-desc="Pull-based metrics 主流 OSS、PromQL 與 alerting">Prometheus</a> 跟 <a href="/blog/backend/04-observability/vendors/grafana-stack/" data-link-title="Grafana Stack" data-link-desc="Grafana / Loki / Tempo / Mimir / Pyroscope 全棧">Grafana Stack</a>（Grafana Cloud Metrics、Mimir-backed）。跑 <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 6 維 audit</a> 後對映 <em>Operational = High → Type C operational redesign hybrid</em>。</p></blockquote>
<h2 id="feature--ops--cost-三維對照">Feature / ops / cost 三維對照</h2>
<table>
  <thead>
      <tr>
          <th>維度</th>
          <th>Self-managed Prometheus</th>
          <th>Grafana Cloud Metrics</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Storage backend</td>
          <td>Local disk + remote_write (optional)</td>
          <td>Mimir + S3 (auto cold tier)</td>
      </tr>
      <tr>
          <td>Retention</td>
          <td>TSDB local 15 天 default</td>
          <td>13 個月 default、可延長</td>
      </tr>
      <tr>
          <td>HA</td>
          <td>Two Prometheus + sidecar</td>
          <td>Built-in multi-AZ</td>
      </tr>
      <tr>
          <td>Cardinality limit</td>
          <td>自管 limit + recording rule</td>
          <td>1.5M active series / tier、scale-up 配額</td>
      </tr>
      <tr>
          <td>Query API</td>
          <td>PromQL + Prometheus HTTP API</td>
          <td>完全相容</td>
      </tr>
      <tr>
          <td>Alert</td>
          <td>Alertmanager self-managed</td>
          <td>Grafana Cloud Alerting</td>
      </tr>
      <tr>
          <td>Dashboard</td>
          <td>Grafana self-managed</td>
          <td>Grafana Cloud (included)</td>
      </tr>
      <tr>
          <td>Long-term storage</td>
          <td>Thanos / Cortex / Mimir 自管</td>
          <td>Mimir 內建</td>
      </tr>
      <tr>
          <td>Cost (mid-tier)</td>
          <td>$500-2000 / mo + ops FTE</td>
          <td>$300-1500 / mo (按 series)</td>
      </tr>
      <tr>
          <td>Operational FTE</td>
          <td>0.3-0.8</td>
          <td>0.05-0.15</td>
      </tr>
  </tbody>
</table>
<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/" 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>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Schema / API</td>
          <td>Low（PromQL + API 完全相容）</td>
      </tr>
      <tr>
          <td>Operational</td>
          <td><strong>High</strong>（HA / retention / scaling 全託管）</td>
      </tr>
      <tr>
          <td>Paradigm</td>
          <td>Low（同 Prometheus metric paradigm）</td>
      </tr>
      <tr>
          <td>Components</td>
          <td>Low</td>
      </tr>
      <tr>
          <td>Application change</td>
          <td>Low（remote_write endpoint 改）</td>
      </tr>
      <tr>
          <td>Data topology</td>
          <td>Low</td>
      </tr>
  </tbody>
</table>
<p>Operational = High → Type C standard。</p>
<h2 id="為什麼遷retention--ops--vendor-consolidation-三條-driver">為什麼遷：retention / ops / vendor consolidation 三條 driver</h2>
<table>
  <thead>
      <tr>
          <th>Driver</th>
          <th>觸發</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Retention</td>
          <td>Prometheus TSDB local 預設 15 天、長期 retention 需要 Thanos / Cortex / Mimir 自管</td>
      </tr>
      <tr>
          <td>Ops FTE</td>
          <td>Self-managed Prometheus + Alertmanager + Grafana 自管全部加起來 0.5-1 FTE</td>
      </tr>
      <tr>
          <td>Vendor consolidation</td>
          <td>已用 Grafana Cloud（logs / traces）、metric 加進 stack 統一</td>
      </tr>
  </tbody>
</table>
<h2 id="operational-redesign">Operational redesign</h2>
<table>
  <thead>
      <tr>
          <th>Concept</th>
          <th>Self-managed</th>
          <th>Grafana Cloud Metrics</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Cluster bootstrap</td>
          <td>Helm chart + manual config</td>
          <td>UI 一鍵建</td>
      </tr>
      <tr>
          <td>HA</td>
          <td>Two Prometheus 配置</td>
          <td>內建 multi-AZ Mimir</td>
      </tr>
      <tr>
          <td>Long-term retention</td>
          <td>Thanos / Cortex / Mimir 自管</td>
          <td>Built-in (S3-backed)</td>
      </tr>
      <tr>
          <td>Cardinality control</td>
          <td>Manual recording rule + relabel</td>
          <td>Adaptive sampling + cardinality limit</td>
      </tr>
      <tr>
          <td>Alerting</td>
          <td>Alertmanager 自管</td>
          <td>Grafana Cloud Alerting (integrated)</td>
      </tr>
      <tr>
          <td>Dashboard</td>
          <td>Grafana self-host</td>
          <td>Grafana Cloud (free tier 包含)</td>
      </tr>
  </tbody>
</table>
<h2 id="migration-4-phase">Migration 4-phase</h2>
<h3 id="phase-0audit">Phase 0：Audit</h3>
<ul>
<li>列所有 Prometheus job / scrape config</li>
<li>統計 active series 數（Mimir tier 計費基準）</li>
<li>估 retention 需求</li>
</ul>
<h3 id="phase-1grafana-cloud-setup">Phase 1：Grafana Cloud setup</h3>
<ul>
<li>Account + organization 設定</li>
<li>API key for <code>remote_write</code></li>
<li>Grafana Cloud Mimir endpoint 啟用</li>
</ul>
<h3 id="phase-2dual-write">Phase 2：Dual-write</h3>





<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"># prometheus.yml</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">remote_write</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">https://prometheus-prod-XX-prod-us-central-0.grafana.net/api/prom/push</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">basic_auth</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="nt">username</span><span class="p">:</span><span class="w"> </span><span class="l">&lt;INSTANCE_ID&gt;</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">password</span><span class="p">:</span><span class="w"> </span><span class="l">&lt;API_KEY&gt;</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">write_relabel_configs</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="w">      </span><span class="c"># Optional: drop high-cardinality before sending</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="w">      </span>- <span class="nt">source_labels</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="l">__name__]</span><span class="w">
</span></span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="w">        </span><span class="nt">regex</span><span class="p">:</span><span class="w"> </span><span class="s1">&#39;high_card_metric_.*&#39;</span><span class="w">
</span></span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="w">        </span><span class="nt">action</span><span class="p">:</span><span class="w"> </span><span class="l">drop</span></span></span></code></pre></div><p>跑 4-8 週、確認 query 結果一致 + cost 在預期。</p>
<h3 id="phase-3cutover">Phase 3：Cutover</h3>
<ul>
<li>Dashboard / alert 切到 Grafana Cloud endpoint</li>
<li>應用層 / Grafana 自管 instance 關閉 query 對 self-managed Prometheus</li>
</ul>
<h3 id="phase-4cleanup">Phase 4：Cleanup</h3>
<ul>
<li>Self-managed Prometheus stop scrape</li>
<li>留 1-2 月歷史查詢能力（用 archive snapshot）</li>
<li>Decommission</li>
</ul>
<h2 id="production-故障演練">Production 故障演練</h2>
<h3 id="case-1cardinality-爆cost-暴漲">Case 1：Cardinality 爆、cost 暴漲</h3>
<p><strong>徵兆</strong>：dual-write 第 2 週 Grafana Cloud series 從預估 100K 漲到 800K、cost 翻 8 倍。</p>
<p><strong>根因</strong>：application-level high-cardinality label（user_id / request_id）沒被 drop、scraped 進來。</p>
<p><strong>修法</strong>：</p>
<ol>
<li><code>write_relabel_configs</code> drop unbounded label</li>
<li>Application metric 設計改 fixed-bucket histogram、不用 unbounded label</li>
<li>Mimir cardinality limit 設保護 + alert</li>
</ol>
<h3 id="case-2recording-rule-對應失效">Case 2：Recording rule 對應失效</h3>
<p><strong>徵兆</strong>：cutover 後 Grafana dashboard 某些 panel 顯示空；發現用了 Prometheus 端 recording rule (<code>job:request_count:rate5m</code>)、Grafana Cloud 端沒對應 rule。</p>
<p><strong>根因</strong>：Prometheus 端 recording rule 是 <em>server-side</em>、不會跟著 remote_write 帶過去；Grafana Cloud 需要自己 setup recording rule。</p>
<p><strong>修法</strong>：</p>
<ol>
<li>Export 所有 recording rule、import 到 Grafana Cloud Mimir</li>
<li>或改用 <em>raw query</em> + Grafana query template、不依賴 recording rule</li>
</ol>
<h3 id="case-3promql-微差行為">Case 3：PromQL 微差行為</h3>
<p><strong>徵兆</strong>：某些 query 在 self-managed Prometheus 跑得好好的、切 Grafana Cloud Mimir 後 returns slightly different results。</p>
<p><strong>根因</strong>：Mimir 對某些 edge case（empty result handling / staleness marker timing）行為跟 Prometheus 略不同；多數 query 一致、&lt; 1% query 受影響。</p>
<p><strong>修法</strong>：</p>
<ol>
<li>Pre-cutover dual-query 驗證、用 critical dashboard 比對</li>
<li>Affected query 重寫、用更 robust PromQL pattern</li>
<li>文件 known incompatibility list</li>
</ol>
<h3 id="case-4alert-routing-改變">Case 4：Alert routing 改變</h3>
<p><strong>徵兆</strong>：Cutover 後 PagerDuty / Slack 收不到 alert；發現 Alertmanager 端 webhook 沒切。</p>
<p><strong>根因</strong>：alert 邏輯從 self-managed Alertmanager 搬到 Grafana Cloud Alerting、routing / contact 配置完全重做。</p>
<p><strong>修法</strong>：</p>
<ol>
<li>Pre-cutover 在 Grafana Cloud 端 rebuild alert + routing</li>
<li>雙 alert pipeline 跑 1-2 週、確認 Grafana Cloud 收到</li>
<li>Cutover 切 routing、SOC drill 一次</li>
</ol>
<h3 id="case-5歷史資料查不到">Case 5：歷史資料查不到</h3>
<p><strong>徵兆</strong>：Cutover 後 SOC 想 query 6 個月前事件、Grafana Cloud 只有 2 個月（dual-write 後的）資料。</p>
<p><strong>根因</strong>：Grafana Cloud 從 dual-write 開始才有資料、之前的 self-managed Prometheus historical data 沒 backfill。</p>
<p><strong>修法</strong>：</p>
<ol>
<li>Phase 2 期間用 <code>promtool tsdb dump</code> + <code>mimirtool</code> 把 self-managed historical 灌進 Mimir</li>
<li>或保留 self-managed Prometheus read-only 6 個月（給 historical query）</li>
<li>Long-term：retention 從 cutover 開始算、historical 是 <em>one-time backfill</em></li>
</ol>
<h2 id="capacity--cost">Capacity / cost</h2>
<table>
  <thead>
      <tr>
          <th>維度</th>
          <th>Self-managed</th>
          <th>Grafana Cloud Metrics</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Compute (100 host, 100K series)</td>
          <td>$500-1000 / mo + ops</td>
          <td>$300-800 / mo</td>
      </tr>
      <tr>
          <td>Operational FTE</td>
          <td>0.3-0.8 = $3K-8K</td>
          <td>0.05-0.15 = $500-1500</td>
      </tr>
      <tr>
          <td>Long-term retention</td>
          <td>Thanos / Cortex / Mimir 自管</td>
          <td>Built-in 13 個月</td>
      </tr>
      <tr>
          <td>Total (mid-tier)</td>
          <td>$4K-9K / mo (含 FTE)</td>
          <td>$1K-2.5K / mo</td>
      </tr>
      <tr>
          <td>Migration cost</td>
          <td>-</td>
          <td>1-2 FTE × 1-2 個月</td>
      </tr>
  </tbody>
</table>
<h2 id="整合--下一步">整合 / 下一步</h2>
<h3 id="跟-datadog--grafana-stack-migration-對位">跟 <a href="/blog/backend/04-observability/vendors/datadog/migrate-to-grafana-stack/" data-link-title="Datadog → Grafana Stack：把 $50K/month bill 拆解到 self-hosted observability" data-link-desc="Datadog 五層計費（host APM / metric / log ingest / log retention / RUM）拆解、對位 Grafana Stack（Mimir / Loki / Tempo / Grafana / Alloy）的 5 層責任；OTel-based agent migration、5 個 production 踩雷（cardinality 爆 / log volume cost / dashboard 不直接轉 / alert routing 換邏輯 / SLO definition 差異）、cost reality check">Datadog → Grafana Stack migration</a> 對位</h3>
<p>兩條 Grafana Stack 路線：</p>
<ul>
<li>Self-host (Mimir + Loki + Tempo) on K8s：開源、自管</li>
<li>Grafana Cloud：SaaS、operational simplification</li>
</ul>
<p>本篇是「self-managed Prometheus → Grafana Cloud」、互補；如果跑兩階段（self-host → Cloud）跟「Datadog → Grafana Cloud」差不多。</p>
<h3 id="跟-opentelemetry-整合">跟 OpenTelemetry 整合</h3>
<p>OTel Collector 可同時 ship 到 Mimir (metric) + Loki (log) + Tempo (trace)；Migration 順便升 OTel 化避免下次 vendor 切換重複。</p>
<h2 id="相關連結">相關連結</h2>
<ul>
<li>Source vendor：<a href="/blog/backend/04-observability/vendors/prometheus/" data-link-title="Prometheus" data-link-desc="Pull-based metrics 主流 OSS、PromQL 與 alerting">Prometheus</a></li>
<li>Target vendor：<a href="/blog/backend/04-observability/vendors/grafana-stack/" data-link-title="Grafana Stack" data-link-desc="Grafana / Loki / Tempo / Mimir / Pyroscope 全棧">Grafana Stack</a></li>
<li>平行 migration playbook (Type C)：<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> / <a href="/blog/backend/03-message-queue/vendors/kafka/migrate-to-msk/" data-link-title="Self-managed Kafka → AWS MSK：把 $15K/month operational cost 拆解到 managed" data-link-desc="Kafka self-managed → MSK 是 Type C operational redesign — protocol 完全相容、operational stack（ZooKeeper / brokers / monitoring / patching）全託管；本文用 cost 拆解開頭、5 個 production 踩雷（client connection pattern / version pinning / metric pipeline / IAM auth / cross-cluster mirror）">Kafka → MSK</a> / <a href="/blog/backend/04-observability/vendors/elastic-stack/migrate-to-elastic-cloud/" data-link-title="Self-managed ELK → Elastic Cloud：5 年 ELK 集群的 lifecycle 收尾" data-link-desc="Self-managed ELK Stack → Elastic Cloud 是 Type C operational redesign — protocol drop-in、operational stack（cluster sizing / shard 治理 / upgrade / backup）全託管；本文按 5 年 ELK lifecycle (build → scale → degrade → save → migrate) 組織、5 個 production 踩雷">ELK → Elastic Cloud</a></li>
<li>平行 D-type 對位：<a href="/blog/backend/04-observability/vendors/datadog/migrate-to-grafana-stack/" data-link-title="Datadog → Grafana Stack：把 $50K/month bill 拆解到 self-hosted observability" data-link-desc="Datadog 五層計費（host APM / metric / log ingest / log retention / RUM）拆解、對位 Grafana Stack（Mimir / Loki / Tempo / Grafana / Alloy）的 5 層責任；OTel-based agent migration、5 個 production 踩雷（cardinality 爆 / log volume cost / dashboard 不直接轉 / alert routing 換邏輯 / SLO definition 差異）、cost reality check">Datadog → Grafana Stack</a></li>
<li>Methodology：<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></li>
</ul>
]]></content:encoded></item><item><title>Datadog → Grafana Stack：把 $50K/month bill 拆解到 self-hosted observability</title><link>https://tarrragon.github.io/blog/backend/04-observability/vendors/datadog/migrate-to-grafana-stack/</link><pubDate>Tue, 19 May 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/backend/04-observability/vendors/datadog/migrate-to-grafana-stack/</guid><description>&lt;blockquote>
&lt;p>本文是跨 vendor migration playbook、cross-link 到 &lt;a href="https://tarrragon.github.io/blog/backend/04-observability/vendors/datadog/" data-link-title="Datadog" data-link-desc="All-in-one SaaS 觀測平台、APM / Logs / Metrics / RUM / Security">Datadog&lt;/a>（source）跟 &lt;a href="https://tarrragon.github.io/blog/backend/04-observability/vendors/grafana-stack/" data-link-title="Grafana Stack" data-link-desc="Grafana / Loki / Tempo / Mimir / Pyroscope 全棧">Grafana Stack&lt;/a>（target）。跟前三篇 migration（&lt;a href="https://tarrragon.github.io/blog/backend/07-security-data-protection/vendors/splunk/migrate-to-elastic-security/" data-link-title="Splunk → Elastic Security Detection Rule Migration：6 段 phased playbook 跟 5 大踩雷" data-link-desc="從 Splunk Enterprise Security 遷到 Elastic Security 的 detection rule translation playbook：SPL ↔ KQL/ES|QL schema 對位、AI-assisted translation pipeline、parallel run 比對、cutover routing、5 個 production 踩雷（macro 沒對應 / time zone 差異 / summary index 不對位 / alert dedup key 衝突 / 過早 decommission）、capacity / cost 對照">Splunk → Elastic&lt;/a> phased / &lt;a href="https://tarrragon.github.io/blog/backend/02-cache-redis/vendors/redis/migrate-to-dragonflydb/" data-link-title="Redis → DragonflyDB：drop-in 相容下的容量躍升 &amp;#43; 5 個踩雷" data-link-desc="DragonflyDB 號稱 Redis drop-in 替代、單機 throughput 25x、記憶體效率 30% 提升；遷移流程簡單但有 5 個 production 踩雷（RDB 版本差 / Lua 腳本不全支援 / Pub-Sub fanout 行為差異 / Cluster mode 兼容度 / Modules 不支援）、跟 Sentinel / Cluster 模式對位">Redis → DragonflyDB&lt;/a> drop-in / &lt;a href="https://tarrragon.github.io/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 &amp;#43; operational phased）、5 個 production 踩雷（extension 不支援 / replication slot 不直通 / autovacuum 行為差 / IAM 認證強制 / cost model 換算）、跟 Patroni / read replica / DR 對位">PostgreSQL → Aurora&lt;/a> hybrid）對照、本篇是 &lt;em>cost-driven multi-tool migration&lt;/em> — 不是換一個產品、是把 &lt;em>一站式 SaaS&lt;/em> 拆成 &lt;em>五個專責 OSS / cloud component&lt;/em>。&lt;/p></description><content:encoded><![CDATA[<blockquote>
<p>本文是跨 vendor migration playbook、cross-link 到 <a href="/blog/backend/04-observability/vendors/datadog/" data-link-title="Datadog" data-link-desc="All-in-one SaaS 觀測平台、APM / Logs / Metrics / RUM / Security">Datadog</a>（source）跟 <a href="/blog/backend/04-observability/vendors/grafana-stack/" data-link-title="Grafana Stack" data-link-desc="Grafana / Loki / Tempo / Mimir / Pyroscope 全棧">Grafana Stack</a>（target）。跟前三篇 migration（<a href="/blog/backend/07-security-data-protection/vendors/splunk/migrate-to-elastic-security/" data-link-title="Splunk → Elastic Security Detection Rule Migration：6 段 phased playbook 跟 5 大踩雷" data-link-desc="從 Splunk Enterprise Security 遷到 Elastic Security 的 detection rule translation playbook：SPL ↔ KQL/ES|QL schema 對位、AI-assisted translation pipeline、parallel run 比對、cutover routing、5 個 production 踩雷（macro 沒對應 / time zone 差異 / summary index 不對位 / alert dedup key 衝突 / 過早 decommission）、capacity / cost 對照">Splunk → Elastic</a> phased / <a href="/blog/backend/02-cache-redis/vendors/redis/migrate-to-dragonflydb/" data-link-title="Redis → DragonflyDB：drop-in 相容下的容量躍升 &#43; 5 個踩雷" data-link-desc="DragonflyDB 號稱 Redis drop-in 替代、單機 throughput 25x、記憶體效率 30% 提升；遷移流程簡單但有 5 個 production 踩雷（RDB 版本差 / Lua 腳本不全支援 / Pub-Sub fanout 行為差異 / Cluster mode 兼容度 / Modules 不支援）、跟 Sentinel / Cluster 模式對位">Redis → DragonflyDB</a> drop-in / <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> hybrid）對照、本篇是 <em>cost-driven multi-tool migration</em> — 不是換一個產品、是把 <em>一站式 SaaS</em> 拆成 <em>五個專責 OSS / cloud component</em>。</p></blockquote>
<h2 id="50kmonth-bill-拆解先看錢花在哪再決定怎麼遷">$50K/month bill 拆解：先看錢花在哪、再決定怎麼遷</h2>
<p>中型 SaaS（100-500 host、5K-50K metric series、TB-level log/day）的 Datadog 月帳單長這樣：</p>
<table>
  <thead>
      <tr>
          <th>計費項</th>
          <th>平均單價</th>
          <th>中型 SaaS 估算 / month</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Infrastructure host</td>
          <td>$15-23 / host</td>
          <td>200 host × $20 = $4,000</td>
      </tr>
      <tr>
          <td>APM host</td>
          <td>$31 / host</td>
          <td>100 host × $31 = $3,100</td>
      </tr>
      <tr>
          <td>Custom metrics</td>
          <td>$0.05 / 100 series</td>
          <td>30K series × $0.05 = $1,500</td>
      </tr>
      <tr>
          <td>Log ingest</td>
          <td>$0.10 / GB ingested</td>
          <td>50TB × $0.10 = $5,000</td>
      </tr>
      <tr>
          <td>Log retention（15-day）</td>
          <td>$1.27 / million events</td>
          <td>50G event × $1.27 = $6,350</td>
      </tr>
      <tr>
          <td>Log indexing</td>
          <td>$1.70 / million events</td>
          <td>50G × $1.70 = $8,500</td>
      </tr>
      <tr>
          <td>Network</td>
          <td>$5 / host</td>
          <td>200 × $5 = $1,000</td>
      </tr>
      <tr>
          <td>RUM / Session</td>
          <td>$1.50 / 1000 session</td>
          <td>30M session × $1.5 = $4,500</td>
      </tr>
      <tr>
          <td>Synthetics</td>
          <td>$5 / 10K test runs</td>
          <td>50K test = $25</td>
      </tr>
      <tr>
          <td>Total</td>
          <td>-</td>
          <td><strong>$34,000 / month</strong>（保守估）</td>
      </tr>
  </tbody>
</table>
<p>擴張到 500 host / 100TB log 的 production：$80K-150K / month 範圍。Grafana stack（self-hosted on K8s + Grafana Cloud 部分服務）對等 capacity 通常 $8K-30K / month — <em>2.5-5x cost reduction</em>。</p>
<p>但 cost 不是唯一 driver。其他 driver：</p>
<ul>
<li><strong>Multi-cloud / hybrid</strong>：Datadog 集中、Grafana 可分散部署符合資料 residency</li>
<li><strong>OpenTelemetry-first</strong>：Grafana stack 對 OTel 是 native、Datadog 仍 vendor-specific agent</li>
<li><strong>Long-term retention</strong>：Loki 用 S3 cold tier 跑 1 年 retention 比 Datadog 便宜 10-50x</li>
</ul>
<h2 id="五個責任五個-component不是替換一個產品">五個責任、五個 component：不是替換一個產品</h2>
<p>Datadog 是 <em>一站式 SaaS</em>、單一 agent + 單一 UI 包 5 個責任。Grafana stack 把責任拆給 5 個專責 component：</p>
<table>
  <thead>
      <tr>
          <th>責任</th>
          <th>Datadog 處理</th>
          <th>Grafana Stack 對應</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Metric</td>
          <td>Datadog metric</td>
          <td>Mimir（Prometheus-compatible long-term）</td>
      </tr>
      <tr>
          <td>Log</td>
          <td>Datadog Logs</td>
          <td>Loki（label-indexed log）</td>
      </tr>
      <tr>
          <td>Trace</td>
          <td>Datadog APM</td>
          <td>Tempo（trace-only object storage）</td>
      </tr>
      <tr>
          <td>Dashboard</td>
          <td>Datadog dashboard</td>
          <td>Grafana</td>
      </tr>
      <tr>
          <td>Agent / shipper</td>
          <td>Datadog Agent</td>
          <td>Alloy（OTel-based collector）+ Grafana Agent / Promtail</td>
      </tr>
  </tbody>
</table>
<p>Migration 是 <em>五個獨立 stream</em>、不是單一 cutover。SRE 對「一個 agent 包所有」的心智模型要拆。</p>
<h2 id="migration-結構每個-component-各自-phased整體-staggered">Migration 結構：每個 component 各自 phased、整體 staggered</h2>
<p>不像前三篇 migration 是線性流程、本篇是 <em>5 個 parallel migration stream</em> + 跨 stream coordination：</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">           Phase 0           Phase 1            Phase 2          Phase 3
</span></span><span class="line"><span class="ln">2</span><span class="cl">           Audit             Deploy             Dual-ship        Cutover
</span></span><span class="line"><span class="ln">3</span><span class="cl">Metric    [audit]──→        [deploy Mimir]──→ [dual-ship]──→  [cutover]
</span></span><span class="line"><span class="ln">4</span><span class="cl">APM       [audit]──→        [deploy Tempo]──→ [dual-ship]──→  [cutover]
</span></span><span class="line"><span class="ln">5</span><span class="cl">Log       [audit]──→        [deploy Loki]──→  [dual-ship]──→  [cutover]
</span></span><span class="line"><span class="ln">6</span><span class="cl">Dashboard [audit]──→        [deploy Grafana]──→ [rebuild]──→   [cutover]
</span></span><span class="line"><span class="ln">7</span><span class="cl">Alert     [audit]──→        [deploy Alertmgr]──→ [parallel]──→ [cutover]</span></span></code></pre></div><p>每個 stream 獨立做 dual-ship + cutover、不必同步；通常 <em>Metric 先遷</em>（cardinality 議題暴露最快）、然後 Log、最後 APM（trace correlation 最依賴 dashboard / alert）。</p>
<h2 id="agent-migrationdatadog-agent--otel-collector--alloy">Agent migration：Datadog Agent → OTel Collector / Alloy</h2>
<p>Datadog Agent 是 vendor-specific binary、抽出來換成 OpenTelemetry Collector / Grafana Alloy：</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"># alloy config (HCL-like)</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="w"></span><span class="l">prometheus.scrape &#34;k8s_pods&#34; {</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="w">  </span><span class="l">targets = discovery.kubernetes.pods.targets</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="w">  </span><span class="l">forward_to = [prometheus.remote_write.mimir.receiver]</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="w"></span>}<span class="w">
</span></span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="w"></span><span class="l">prometheus.remote_write &#34;mimir&#34; {</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="w">  </span><span class="l">endpoint {</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="w">    </span><span class="l">url = &#34;https://mimir.internal/api/v1/push&#34;</span><span class="w">
</span></span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="w">  </span>}<span class="w">
</span></span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="w"></span>}<span class="w">
</span></span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">13</span><span class="cl"><span class="w"></span><span class="l">loki.source.kubernetes &#34;pods&#34; {</span><span class="w">
</span></span></span><span class="line"><span class="ln">14</span><span class="cl"><span class="w">  </span><span class="l">targets = discovery.kubernetes.pods.targets</span><span class="w">
</span></span></span><span class="line"><span class="ln">15</span><span class="cl"><span class="w">  </span><span class="l">forward_to = [loki.write.production.receiver]</span><span class="w">
</span></span></span><span class="line"><span class="ln">16</span><span class="cl"><span class="w"></span>}<span class="w">
</span></span></span><span class="line"><span class="ln">17</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">18</span><span class="cl"><span class="w"></span><span class="l">otelcol.receiver.otlp &#34;default&#34; {</span><span class="w">
</span></span></span><span class="line"><span class="ln">19</span><span class="cl"><span class="w">  </span><span class="l">grpc {}</span><span class="w">
</span></span></span><span class="line"><span class="ln">20</span><span class="cl"><span class="w">  </span><span class="l">output {</span><span class="w">
</span></span></span><span class="line"><span class="ln">21</span><span class="cl"><span class="w">    </span><span class="l">traces = [otelcol.exporter.otlp.tempo.input]</span><span class="w">
</span></span></span><span class="line"><span class="ln">22</span><span class="cl"><span class="w">  </span>}<span class="w">
</span></span></span><span class="line"><span class="ln">23</span><span class="cl"><span class="w"></span>}</span></span></code></pre></div><p>Migration 期間 <em>dual-shipper</em> 是標準作法：</p>
<ul>
<li>Datadog Agent 跟 Alloy 並存（短期 capacity 兩倍）</li>
<li>同 host 同時 ship 兩端、觀察一致性</li>
<li>漸進 disable Datadog Agent 的 metric / log / APM 子模組</li>
</ul>
<h2 id="production-故障演練">Production 故障演練</h2>
<h3 id="case-1cardinality-爆mimir-端-series-暴增">Case 1：Cardinality 爆，Mimir 端 series 暴增</h3>
<p><strong>徵兆</strong>：Datadog 端 30K series、ship 到 Mimir 後 series 變 500K、Mimir indexer OOM。</p>
<p><strong>根因</strong>：Datadog 內部對 tag 做 <em>自動 aggregation</em> 跟 <em>low-cardinality enforcement</em>；Prometheus / Mimir 對 <em>每個 unique label set</em> 算一個 series、application code 的 high-cardinality label（user_id / request_id）直接爆。</p>
<p><strong>修法</strong>：</p>
<ol>
<li><strong>Audit 階段</strong> 跑 <code>topk(100, count by (__name__) ({__name__=~&quot;.+&quot;}))</code> 找 high-cardinality metric</li>
<li><strong>drop high-cardinality label</strong>：Alloy / OTel collector 端 <code>relabel</code> 規則 drop user_id 等 unbounded label</li>
<li><strong>改 histogram bucket</strong>：高 cardinality 通常來自 label combination、改用 fixed-bucket histogram</li>
<li><strong>適當改 metric 為 log</strong>：請求 ID 是 trace context、不該是 metric label</li>
</ol>
<h3 id="case-2log-volume-cost-預估失準">Case 2：Log volume cost 預估失準</h3>
<p><strong>徵兆</strong>：Loki 部署 1 個月後 S3 帳單比預估高 2x；object storage 跟 query GB-scan 都超預期。</p>
<p><strong>根因</strong>：Datadog 對 log 做自動 sampling / aggregation、bill 是 indexed event；Loki 是 <em>全量 raw ingest</em> + S3 cold storage、按實際 byte 計費。raw log volume 比 indexed event 高 3-10x。</p>
<p><strong>修法</strong>：</p>
<ol>
<li><strong>Ingest-side sampling</strong>：Alloy / Promtail 端 sample debug / info log、只 ingest warn / error 全量</li>
<li><strong>Log structure</strong>：JSON log 比 text log 壓縮率高、Loki S3 size 少 50%</li>
<li><strong>Retention tier</strong>：hot 7 天 S3 standard / cold 1 年 S3 Glacier、retention budget 控制</li>
</ol>
<h3 id="case-3datadog-dashboard-不能直接轉-grafana">Case 3：Datadog dashboard 不能直接轉 Grafana</h3>
<p><strong>徵兆</strong>：Migration 計畫設「dashboard 自動轉換」、實際跑 Datadog API export → Grafana import、80% dashboard 缺 widget / metric 對不上。</p>
<p><strong>根因</strong>：</p>
<ul>
<li>Datadog query syntax 跟 Grafana / Mimir 的 PromQL 不直接相容</li>
<li>Datadog widget type（top-list / hostmap）Grafana 沒對應</li>
<li>Tag-based aggregation 對應 Prometheus label 但語法不同</li>
</ul>
<p><strong>修法</strong>：</p>
<ol>
<li><strong>接受重建</strong>：production-grade dashboard 必須人工重建、不要期待自動轉</li>
<li><strong>Prioritize</strong>：先重建 <em>SOC 用 / production-critical</em> 30%、其他 deprecate</li>
<li><strong>migration window 增 4-6 週</strong>：dashboard rebuild 是 underestimated effort</li>
</ol>
<h3 id="case-4alert-routing-換邏輯pagerduty-integration-不通">Case 4：Alert routing 換邏輯，PagerDuty integration 不通</h3>
<p><strong>徵兆</strong>：Cutover 後 alert 不送 PagerDuty、SOC 半小時才發現；alert 端 webhook 配置正確、但 payload format 跟 Datadog 不同、PagerDuty 端 rule 過濾掉。</p>
<p><strong>根因</strong>：</p>
<ul>
<li>Datadog alert payload 含 <code>event_type=alert</code>、PagerDuty integration 用這個 routing</li>
<li>Alertmanager 預設 payload 結構不同</li>
<li>PagerDuty rule 端針對 Datadog event 寫 schema、Alertmanager event 不 match</li>
</ul>
<p><strong>修法</strong>：</p>
<ol>
<li><strong>Pre-cutover test</strong>：Alertmanager → PagerDuty 跑 dry-run、send test alert 驗證</li>
<li><strong>PagerDuty Service</strong>：建獨立 Grafana-source Service、不共用 Datadog Service</li>
<li><strong>Alertmanager template</strong>：用 webhook 自定 JSON template、payload 接近 Datadog 結構</li>
</ol>
<h3 id="case-5slo-definition-跟-monitor-type-對不上">Case 5：SLO definition 跟 monitor type 對不上</h3>
<p><strong>徵兆</strong>：Datadog SLO 跑 99.9% availability、轉到 Grafana SLO + Mimir 後實際 9X% 數字不一致；SOC 跑 dashboard 比對 5 個 SLO、4 個誤差 0.1-0.3%。</p>
<p><strong>根因</strong>：</p>
<ul>
<li>Datadog SLO 計算 over time window 用內部 query；Grafana SLO 用 PromQL 寫公式</li>
<li>Datadog 對 <code>success_rate</code> 處理 missing data 跟 PromQL 預設不同</li>
<li>Time bucket boundary 處理差異</li>
</ul>
<p><strong>修法</strong>：</p>
<ol>
<li><strong>重定義 SLO 在 PromQL</strong>：不嘗試「複製」、是「重定義」、認真寫 PromQL 表達式</li>
<li><strong>接受 ±0.1% drift</strong>：production-critical SLO 跑 dual-track 1-2 個月、tune PromQL 到 acceptable drift</li>
<li><strong>SLO migration 不是 dashboard migration 子集</strong>：獨立 stream、留更多時間</li>
</ol>
<h2 id="capacity--cost-對照">Capacity / cost 對照</h2>
<table>
  <thead>
      <tr>
          <th>維度</th>
          <th>Datadog</th>
          <th>Grafana Stack（self-hosted on K8s）</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Setup cost</td>
          <td>低（SaaS）</td>
          <td>中高（K8s deploy + storage backend）</td>
      </tr>
      <tr>
          <td>Operational cost (200 host)</td>
          <td>$34K / month</td>
          <td>$8-12K / month（含 S3 + K8s）</td>
      </tr>
      <tr>
          <td>Operational cost (500 host)</td>
          <td>$80-150K / month</td>
          <td>$15-30K / month</td>
      </tr>
      <tr>
          <td>Operational FTE</td>
          <td>0.1-0.3</td>
          <td>1-2 FTE（K8s + storage + Grafana operator）</td>
      </tr>
      <tr>
          <td>Long-term retention</td>
          <td>$1.27 / million event for 15+ day</td>
          <td>S3 + Loki：~$0.02 / GB / month</td>
      </tr>
      <tr>
          <td>Multi-cloud / hybrid</td>
          <td>受 Datadog region 限</td>
          <td>自由部署</td>
      </tr>
      <tr>
          <td>Vendor lock-in</td>
          <td>高</td>
          <td>低（OSS + OTel）</td>
      </tr>
      <tr>
          <td>Time to value</td>
          <td>1-2 週</td>
          <td>4-8 週</td>
      </tr>
      <tr>
          <td>Migration cost (one-time)</td>
          <td>-</td>
          <td>1-3 FTE × 3 個月</td>
      </tr>
  </tbody>
</table>
<p><strong>Break-even point</strong>：~150 host 規模、3 年 amortized 後 self-hosted cheaper；&lt; 100 host 規模 SaaS 較 ROI 高。</p>
<h2 id="整合--下一步">整合 / 下一步</h2>
<h3 id="跟-opentelemetry-對齊">跟 OpenTelemetry 對齊</h3>
<p>Migration 是 <em>OTel-first 轉型</em> 的機會：</p>
<ul>
<li>Application code 用 OTel SDK、避免 Datadog SDK lock-in</li>
<li>Trace context propagation 走 W3C Trace Context</li>
<li>未來換 backend 不用再改 application</li>
</ul>
<h3 id="跟-splunk--elastic-對照">跟 <a href="/blog/backend/07-security-data-protection/vendors/splunk/migrate-to-elastic-security/" data-link-title="Splunk → Elastic Security Detection Rule Migration：6 段 phased playbook 跟 5 大踩雷" data-link-desc="從 Splunk Enterprise Security 遷到 Elastic Security 的 detection rule translation playbook：SPL ↔ KQL/ES|QL schema 對位、AI-assisted translation pipeline、parallel run 比對、cutover routing、5 個 production 踩雷（macro 沒對應 / time zone 差異 / summary index 不對位 / alert dedup key 衝突 / 過早 decommission）、capacity / cost 對照">Splunk → Elastic</a> 對照</h3>
<p>兩篇都是 <em>cost-driven SaaS migration</em>、但細節差：</p>
<ul>
<li>Splunk → Elastic 是 SIEM 領域、schema translation 是核心議題</li>
<li>Datadog → Grafana 是 multi-tool 拆分、agent + dashboard 重建是核心</li>
<li>共同 pattern：dual-ship → parallel run → cutover</li>
</ul>
<h3 id="反向遷移grafana-stack--datadog">反向遷移（Grafana Stack → Datadog）</h3>
<p>存在但少數 — 主要是 <em>operational complexity reduction</em>（不想自管 Mimir / Loki）；schema 對位方向相反、agent 換回 Datadog Agent。</p>
<h3 id="下一步議題">下一步議題</h3>
<ul>
<li><strong>Grafana Cloud 混合</strong>：部分 component（Tempo）用 Grafana Cloud SaaS、其他 self-host、混合架構</li>
<li><strong>OpenTelemetry Collector 跟 Alloy 取捨</strong>：兩者都是 OTel-based、Alloy 是 Grafana 自家 fork</li>
<li><strong>Vector vs Alloy vs Fluentd</strong>：log shipper 戰場、cost / 功能 / OTel 整合度比較</li>
</ul>
<h2 id="相關連結">相關連結</h2>
<ul>
<li>Source vendor：<a href="/blog/backend/04-observability/vendors/datadog/" data-link-title="Datadog" data-link-desc="All-in-one SaaS 觀測平台、APM / Logs / Metrics / RUM / Security">Datadog</a></li>
<li>Target vendor：<a href="/blog/backend/04-observability/vendors/grafana-stack/" data-link-title="Grafana Stack" data-link-desc="Grafana / Loki / Tempo / Mimir / Pyroscope 全棧">Grafana Stack</a></li>
<li>平行 vendor：<a href="/blog/backend/04-observability/vendors/elastic-stack/" data-link-title="Elastic Stack" data-link-desc="ELK：Elasticsearch / Logstash / Kibana &#43; Beats / APM">Elastic Stack</a> / <a href="/blog/backend/04-observability/vendors/opentelemetry/" data-link-title="OpenTelemetry" data-link-desc="可觀測性開放標準、SDK 與 Collector">OpenTelemetry</a></li>
<li>平行 migration playbook：<a href="/blog/backend/07-security-data-protection/vendors/splunk/migrate-to-elastic-security/" data-link-title="Splunk → Elastic Security Detection Rule Migration：6 段 phased playbook 跟 5 大踩雷" data-link-desc="從 Splunk Enterprise Security 遷到 Elastic Security 的 detection rule translation playbook：SPL ↔ KQL/ES|QL schema 對位、AI-assisted translation pipeline、parallel run 比對、cutover routing、5 個 production 踩雷（macro 沒對應 / time zone 差異 / summary index 不對位 / alert dedup key 衝突 / 過早 decommission）、capacity / cost 對照">Splunk → Elastic Security</a> / <a href="/blog/backend/02-cache-redis/vendors/redis/migrate-to-dragonflydb/" data-link-title="Redis → DragonflyDB：drop-in 相容下的容量躍升 &#43; 5 個踩雷" data-link-desc="DragonflyDB 號稱 Redis drop-in 替代、單機 throughput 25x、記憶體效率 30% 提升；遷移流程簡單但有 5 個 production 踩雷（RDB 版本差 / Lua 腳本不全支援 / Pub-Sub fanout 行為差異 / Cluster mode 兼容度 / Modules 不支援）、跟 Sentinel / Cluster 模式對位">Redis → DragonflyDB</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></li>
<li>Methodology：<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></li>
</ul>
]]></content:encoded></item></channel></rss>