<?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>Spotify on Tarragon</title><link>https://tarrragon.github.io/blog/backend/06-reliability/cases/spotify/</link><description>Recent content in Spotify on Tarragon</description><generator>Hugo -- gohugo.io</generator><language>zh-TW</language><copyright>Tarragon (CC BY 4.0)</copyright><lastBuildDate>Fri, 01 May 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://tarrragon.github.io/blog/backend/06-reliability/cases/spotify/index.xml" rel="self" type="application/rss+xml"/><item><title>Spotify：Backstage Service Catalog 與 Reliability Metadata</title><link>https://tarrragon.github.io/blog/backend/06-reliability/cases/spotify/backstage-service-catalog-and-reliability-metadata/</link><pubDate>Tue, 23 Jun 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/backend/06-reliability/cases/spotify/backstage-service-catalog-and-reliability-metadata/</guid><description>&lt;p>Service catalog 在可靠性工程中的責任是讓每個服務的 reliability metadata 有單一查詢入口。事故發生時，團隊能在同一個地方找到 owner、SLO 狀態、依賴圖與 runbook，而不是在 wiki、Slack 與個人筆記之間來回搜尋。&lt;/p>
&lt;h2 id="問題場景">問題場景&lt;/h2>
&lt;p>Squad-based 組織結構讓團隊能獨立交付，但也讓服務數量快速增長。當服務超過數百個，metadata 開始散落在不同系統：ownership 記在 wiki、SLO 記在 monitoring 平台、runbook 記在文件庫、依賴關係靠口頭傳遞。事故時花時間找 owner 和 runbook 的成本直接拉長 &lt;a href="https://tarrragon.github.io/blog/backend/knowledge-cards/mttr/" data-link-title="MTTR" data-link-desc="說明平均修復時間如何作為事故處理能力指標">MTTR&lt;/a>。Spotify 用 Backstage 作為 service catalog，把這些 metadata 收攏到同一個入口。&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;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>Service ownership&lt;/td>
 &lt;td>這個服務歸誰管&lt;/td>
 &lt;td>強制 owner team&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>SLO metadata&lt;/td>
 &lt;td>這個服務的可靠性承諾是什麼&lt;/td>
 &lt;td>catalog 內嵌 SLO&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Dependency graph&lt;/td>
 &lt;td>這個服務依賴誰、誰依賴它&lt;/td>
 &lt;td>可查詢依賴圖&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Runbook linkage&lt;/td>
 &lt;td>出事時該看哪份 runbook&lt;/td>
 &lt;td>一鍵連結&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Metadata freshness&lt;/td>
 &lt;td>catalog 資料是否仍然準確&lt;/td>
 &lt;td>過期警告機制&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;p>Service ownership 是最基礎的一層。每個服務在 catalog 中必須有明確的 owner team，沒有 owner 的服務標記為 orphan 並進入清理追蹤。ownership 不只是名義歸屬，而是事故時的第一接手責任。&lt;/p>
