<?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>Log-Pipeline on Tarragon</title><link>https://tarrragon.github.io/blog/tags/log-pipeline/</link><description>Recent content in Log-Pipeline 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/log-pipeline/index.xml" rel="self" type="application/rss+xml"/><item><title>Index Lifecycle Management 與 Log Pipeline</title><link>https://tarrragon.github.io/blog/backend/04-observability/vendors/elastic-stack/ilm-log-pipeline/</link><pubDate>Mon, 22 Jun 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/backend/04-observability/vendors/elastic-stack/ilm-log-pipeline/</guid><description>&lt;blockquote>
&lt;p>本文是 &lt;a href="https://tarrragon.github.io/blog/backend/04-observability/vendors/elastic-stack/" data-link-title="Elastic Stack" data-link-desc="ELK：Elasticsearch / Logstash / Kibana &amp;#43; Beats / APM">Elastic Stack&lt;/a> 的 vendor deep article，深化 overview「Index Lifecycle Management」跟「採集 pipeline」段。初次接觸 Elastic 的讀者建議先讀 &lt;a href="https://tarrragon.github.io/blog/backend/04-observability/vendors/elastic-stack/" data-link-title="Elastic Stack" data-link-desc="ELK：Elasticsearch / Logstash / Kibana &amp;#43; Beats / APM">Elastic Stack 服務頁&lt;/a>。&lt;/p>&lt;/blockquote>
&lt;h2 id="問題情境">問題情境&lt;/h2>
&lt;p>Elastic Stack 部署後，工程師通常能快速搜尋到 log。問題出在規模成長後：index 數量膨脹導致 cluster 效能退化、disk 滿了才發現沒有 lifecycle policy、shard 太小或太大造成查詢效能不均、採集 agent 的選擇在 Beats / Logstash / Elastic Agent / Fluent Bit 之間搖擺不定。ILM 跟 log pipeline 設計是 Elastic Stack 從「能用」到「可治理」的關鍵步驟。&lt;/p>
&lt;h2 id="核心概念">核心概念&lt;/h2>
&lt;h3 id="data-stream-vs-index-alias">Data Stream vs Index Alias&lt;/h3>
&lt;p>Elasticsearch 7.9+ 引入 data stream，取代傳統 index alias + rollover 模式。兩者的核心差異：&lt;/p>
&lt;p>&lt;strong>Data stream&lt;/strong> 是 append-only 的 time-series 資料結構。每個 data stream 下有多個 backing index，由 ILM 自動管理 rollover。寫入只能 append（沒有 update / delete single document），適合 log、metrics、traces。&lt;/p>
&lt;p>&lt;strong>Index alias&lt;/strong> 是傳統模式 — 手動建立 write alias 指向 current index，配合 ILM rollover action 觸發新 index 建立。支援 update / delete，適合需要修改文件的場景（例如 enrichment pipeline 的 lookup index）。&lt;/p>
&lt;p>選擇判讀：time-series 資料（log / metrics / APM trace）一律用 data stream。需要文件修改的 reference data、lookup table 用 index alias。新部署預設用 data stream，除非有明確理由。&lt;/p>
&lt;h3 id="ilm-policy-設計">ILM Policy 設計&lt;/h3>
&lt;p>ILM（Index Lifecycle Management）把 index 的生命週期分成五個 phase：&lt;/p>
&lt;p>&lt;strong>Hot phase&lt;/strong>：active write + 高頻查詢。Index 在 hot data node 上，用 SSD。Rollover 條件觸發後，current index 變 read-only，新 index 繼續寫入。&lt;/p>
&lt;p>&lt;strong>Warm phase&lt;/strong>：read-only + 中頻查詢。Index 搬到 warm data node（可以是 HDD 或較便宜的 SSD）。通常在 rollover 後 1-7 天觸發。可以執行 force merge（減少 segment 數量、提升查詢效能）跟 shrink（減少 shard 數量）。&lt;/p>
&lt;p>&lt;strong>Cold phase&lt;/strong>：searchable snapshot + 低頻查詢。Index 轉成 partial searchable snapshot，資料存在 object storage（S3 / GCS / Azure Blob），本地只保留 cache。查詢可用但較慢。適合 30 天到 1 年的保留。&lt;/p></description><content:encoded><![CDATA[<blockquote>
<p>本文是 <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> 的 vendor deep article，深化 overview「Index Lifecycle Management」跟「採集 pipeline」段。初次接觸 Elastic 的讀者建議先讀 <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>。</p></blockquote>
<h2 id="問題情境">問題情境</h2>
<p>Elastic Stack 部署後，工程師通常能快速搜尋到 log。問題出在規模成長後：index 數量膨脹導致 cluster 效能退化、disk 滿了才發現沒有 lifecycle policy、shard 太小或太大造成查詢效能不均、採集 agent 的選擇在 Beats / Logstash / Elastic Agent / Fluent Bit 之間搖擺不定。ILM 跟 log pipeline 設計是 Elastic Stack 從「能用」到「可治理」的關鍵步驟。</p>
<h2 id="核心概念">核心概念</h2>
<h3 id="data-stream-vs-index-alias">Data Stream vs Index Alias</h3>
<p>Elasticsearch 7.9+ 引入 data stream，取代傳統 index alias + rollover 模式。兩者的核心差異：</p>
<p><strong>Data stream</strong> 是 append-only 的 time-series 資料結構。每個 data stream 下有多個 backing index，由 ILM 自動管理 rollover。寫入只能 append（沒有 update / delete single document），適合 log、metrics、traces。</p>
<p><strong>Index alias</strong> 是傳統模式 — 手動建立 write alias 指向 current index，配合 ILM rollover action 觸發新 index 建立。支援 update / delete，適合需要修改文件的場景（例如 enrichment pipeline 的 lookup index）。</p>
<p>選擇判讀：time-series 資料（log / metrics / APM trace）一律用 data stream。需要文件修改的 reference data、lookup table 用 index alias。新部署預設用 data stream，除非有明確理由。</p>
<h3 id="ilm-policy-設計">ILM Policy 設計</h3>
<p>ILM（Index Lifecycle Management）把 index 的生命週期分成五個 phase：</p>
<p><strong>Hot phase</strong>：active write + 高頻查詢。Index 在 hot data node 上，用 SSD。Rollover 條件觸發後，current index 變 read-only，新 index 繼續寫入。</p>
<p><strong>Warm phase</strong>：read-only + 中頻查詢。Index 搬到 warm data node（可以是 HDD 或較便宜的 SSD）。通常在 rollover 後 1-7 天觸發。可以執行 force merge（減少 segment 數量、提升查詢效能）跟 shrink（減少 shard 數量）。</p>
<p><strong>Cold phase</strong>：searchable snapshot + 低頻查詢。Index 轉成 partial searchable snapshot，資料存在 object storage（S3 / GCS / Azure Blob），本地只保留 cache。查詢可用但較慢。適合 30 天到 1 年的保留。</p>
<p><strong>Frozen phase</strong>：fully mounted searchable snapshot + 極低頻查詢。資料完全在 object storage，本地無 cache。查詢最慢但成本最低。適合 1 年以上的合規保留。</p>
<p><strong>Delete phase</strong>：刪除 index。保留期到期後自動清理。</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">PUT _ilm/policy/application-log-policy
</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">  &#34;policy&#34;: {
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">    &#34;phases&#34;: {
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">      &#34;hot&#34;: {
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">        &#34;actions&#34;: {
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">          &#34;rollover&#34;: {
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">            &#34;max_primary_shard_size&#34;: &#34;30gb&#34;,
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">            &#34;max_age&#34;: &#34;1d&#34;
</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">      },
</span></span><span class="line"><span class="ln">13</span><span class="cl">      &#34;warm&#34;: {
</span></span><span class="line"><span class="ln">14</span><span class="cl">        &#34;min_age&#34;: &#34;3d&#34;,
</span></span><span class="line"><span class="ln">15</span><span class="cl">        &#34;actions&#34;: {
</span></span><span class="line"><span class="ln">16</span><span class="cl">          &#34;forcemerge&#34;: {&#34;max_num_segments&#34;: 1},
</span></span><span class="line"><span class="ln">17</span><span class="cl">          &#34;shrink&#34;: {&#34;number_of_shards&#34;: 1}
</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></span><span class="line"><span class="ln">20</span><span class="cl">      &#34;cold&#34;: {
</span></span><span class="line"><span class="ln">21</span><span class="cl">        &#34;min_age&#34;: &#34;30d&#34;,
</span></span><span class="line"><span class="ln">22</span><span class="cl">        &#34;actions&#34;: {
</span></span><span class="line"><span class="ln">23</span><span class="cl">          &#34;searchable_snapshot&#34;: {
</span></span><span class="line"><span class="ln">24</span><span class="cl">            &#34;snapshot_repository&#34;: &#34;s3-repo&#34;
</span></span><span class="line"><span class="ln">25</span><span class="cl">          }
</span></span><span class="line"><span class="ln">26</span><span class="cl">        }
</span></span><span class="line"><span class="ln">27</span><span class="cl">      },
</span></span><span class="line"><span class="ln">28</span><span class="cl">      &#34;delete&#34;: {
</span></span><span class="line"><span class="ln">29</span><span class="cl">        &#34;min_age&#34;: &#34;365d&#34;,
</span></span><span class="line"><span class="ln">30</span><span class="cl">        &#34;actions&#34;: {&#34;delete&#34;: {}}
</span></span><span class="line"><span class="ln">31</span><span class="cl">      }
</span></span><span class="line"><span class="ln">32</span><span class="cl">    }
</span></span><span class="line"><span class="ln">33</span><span class="cl">  }
</span></span><span class="line"><span class="ln">34</span><span class="cl">}</span></span></code></pre></div><p>Rollover 條件的選擇：<code>max_primary_shard_size</code> 比 <code>max_size</code> 更精確（直接控制單一 primary shard 大小）。目標是每個 primary shard 在 20-50 GB 之間。太小（&lt; 5 GB）造成 shard 過多、cluster state 膨脹；太大（&gt; 50 GB）造成 recovery 慢、query 效能下降。</p>
<h3 id="儲存成長回推-lifecycle-設計">儲存成長回推 lifecycle 設計</h3>
<p><a href="/blog/backend/04-observability/cases/discord-storage-growth-observability-gap/" data-link-title="4.C13 Discord：從儲存問題回推觀測缺口" data-link-desc="每次儲存遷移都暴露觀測盲區，把儲存成長問題重新框架為訊號設計問題。">Discord 儲存成長案例</a>揭露一個在快速成長服務反覆出現的模式：資料量倍增後才發現 ILM 的 hot → warm → cold 邊界不對、hot tier 佔比過高是最常見的成本問題。</p>
<p>問題的根源是 ILM policy 在服務初期設計、之後沒有隨資料量調整。一個服務從 10 GB/day 成長到 100 GB/day 時：</p>
<ul>
<li><strong>Hot tier 膨脹</strong>：原本 hot phase 設 7 天、10 GB/day × 7 天 = 70 GB。成長到 100 GB/day 後、hot tier 變成 700 GB、SSD 成本是原來的 10 倍</li>
<li><strong>Warm tier 延遲啟動</strong>：如果 warm phase 的 <code>min_age</code> 仍然是 7 天、資料在最貴的 tier 停留太久</li>
<li><strong>Cold/frozen phase 未啟用</strong>：初期資料量小時 cold phase 看不到成本效益、成長後才發現 30 天以上的資料全在 warm tier SSD 上</li>
</ul>
<p>修法是把 ILM review 放進服務的 capacity review cadence（季度或半年）。Review 時看三個指標：<code>hot_data_size / total_data_size</code>（hot tier 佔比超過 30% 就該重新評估）、<code>warm_tier_age_distribution</code>（warm tier 是否堆了太多舊資料）、<code>monthly_storage_cost_trend</code>（成本是否跟資料量同比例增長）。</p>
<p>Searchable snapshot（cold/frozen phase）是成本降幅最大的一步 — 資料從 local SSD 搬到 object storage，儲存成本降 70-90%。但搬遷後查詢延遲從 ms 退化到秒級。判讀「什麼資料該移」的訊號是該 index 在過去 30 天的查詢頻率 — 沒被查過的 index 留在 warm tier 是浪費。</p>
<h3 id="採集-pipelinebeats-vs-elastic-agent-vs-第三方">採集 Pipeline：Beats vs Elastic Agent vs 第三方</h3>
<table>
  <thead>
      <tr>
          <th>採集工具</th>
          <th>定位</th>
          <th>適用場景</th>
          <th>管理模式</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Filebeat</td>
          <td>單用途 log 採集</td>
          <td>成熟穩定、資源消耗低、K8s 環境輕量</td>
          <td>手動 config / ConfigMap</td>
      </tr>
      <tr>
          <td>Metricbeat</td>
          <td>單用途 metrics 採集</td>
          <td>host / container / service metrics</td>
          <td>手動 config</td>
      </tr>
      <tr>
          <td>Elastic Agent</td>
          <td>統一採集 agent</td>
          <td>logs + metrics + security + APM、Fleet 集中管理</td>
          <td>Fleet Server 集中</td>
      </tr>
      <tr>
          <td>Logstash</td>
          <td>重型 ETL pipeline</td>
          <td>複雜 parsing / enrichment / 多 output</td>
          <td>手動 config</td>
      </tr>
      <tr>
          <td>Fluent Bit / Vector</td>
          <td>第三方輕量 agent</td>
          <td>多 destination、低 resource、OTel 整合</td>
          <td>手動 config</td>
      </tr>
  </tbody>
