<?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>Dependency-Budget on Tarragon</title><link>https://tarrragon.github.io/blog/tags/dependency-budget/</link><description>Recent content in Dependency-Budget on Tarragon</description><generator>Hugo -- gohugo.io</generator><language>zh-TW</language><copyright>Tarragon (CC BY 4.0)</copyright><lastBuildDate>Fri, 03 Jul 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://tarrragon.github.io/blog/tags/dependency-budget/index.xml" rel="self" type="application/rss+xml"/><item><title>單點故障盤點</title><link>https://tarrragon.github.io/blog/devops/06-high-availability/spof-inventory/</link><pubDate>Fri, 03 Jul 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/devops/06-high-availability/spof-inventory/</guid><description>&lt;p>哪些元件一掛、整個系統就跟著掛？把這些點找出來，就是單點故障盤點。高可用的核心是冗餘——每個單點都有替代路徑——但在設計冗餘之前，得先知道單點在哪。盤點的方法是主動反推，而不是等出事後回頭找：假設某個變更已經在 production 造成了事故，倒著推它會怎麼壞、壞了會擴散到哪。這種 pre-mortem 的成本極低（一次結構化討論），卻能在事故發生前就把單點攤開。&lt;/p>
&lt;h2 id="pre-mortem假設已經出事反推路徑">Pre-mortem：假設已經出事，反推路徑&lt;/h2>
&lt;p>Pre-mortem 的核心假設是「這個變更已經在 production 造成事故」，從這個假設反向推導失敗路徑。它分四步走。先列出所有依賴與資料路徑——服務之間的依賴、資料的寫入路徑、對外部的呼叫、以及 schema、config、流量路由這些容易被忽略的隱性依賴。再對每一條路徑問「它斷了、慢了、或回錯了會怎樣」，追蹤影響怎麼擴散到直接依賴方、上游呼叫者、使用者可見的行為、以及資料一致性。接著判斷現有的驗證擋不擋得住這些失敗——CI、壓測、chaos、contract test 有沒有覆蓋，重點是找出「以為有覆蓋、實際上沒有」的那些。最後把識別出的缺口路由出去。&lt;/p>
&lt;p>第四步最容易失敗。缺口列了、但沒有 owner、沒有 deadline、沒有路由到下一步，pre-mortem 就淪為一份會議紀錄——問題盤點出來了卻沒人修，跟沒盤點差別不大。上線前補得了的缺口進就緒審查、失敗假設值得驗證的轉成 chaos 實驗、上線前補不了的進技術債追蹤。盤點的價值不在列出多少缺口，在每個缺口都有明確的去處。&lt;/p>
&lt;h2 id="依賴-budget自家可用性被依賴封頂">依賴 budget：自家可用性被依賴封頂&lt;/h2>
&lt;p>盤點單點時，一個容易被忽略的單點是外部依賴。自家服務的可用性是所有依賴可用性的乘積——一個 99.9% 的依賴，乘上自家的 99.9%，上限就只剩 99.8%。這意味著關鍵路徑上每多一個沒有替代路徑的依賴，就把自家可用性的天花板往下壓一層。盤點依賴風險不能只看它宣稱的 SLA，要看它失效之後自家還剩多少降級能力、以及失效的 blast radius 有多大。&lt;/p>
&lt;p>依賴盤點有三個關鍵訊號要查：關鍵路徑上有沒有「不知道掛了會怎樣」的依賴（這種是最危險的單點，因為連影響都沒摸清）、每個依賴有沒有明確的 failure domain（它的失效會被關在哪個範圍）、以及有沒有 graceful degradation 或 fallback（依賴掛了能不能降級服務而非整個停）。這三個訊號裡，控制面類的依賴風險通常最高——它一掛，可能連恢復動作本身都做不了。&lt;/p>
&lt;h2 id="失效模式分類與排序">失效模式分類與排序&lt;/h2>
&lt;p>盤點出來的缺口要分類、排序，不能一視同仁。按失效模式分成四類看得比較清楚：高風險變更缺差異化的驗證 gate、壓測模型沒覆蓋失敗流量（retry 風暴、timeout 級聯、佇列堆積）、rollback 或 DR 路徑事故前沒真的跑過（「有計畫但沒演練」，特徵是 schema 已經不向下相容、failover 的 config 已經漂移）、以及告警延遲或缺失讓使用者比監控先發現。&lt;/p>
&lt;p>排序用三個軸：嚴重度（失效的 blast radius 有多大——單服務、跨服務、跨區、還是跨租戶）、發生機率（這條失效路徑多常被觸及）、偵測難度（發現要多久）。三軸相乘，高嚴重度、高機率、又難偵測的缺口最先處理——難偵測特別致命，因為它讓一個高影響的故障可以悄悄壞很久。這裡的陷阱是把評分本身當成目標，維護一套精密評分的成本超過了它帶來的判讀價值，就本末倒置了。&lt;/p>
&lt;h2 id="失效局部化把單點的影響關進小範圍">失效局部化：把單點的影響關進小範圍&lt;/h2>
&lt;p>盤點的目標不只是找出單點，更是把單點失效的影響局部化——限制在最小的可影響範圍內。一個依賴退化，理想的結果不是「整個服務全停」，而是「只有一個 cell 受影響」。做到這點的機制包括把系統切成獨立的 cell（劃出擴散邊界）、用某種分片讓不同用戶的故障不重疊、讓控制面與資料面解耦（控制面掛了資料面還能服務）、以及讓失敗時的工作量保持恆定（避免故障觸發額外負載放大）。&lt;/p>
&lt;p>局部化改變了依賴 budget 的算法。當單一依賴的失效被關在一個 cell 裡，budget 算式裡「這個依賴失效」對應的就不是「整個服務全停」，而是「最大可影響一個 cell」——同樣的依賴、同樣的失效機率，影響面小了一個數量級。盤點單點時要問的不只是「它會不會掛」，還有「它掛了的影響能不能被關起來」。&lt;/p>
&lt;h2 id="下一步路由">下一步路由&lt;/h2>
&lt;ul>
&lt;li>找出單點之後，怎麼用冗餘給它替代路徑 → &lt;a href="https://tarrragon.github.io/blog/devops/06-high-availability/redundancy-patterns/" data-link-title="冗餘設計模式" data-link-desc="在 active-passive、active-active、multi-region 之間選冗餘模式時，用資料同步方式與 standby 是否服務流量來區分，並知道冗餘不等於備份">冗餘設計模式&lt;/a>&lt;/li>
&lt;li>單點掛了怎麼自動切到替代路徑 → &lt;a href="https://tarrragon.github.io/blog/devops/06-high-availability/failover-mechanism/" data-link-title="Failover 機制" data-link-desc="設計單點掛掉自動切到替代路徑的機制時，釐清觸發靠探活、故障域要先劃定、恢復順序的循環等待風險、以及 rollback 與 roll-forward 怎麼選">Failover 機制&lt;/a>&lt;/li>
&lt;li>rollback 與 DR 路徑「有計畫但沒演練」怎麼補 → &lt;a href="https://tarrragon.github.io/blog/devops/06-high-availability/disaster-recovery/" data-link-title="Disaster recovery 策略" data-link-desc="設計災難復原時，先確認恢復路徑走得通再談 RTO/RPO、用 restore drill 把估值變量值、以及知道恢復不是切回流量就結束">Disaster recovery 策略&lt;/a>&lt;/li>
&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 計算與設計約束">backend 依賴可靠性預算&lt;/a>&lt;/li>
&lt;/ul></description><content:encoded><![CDATA[<p>哪些元件一掛、整個系統就跟著掛？把這些點找出來，就是單點故障盤點。高可用的核心是冗餘——每個單點都有替代路徑——但在設計冗餘之前，得先知道單點在哪。盤點的方法是主動反推，而不是等出事後回頭找：假設某個變更已經在 production 造成了事故，倒著推它會怎麼壞、壞了會擴散到哪。這種 pre-mortem 的成本極低（一次結構化討論），卻能在事故發生前就把單點攤開。</p>
<h2 id="pre-mortem假設已經出事反推路徑">Pre-mortem：假設已經出事，反推路徑</h2>
<p>Pre-mortem 的核心假設是「這個變更已經在 production 造成事故」，從這個假設反向推導失敗路徑。它分四步走。先列出所有依賴與資料路徑——服務之間的依賴、資料的寫入路徑、對外部的呼叫、以及 schema、config、流量路由這些容易被忽略的隱性依賴。再對每一條路徑問「它斷了、慢了、或回錯了會怎樣」，追蹤影響怎麼擴散到直接依賴方、上游呼叫者、使用者可見的行為、以及資料一致性。接著判斷現有的驗證擋不擋得住這些失敗——CI、壓測、chaos、contract test 有沒有覆蓋，重點是找出「以為有覆蓋、實際上沒有」的那些。最後把識別出的缺口路由出去。</p>
<p>第四步最容易失敗。缺口列了、但沒有 owner、沒有 deadline、沒有路由到下一步，pre-mortem 就淪為一份會議紀錄——問題盤點出來了卻沒人修，跟沒盤點差別不大。上線前補得了的缺口進就緒審查、失敗假設值得驗證的轉成 chaos 實驗、上線前補不了的進技術債追蹤。盤點的價值不在列出多少缺口，在每個缺口都有明確的去處。</p>
<h2 id="依賴-budget自家可用性被依賴封頂">依賴 budget：自家可用性被依賴封頂</h2>
<p>盤點單點時，一個容易被忽略的單點是外部依賴。自家服務的可用性是所有依賴可用性的乘積——一個 99.9% 的依賴，乘上自家的 99.9%，上限就只剩 99.8%。這意味著關鍵路徑上每多一個沒有替代路徑的依賴，就把自家可用性的天花板往下壓一層。盤點依賴風險不能只看它宣稱的 SLA，要看它失效之後自家還剩多少降級能力、以及失效的 blast radius 有多大。</p>
<p>依賴盤點有三個關鍵訊號要查：關鍵路徑上有沒有「不知道掛了會怎樣」的依賴（這種是最危險的單點，因為連影響都沒摸清）、每個依賴有沒有明確的 failure domain（它的失效會被關在哪個範圍）、以及有沒有 graceful degradation 或 fallback（依賴掛了能不能降級服務而非整個停）。這三個訊號裡，控制面類的依賴風險通常最高——它一掛，可能連恢復動作本身都做不了。</p>
<h2 id="失效模式分類與排序">失效模式分類與排序</h2>
<p>盤點出來的缺口要分類、排序，不能一視同仁。按失效模式分成四類看得比較清楚：高風險變更缺差異化的驗證 gate、壓測模型沒覆蓋失敗流量（retry 風暴、timeout 級聯、佇列堆積）、rollback 或 DR 路徑事故前沒真的跑過（「有計畫但沒演練」，特徵是 schema 已經不向下相容、failover 的 config 已經漂移）、以及告警延遲或缺失讓使用者比監控先發現。</p>
<p>排序用三個軸：嚴重度（失效的 blast radius 有多大——單服務、跨服務、跨區、還是跨租戶）、發生機率（這條失效路徑多常被觸及）、偵測難度（發現要多久）。三軸相乘，高嚴重度、高機率、又難偵測的缺口最先處理——難偵測特別致命，因為它讓一個高影響的故障可以悄悄壞很久。這裡的陷阱是把評分本身當成目標，維護一套精密評分的成本超過了它帶來的判讀價值，就本末倒置了。</p>
<h2 id="失效局部化把單點的影響關進小範圍">失效局部化：把單點的影響關進小範圍</h2>
<p>盤點的目標不只是找出單點，更是把單點失效的影響局部化——限制在最小的可影響範圍內。一個依賴退化，理想的結果不是「整個服務全停」，而是「只有一個 cell 受影響」。做到這點的機制包括把系統切成獨立的 cell（劃出擴散邊界）、用某種分片讓不同用戶的故障不重疊、讓控制面與資料面解耦（控制面掛了資料面還能服務）、以及讓失敗時的工作量保持恆定（避免故障觸發額外負載放大）。</p>
<p>局部化改變了依賴 budget 的算法。當單一依賴的失效被關在一個 cell 裡，budget 算式裡「這個依賴失效」對應的就不是「整個服務全停」，而是「最大可影響一個 cell」——同樣的依賴、同樣的失效機率，影響面小了一個數量級。盤點單點時要問的不只是「它會不會掛」，還有「它掛了的影響能不能被關起來」。</p>
<h2 id="下一步路由">下一步路由</h2>
<ul>
<li>找出單點之後，怎麼用冗餘給它替代路徑 → <a href="/blog/devops/06-high-availability/redundancy-patterns/" data-link-title="冗餘設計模式" data-link-desc="在 active-passive、active-active、multi-region 之間選冗餘模式時，用資料同步方式與 standby 是否服務流量來區分，並知道冗餘不等於備份">冗餘設計模式</a></li>
<li>單點掛了怎麼自動切到替代路徑 → <a href="/blog/devops/06-high-availability/failover-mechanism/" data-link-title="Failover 機制" data-link-desc="設計單點掛掉自動切到替代路徑的機制時，釐清觸發靠探活、故障域要先劃定、恢復順序的循環等待風險、以及 rollback 與 roll-forward 怎麼選">Failover 機制</a></li>
<li>rollback 與 DR 路徑「有計畫但沒演練」怎麼補 → <a href="/blog/devops/06-high-availability/disaster-recovery/" data-link-title="Disaster recovery 策略" data-link-desc="設計災難復原時，先確認恢復路徑走得通再談 RTO/RPO、用 restore drill 把估值變量值、以及知道恢復不是切回流量就結束">Disaster recovery 策略</a></li>
<li>依賴的可靠性預算與失效局部化的完整設計 → <a href="/blog/backend/06-reliability/dependency-reliability-budget/" data-link-title="6.14 Dependency Reliability Budget" data-link-desc="把內外依賴的可靠性納入 SLO 計算與設計約束">backend 依賴可靠性預算</a></li>
</ul>
]]></content:encoded></item></channel></rss>