&lt;p>SLO metadata 讓 catalog 不只是目錄，而是可靠性狀態的即時入口。團隊能在 catalog 頁面直接看到服務目前的 &lt;a href="https://tarrragon.github.io/blog/backend/knowledge-cards/error-budget/" data-link-title="Error Budget" data-link-desc="說明 SLO 允許的失敗額度如何影響發版與可靠性投入">error budget&lt;/a> 消耗狀態，判斷該服務的變更風險。&lt;/p>
&lt;p>Dependency graph 的價值在事故時最明顯。當一個服務異常時，catalog 能回答「還有誰會被影響」和「這個問題可能從哪裡傳過來」，讓事故指揮能快速判斷 &lt;a href="https://tarrragon.github.io/blog/backend/knowledge-cards/blast-radius/" data-link-title="Blast Radius" data-link-desc="說明事故影響面如何估算與隔離">blast radius&lt;/a>。&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;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>Orphan service count&lt;/td>
 &lt;td>無 owner 服務是否持續增加&lt;/td>
 &lt;td>&lt;a href="https://tarrragon.github.io/blog/backend/06-reliability/reliability-debt-backlog/" data-link-title="6.21 Reliability Debt Backlog" data-link-desc="把反覆事故、演練缺口與手動修復累積成可排序、可關閉的 reliability debt">6.21&lt;/a>&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Metadata freshness&lt;/td>
 &lt;td>catalog 資料是否仍然準確&lt;/td>
 &lt;td>&lt;a href="https://tarrragon.github.io/blog/backend/06-reliability/reliability-metrics-governance/" data-link-title="6.18 Reliability Metrics Governance" data-link-desc="DORA / SPACE 指標的選用、量測陷阱、anti-gaming 與團隊階段適配">6.18&lt;/a>&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Dependency coverage&lt;/td>
 &lt;td>依賴圖是否涵蓋關鍵路徑&lt;/td>
 &lt;td>&lt;a href="https://tarrragon.github.io/blog/backend/06-reliability/dependency-reliability-budget/" data-link-title="6.14 Dependency Reliability Budget" data-link-desc="把內外依賴的可靠性納入 SLO 計算與設計約束">6.14&lt;/a>&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>MTTR vs catalog coverage&lt;/td>
 &lt;td>catalog 覆蓋率是否與恢復速度相關&lt;/td>
 &lt;td>&lt;a href="https://tarrragon.github.io/blog/backend/08-incident-response/containment-recovery-strategy/" data-link-title="8.3 止血、降級與回復策略" data-link-desc="把短期止血與正式回復拆成可執行步驟">8.3&lt;/a>&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;h2 id="常見陷阱">常見陷阱&lt;/h2>