</table>
<p>選擇判讀：</p>
<ul>
<li><strong>新部署、想要集中管理</strong>：Elastic Agent + Fleet。Fleet Server 提供 policy 集中推送、版本升級、health monitoring。代價是 Fleet Server 自身需要維運。</li>
<li><strong>既有 Beats 部署、穩定運行</strong>：不急著遷移。Elastic Agent 的 Beats integration 內部仍用 Beats 引擎。</li>
<li><strong>K8s 環境、resource 敏感</strong>：Filebeat DaemonSet。資源消耗 ~50-100 MB per node，比 Elastic Agent 低。</li>
<li><strong>多 destination（ES + S3 + Kafka）</strong>：Logstash 或 Vector。Beats 的 output 只能寫一個 destination（除非用 output plugin hack）。</li>
<li><strong>已有 OTel Collector</strong>：OTel Collector 可以直接把 log 送到 Elasticsearch（OTLP exporter 或 Elasticsearch exporter），不需要額外 Beats。</li>
</ul>
<h2 id="配置-step-by-step">配置 step-by-step</h2>
<h3 id="ingest-pipeline-設計">Ingest Pipeline 設計</h3>
<p>Ingest pipeline 在 Elasticsearch 層做 log 的 parsing 跟 enrichment，在 index 前處理。</p>
<p>常用 processor：</p>
<ul>
<li><strong>grok</strong>：regex pattern 解析非結構化 log。適合 nginx access log、syslog 等固定格式。</li>
<li><strong>dissect</strong>：delimiter-based parsing。比 grok 快 5-10 倍，但只能處理固定 delimiter 格式。</li>
<li><strong>date</strong>：把 log 中的 timestamp string 解析成 <code>@timestamp</code>。</li>
<li><strong>geoip</strong>：IP 地址轉地理位置。</li>
<li><strong>script</strong>：Painless script 做自訂轉換。效能代價高，只在其他 processor 做不到時使用。</li>
<li><strong>set / rename / remove</strong>：field 操作。</li>
</ul>
<p>Pipeline 設計原則：先用 dissect（快）、dissect 做不到才用 grok（慢）。Pipeline 中的 processor 數量跟複雜度直接影響 ingest 吞吐。高 volume 場景（&gt; 10K events/sec per node）要做 ingest pipeline benchmark。</p>
<h3 id="mapping-template-與-dynamic-mapping-治理">Mapping Template 與 Dynamic Mapping 治理</h3>
<p>Mapping template 定義 index 的 field type。Dynamic mapping 對未知 field 自動建立 mapping — 這是 Elastic 的便利功能，也是最常見的治理問題。</p>
<p><strong>Dynamic mapping 風險</strong>：application log 帶 arbitrary JSON payload，dynamic mapping 對每個 key 建立 field mapping。一個 log 帶 100 個 unique key → 100 個 field mapping。大量 unique key 會導致 mapping explosion（field 數量爆、cluster state 膨脹、query routing 變慢）。</p>
<p><strong>治理策略</strong>：</p>
<ul>
<li>用 <code>dynamic: strict</code> 或 <code>dynamic: false</code>（strict = 拒絕未定義 field、false = 接受但不 index）</li>
<li>在 mapping template 明確定義已知 field，用 <code>dynamic_templates</code> 控制未知 field 的行為</li>
<li>對 arbitrary JSON payload 用 <code>flattened</code> field type（ES 7.3+）— 整個 JSON 存為 keyword，可查但不逐 key index</li>
</ul>





