<?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>Ingestion on Tarragon</title><link>https://tarrragon.github.io/blog/tags/ingestion/</link><description>Recent content in Ingestion on Tarragon</description><generator>Hugo -- gohugo.io</generator><language>zh-TW</language><copyright>Tarragon (CC BY 4.0)</copyright><lastBuildDate>Sat, 20 Jun 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://tarrragon.github.io/blog/tags/ingestion/index.xml" rel="self" type="application/rss+xml"/><item><title>Ingestion Scaling</title><link>https://tarrragon.github.io/blog/monitoring/04-collector/ingestion-scaling/</link><pubDate>Sat, 20 Jun 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/monitoring/04-collector/ingestion-scaling/</guid><description>&lt;p>Ingestion scaling 處理的是「大量事件同時湧入 collector 時怎麼辦」。這和 storage scaling（&lt;a href="https://tarrragon.github.io/blog/monitoring/04-collector/scaling-evolution/" data-link-title="規模演進" data-link-desc="可插拔 Storage Backend 架構 — SQLite 預設、PostgreSQL 觸發切換、時間序列 DB 長期演進">SQLite → PostgreSQL 的可插拔 backend&lt;/a>）是兩個獨立的擴展軸 — storage scaling 解決「查得動嗎」，ingestion scaling 解決「收得下嗎」。一個 collector 可能 storage 用 PostgreSQL（查詢能力足夠）但 ingestion 撐不住（HTTP 請求太多），反之亦然。&lt;/p>
&lt;h2 id="四層防線">四層防線&lt;/h2>
&lt;p>每一層在不同規模觸發，由近到遠依序啟用。前一層能擋住的流量不需要啟用後一層。本章的四層按防線位置劃分（SDK / Collector / 基礎設施兩層）。DevOps 的&lt;a href="https://tarrragon.github.io/blog/devops/07-burst-traffic/scale-tier-response/" data-link-title="規模分級應對表" data-link-desc="自用級 → 中型 → 大型 → 商業網站級的四級應對方案 — 每級的觸發條件、架構組成和成本">規模分級應對表&lt;/a>按 events/sec 量級劃分（Tier 1-4），兩者視角不同但覆蓋相同的擴展路徑。&lt;/p>
&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>一&lt;/td>
 &lt;td>SDK 端取樣 + 聚合前移&lt;/td>
 &lt;td>SDK&lt;/td>
 &lt;td>高頻事件超過合理粒度&lt;/td>
 &lt;td>所有規模&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>二&lt;/td>
 &lt;td>Collector 單機背壓 + rate limit&lt;/td>
 &lt;td>Collector&lt;/td>
 &lt;td>寫入 channel 接近滿載&lt;/td>
 &lt;td>自用 ~ 小型&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>三&lt;/td>
 &lt;td>水平擴展（多 collector + LB）&lt;/td>
 &lt;td>基礎設施&lt;/td>
 &lt;td>單機 CPU / 連線數飽和&lt;/td>
 &lt;td>中型 ~ 大型&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>四&lt;/td>
 &lt;td>Queue 解耦（Kafka / NATS）&lt;/td>
 &lt;td>基礎設施&lt;/td>
 &lt;td>突發流量超過 collector 群的即時處理能力&lt;/td>
 &lt;td>商業網站級&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;h2 id="第一層sdk-端的流量控制">第一層：SDK 端的流量控制&lt;/h2>