&lt;p>Catalog 最常見的失效模式是變成靜態文件。若 metadata 靠人工維護但沒有 freshness check，catalog 會隨時間漂移 — owner 換了團隊但 catalog 沒更新、SLO 調整了但 catalog 還是舊值、依賴關係變了但 graph 沒有同步。事故時從 catalog 拿到過期資訊，比沒有 catalog 更危險，因為團隊會信任它。維持 catalog 價值的關鍵是自動化校驗：定期掃描 orphan service、比對 SLO metadata 與 monitoring 平台的實際值、用 runtime trace 驗證依賴圖的準確性。&lt;/p>
&lt;h2 id="下一步路由">下一步路由&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/backend/06-reliability/dependency-reliability-budget/" data-link-title="6.14 Dependency Reliability Budget" data-link-desc="把內外依賴的可靠性納入 SLO 計算與設計約束">6.14 dependency reliability budget&lt;/a>：catalog 的依賴圖是 dependency budget 的資料來源&lt;/li>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/backend/06-reliability/reliability-metrics-governance/" data-link-title="6.18 Reliability Metrics Governance" data-link-desc="DORA / SPACE 指標的選用、量測陷阱、anti-gaming 與團隊階段適配">6.18 reliability metrics governance&lt;/a>：catalog coverage 與 metadata freshness 本身是可靠性指標&lt;/li>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/backend/06-reliability/reliability-readiness-review/" data-link-title="6.19 Reliability Readiness Review" data-link-desc="把上線前、重大變更前與高風險操作前的可靠性準備度變成可檢查門檻">6.19 reliability readiness review&lt;/a>：readiness checklist 可從 catalog 自動拉取&lt;/li>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/backend/06-reliability/reliability-debt-backlog/" data-link-title="6.21 Reliability Debt Backlog" data-link-desc="把反覆事故、演練缺口與手動修復累積成可排序、可關閉的 reliability debt">6.21 reliability debt backlog&lt;/a>：orphan service 與過期 metadata 是 reliability debt&lt;/li>
&lt;/ul>
&lt;h2 id="引用源">引用源&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://backstage.io/">Backstage.io&lt;/a>：Spotify 開源的 developer portal 框架&lt;/li>
&lt;li>&lt;a href="https://backstage.spotify.com/">Spotify Engineering: What is Backstage?&lt;/a>：Backstage 的設計理念與架構&lt;/li>
&lt;/ul></description><content:encoded><![CDATA[<p>Service catalog 在可靠性工程中的責任是讓每個服務的 reliability metadata 有單一查詢入口。事故發生時，團隊能在同一個地方找到 owner、SLO 狀態、依賴圖與 runbook，而不是在 wiki、Slack 與個人筆記之間來回搜尋。</p>
<h2 id="問題場景">問題場景</h2>
<p>Squad-based 組織結構讓團隊能獨立交付，但也讓服務數量快速增長。當服務超過數百個，metadata 開始散落在不同系統：ownership 記在 wiki、SLO 記在 monitoring 平台、runbook 記在文件庫、依賴關係靠口頭傳遞。事故時花時間找 owner 和 runbook 的成本直接拉長 <a href="/blog/backend/knowledge-cards/mttr/" data-link-title="MTTR" data-link-desc="說明平均修復時間如何作為事故處理能力指標">MTTR</a>。Spotify 用 Backstage 作為 service catalog，把這些 metadata 收攏到同一個入口。</p>
<h2 id="決策機制">決策機制</h2>
<table>
  <thead>
      <tr>
          <th>機制</th>
          <th>核心問題</th>
          <th>交付結果</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Service ownership</td>
          <td>這個服務歸誰管</td>
          <td>強制 owner team</td>
      </tr>
      <tr>
          <td>SLO metadata</td>
          <td>這個服務的可靠性承諾是什麼</td>
          <td>catalog 內嵌 SLO</td>
      </tr>
      <tr>
          <td>Dependency graph</td>
          <td>這個服務依賴誰、誰依賴它</td>
          <td>可查詢依賴圖</td>
      </tr>
      <tr>
          <td>Runbook linkage</td>
          <td>出事時該看哪份 runbook</td>
          <td>一鍵連結</td>
      </tr>
      <tr>
          <td>Metadata freshness</td>
          <td>catalog 資料是否仍然準確</td>
          <td>過期警告機制</td>
      </tr>
  </tbody>
</table>
<p>Service ownership 是最基礎的一層。每個服務在 catalog 中必須有明確的 owner team，沒有 owner 的服務標記為 orphan 並進入清理追蹤。ownership 不只是名義歸屬，而是事故時的第一接手責任。</p>
<p>SLO metadata 讓 catalog 不只是目錄，而是可靠性狀態的即時入口。團隊能在 catalog 頁面直接看到服務目前的 <a href="/blog/backend/knowledge-cards/error-budget/" data-link-title="Error Budget" data-link-desc="說明 SLO 允許的失敗額度如何影響發版與可靠性投入">error budget</a> 消耗狀態，判斷該服務的變更風險。</p>
<p>Dependency graph 的價值在事故時最明顯。當一個服務異常時，catalog 能回答「還有誰會被影響」和「這個問題可能從哪裡傳過來」，讓事故指揮能快速判斷 <a href="/blog/backend/knowledge-cards/blast-radius/" data-link-title="Blast Radius" data-link-desc="說明事故影響面如何估算與隔離">blast radius</a>。</p>
<h2 id="可觀測訊號">可觀測訊號</h2>
<table>
  <thead>
      <tr>
          <th>訊號</th>
          <th>判讀重點</th>
          <th>對應章節</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Orphan service count</td>
          <td>無 owner 服務是否持續增加</td>
          <td><a href="/blog/backend/06-reliability/reliability-debt-backlog/" data-link-title="6.21 Reliability Debt Backlog" data-link-desc="把反覆事故、演練缺口與手動修復累積成可排序、可關閉的 reliability debt">6.21</a></td>
      </tr>
      <tr>
          <td>Metadata freshness</td>
          <td>catalog 資料是否仍然準確</td>
          <td><a href="/blog/backend/06-reliability/reliability-metrics-governance/" data-link-title="6.18 Reliability Metrics Governance" data-link-desc="DORA / SPACE 指標的選用、量測陷阱、anti-gaming 與團隊階段適配">6.18</a></td>
      </tr>
      <tr>
          <td>Dependency coverage</td>
          <td>依賴圖是否涵蓋關鍵路徑</td>
          <td><a href="/blog/backend/06-reliability/dependency-reliability-budget/" data-link-title="6.14 Dependency Reliability Budget" data-link-desc="把內外依賴的可靠性納入 SLO 計算與設計約束">6.14</a></td>
      </tr>
      <tr>
          <td>MTTR vs catalog coverage</td>
          <td>catalog 覆蓋率是否與恢復速度相關</td>
          <td><a href="/blog/backend/08-incident-response/containment-recovery-strategy/" data-link-title="8.3 止血、降級與回復策略" data-link-desc="把短期止血與正式回復拆成可執行步驟">8.3</a></td>
      </tr>
  </tbody>
</table>
<h2 id="常見陷阱">常見陷阱</h2>
<p>Catalog 最常見的失效模式是變成靜態文件。若 metadata 靠人工維護但沒有 freshness check，catalog 會隨時間漂移 — owner 換了團隊但 catalog 沒更新、SLO 調整了但 catalog 還是舊值、依賴關係變了但 graph 沒有同步。事故時從 catalog 拿到過期資訊，比沒有 catalog 更危險，因為團隊會信任它。維持 catalog 價值的關鍵是自動化校驗：定期掃描 orphan service、比對 SLO metadata 與 monitoring 平台的實際值、用 runtime trace 驗證依賴圖的準確性。</p>
<h2 id="下一步路由">下一步路由</h2>
<ul>
<li><a href="/blog/backend/06-reliability/dependency-reliability-budget/" data-link-title="6.14 Dependency Reliability Budget" data-link-desc="把內外依賴的可靠性納入 SLO 計算與設計約束">6.14 dependency reliability budget</a>：catalog 的依賴圖是 dependency budget 的資料來源</li>
<li><a href="/blog/backend/06-reliability/reliability-metrics-governance/" data-link-title="6.18 Reliability Metrics Governance" data-link-desc="DORA / SPACE 指標的選用、量測陷阱、anti-gaming 與團隊階段適配">6.18 reliability metrics governance</a>：catalog coverage 與 metadata freshness 本身是可靠性指標</li>
<li><a href="/blog/backend/06-reliability/reliability-readiness-review/" data-link-title="6.19 Reliability Readiness Review" data-link-desc="把上線前、重大變更前與高風險操作前的可靠性準備度變成可檢查門檻">6.19 reliability readiness review</a>：readiness checklist 可從 catalog 自動拉取</li>
<li><a href="/blog/backend/06-reliability/reliability-debt-backlog/" data-link-title="6.21 Reliability Debt Backlog" data-link-desc="把反覆事故、演練缺口與手動修復累積成可排序、可關閉的 reliability debt">6.21 reliability debt backlog</a>：orphan service 與過期 metadata 是 reliability debt</li>
</ul>
<h2 id="引用源">引用源</h2>
<ul>
<li><a href="https://backstage.io/">Backstage.io</a>：Spotify 開源的 developer portal 框架</li>
<li><a href="https://backstage.spotify.com/">Spotify Engineering: What is Backstage?</a>：Backstage 的設計理念與架構</li>
</ul>
]]></content:encoded></item><item><title>Spotify：平台工程與可靠性契約</title><link>https://tarrragon.github.io/blog/backend/06-reliability/cases/spotify/platform-engineering-and-reliability-contracts/</link><pubDate>Thu, 07 May 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/backend/06-reliability/cases/spotify/platform-engineering-and-reliability-contracts/</guid><description>&lt;p>Spotify 案例的核心責任是把可靠性標準平台化。當團隊自治程度高，若沒有共同契約，跨服務風險會在整合時爆發。&lt;/p>
&lt;h2 id="問題場景">問題場景&lt;/h2>
&lt;p>不同團隊採用不同部署與觀測習慣，單隊看似穩定，但跨服務路徑會出現隱性斷點，導致事故時難以協同定位。&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;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>Reliability contract&lt;/td>
 &lt;td>每個服務最低要提供什麼&lt;/td>
 &lt;td>基線能力&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Platform self-service&lt;/td>
 &lt;td>標準如何降低導入成本&lt;/td>
 &lt;td>擴散能力&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Cross-team evidence&lt;/td>
 &lt;td>證據如何跨團隊共享&lt;/td>
 &lt;td>協作效率&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;h2 id="可觀測訊號">可觀測訊號&lt;/h2>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>訊號&lt;/th>
 &lt;th>判讀重點&lt;/th>
 &lt;th>對應章節&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>contract compliance rate&lt;/td>
 &lt;td>契約覆蓋是否足夠&lt;/td>
 &lt;td>&lt;a href="https://tarrragon.github.io/blog/backend/06-reliability/contract-testing/" data-link-title="6.10 Contract Testing 與 Schema 演進" data-link-desc="把跨服務 / API / event schema 的隱性期待變成可驗證契約，控制演進相容性">6.10&lt;/a>&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>release dependency failures&lt;/td>
 &lt;td>依賴變更是否常破壞發布&lt;/td>
 &lt;td>&lt;a href="https://tarrragon.github.io/blog/backend/06-reliability/dependency-reliability-budget/" data-link-title="6.14 Dependency Reliability Budget" data-link-desc="把內外依賴的可靠性納入 SLO 計算與設計約束">6.14&lt;/a>&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>cross-team incident handoff latency&lt;/td>
 &lt;td>交接是否有共同語言&lt;/td>
 &lt;td>&lt;a href="https://tarrragon.github.io/blog/backend/08-incident-response/incident-command-roles/" data-link-title="8.2 事故指揮與角色分工" data-link-desc="定義 incident commander 與跨角色協作責任">8.2&lt;/a>&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;h2 id="下一步路由">下一步路由&lt;/h2>