<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">PUT _index_template/app-logs
</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">  &#34;index_patterns&#34;: [&#34;app-logs-*&#34;],
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">  &#34;template&#34;: {
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">    &#34;mappings&#34;: {
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">      &#34;dynamic&#34;: &#34;strict&#34;,
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">      &#34;properties&#34;: {
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">        &#34;@timestamp&#34;: {&#34;type&#34;: &#34;date&#34;},
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">        &#34;message&#34;: {&#34;type&#34;: &#34;text&#34;},
</span></span><span class="line"><span class="ln">10</span><span class="cl">        &#34;log.level&#34;: {&#34;type&#34;: &#34;keyword&#34;},
</span></span><span class="line"><span class="ln">11</span><span class="cl">        &#34;service.name&#34;: {&#34;type&#34;: &#34;keyword&#34;},
</span></span><span class="line"><span class="ln">12</span><span class="cl">        &#34;trace.id&#34;: {&#34;type&#34;: &#34;keyword&#34;},
</span></span><span class="line"><span class="ln">13</span><span class="cl">        &#34;metadata&#34;: {&#34;type&#34;: &#34;flattened&#34;}
</span></span><span class="line"><span class="ln">14</span><span class="cl">      }
</span></span><span class="line"><span class="ln">15</span><span class="cl">    }
</span></span><span class="line"><span class="ln">16</span><span class="cl">  }
</span></span><span class="line"><span class="ln">17</span><span class="cl">}</span></span></code></pre></div><h3 id="shard-sizing">Shard Sizing</h3>
<p>Shard sizing 是 Elastic Stack 效能的核心變數。</p>
<p><strong>目標</strong>：每個 primary shard 20-50 GB（Elastic 官方建議）。每個 data node 管理的 shard 數量上限約 20 per GB heap（預設 heap 一般設 30 GB → ~600 shard per node）。</p>
<table>
  <thead>
      <tr>
          <th>場景</th>
          <th>日 ingest 量</th>
          <th>primary shard 數</th>
          <th>rollover 頻率</th>
          <th>建議</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>小型（&lt; 10 GB/day）</td>
          <td>5 GB</td>
          <td>1</td>
          <td>每天或 max_size 30 GB</td>
          <td>簡單 ILM 即可</td>
      </tr>
      <tr>
          <td>中型（10-100 GB/day）</td>
          <td>50 GB</td>
          <td>2-3</td>
          <td>每天</td>
          <td>warm + cold ILM</td>
      </tr>
      <tr>
          <td>大型（100+ GB/day）</td>
          <td>500 GB</td>
          <td>10-15</td>
          <td>每小時或 max_size 30 GB</td>
          <td>hot-warm-cold-frozen 全用</td>
      </tr>
  </tbody>