&lt;p>流量控制的最有效位置是事件產生的源頭。SDK 端減少的事件量，後面每一層都不需要處理。&lt;/p>
&lt;h3 id="動態取樣">動態取樣&lt;/h3>
&lt;p>SDK 在收到 collector 的 HTTP 429（Too Many Requests）回應時，自動降低取樣率。恢復正常後逐步回升。&lt;/p>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-text" data-lang="text">&lt;span class="line">&lt;span class="ln">1&lt;/span>&lt;span class="cl">正常 → sampling 1.0
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">2&lt;/span>&lt;span class="cl">收到 429 → sampling 降到 0.5
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">3&lt;/span>&lt;span class="cl">持續 429 → sampling 降到 0.1
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">4&lt;/span>&lt;span class="cl">連續 10 次成功 → sampling 回升到 0.5
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">5&lt;/span>&lt;span class="cl">連續 30 次成功 → sampling 回到 1.0&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>動態取樣的控制邏輯在 SDK 端實作，不需要 collector 端額外支援 — 429 回應碼就是觸發訊號。和&lt;a href="https://tarrragon.github.io/blog/monitoring/03-sdk-design/sensor-lifecycle-management/" data-link-title="感測器生命週期管理" data-link-desc="產品生命週期的五個階段各啟用什麼感測器 — feature flag 整合、取樣率動態調整、感測器開關的可觀察性">感測器生命週期管理&lt;/a>的靜態取樣率互補 — 靜態取樣在 config 中設定、動態取樣在執行期自動調整。&lt;/p>
&lt;h3 id="聚合前移">聚合前移&lt;/h3>
&lt;p>SDK 端累積一段時間的同名事件，送出摘要而非逐筆。適合 metric 類的高頻取樣。&lt;/p>
&lt;p>例：原本每 100ms 送一筆 &lt;code>render.frame_drop&lt;/code>，改成每 5 秒送一筆 &lt;code>render.frame_drop_summary&lt;/code>（帶 count + min + max + avg）。事件數從 50 筆/5s 降到 1 筆/5s。&lt;/p>
&lt;p>聚合前移犧牲事件粒度換取吞吐量。只適合「趨勢比每筆細節重要」的 metric 類事件。Error 和 lifecycle 事件不做聚合 — 每筆的 stack trace 和狀態轉換都有 debug 價值。&lt;/p></description><content:encoded><![CDATA[<p>Ingestion scaling 處理的是「大量事件同時湧入 collector 時怎麼辦」。這和 storage scaling（<a href="/blog/monitoring/04-collector/scaling-evolution/" data-link-title="規模演進" data-link-desc="可插拔 Storage Backend 架構 — SQLite 預設、PostgreSQL 觸發切換、時間序列 DB 長期演進">SQLite → PostgreSQL 的可插拔 backend</a>）是兩個獨立的擴展軸 — storage scaling 解決「查得動嗎」，ingestion scaling 解決「收得下嗎」。一個 collector 可能 storage 用 PostgreSQL（查詢能力足夠）但 ingestion 撐不住（HTTP 請求太多），反之亦然。</p>
<h2 id="四層防線">四層防線</h2>
<p>每一層在不同規模觸發，由近到遠依序啟用。前一層能擋住的流量不需要啟用後一層。本章的四層按防線位置劃分（SDK / Collector / 基礎設施兩層）。DevOps 的<a href="/blog/devops/07-burst-traffic/scale-tier-response/" data-link-title="規模分級應對表" data-link-desc="自用級 → 中型 → 大型 → 商業網站級的四級應對方案 — 每級的觸發條件、架構組成和成本">規模分級應對表</a>按 events/sec 量級劃分（Tier 1-4），兩者視角不同但覆蓋相同的擴展路徑。</p>
<table>
  <thead>
      <tr>
          <th>層</th>
          <th>機制</th>
          <th>在哪裡做</th>
          <th>觸發條件</th>
          <th>適用規模</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>一</td>
          <td>SDK 端取樣 + 聚合前移</td>
          <td>SDK</td>
          <td>高頻事件超過合理粒度</td>
          <td>所有規模</td>
      </tr>
      <tr>
          <td>二</td>
          <td>Collector 單機背壓 + rate limit</td>
          <td>Collector</td>
          <td>寫入 channel 接近滿載</td>
          <td>自用 ~ 小型</td>
      </tr>
      <tr>
          <td>三</td>
          <td>水平擴展（多 collector + LB）</td>
          <td>基礎設施</td>
          <td>單機 CPU / 連線數飽和</td>
          <td>中型 ~ 大型</td>
      </tr>
      <tr>
          <td>四</td>
          <td>Queue 解耦（Kafka / NATS）</td>
          <td>基礎設施</td>
          <td>突發流量超過 collector 群的即時處理能力</td>
          <td>商業網站級</td>
      </tr>
  </tbody>
</table>
<h2 id="第一層sdk-端的流量控制">第一層：SDK 端的流量控制</h2>
<p>流量控制的最有效位置是事件產生的源頭。SDK 端減少的事件量，後面每一層都不需要處理。</p>
<h3 id="動態取樣">動態取樣</h3>
<p>SDK 在收到 collector 的 HTTP 429（Too Many Requests）回應時，自動降低取樣率。恢復正常後逐步回升。</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">正常 → sampling 1.0
</span></span><span class="line"><span class="ln">2</span><span class="cl">收到 429 → sampling 降到 0.5
</span></span><span class="line"><span class="ln">3</span><span class="cl">持續 429 → sampling 降到 0.1
</span></span><span class="line"><span class="ln">4</span><span class="cl">連續 10 次成功 → sampling 回升到 0.5
</span></span><span class="line"><span class="ln">5</span><span class="cl">連續 30 次成功 → sampling 回到 1.0</span></span></code></pre></div><p>動態取樣的控制邏輯在 SDK 端實作，不需要 collector 端額外支援 — 429 回應碼就是觸發訊號。和<a href="/blog/monitoring/03-sdk-design/sensor-lifecycle-management/" data-link-title="感測器生命週期管理" data-link-desc="產品生命週期的五個階段各啟用什麼感測器 — feature flag 整合、取樣率動態調整、感測器開關的可觀察性">感測器生命週期管理</a>的靜態取樣率互補 — 靜態取樣在 config 中設定、動態取樣在執行期自動調整。</p>
<h3 id="聚合前移">聚合前移</h3>
<p>SDK 端累積一段時間的同名事件，送出摘要而非逐筆。適合 metric 類的高頻取樣。</p>
<p>例：原本每 100ms 送一筆 <code>render.frame_drop</code>，改成每 5 秒送一筆 <code>render.frame_drop_summary</code>（帶 count + min + max + avg）。事件數從 50 筆/5s 降到 1 筆/5s。</p>
<p>聚合前移犧牲事件粒度換取吞吐量。只適合「趨勢比每筆細節重要」的 metric 類事件。Error 和 lifecycle 事件不做聚合 — 每筆的 stack trace 和狀態轉換都有 debug 價值。</p>
<h3 id="優先級丟棄">優先級丟棄</h3>
<p>SDK 的離線 buffer 滿時，按優先級丟棄。Error 的 debug 價值最高，最後丟。</p>
<table>
  <thead>
      <tr>
          <th>優先級</th>
          <th>事件類型</th>
          <th>理由</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>高</td>
          <td>error</td>
          <td>每筆都可能是需要修的 bug</td>
      </tr>
      <tr>
          <td>高</td>
          <td>lifecycle</td>
          <td>session 邊界和狀態轉換、影響 debug 和 cohort</td>
      </tr>
      <tr>
          <td>中</td>
          <td>metric</td>
          <td>丟幾筆不影響趨勢（聚合摘要仍然有效）</td>
      </tr>
      <tr>
          <td>低</td>
          <td>event</td>
          <td>行為事件在取樣後丟幾筆對 funnel 影響有限</td>
      </tr>
  </tbody>
</table>
<h2 id="第二層collector-單機的防護">第二層：Collector 單機的防護</h2>
<p>Collector 在自身能力範圍內保護自己不被壓垮。和 <a href="/blog/monitoring/04-collector/architecture/" data-link-title="Collector 架構" data-link-desc="HTTP endpoint → JSON Schema 驗證 → 儲存 → 查詢 → rule engine 的五段式處理鏈路">architecture.md 的並發寫入策略</a>直接相關 — 寫入 channel 是背壓的實作基礎。背壓和流量管控的通用概念見 <a href="/blog/devops/03-traffic-management/" data-link-title="模組三：流量管控" data-link-desc="收到的流量超過處理能力時怎麼辦 — 背壓、rate limit、熔斷、bulkhead 四種防護機制">DevOps 流量管控</a>。</p>
<h3 id="寫入-channel-容量--背壓">寫入 channel 容量 + 背壓</h3>
<p>Single-writer goroutine pattern 的 Go channel 有固定容量（如 10,000）。Channel 滿時 HTTP handler 無法送入事件，此時回 429：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="ln">1</span><span class="cl"><span class="k">select</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="k">case</span> <span class="nx">writeCh</span> <span class="o">&lt;-</span> <span class="nx">event</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">    <span class="nx">w</span><span class="p">.</span><span class="nf">WriteHeader</span><span class="p">(</span><span class="nx">http</span><span class="p">.</span><span class="nx">StatusAccepted</span><span class="p">)</span> <span class="c1">// 202</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="k">default</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl">    <span class="nx">w</span><span class="p">.</span><span class="nf">Header</span><span class="p">().</span><span class="nf">Set</span><span class="p">(</span><span class="s">&#34;Retry-After&#34;</span><span class="p">,</span> <span class="s">&#34;5&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">6</span><span class="cl">    <span class="nx">w</span><span class="p">.</span><span class="nf">WriteHeader</span><span class="p">(</span><span class="nx">http</span><span class="p">.</span><span class="nx">StatusTooManyRequests</span><span class="p">)</span> <span class="c1">// 429</span>
</span></span><span class="line"><span class="ln">7</span><span class="cl"><span class="p">}</span></span></span></code></pre></div><p>Channel 容量的設定依據：容量 × 每筆事件的記憶體大小 = 背壓 buffer 的記憶體上限。10,000 筆 × 每筆 ~1KB = ~10MB，對多數機器微不足道。</p>
<h3 id="per-sdk-rate-limiting">Per-SDK rate limiting</h3>
<p>按 source.app（或 API key，啟用認證後）限制每個 SDK 實例的請求速率。防止單一 SDK 的 bug（無限迴圈送事件）打爆 collector。</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="ln">1</span><span class="cl"><span class="c1">// 每個 source.app 一個 rate limiter</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="nx">limiter</span> <span class="o">:=</span> <span class="nx">rateLimiters</span><span class="p">.</span><span class="nf">GetOrCreate</span><span class="p">(</span><span class="nx">sourceApp</span><span class="p">,</span> <span class="nx">rate</span><span class="p">.</span><span class="nf">Limit</span><span class="p">(</span><span class="mi">100</span><span class="p">))</span> <span class="c1">// 100 events/sec</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="k">if</span> <span class="p">!</span><span class="nx">limiter</span><span class="p">.</span><span class="nf">Allow</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl">    <span class="nx">w</span><span class="p">.</span><span class="nf">WriteHeader</span><span class="p">(</span><span class="nx">http</span><span class="p">.</span><span class="nx">StatusTooManyRequests</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl">    <span class="k">return</span>
</span></span><span class="line"><span class="ln">6</span><span class="cl"><span class="p">}</span></span></span></code></pre></div><h3 id="error-快通道">Error 快通道</h3>
<p>Error 事件不經 rate limit — 它們的 debug 價值最高，且在正常情況下數量遠少於其他類型。Error storm（app 出 bug 導致大量 error）時，error 的量可能暴增，但這正是最需要記錄的時刻。</p>
<p>Error 快通道用獨立的 channel 或跳過 rate limiter 的 check。如果 error 量也超出承載，用第一層的 SDK 端優先級丟棄處理。</p>
<h2 id="第三層水平擴展">第三層：水平擴展</h2>
<p>單機的 CPU、記憶體或網路頻寬飽和時，水平擴展 — 多個 collector 實例分攤流量。水平擴展的通用模式見 <a href="/blog/devops/02-horizontal-scaling/" data-link-title="模組二：水平擴展" data-link-desc="一個實例不夠時怎麼加第二個 — stateless 設計、shared storage、session 處理的工程約束">DevOps 水平擴展</a>。</p>
<h3 id="前提已切換到-postgresql">前提：已切換到 PostgreSQL</h3>
<p>SQLite backend 不支援水平擴展。每個 collector 實例有各自的 SQLite 檔案，無法合併查詢。水平擴展的前提是所有 collector 寫入同一個 PostgreSQL。</p>
<h3 id="架構">架構</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln"> 1</span><span class="cl">SDK ──→ Load Balancer (nginx / HAProxy)
</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></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">   Collector A  Collector B
</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></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">        PostgreSQL
</span></span><span class="line"><span class="ln">10</span><span class="cl">             │
</span></span><span class="line"><span class="ln">11</span><span class="cl">             ▼
</span></span><span class="line"><span class="ln">12</span><span class="cl">         Dashboard</span></span></code></pre></div><p>Collector 實例是 stateless 的 — 不在記憶體保存查詢狀態，所有持久化資料在 PostgreSQL。任何 collector 接收的事件都能被任何 dashboard 查到。</p>
<p>Load balancer 用 round-robin 或 least-connections 分配。不需要 sticky session — collector 不保存 session 狀態。</p>
<h3 id="多機的-downsample-和-purge">多機的 Downsample 和 Purge</h3>
<p>Downsample 和 Purge job 只能由一個 collector 實例執行（避免重複處理）。用 PostgreSQL 的 advisory lock 或外部的 distributed lock 確保單一執行者。</p>
<h2 id="第四層queue-解耦">第四層：Queue 解耦</h2>
<p>突發流量超過 collector 群的即時處理能力時，在 collector 和 storage 之間插入 message queue 做緩衝。Queue 緩衝的通用概念見 <a href="/blog/devops/07-burst-traffic/" data-link-title="模組七：突發流量應對" data-link-desc="行銷活動或新聞曝光帶來 10x-100x 流量時怎麼撐 — 突發分類、降級策略、queue 緩衝、規模分級應對">DevOps 突發流量應對</a>，message queue 的選型見 <a href="/blog/backend/03-message-queue/" data-link-title="模組三：訊息佇列與事件傳遞" data-link-desc="整理 durable queue、broker、retry、outbox 與 idempotency 的後端實務">Backend 模組三 非同步與訊息佇列</a>。</p>
<h3 id="架構-1">架構</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln"> 1</span><span class="cl">SDK ──→ Collector (ingestion only)
</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></span><span class="line"><span class="ln"> 4</span><span class="cl">        Queue (Kafka / NATS / Redis Streams)
</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></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">    Worker A   Worker B
</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></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">        PostgreSQL</span></span></code></pre></div><p>Collector 的職責簡化為「接收 → 驗證 → 寫入 queue → 回 202」。寫入 queue 比寫入 DB 快得多（append-only、不需要索引更新），collector 的吞吐上限大幅提升。</p>
<p>Worker 從 queue 消費、寫入 PostgreSQL。Worker 按自己的速度處理 — 高峰時 queue 積壓，高峰過後 worker 消化積壓。Queue 的持久化保證事件不遺失。</p>
<h3 id="queue-的選擇">Queue 的選擇</h3>
<table>
  <thead>
      <tr>
          <th>Queue</th>
          <th>適合場景</th>
          <th>代價</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Kafka</td>
          <td>高吞吐（百萬 events/sec）、需要 replay</td>
          <td>運維重（ZooKeeper / KRaft）</td>
      </tr>
      <tr>
          <td>NATS JetStream</td>
          <td>輕量、Go 原生、足夠的持久化</td>
          <td>生態較小</td>
      </tr>
      <tr>
          <td>Redis Streams</td>
          <td>簡單、如果已有 Redis</td>
          <td>不是專門的 queue、持久化設定需注意</td>
      </tr>
  </tbody>
</table>
<p>自架監控工具的 queue 層級推薦 NATS JetStream — Go 原生 client、單 binary 部署、JetStream 提供持久化和 replay。</p>
<h3 id="觸發條件">觸發條件</h3>
<p>Queue 解耦的引入時機是「collector 群已水平擴展但仍無法處理突發流量」。如果日常流量 collector 群能處理，只有行銷活動 / 新聞曝光的短暫高峰需要 queue 緩衝，queue 的維護成本可能高於收益 — 考慮用第一層的動態取樣在源頭降量。</p>
<h2 id="功能分層整合">功能分層整合</h2>
<p>擴展 <a href="/blog/monitoring/04-collector/feature-tier-boundary/" data-link-title="功能分層與 Backend 選擇" data-link-desc="SQLite 層和 PostgreSQL 層各自承載哪些功能 — 分界線是查詢模式而非資料量、觸發升級的是功能需求而非規模成長">功能分層與 Backend 選擇</a> 的分層表，加入 ingestion 維度：</p>
<table>
  <thead>
      <tr>
          <th>功能層級</th>
          <th>Storage</th>
          <th>Ingestion</th>
          <th>適用規模</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>SQLite 層</td>
          <td>SQLite embedded</td>
          <td>單 collector + 背壓</td>
          <td>自用 ~ 小型團隊</td>
      </tr>
      <tr>
          <td>PostgreSQL 層</td>
          <td>PostgreSQL</td>
          <td>多 collector + LB</td>
          <td>中型 ~ 大型</td>
      </tr>
      <tr>
          <td>Queue 層</td>
          <td>PostgreSQL</td>
          <td>Collector + Queue + Worker</td>
          <td>商業網站級</td>
      </tr>
  </tbody>
</table>
<p>每一層是前一層的超集 — Queue 層包含 PostgreSQL 層的所有查詢能力，加上 ingestion 的 queue 緩衝。</p>
<h2 id="下一步路由">下一步路由</h2>
<ul>
<li>Collector 的並發寫入策略 → <a href="/blog/monitoring/04-collector/architecture/" data-link-title="Collector 架構" data-link-desc="HTTP endpoint → JSON Schema 驗證 → 儲存 → 查詢 → rule engine 的五段式處理鏈路">Collector 架構</a></li>
<li>Storage 端的擴展設計 → <a href="/blog/monitoring/04-collector/scaling-evolution/" data-link-title="規模演進" data-link-desc="可插拔 Storage Backend 架構 — SQLite 預設、PostgreSQL 觸發切換、時間序列 DB 長期演進">規模演進</a></li>
<li>功能分層的定義 → <a href="/blog/monitoring/04-collector/feature-tier-boundary/" data-link-title="功能分層與 Backend 選擇" data-link-desc="SQLite 層和 PostgreSQL 層各自承載哪些功能 — 分界線是查詢模式而非資料量、觸發升級的是功能需求而非規模成長">功能分層與 Backend 選擇</a></li>
<li>背壓和流量管控的通用概念 → <a href="/blog/devops/03-traffic-management/" data-link-title="模組三：流量管控" data-link-desc="收到的流量超過處理能力時怎麼辦 — 背壓、rate limit、熔斷、bulkhead 四種防護機制">DevOps 流量管控</a></li>
<li>水平擴展的通用模式 → <a href="/blog/devops/02-horizontal-scaling/" data-link-title="模組二：水平擴展" data-link-desc="一個實例不夠時怎麼加第二個 — stateless 設計、shared storage、session 處理的工程約束">DevOps 水平擴展</a></li>
<li>突發流量應對 → <a href="/blog/devops/07-burst-traffic/" data-link-title="模組七：突發流量應對" data-link-desc="行銷活動或新聞曝光帶來 10x-100x 流量時怎麼撐 — 突發分類、降級策略、queue 緩衝、規模分級應對">DevOps 突發流量</a></li>
<li>Message queue 選型 → <a href="/blog/backend/03-message-queue/" data-link-title="模組三：訊息佇列與事件傳遞" data-link-desc="整理 durable queue、broker、retry、outbox 與 idempotency 的後端實務">Backend 模組三 非同步與訊息佇列</a></li>
<li>端到端資料完整性（資料損失地圖、完整性指標）→ <a href="/blog/monitoring/04-collector/data-integrity/" data-link-title="端到端資料完整性" data-link-desc="從 SDK 到 storage 的資料損失地圖 — 每個環節的損失類型、控制策略、完整性指標、被自己 SDK DDoS 的防護">端到端資料完整性</a></li>
</ul>
]]></content:encoded></item></channel></rss>