&lt;p>先補 &lt;a href="https://tarrragon.github.io/blog/backend/06-reliability/contract-testing/" data-link-title="6.10 Contract Testing 與 Schema 演進" data-link-desc="把跨服務 / API / event schema 的隱性期待變成可驗證契約，控制演進相容性">6.10&lt;/a> 的契約欄位，再以 &lt;a href="https://tarrragon.github.io/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&lt;/a> 對齊 owner 與責任邊界。&lt;/p></description><content:encoded><![CDATA[<p>Spotify 案例的核心責任是把可靠性標準平台化。當團隊自治程度高，若沒有共同契約，跨服務風險會在整合時爆發。</p>
<h2 id="問題場景">問題場景</h2>
<p>不同團隊採用不同部署與觀測習慣，單隊看似穩定，但跨服務路徑會出現隱性斷點，導致事故時難以協同定位。</p>
<h2 id="決策機制">決策機制</h2>
<table>
  <thead>
      <tr>
          <th>機制</th>
          <th>核心問題</th>
          <th>交付結果</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Reliability contract</td>
          <td>每個服務最低要提供什麼</td>
          <td>基線能力</td>
      </tr>
      <tr>
          <td>Platform self-service</td>
          <td>標準如何降低導入成本</td>
          <td>擴散能力</td>
      </tr>
      <tr>
          <td>Cross-team evidence</td>
          <td>證據如何跨團隊共享</td>
          <td>協作效率</td>
      </tr>
  </tbody>