</table>
<p>Shard 過多的症狀：cluster state 過大（<code>_cluster/stats</code> 的 <code>indices.shards.total</code> 數千或數萬）、master node CPU 高（維護 cluster state）、recovery 慢。</p>
<p>Shard 過大的症狀：single shard query 慢（&gt; 500ms for simple filter）、segment merge 時間長、recovery 時單一 shard 復原需要數分鐘。</p>
<h3 id="shard-count-治理">Shard count 治理</h3>
<p>大量 index 場景（微服務架構下每個服務每天產生一個 data stream backing index）容易累積過多 shard。一個 50 服務的組織、每個服務每天 rollover 一次、primary + 1 replica = 100 shard/day。30 天後 hot + warm tier 有 3000 個 shard。</p>
<p>Elasticsearch 的經驗法則是每個 data node 管理的 shard 數量上限約 20 per GB heap。30 GB heap 的 node 約能管 600 個 shard。3000 個 shard 需要至少 5 個 data node 才不觸發效能退化。</p>
<p>降低 shard 數量的手段：</p>
<ul>
<li><strong>ILM shrink action</strong>：warm phase 把 primary shard 數量縮減（例如 3 → 1）。適合查詢頻率下降的舊 index</li>
<li><strong>延長 rollover 週期</strong>：如果單個服務的日資料量只有 1-2 GB，每天 rollover 產生的 shard 太小。調整 rollover 條件為 <code>max_primary_shard_size: 30gb</code>（讓系統自動決定 rollover 時機）而非固定 <code>max_age: 1d</code></li>
<li><strong>合併小服務</strong>：QPS 很低的服務共用同一個 data stream（用 <code>service.name</code> field 區分），減少 data stream 數量</li>
</ul>
<p>監控指標：<code>_cat/health</code> 的 <code>active_shards</code> 持續觀察趨勢。設 alert 在 shard count 超過 <code>data_node_count × 500</code> 時通知（留 buffer 給 recovery 跟 rebalance）。</p>
<h2 id="故障演練與邊界">故障演練與邊界</h2>
<h3 id="ilm-rollover-沒觸發">ILM rollover 沒觸發</h3>
<p><strong>觸發條件</strong>：ILM policy 已設定但 rollover action 沒有執行。常見原因：index 沒有正確關聯到 ILM policy、或 ILM 被暫停（<code>_ilm/stop</code>）。</p>
<p><strong>判讀</strong>：用 <code>GET &lt;index&gt;/_ilm/explain</code> 看 ILM 狀態。<code>managed: false</code> 代表 index 不受 ILM 管理。<code>step: ERROR</code> 代表 ILM 卡在某個 action。</p>
<p><strong>修復</strong>：確認 index template 的 <code>index.lifecycle.name</code> 指向正確的 ILM policy。如果 ILM step error，用 <code>POST &lt;index&gt;/_ilm/retry</code> 重試。</p>
<h3 id="searchable-snapshot-查詢延遲高">Searchable snapshot 查詢延遲高</h3>
<p><strong>觸發條件</strong>：cold / frozen phase 的 searchable snapshot index 被高頻查詢。</p>
<p><strong>表現</strong>：query latency 從 ms 級退化到秒級。原因是每次查詢需要從 object storage（S3 / GCS）拉資料。</p>
<p><strong>修復</strong>：cold phase 有 local cache、查重複 query 較快；frozen phase 無 cache、每次都拉。如果查詢頻率高到需要 sub-second 回應，這些 index 不應該在 cold/frozen phase — 調整 ILM policy 的 <code>min_age</code> 讓它們留在 warm phase 更久。</p>
<h3 id="cross-cluster-search-vs-replication">Cross-cluster search vs replication</h3>
<p><strong>Cross-cluster search（CCS）</strong>：查詢時 fan-out 到遠端 cluster。適合偶爾跨 cluster 查詢、不需要常駐複製。代價是查詢 latency 包含跨 cluster 的網路延遲。</p>
<p><strong>Cross-cluster replication（CCR）</strong>：把 index 從 leader cluster 持續複製到 follower cluster。適合 DR、地理就近讀取。代價是複製的 storage 跟網路頻寬成本。</p>
<p>選擇判讀：「偶爾查」→ CCS。「需要低延遲讀 + DR」→ CCR。兩者可以並存。</p>
<h2 id="容量與成本">容量與成本</h2>
<p>Elastic Stack 的成本由三個維度決定：</p>
<p><strong>License tier</strong>：Basic（免費、含 ILM / data streams）→ Gold（ML / alerting）→ Platinum（SIEM / endpoint）→ Enterprise。Elastic Cloud 的計費另加 infrastructure cost。</p>
<p><strong>Data tier storage</strong>：hot tier 用 SSD（最貴）、warm tier 用 HDD 或便宜 SSD、cold/frozen tier 用 object storage（最便宜）。ILM 的 phase 設計直接影響 storage cost。</p>
<p><strong>Node 數量</strong>：每增加 data node 增加 compute 成本。Shard sizing 跟 ILM 設計決定需要多少 node。</p>
<p>成本最佳化優先序：</p>
<ol>
<li><strong>ILM + searchable snapshot</strong>：30 天後移到 cold/frozen，storage 成本降 70-90%</li>
<li><strong>Shard sizing</strong>：避免 shard 過多造成的 cluster overhead</li>
<li><strong>Ingest pipeline</strong>：在 ingest 層 drop 不需要的 field，減少 index size</li>
<li><strong>Mapping 治理</strong>：避免 mapping explosion 造成的 cluster state overhead</li>
<li><strong>Retention policy</strong>：明確設定 delete phase，不讓過期資料佔空間</li>
</ol>
<h2 id="整合與下一步">整合與下一步</h2>
<ul>
<li><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>：overview 與日常操作</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/telemetry-data-quality/" data-link-title="4.17 Telemetry Data Quality" data-link-desc="把 missing signal、schema drift、sampling bias 與 timestamp skew 變成資料品質問題">4.17 telemetry data quality</a>：mapping drift 跟 field missing 的資料品質面</li>
<li><a href="/blog/backend/04-observability/cases/healthcare-access-traceability-and-retention/" data-link-title="Healthcare：存取可追溯性與保留邊界" data-link-desc="在資料主權限制下，建立可追溯存取證據與分層保留策略。">4.C3 Healthcare retention</a>：ILM + searchable snapshot 在合規場景的應用</li>
<li><a href="../migrate-to-elastic-cloud/">Elastic Cloud migration</a>：從自管 Elastic 遷移到 Elastic Cloud</li>
</ul>
]]></content:encoded></item></channel></rss>