</table>
<h2 id="可觀測訊號">可觀測訊號</h2>
<table>
  <thead>
      <tr>
          <th>訊號</th>
          <th>判讀重點</th>
          <th>對應章節</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>contract compliance rate</td>
          <td>契約覆蓋是否足夠</td>
          <td><a href="/blog/backend/06-reliability/contract-testing/" data-link-title="6.10 Contract Testing 與 Schema 演進" data-link-desc="把跨服務 / API / event schema 的隱性期待變成可驗證契約，控制演進相容性">6.10</a></td>
      </tr>
      <tr>
          <td>release dependency failures</td>
          <td>依賴變更是否常破壞發布</td>
          <td><a href="/blog/backend/06-reliability/dependency-reliability-budget/" data-link-title="6.14 Dependency Reliability Budget" data-link-desc="把內外依賴的可靠性納入 SLO 計算與設計約束">6.14</a></td>
      </tr>
      <tr>
          <td>cross-team incident handoff latency</td>
          <td>交接是否有共同語言</td>
          <td><a href="/blog/backend/08-incident-response/incident-command-roles/" data-link-title="8.2 事故指揮與角色分工" data-link-desc="定義 incident commander 與跨角色協作責任">8.2</a></td>
      </tr>
  </tbody>
</table>
<h2 id="下一步路由">下一步路由</h2>
<p>先補 <a href="/blog/backend/06-reliability/contract-testing/" data-link-title="6.10 Contract Testing 與 Schema 演進" data-link-desc="把跨服務 / API / event schema 的隱性期待變成可驗證契約，控制演進相容性">6.10</a> 的契約欄位，再以 <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</a> 對齊 owner 與責任邊界。</p>
]]></content:encoded></item></channel></rss>