<?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>模組六：高可用與災難復原 on Tarragon</title><link>https://tarrragon.github.io/blog/devops/operations/06-high-availability/</link><description>Recent content in 模組六：高可用與災難復原 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 +0800</lastBuildDate><atom:link href="https://tarrragon.github.io/blog/devops/operations/06-high-availability/index.xml" rel="self" type="application/rss+xml"/><item><title>單點故障盤點</title><link>https://tarrragon.github.io/blog/devops/operations/06-high-availability/spof-inventory/</link><pubDate>Fri, 03 Jul 2026 00:00:00 +0800</pubDate><guid>https://tarrragon.github.io/blog/devops/operations/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>依賴盤點有三個關鍵訊號要查：關鍵路徑上有沒有「不知道掛了會怎樣」的依賴（這種是最危險的單點，因為連影響都沒摸清）、每個依賴有沒有明確的 &lt;a href="https://tarrragon.github.io/blog/backend/knowledge-cards/failure-domain/" data-link-title="Failure Domain（失效域）" data-link-desc="判斷兩個元件會不會因為同一件事一起停掉、備援或監控是否獨立於被保護的對象時，查它們共用了哪些會失效的依賴">failure domain&lt;/a>（失效域：哪些元件會因為同一個原因跟它一起停掉；它停掉時影響到哪個範圍是 &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>）、以及有沒有 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（劃出擴散邊界）、用某種分片讓不同用戶的故障不重疊、讓控制面與資料面解耦（控制面掛了資料面還能服務）、以及讓失敗時的工作量保持恆定（避免故障觸發額外負載放大）。所有服務放在同一台主機時，主機的記憶體、磁碟與 CPU 都是共同的單點，它們會讓哪些服務一起出事，見 &lt;a href="https://tarrragon.github.io/blog/devops/operations/05-capacity-planning/shared-host-contention/" data-link-title="共用主機的資源競爭：容量估算、故障範圍、隔離層級與監控的位置" data-link-desc="多個服務、資料庫與監控放在同一台主機（或同一台實體機上的多台虛擬機）時，資源競爭在容量估算、故障範圍、隔離的做法與監控的位置上各自要考慮什麼：共用發生在哪些層、量到的數字什麼時候能互相比較、哪些服務適合放在一起、從同機加限制到專用實體機的隔離層級與各層的觸發條件">共用主機的資源競爭&lt;/a>〈故障範圍〉。&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/operations/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/operations/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/operations/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>依賴盤點有三個關鍵訊號要查：關鍵路徑上有沒有「不知道掛了會怎樣」的依賴（這種是最危險的單點，因為連影響都沒摸清）、每個依賴有沒有明確的 <a href="/blog/backend/knowledge-cards/failure-domain/" data-link-title="Failure Domain（失效域）" data-link-desc="判斷兩個元件會不會因為同一件事一起停掉、備援或監控是否獨立於被保護的對象時，查它們共用了哪些會失效的依賴">failure domain</a>（失效域：哪些元件會因為同一個原因跟它一起停掉；它停掉時影響到哪個範圍是 <a href="/blog/backend/knowledge-cards/blast-radius/" data-link-title="Blast Radius" data-link-desc="說明事故影響面如何估算與隔離">blast radius</a>）、以及有沒有 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（劃出擴散邊界）、用某種分片讓不同用戶的故障不重疊、讓控制面與資料面解耦（控制面掛了資料面還能服務）、以及讓失敗時的工作量保持恆定（避免故障觸發額外負載放大）。所有服務放在同一台主機時，主機的記憶體、磁碟與 CPU 都是共同的單點，它們會讓哪些服務一起出事，見 <a href="/blog/devops/operations/05-capacity-planning/shared-host-contention/" data-link-title="共用主機的資源競爭：容量估算、故障範圍、隔離層級與監控的位置" data-link-desc="多個服務、資料庫與監控放在同一台主機（或同一台實體機上的多台虛擬機）時，資源競爭在容量估算、故障範圍、隔離的做法與監控的位置上各自要考慮什麼：共用發生在哪些層、量到的數字什麼時候能互相比較、哪些服務適合放在一起、從同機加限制到專用實體機的隔離層級與各層的觸發條件">共用主機的資源競爭</a>〈故障範圍〉。</p>
<p>局部化改變了依賴 budget 的算法。當單一依賴的失效被關在一個 cell 裡，budget 算式裡「這個依賴失效」對應的就不是「整個服務全停」，而是「最大可影響一個 cell」——同樣的依賴、同樣的失效機率，影響面小了一個數量級。盤點單點時要問的不只是「它會不會掛」，還有「它掛了的影響能不能被關起來」。</p>
<h2 id="下一步路由">下一步路由</h2>
<ul>
<li>找出單點之後，怎麼用冗餘給它替代路徑 → <a href="/blog/devops/operations/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/operations/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/operations/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><item><title>冗餘設計模式</title><link>https://tarrragon.github.io/blog/devops/operations/06-high-availability/redundancy-patterns/</link><pubDate>Fri, 03 Jul 2026 00:00:00 +0800</pubDate><guid>https://tarrragon.github.io/blog/devops/operations/06-high-availability/redundancy-patterns/</guid><description>&lt;p>單點有了替代路徑之後，那一份備援要怎麼擺——閒著等、還是也一起服務？冗餘設計模式沿兩個維度區分：備援的那一份服不服務流量（active-passive 的備援閒著等、active-active 與機群式的備援也在幹活），以及資料怎麼同步（同步副本幾乎不丟資料、非同步副本有延遲窗口）。選哪一種，決定了冗餘的成本、切換的速度、以及切換時可能丟多少資料。&lt;/p>
&lt;h2 id="active-passive備援熱備不服務流量">Active-passive：備援熱備、不服務流量&lt;/h2>
&lt;p>Active-passive 是最基礎的冗餘形態：有一個備援節點存在、隨時準備接手，但平時不服務任何流量。雲端資料庫的 multi-AZ 就是它的典型形態——用一個布林屬性開啟，背後是在另一個可用區維護一個同步副本，主庫的可用區故障時自動切到這個 standby，秒級到一兩分鐘的窗口後恢復。這個 standby 是熱備、不可讀——它不接受任何查詢流量、也不提供讀取擴展，純粹在那裡等 failover。要分攤讀流量得另開唯讀副本（那是另一個資源、另一個機制）。&lt;/p>
&lt;p>Active-passive 的可用性不是零中斷。failover 期間，應用到資料庫的連線會斷、需要重連；應用層若沒有連線中斷後的重試邏輯，這個 failover 就從「透明切換」變成「使用者可見的服務中斷」。冗餘節點準備好了，不代表切換對上層是無感的——上層要配合處理切換瞬間的連線中斷，冗餘才真的透明。這個「切換對上層透明」的前提，是 failover 機制那章的主題。&lt;/p>
&lt;h2 id="active-active備援也服務流量">Active-active：備援也服務流量&lt;/h2>
&lt;p>Active-active 讓備援的那一份也承接流量，不是閒著等。它的好處是那份冗餘資源沒有閒置——平時就在分攤負載、故障時少一份也還撐得住。代價是它要求所有份都能同時服務，對有狀態的部分（資料庫）意味著多份要同時可寫或至少可讀，資料一致性的協調比 active-passive 複雜得多。無狀態的應用層做 active-active 很自然（每個實例都對等，這正是 &lt;a href="https://tarrragon.github.io/blog/devops/operations/02-horizontal-scaling/" data-link-title="模組二：水平擴展" data-link-desc="一個實例不夠時怎麼加第二個 — stateless 設計、shared storage、session 處理的工程約束">水平擴展&lt;/a> 的無狀態設計）；有狀態的資料層做 active-active 要處理多寫衝突或讀寫分離，難度高得多。&lt;/p>
&lt;h2 id="n1nm無狀態機群的冗餘">N+1／N+M：無狀態機群的冗餘&lt;/h2>
&lt;p>無狀態機群的冗餘不是「一份主、一份備」的成對，而是「N 台在服務、多備 M 台」的機群。這是無狀態水平擴展的自然延伸——每台實例對等，冗餘就是多開幾台一樣的實例。N+1 表示在滿足負載所需的 N 台之外多備 1 台，能容忍同時掛 1 台不掉服務；要容忍同時掛 M 台就是 N+M。&lt;/p>
&lt;p>N+M 跟 active-passive 熱備對的差別在成本結構。熱備是 1:1、一份整份閒置，成本翻倍（2x）；N+M 的備援攤到整個機群，一個 10 台的機群多備 1 台只多約 10% 的開銷。所以無狀態層的高可用便宜得多——它不需要為每一份服務的實例都配一份閒置備援，只要機群整體多留幾台的餘裕。這條讓成本章的「冗餘至少 2x」有了下限：2x 是有狀態熱備的上界、N+1／N+M 是無狀態機群的下界，見 &lt;a href="https://tarrragon.github.io/blog/devops/operations/06-high-availability/ha-cost/" data-link-title="高可用的成本" data-link-desc="判斷高可用值不值得時，用停機的商業代價衡量冗餘的 2x 成本、按可用性等級階梯評估投資、以及知道沒驗證的冗餘等於白付">高可用的成本&lt;/a>。&lt;/p>
&lt;h2 id="multi-region在冗餘之上疊地理層">Multi-region：在冗餘之上疊地理層&lt;/h2>
&lt;p>Multi-region 是在 active-passive 或 active-active 之上再疊一層地理冗餘，解的是「整個 region 不可用」的極端情境。它靠幾個機制組合：跨 region 的唯讀副本、跨 region 的物件儲存複製、以及 DNS 層的 failover 路由（健康檢查加 DNS 切換）。做到極致的可用性很可觀——有客服平台跨 15 個 region 用分散式資料庫達成 99.999% 的可用性，等於一年只停機約 5 分鐘。&lt;/p>
&lt;p>Multi-region 跟同 region 冗餘的關鍵差異在資料同步。同 region 的 multi-AZ 是同步副本，failover 幾乎不丟資料；跨 region 的複製是非同步的、有延遲，failover 時會落在「複製延遲窗口」裡的資料就丟了。這個同步方式的差異直接決定了能承受多少資料遺失——同步副本對應接近零的資料落差，非同步跨 region 對應一個延遲窗口的落差。這條差異是 &lt;a href="https://tarrragon.github.io/blog/devops/operations/06-high-availability/disaster-recovery/" data-link-title="Disaster recovery 策略" data-link-desc="設計災難復原時，先確認恢復路徑走得通再談 RTO/RPO、用 restore drill 把估值變量值、以及知道恢復不是切回流量就結束">disaster recovery&lt;/a> 裡 RPO 的來源。&lt;/p>
&lt;h2 id="冗餘不等於備份">冗餘不等於備份&lt;/h2>
&lt;p>冗餘模式有一個常見的誤解要拆穿：冗餘防的是硬體與可用區故障，不防邏輯損壞。multi-AZ 的 standby 是同步副本——一個誤刪的 table、一個算錯的批次 UPDATE、一個有 bug 的 migration，會被同步複製到 standby，兩份一起壞。active-active 也一樣，錯誤的寫入會傳到每一份。冗餘讓「硬體掛了還有另一份」，但那另一份跟壞掉的這份內容一模一樣，對邏輯錯誤毫無保護。&lt;/p>
&lt;p>防邏輯損壞的是另一條正交的防線：備份與時間點還原（PITR）。冗餘管的是可用性（硬體或 AZ 掛了服務不中斷），備份管的是可還原性（資料被邏輯性破壞後能倒回某個時間點）。這兩者職責正交，要分別配置、分別驗證——不能把冗餘當成備份，也不能因為有備份就省掉冗餘。&lt;/p>
&lt;h2 id="冗餘要靠-drill-驗證">冗餘要靠 drill 驗證&lt;/h2>
&lt;p>冗餘設計「宣稱有效」不等於「實測有效」。一個 multi-AZ 切換窗口寫在文件上說「秒級」，跟它在真實故障下確實秒級切換，是兩回事——中間可能卡在應用沒重連、監控誤報、或 failover 腳本的某個前提在 production 不成立。驗證的手段是 chaos drill：用基礎設施層的故障注入（AZ failure、region failure，雲端的 chaos 工具支援）真的打掉一個可用區，看冗餘有沒有按預期接手、切換窗口是不是真的在承諾內。冗餘設計要從紙面轉成證據，靠的是演練，這條延伸到 &lt;a href="https://tarrragon.github.io/blog/devops/operations/06-high-availability/disaster-recovery/" data-link-title="Disaster recovery 策略" data-link-desc="設計災難復原時，先確認恢復路徑走得通再談 RTO/RPO、用 restore drill 把估值變量值、以及知道恢復不是切回流量就結束">disaster recovery&lt;/a> 的演練節奏。&lt;/p>
&lt;h2 id="下一步路由">下一步路由&lt;/h2>
&lt;ul>
&lt;li>冗餘準備好了，切換怎麼觸發、怎麼對上層透明 → &lt;a href="https://tarrragon.github.io/blog/devops/operations/06-high-availability/failover-mechanism/" data-link-title="Failover 機制" data-link-desc="設計單點掛掉自動切到替代路徑的機制時，釐清觸發靠探活、故障域要先劃定、恢復順序的循環等待風險、以及 rollback 與 roll-forward 怎麼選">Failover 機制&lt;/a>&lt;/li>
&lt;li>同步 vs 非同步副本怎麼對應 RPO、演練怎麼跑 → &lt;a href="https://tarrragon.github.io/blog/devops/operations/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>冗餘至少 2x 資源，值不值得 → &lt;a href="https://tarrragon.github.io/blog/devops/operations/06-high-availability/ha-cost/" data-link-title="高可用的成本" data-link-desc="判斷高可用值不值得時，用停機的商業代價衡量冗餘的 2x 成本、按可用性等級階梯評估投資、以及知道沒驗證的冗餘等於白付">高可用的成本&lt;/a>&lt;/li>
&lt;li>multi-AZ 是 infra 層的能力，怎麼在 IaC 開啟 → &lt;a href="https://tarrragon.github.io/blog/devops/infra/05-core-services/stateful-protection-dependency/" data-link-title="Stateful 資源保護與跨服務依賴表達" data-link-desc="stateful 資源的保護策略（multi-AZ、備份、刪除保護）、stateful 與 stateless 的操作差異，以及用 output 與 data source 表達服務間依賴">infra Stateful 資源保護&lt;/a>&lt;/li>
&lt;/ul></description><content:encoded><![CDATA[<p>單點有了替代路徑之後，那一份備援要怎麼擺——閒著等、還是也一起服務？冗餘設計模式沿兩個維度區分：備援的那一份服不服務流量（active-passive 的備援閒著等、active-active 與機群式的備援也在幹活），以及資料怎麼同步（同步副本幾乎不丟資料、非同步副本有延遲窗口）。選哪一種，決定了冗餘的成本、切換的速度、以及切換時可能丟多少資料。</p>
<h2 id="active-passive備援熱備不服務流量">Active-passive：備援熱備、不服務流量</h2>
<p>Active-passive 是最基礎的冗餘形態：有一個備援節點存在、隨時準備接手，但平時不服務任何流量。雲端資料庫的 multi-AZ 就是它的典型形態——用一個布林屬性開啟，背後是在另一個可用區維護一個同步副本，主庫的可用區故障時自動切到這個 standby，秒級到一兩分鐘的窗口後恢復。這個 standby 是熱備、不可讀——它不接受任何查詢流量、也不提供讀取擴展，純粹在那裡等 failover。要分攤讀流量得另開唯讀副本（那是另一個資源、另一個機制）。</p>
<p>Active-passive 的可用性不是零中斷。failover 期間，應用到資料庫的連線會斷、需要重連；應用層若沒有連線中斷後的重試邏輯，這個 failover 就從「透明切換」變成「使用者可見的服務中斷」。冗餘節點準備好了，不代表切換對上層是無感的——上層要配合處理切換瞬間的連線中斷，冗餘才真的透明。這個「切換對上層透明」的前提，是 failover 機制那章的主題。</p>
<h2 id="active-active備援也服務流量">Active-active：備援也服務流量</h2>
<p>Active-active 讓備援的那一份也承接流量，不是閒著等。它的好處是那份冗餘資源沒有閒置——平時就在分攤負載、故障時少一份也還撐得住。代價是它要求所有份都能同時服務，對有狀態的部分（資料庫）意味著多份要同時可寫或至少可讀，資料一致性的協調比 active-passive 複雜得多。無狀態的應用層做 active-active 很自然（每個實例都對等，這正是 <a href="/blog/devops/operations/02-horizontal-scaling/" data-link-title="模組二：水平擴展" data-link-desc="一個實例不夠時怎麼加第二個 — stateless 設計、shared storage、session 處理的工程約束">水平擴展</a> 的無狀態設計）；有狀態的資料層做 active-active 要處理多寫衝突或讀寫分離，難度高得多。</p>
<h2 id="n1nm無狀態機群的冗餘">N+1／N+M：無狀態機群的冗餘</h2>
<p>無狀態機群的冗餘不是「一份主、一份備」的成對，而是「N 台在服務、多備 M 台」的機群。這是無狀態水平擴展的自然延伸——每台實例對等，冗餘就是多開幾台一樣的實例。N+1 表示在滿足負載所需的 N 台之外多備 1 台，能容忍同時掛 1 台不掉服務；要容忍同時掛 M 台就是 N+M。</p>
<p>N+M 跟 active-passive 熱備對的差別在成本結構。熱備是 1:1、一份整份閒置，成本翻倍（2x）；N+M 的備援攤到整個機群，一個 10 台的機群多備 1 台只多約 10% 的開銷。所以無狀態層的高可用便宜得多——它不需要為每一份服務的實例都配一份閒置備援，只要機群整體多留幾台的餘裕。這條讓成本章的「冗餘至少 2x」有了下限：2x 是有狀態熱備的上界、N+1／N+M 是無狀態機群的下界，見 <a href="/blog/devops/operations/06-high-availability/ha-cost/" data-link-title="高可用的成本" data-link-desc="判斷高可用值不值得時，用停機的商業代價衡量冗餘的 2x 成本、按可用性等級階梯評估投資、以及知道沒驗證的冗餘等於白付">高可用的成本</a>。</p>
<h2 id="multi-region在冗餘之上疊地理層">Multi-region：在冗餘之上疊地理層</h2>
<p>Multi-region 是在 active-passive 或 active-active 之上再疊一層地理冗餘，解的是「整個 region 不可用」的極端情境。它靠幾個機制組合：跨 region 的唯讀副本、跨 region 的物件儲存複製、以及 DNS 層的 failover 路由（健康檢查加 DNS 切換）。做到極致的可用性很可觀——有客服平台跨 15 個 region 用分散式資料庫達成 99.999% 的可用性，等於一年只停機約 5 分鐘。</p>
<p>Multi-region 跟同 region 冗餘的關鍵差異在資料同步。同 region 的 multi-AZ 是同步副本，failover 幾乎不丟資料；跨 region 的複製是非同步的、有延遲，failover 時會落在「複製延遲窗口」裡的資料就丟了。這個同步方式的差異直接決定了能承受多少資料遺失——同步副本對應接近零的資料落差，非同步跨 region 對應一個延遲窗口的落差。這條差異是 <a href="/blog/devops/operations/06-high-availability/disaster-recovery/" data-link-title="Disaster recovery 策略" data-link-desc="設計災難復原時，先確認恢復路徑走得通再談 RTO/RPO、用 restore drill 把估值變量值、以及知道恢復不是切回流量就結束">disaster recovery</a> 裡 RPO 的來源。</p>
<h2 id="冗餘不等於備份">冗餘不等於備份</h2>
<p>冗餘模式有一個常見的誤解要拆穿：冗餘防的是硬體與可用區故障，不防邏輯損壞。multi-AZ 的 standby 是同步副本——一個誤刪的 table、一個算錯的批次 UPDATE、一個有 bug 的 migration，會被同步複製到 standby，兩份一起壞。active-active 也一樣，錯誤的寫入會傳到每一份。冗餘讓「硬體掛了還有另一份」，但那另一份跟壞掉的這份內容一模一樣，對邏輯錯誤毫無保護。</p>
<p>防邏輯損壞的是另一條正交的防線：備份與時間點還原（PITR）。冗餘管的是可用性（硬體或 AZ 掛了服務不中斷），備份管的是可還原性（資料被邏輯性破壞後能倒回某個時間點）。這兩者職責正交，要分別配置、分別驗證——不能把冗餘當成備份，也不能因為有備份就省掉冗餘。</p>
<h2 id="冗餘要靠-drill-驗證">冗餘要靠 drill 驗證</h2>
<p>冗餘設計「宣稱有效」不等於「實測有效」。一個 multi-AZ 切換窗口寫在文件上說「秒級」，跟它在真實故障下確實秒級切換，是兩回事——中間可能卡在應用沒重連、監控誤報、或 failover 腳本的某個前提在 production 不成立。驗證的手段是 chaos drill：用基礎設施層的故障注入（AZ failure、region failure，雲端的 chaos 工具支援）真的打掉一個可用區，看冗餘有沒有按預期接手、切換窗口是不是真的在承諾內。冗餘設計要從紙面轉成證據，靠的是演練，這條延伸到 <a href="/blog/devops/operations/06-high-availability/disaster-recovery/" data-link-title="Disaster recovery 策略" data-link-desc="設計災難復原時，先確認恢復路徑走得通再談 RTO/RPO、用 restore drill 把估值變量值、以及知道恢復不是切回流量就結束">disaster recovery</a> 的演練節奏。</p>
<h2 id="下一步路由">下一步路由</h2>
<ul>
<li>冗餘準備好了，切換怎麼觸發、怎麼對上層透明 → <a href="/blog/devops/operations/06-high-availability/failover-mechanism/" data-link-title="Failover 機制" data-link-desc="設計單點掛掉自動切到替代路徑的機制時，釐清觸發靠探活、故障域要先劃定、恢復順序的循環等待風險、以及 rollback 與 roll-forward 怎麼選">Failover 機制</a></li>
<li>同步 vs 非同步副本怎麼對應 RPO、演練怎麼跑 → <a href="/blog/devops/operations/06-high-availability/disaster-recovery/" data-link-title="Disaster recovery 策略" data-link-desc="設計災難復原時，先確認恢復路徑走得通再談 RTO/RPO、用 restore drill 把估值變量值、以及知道恢復不是切回流量就結束">Disaster recovery 策略</a></li>
<li>冗餘至少 2x 資源，值不值得 → <a href="/blog/devops/operations/06-high-availability/ha-cost/" data-link-title="高可用的成本" data-link-desc="判斷高可用值不值得時，用停機的商業代價衡量冗餘的 2x 成本、按可用性等級階梯評估投資、以及知道沒驗證的冗餘等於白付">高可用的成本</a></li>
<li>multi-AZ 是 infra 層的能力，怎麼在 IaC 開啟 → <a href="/blog/devops/infra/05-core-services/stateful-protection-dependency/" data-link-title="Stateful 資源保護與跨服務依賴表達" data-link-desc="stateful 資源的保護策略（multi-AZ、備份、刪除保護）、stateful 與 stateless 的操作差異，以及用 output 與 data source 表達服務間依賴">infra Stateful 資源保護</a></li>
</ul>
]]></content:encoded></item><item><title>Failover 機制</title><link>https://tarrragon.github.io/blog/devops/operations/06-high-availability/failover-mechanism/</link><pubDate>Fri, 03 Jul 2026 00:00:00 +0800</pubDate><guid>https://tarrragon.github.io/blog/devops/operations/06-high-availability/failover-mechanism/</guid><description>&lt;p>單點掛了，怎麼自動切到替代路徑？failover 機制把這件事拆成三個環節：怎麼知道要切（觸發）、切到哪與怎麼切（切換）、以及事後怎麼把系統收回穩態（恢復順序）。三者裡最危險的往往是恢復順序、而不是切換本身——切換做對了、恢復動作卻因為依賴一個還沒恢復的元件而卡死，把一次可控的故障拖成漫長的中斷。&lt;/p>
&lt;h2 id="觸發探活是-failover-的前提">觸發：探活是 failover 的前提&lt;/h2>
&lt;p>Failover 的觸發條件是探活——健康檢查判定某個節點不健康，才觸發切換。這是 &lt;a href="https://tarrragon.github.io/blog/devops/operations/04-service-health/" data-link-title="模組四：服務探活與自動恢復" data-link-desc="服務掛了怎麼自動發現和恢復 — health check 設計、liveness vs readiness、systemd watchdog、process supervisor">模組四 服務探活&lt;/a> 的主題：沒有可靠的探活，failover 要嘛切得太晚（壞了很久才發現）、要嘛切得太急（一次抖動就誤判、觸發不必要的 failover）。自動 failover 快、但依賴探活的準確度，探活抖動會讓它反覆切換；手動 failover 慢、但多了一層人的判斷，適合切換代價高、誤切損失大的場景。選自動還是手動，取決於「切錯的代價」跟「切慢的代價」哪個大。&lt;/p>
&lt;h2 id="切換先劃定故障域否則恢復動作變放大器">切換：先劃定故障域，否則恢復動作變放大器&lt;/h2>
&lt;p>切換之前要先知道這次故障的邊界到哪——它最多會影響到哪個範圍。這個故障影響得到的範圍（&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;a href="https://tarrragon.github.io/blog/backend/knowledge-cards/failure-domain/" data-link-title="Failure Domain（失效域）" data-link-desc="判斷兩個元件會不會因為同一件事一起停掉、備援或監控是否獨立於被保護的對象時，查它們共用了哪些會失效的依賴">Failure Domain&lt;/a>）如果沒有預先定義，恢復動作本身可能變成新的放大器：以為只是切一個節點、實際上牽動了跨區的共享路徑，切換的動作反而把故障擴散得更廣。跨區的高可用尤其要先劃清楚「這個故障最多蔓延到哪裡」，才知道 failover 要切多大範圍、以及切換不會誤傷到本來健康的部分。&lt;/p>
&lt;p>切換要盯三個訊號判斷它有沒有失控：跨區的錯誤是不是在越界擴散、failover 的完成進度有沒有在收斂、以及共享的依賴有沒有變成瓶頸。這三個訊號來自大型平台跨區故障的實戰——它們揭露一件事：大規模系統真正的擴散面在跨區共享的相依路徑、不在單點失效本身，單點失效只是觸發點。&lt;/p>
&lt;h2 id="恢復順序循環等待是最大的風險">恢復順序：循環等待是最大的風險&lt;/h2>
&lt;p>恢復順序決定整體恢復時間，而它最大的風險是循環等待。系統大致分兩層：控制面是管理與調度那一層（下發設定、決定路由、協調誰接手），資料面是實際處理請求流量那一層。當控制面與資料面共用某條路徑、而恢復動作又依賴一個尚未恢復的控制面服務時，恢復就卡在一個環裡——要恢復 A 得先有 B、要恢復 B 得先有 A。有大型平台在一次全區故障裡就撞到這個：恢復需要的工具本身依賴了已經故障的系統（網路路由、DNS、遠端存取），結果連「開始恢復」這個動作都做不了，故障時間被恢復工具的循環依賴大幅拉長。&lt;/p>
&lt;p>所以恢復要分批、不能同時恢復所有路徑。同時把多條路徑一起拉起來，可能在剛恢復、還很脆弱的依賴上引發回源放大（原本被快取或前端擋掉的請求，因為那層還沒回來、全部同時回打源頭）或連鎖過載，把一次可控的恢復變成第二次故障。可靠的做法是依事故的時間線與既定的 runbook 安排恢復批次，每一批先驗證 baseline 穩定了、再進下一批。恢復順序的設計原則因此有兩條：讓恢復路徑不依賴任何可能故障的控制面（恢復工具要能在控制面掛掉時獨立運作）、以及分批推進而非一次全開。&lt;/p>
&lt;h2 id="資料一致性rollback-還是-roll-forward">資料一致性：rollback 還是 roll-forward&lt;/h2>
&lt;p>Failover 或變更失敗時，除了切走流量，還有一個資料層的決策：退回舊版（rollback）還是往前修（roll-forward）。判斷取決於這個變更可不可逆、以及新資料是否已經依賴了新結構。可逆的（schema 向下相容、feature flag 可關、路由可切回）用 rollback，它通常比 roll-forward 快收斂，因為退回的是一個已經被驗證過的行為；不可逆的（新版已經寫入了不能回退的資料）只能 roll-forward。還有一種混合：先 rollback 止血、穩定後再 roll-forward 修復。&lt;/p>
&lt;p>這個判斷有一個容易漏的層次：rollback 的安全性不只看部署層、還要看資料語義層。一個交易系統的 rollback，要同時處理 schema 相容跟冪等重播——退回程式版本容易，但那段期間寫入的資料若跟新版本的語義綁定，光退版會留下不一致。判斷 rollback 還是 roll-forward，五個軸要一起看：schema 相容性、資料狀態、修復時間、feature flag、下游依賴。&lt;/p>
&lt;h2 id="依賴隔離切斷共享相依的放大">依賴隔離：切斷共享相依的放大&lt;/h2>
&lt;p>Failover 能不能乾淨切換，很大程度取決於依賴有沒有被隔離。共享的相依路徑是故障放大的主要通道——一個依賴退化，透過共享路徑拖垮所有用到它的服務。隔離的做法是把不同的工作負載、不同的租戶關進各自的資源池，一個池的故障不外溢到別的池，這正是 &lt;a href="https://tarrragon.github.io/blog/devops/operations/03-traffic-management/" data-link-title="模組三：流量管控" data-link-desc="收到的流量超過處理能力時怎麼辦 — 背壓、rate limit、熔斷、bulkhead 四種防護機制">模組三 流量管控&lt;/a> 的 bulkhead 隔離搬到高可用場景。依賴隔離做得好，failover 只需要切掉受影響的那個隔離區，不必動到整個系統。&lt;/p>
&lt;h2 id="下一步路由">下一步路由&lt;/h2>
&lt;ul>
&lt;li>Failover 的觸發前提——探活怎麼做 → &lt;a href="https://tarrragon.github.io/blog/devops/operations/04-service-health/" data-link-title="模組四：服務探活與自動恢復" data-link-desc="服務掛了怎麼自動發現和恢復 — health check 設計、liveness vs readiness、systemd watchdog、process supervisor">模組四 服務探活&lt;/a>&lt;/li>
&lt;li>冗餘準備好才有得切、切換對上層透明的前提 → &lt;a href="https://tarrragon.github.io/blog/devops/operations/06-high-availability/redundancy-patterns/" data-link-title="冗餘設計模式" data-link-desc="在 active-passive、active-active、multi-region 之間選冗餘模式時，用資料同步方式與 standby 是否服務流量來區分，並知道冗餘不等於備份">冗餘設計模式&lt;/a>&lt;/li>
&lt;li>恢復順序、restore 驗證與演練節奏 → &lt;a href="https://tarrragon.github.io/blog/devops/operations/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/devops/operations/09-host-lifecycle/suspend-and-resume-service/" data-link-title="服務暫停與恢復上線：只停服務、停止主機、終止主機到全部刪除各自保留的資源，暫停期間仍計費與仍被指向的資源，恢復前要查的漂移與恢復的順序" data-link-desc="一台主機上的服務要暫停一段時間再恢復：只停服務、停止主機、終止主機保留設定、全部刪除靠 repo 重建各自保留什麼與付出什麼，怎麼依保留的月費、重建的成本與漂移量選擇，暫停期間仍在計費的資源（含在作業系統裡 shutdown 不停止計費），仍被 DNS 與 CDN 指向的結果（Cloudflare 521、522，釋放 IP 之後的懸空 DNS），恢復前要重新確認的漂移，以及依元件依賴排出的恢復順序與驗證">服務暫停與恢復上線：只停服務、停止主機、終止主機到全部刪除各自保留的資源，暫停期間仍計費與仍被指向的資源，恢復前要查的漂移與恢復的順序&lt;/a>〈恢復的順序：依元件之間的依賴排列〉&lt;/li>
&lt;li>Bulkhead 隔離怎麼切斷共享相依 → &lt;a href="https://tarrragon.github.io/blog/devops/operations/03-traffic-management/" data-link-title="模組三：流量管控" data-link-desc="收到的流量超過處理能力時怎麼辦 — 背壓、rate limit、熔斷、bulkhead 四種防護機制">模組三 流量管控&lt;/a>&lt;/li>
&lt;/ul></description><content:encoded><![CDATA[<p>單點掛了，怎麼自動切到替代路徑？failover 機制把這件事拆成三個環節：怎麼知道要切（觸發）、切到哪與怎麼切（切換）、以及事後怎麼把系統收回穩態（恢復順序）。三者裡最危險的往往是恢復順序、而不是切換本身——切換做對了、恢復動作卻因為依賴一個還沒恢復的元件而卡死，把一次可控的故障拖成漫長的中斷。</p>
<h2 id="觸發探活是-failover-的前提">觸發：探活是 failover 的前提</h2>
<p>Failover 的觸發條件是探活——健康檢查判定某個節點不健康，才觸發切換。這是 <a href="/blog/devops/operations/04-service-health/" data-link-title="模組四：服務探活與自動恢復" data-link-desc="服務掛了怎麼自動發現和恢復 — health check 設計、liveness vs readiness、systemd watchdog、process supervisor">模組四 服務探活</a> 的主題：沒有可靠的探活，failover 要嘛切得太晚（壞了很久才發現）、要嘛切得太急（一次抖動就誤判、觸發不必要的 failover）。自動 failover 快、但依賴探活的準確度，探活抖動會讓它反覆切換；手動 failover 慢、但多了一層人的判斷，適合切換代價高、誤切損失大的場景。選自動還是手動，取決於「切錯的代價」跟「切慢的代價」哪個大。</p>
<h2 id="切換先劃定故障域否則恢復動作變放大器">切換：先劃定故障域，否則恢復動作變放大器</h2>
<p>切換之前要先知道這次故障的邊界到哪——它最多會影響到哪個範圍。這個故障影響得到的範圍（<a href="/blog/backend/knowledge-cards/blast-radius/" data-link-title="Blast Radius" data-link-desc="說明事故影響面如何估算與隔離">blast radius</a>，它由哪些元件共用失效域決定，見 <a href="/blog/backend/knowledge-cards/failure-domain/" data-link-title="Failure Domain（失效域）" data-link-desc="判斷兩個元件會不會因為同一件事一起停掉、備援或監控是否獨立於被保護的對象時，查它們共用了哪些會失效的依賴">Failure Domain</a>）如果沒有預先定義，恢復動作本身可能變成新的放大器：以為只是切一個節點、實際上牽動了跨區的共享路徑，切換的動作反而把故障擴散得更廣。跨區的高可用尤其要先劃清楚「這個故障最多蔓延到哪裡」，才知道 failover 要切多大範圍、以及切換不會誤傷到本來健康的部分。</p>
<p>切換要盯三個訊號判斷它有沒有失控：跨區的錯誤是不是在越界擴散、failover 的完成進度有沒有在收斂、以及共享的依賴有沒有變成瓶頸。這三個訊號來自大型平台跨區故障的實戰——它們揭露一件事：大規模系統真正的擴散面在跨區共享的相依路徑、不在單點失效本身，單點失效只是觸發點。</p>
<h2 id="恢復順序循環等待是最大的風險">恢復順序：循環等待是最大的風險</h2>
<p>恢復順序決定整體恢復時間，而它最大的風險是循環等待。系統大致分兩層：控制面是管理與調度那一層（下發設定、決定路由、協調誰接手），資料面是實際處理請求流量那一層。當控制面與資料面共用某條路徑、而恢復動作又依賴一個尚未恢復的控制面服務時，恢復就卡在一個環裡——要恢復 A 得先有 B、要恢復 B 得先有 A。有大型平台在一次全區故障裡就撞到這個：恢復需要的工具本身依賴了已經故障的系統（網路路由、DNS、遠端存取），結果連「開始恢復」這個動作都做不了，故障時間被恢復工具的循環依賴大幅拉長。</p>
<p>所以恢復要分批、不能同時恢復所有路徑。同時把多條路徑一起拉起來，可能在剛恢復、還很脆弱的依賴上引發回源放大（原本被快取或前端擋掉的請求，因為那層還沒回來、全部同時回打源頭）或連鎖過載，把一次可控的恢復變成第二次故障。可靠的做法是依事故的時間線與既定的 runbook 安排恢復批次，每一批先驗證 baseline 穩定了、再進下一批。恢復順序的設計原則因此有兩條：讓恢復路徑不依賴任何可能故障的控制面（恢復工具要能在控制面掛掉時獨立運作）、以及分批推進而非一次全開。</p>
<h2 id="資料一致性rollback-還是-roll-forward">資料一致性：rollback 還是 roll-forward</h2>
<p>Failover 或變更失敗時，除了切走流量，還有一個資料層的決策：退回舊版（rollback）還是往前修（roll-forward）。判斷取決於這個變更可不可逆、以及新資料是否已經依賴了新結構。可逆的（schema 向下相容、feature flag 可關、路由可切回）用 rollback，它通常比 roll-forward 快收斂，因為退回的是一個已經被驗證過的行為；不可逆的（新版已經寫入了不能回退的資料）只能 roll-forward。還有一種混合：先 rollback 止血、穩定後再 roll-forward 修復。</p>
<p>這個判斷有一個容易漏的層次：rollback 的安全性不只看部署層、還要看資料語義層。一個交易系統的 rollback，要同時處理 schema 相容跟冪等重播——退回程式版本容易，但那段期間寫入的資料若跟新版本的語義綁定，光退版會留下不一致。判斷 rollback 還是 roll-forward，五個軸要一起看：schema 相容性、資料狀態、修復時間、feature flag、下游依賴。</p>
<h2 id="依賴隔離切斷共享相依的放大">依賴隔離：切斷共享相依的放大</h2>
<p>Failover 能不能乾淨切換，很大程度取決於依賴有沒有被隔離。共享的相依路徑是故障放大的主要通道——一個依賴退化，透過共享路徑拖垮所有用到它的服務。隔離的做法是把不同的工作負載、不同的租戶關進各自的資源池，一個池的故障不外溢到別的池，這正是 <a href="/blog/devops/operations/03-traffic-management/" data-link-title="模組三：流量管控" data-link-desc="收到的流量超過處理能力時怎麼辦 — 背壓、rate limit、熔斷、bulkhead 四種防護機制">模組三 流量管控</a> 的 bulkhead 隔離搬到高可用場景。依賴隔離做得好，failover 只需要切掉受影響的那個隔離區，不必動到整個系統。</p>
<h2 id="下一步路由">下一步路由</h2>
<ul>
<li>Failover 的觸發前提——探活怎麼做 → <a href="/blog/devops/operations/04-service-health/" data-link-title="模組四：服務探活與自動恢復" data-link-desc="服務掛了怎麼自動發現和恢復 — health check 設計、liveness vs readiness、systemd watchdog、process supervisor">模組四 服務探活</a></li>
<li>冗餘準備好才有得切、切換對上層透明的前提 → <a href="/blog/devops/operations/06-high-availability/redundancy-patterns/" data-link-title="冗餘設計模式" data-link-desc="在 active-passive、active-active、multi-region 之間選冗餘模式時，用資料同步方式與 standby 是否服務流量來區分，並知道冗餘不等於備份">冗餘設計模式</a></li>
<li>恢復順序、restore 驗證與演練節奏 → <a href="/blog/devops/operations/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/devops/operations/09-host-lifecycle/suspend-and-resume-service/" data-link-title="服務暫停與恢復上線：只停服務、停止主機、終止主機到全部刪除各自保留的資源，暫停期間仍計費與仍被指向的資源，恢復前要查的漂移與恢復的順序" data-link-desc="一台主機上的服務要暫停一段時間再恢復：只停服務、停止主機、終止主機保留設定、全部刪除靠 repo 重建各自保留什麼與付出什麼，怎麼依保留的月費、重建的成本與漂移量選擇，暫停期間仍在計費的資源（含在作業系統裡 shutdown 不停止計費），仍被 DNS 與 CDN 指向的結果（Cloudflare 521、522，釋放 IP 之後的懸空 DNS），恢復前要重新確認的漂移，以及依元件依賴排出的恢復順序與驗證">服務暫停與恢復上線：只停服務、停止主機、終止主機到全部刪除各自保留的資源，暫停期間仍計費與仍被指向的資源，恢復前要查的漂移與恢復的順序</a>〈恢復的順序：依元件之間的依賴排列〉</li>
<li>Bulkhead 隔離怎麼切斷共享相依 → <a href="/blog/devops/operations/03-traffic-management/" data-link-title="模組三：流量管控" data-link-desc="收到的流量超過處理能力時怎麼辦 — 背壓、rate limit、熔斷、bulkhead 四種防護機制">模組三 流量管控</a></li>
</ul>
]]></content:encoded></item><item><title>Disaster recovery 策略</title><link>https://tarrragon.github.io/blog/devops/operations/06-high-availability/disaster-recovery/</link><pubDate>Fri, 03 Jul 2026 00:00:00 +0800</pubDate><guid>https://tarrragon.github.io/blog/devops/operations/06-high-availability/disaster-recovery/</guid><description>&lt;p>Disaster recovery 回答「災難發生後，服務能不能回來」。它有一條先於一切的原則：先確認路徑，再談速度。一份 backup 在被 restore 驗證過之前，它只是備份、不是復原能力；一套 failover 的 config 在沒跟 production 對齊之前，它只是文件、不是可執行的操作路由。RTO 跟 RPO 這些速度指標，是在「路徑確實走得通」之後才有意義的——路徑不通，再漂亮的目標數字都是空的。&lt;/p>
&lt;h2 id="rto-與-rpo是承諾不能是猜測">RTO 與 RPO：是承諾，不能是猜測&lt;/h2>
&lt;p>RTO（恢復時間目標）是「多久之內要恢復服務」，RPO（資料遺失目標）是「最多能丟多少資料」。這兩個數字有一個常見的陷阱：它們常常是估值、不是量值。一個寫在文件上「4 小時 RTO」的承諾，如果從沒真的跑過一次完整恢復，那 4 小時只是猜的——實際上 restore 本身可能就要 6 小時，這個承諾是空的。&lt;/p>
&lt;p>量 RTO 要量完整的時間，不只是資料還原那一段。真實的 RTO 從「決定啟動恢復」算起，涵蓋判斷、決策、執行、驗證，一路到服務真的恢復——中間任何一段的時間都算數。RPO 則由冗餘的資料同步方式決定：同步副本的 RPO 接近零，非同步跨 region 副本的 RPO 是那個複製延遲的窗口，這條在 &lt;a href="https://tarrragon.github.io/blog/devops/operations/06-high-availability/redundancy-patterns/" data-link-title="冗餘設計模式" data-link-desc="在 active-passive、active-active、multi-region 之間選冗餘模式時，用資料同步方式與 standby 是否服務流量來區分，並知道冗餘不等於備份">冗餘設計模式&lt;/a> 講過。要讓這兩個數字從猜測變成承諾，只有一條路：用 restore drill 實際量測，拿量到的真實值去更新承諾。&lt;/p>
&lt;h2 id="rto-由備援的就緒程度決定">RTO 由備援的就緒程度決定&lt;/h2>
&lt;p>要達到某個 RTO，付出的成本取決於備援平時準備到多「熱」，這條光譜有公認的命名。最冷的是純備份還原（backup-restore）——平時只有備份、故障時從零重建環境，最便宜、但 RTO 最長。往上是 pilot-light——核心元件（如資料庫的副本）常態開著、其餘按需啟動，故障時把周邊點亮，中等成本與 RTO。再往上是 warm-standby——一個縮小規格的完整環境常態運轉、故障時放大到全量，RTO 更短。最熱的是 hot-standby（即 &lt;a href="https://tarrragon.github.io/blog/devops/operations/06-high-availability/redundancy-patterns/" data-link-title="冗餘設計模式" data-link-desc="在 active-passive、active-active、multi-region 之間選冗餘模式時，用資料同步方式與 standby 是否服務流量來區分，並知道冗餘不等於備份">冗餘設計模式&lt;/a> 的 active-passive 熱備）——全規格備援常開、秒級到分鐘級切換，RTO 最短、成本最高。RTO 承諾要往哪一級靠，跟停機的商業代價一起算，見 &lt;a href="https://tarrragon.github.io/blog/devops/operations/06-high-availability/ha-cost/" data-link-title="高可用的成本" data-link-desc="判斷高可用值不值得時，用停機的商業代價衡量冗餘的 2x 成本、按可用性等級階梯評估投資、以及知道沒驗證的冗餘等於白付">高可用的成本&lt;/a>。&lt;/p>
&lt;h2 id="restore-驗證的三個層次">Restore 驗證的三個層次&lt;/h2>
&lt;p>備份的價值只在還原的那一刻才被證明。一個從沒被 restore 過的 backup，等於一個沒被驗證過的假設。restore 驗證要覆蓋三個層次。第一層是資料完整性——用 row count 比對、checksum、對帳查詢確認資料真的完整，這裡的失敗模式是 backup 的時段跨越了某個批次 job、或增量備份的鏈條中間斷了。第二層是服務可用性——config、secret、schema 版本、連線池這些元件 restore 之後可能失效，要跑 smoke test 加健康檢查確認服務真的起得來，不是只有資料回來了。第三層是恢復時間量測——這次 restore 實際花多久，拿去校準 RTO 承諾。&lt;/p>
&lt;p>這三層裡最容易被跳過的是「真的跑一次」。backup 有排程、每天都在備，但 restore 從來沒跑過——而 restore 是唯一能證明備份可用的手段。備份排程做得再勤，沒驗證過還原，就是在累積一堆不知道能不能用的檔案。&lt;/p>
&lt;h2 id="恢復不是切回流量就結束">恢復不是切回流量就結束&lt;/h2>
&lt;p>一個危險的誤解是把「切回流量」當成恢復完成。真實的恢復往往在切回流量之後還有很長一段。有遊戲平台的一次故障中斷了 73 小時，拉長的原因不在切換本身——是資料一致性要重建、快取要預熱、依賴服務要按正確順序啟動，這些在流量切回來之後才開始、而且各自要花時間。恢復的實際成本包含這些「切回之後」的收尾，把它們算漏，RTO 就會嚴重低估。&lt;/p>
&lt;p>恢復還要分批、不能一次全開——這條分批推進、恢復工具不依賴故障控制面的紀律，跟 &lt;a href="https://tarrragon.github.io/blog/devops/operations/06-high-availability/failover-mechanism/" data-link-title="Failover 機制" data-link-desc="設計單點掛掉自動切到替代路徑的機制時，釐清觸發靠探活、故障域要先劃定、恢復順序的循環等待風險、以及 rollback 與 roll-forward 怎麼選">Failover 機制&lt;/a> 的恢復順序是同一套，在那裡展開。DR 這裡要補的是它跟 RTO 的關係：分批恢復本身要花時間、每批之間的驗證也要花時間，這些全部算進 RTO——把「切回之後」的收尾與分批的時間算漏，RTO 就會嚴重低估。&lt;/p>
&lt;h2 id="演練節奏計畫不演練就會漂移">演練節奏：計畫不演練就會漂移&lt;/h2>
&lt;p>DR 的能力會隨系統演進而悄悄失效——一份寫在 wiki、過去 12 個月沒演練過的 DR plan，基本上不可信，因為這 12 個月裡 production 一直在變、plan 早就跟現實漂移了。維持 DR 能力靠固定節奏的演練，不同類型有不同頻率：桌面推演（走一遍決策路由與角色分工）每季、局部 failover（切一個子系統、驗自動化腳本在 production 真的可執行）每半年、全區 failover（整區從災難回來、輸出 RTO/RPO 與資料一致性檢查）每年、資料還原演練每季。演練暴露的缺口要回寫進技術債追蹤——高優先的下個發布週期前修、次要的排入固定追蹤，不能演練完就散會。&lt;/p>
&lt;h2 id="dr-與-chaos-的分工">DR 與 chaos 的分工&lt;/h2>
&lt;p>DR 演練跟 chaos testing 容易混淆，但驗的是不同的事。chaos 驗「故障持續期間，服務能不能維持」——成功條件是穩態不被破壞、實驗結束系統還在運作；DR 驗「災難發生後，能不能回來」——成功條件是恢復路徑可執行、且符合 RTO/RPO，要經歷一次完整的失效加恢復循環。兩者的交集是 failover drill：chaos 關心切換期間退化多少，DR 關心切換完成後恢復的品質。要驗證高可用，兩者都需要——一個保證撐得住，一個保證回得來。&lt;/p>
&lt;h2 id="下一步路由">下一步路由&lt;/h2>
&lt;ul>
&lt;li>RPO 的來源——同步 vs 非同步副本 → &lt;a href="https://tarrragon.github.io/blog/devops/operations/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/operations/06-high-availability/failover-mechanism/" data-link-title="Failover 機制" data-link-desc="設計單點掛掉自動切到替代路徑的機制時，釐清觸發靠探活、故障域要先劃定、恢復順序的循環等待風險、以及 rollback 與 roll-forward 怎麼選">Failover 機制&lt;/a>&lt;/li>
&lt;li>計畫內的暫停之後恢復一台主機：恢復工具不必避開已經故障的控制面，順序由每一段要用到前一段的產出、對外開放之前先裝好更新這兩個依賴決定 → &lt;a href="https://tarrragon.github.io/blog/devops/operations/09-host-lifecycle/suspend-and-resume-service/" data-link-title="服務暫停與恢復上線：只停服務、停止主機、終止主機到全部刪除各自保留的資源，暫停期間仍計費與仍被指向的資源，恢復前要查的漂移與恢復的順序" data-link-desc="一台主機上的服務要暫停一段時間再恢復：只停服務、停止主機、終止主機保留設定、全部刪除靠 repo 重建各自保留什麼與付出什麼，怎麼依保留的月費、重建的成本與漂移量選擇，暫停期間仍在計費的資源（含在作業系統裡 shutdown 不停止計費），仍被 DNS 與 CDN 指向的結果（Cloudflare 521、522，釋放 IP 之後的懸空 DNS），恢復前要重新確認的漂移，以及依元件依賴排出的恢復順序與驗證">服務暫停與恢復上線：只停服務、停止主機、終止主機到全部刪除各自保留的資源，暫停期間仍計費與仍被指向的資源，恢復前要查的漂移與恢復的順序&lt;/a>〈恢復的順序：依元件之間的依賴排列〉&lt;/li>
&lt;li>這一切要付多少、值不值得 → &lt;a href="https://tarrragon.github.io/blog/devops/operations/06-high-availability/ha-cost/" data-link-title="高可用的成本" data-link-desc="判斷高可用值不值得時，用停機的商業代價衡量冗餘的 2x 成本、按可用性等級階梯評估投資、以及知道沒驗證的冗餘等於白付">高可用的成本&lt;/a>&lt;/li>
&lt;li>DR 與 rollback 演練的完整方法 → &lt;a href="https://tarrragon.github.io/blog/backend/06-reliability/dr-rollback-rehearsal/" data-link-title="6.7 DR 演練與 Rollback Rehearsal" data-link-desc="把回復路徑從紙面計畫變成定期可重播、可量測的驗證流程">backend DR 與 rollback 演練&lt;/a>&lt;/li>
&lt;/ul></description><content:encoded><![CDATA[<p>Disaster recovery 回答「災難發生後，服務能不能回來」。它有一條先於一切的原則：先確認路徑，再談速度。一份 backup 在被 restore 驗證過之前，它只是備份、不是復原能力；一套 failover 的 config 在沒跟 production 對齊之前，它只是文件、不是可執行的操作路由。RTO 跟 RPO 這些速度指標，是在「路徑確實走得通」之後才有意義的——路徑不通，再漂亮的目標數字都是空的。</p>
<h2 id="rto-與-rpo是承諾不能是猜測">RTO 與 RPO：是承諾，不能是猜測</h2>
<p>RTO（恢復時間目標）是「多久之內要恢復服務」，RPO（資料遺失目標）是「最多能丟多少資料」。這兩個數字有一個常見的陷阱：它們常常是估值、不是量值。一個寫在文件上「4 小時 RTO」的承諾，如果從沒真的跑過一次完整恢復，那 4 小時只是猜的——實際上 restore 本身可能就要 6 小時，這個承諾是空的。</p>
<p>量 RTO 要量完整的時間，不只是資料還原那一段。真實的 RTO 從「決定啟動恢復」算起，涵蓋判斷、決策、執行、驗證，一路到服務真的恢復——中間任何一段的時間都算數。RPO 則由冗餘的資料同步方式決定：同步副本的 RPO 接近零，非同步跨 region 副本的 RPO 是那個複製延遲的窗口，這條在 <a href="/blog/devops/operations/06-high-availability/redundancy-patterns/" data-link-title="冗餘設計模式" data-link-desc="在 active-passive、active-active、multi-region 之間選冗餘模式時，用資料同步方式與 standby 是否服務流量來區分，並知道冗餘不等於備份">冗餘設計模式</a> 講過。要讓這兩個數字從猜測變成承諾，只有一條路：用 restore drill 實際量測，拿量到的真實值去更新承諾。</p>
<h2 id="rto-由備援的就緒程度決定">RTO 由備援的就緒程度決定</h2>
<p>要達到某個 RTO，付出的成本取決於備援平時準備到多「熱」，這條光譜有公認的命名。最冷的是純備份還原（backup-restore）——平時只有備份、故障時從零重建環境，最便宜、但 RTO 最長。往上是 pilot-light——核心元件（如資料庫的副本）常態開著、其餘按需啟動，故障時把周邊點亮，中等成本與 RTO。再往上是 warm-standby——一個縮小規格的完整環境常態運轉、故障時放大到全量，RTO 更短。最熱的是 hot-standby（即 <a href="/blog/devops/operations/06-high-availability/redundancy-patterns/" data-link-title="冗餘設計模式" data-link-desc="在 active-passive、active-active、multi-region 之間選冗餘模式時，用資料同步方式與 standby 是否服務流量來區分，並知道冗餘不等於備份">冗餘設計模式</a> 的 active-passive 熱備）——全規格備援常開、秒級到分鐘級切換，RTO 最短、成本最高。RTO 承諾要往哪一級靠，跟停機的商業代價一起算，見 <a href="/blog/devops/operations/06-high-availability/ha-cost/" data-link-title="高可用的成本" data-link-desc="判斷高可用值不值得時，用停機的商業代價衡量冗餘的 2x 成本、按可用性等級階梯評估投資、以及知道沒驗證的冗餘等於白付">高可用的成本</a>。</p>
<h2 id="restore-驗證的三個層次">Restore 驗證的三個層次</h2>
<p>備份的價值只在還原的那一刻才被證明。一個從沒被 restore 過的 backup，等於一個沒被驗證過的假設。restore 驗證要覆蓋三個層次。第一層是資料完整性——用 row count 比對、checksum、對帳查詢確認資料真的完整，這裡的失敗模式是 backup 的時段跨越了某個批次 job、或增量備份的鏈條中間斷了。第二層是服務可用性——config、secret、schema 版本、連線池這些元件 restore 之後可能失效，要跑 smoke test 加健康檢查確認服務真的起得來，不是只有資料回來了。第三層是恢復時間量測——這次 restore 實際花多久，拿去校準 RTO 承諾。</p>
<p>這三層裡最容易被跳過的是「真的跑一次」。backup 有排程、每天都在備，但 restore 從來沒跑過——而 restore 是唯一能證明備份可用的手段。備份排程做得再勤，沒驗證過還原，就是在累積一堆不知道能不能用的檔案。</p>
<h2 id="恢復不是切回流量就結束">恢復不是切回流量就結束</h2>
<p>一個危險的誤解是把「切回流量」當成恢復完成。真實的恢復往往在切回流量之後還有很長一段。有遊戲平台的一次故障中斷了 73 小時，拉長的原因不在切換本身——是資料一致性要重建、快取要預熱、依賴服務要按正確順序啟動，這些在流量切回來之後才開始、而且各自要花時間。恢復的實際成本包含這些「切回之後」的收尾，把它們算漏，RTO 就會嚴重低估。</p>
<p>恢復還要分批、不能一次全開——這條分批推進、恢復工具不依賴故障控制面的紀律，跟 <a href="/blog/devops/operations/06-high-availability/failover-mechanism/" data-link-title="Failover 機制" data-link-desc="設計單點掛掉自動切到替代路徑的機制時，釐清觸發靠探活、故障域要先劃定、恢復順序的循環等待風險、以及 rollback 與 roll-forward 怎麼選">Failover 機制</a> 的恢復順序是同一套，在那裡展開。DR 這裡要補的是它跟 RTO 的關係：分批恢復本身要花時間、每批之間的驗證也要花時間，這些全部算進 RTO——把「切回之後」的收尾與分批的時間算漏，RTO 就會嚴重低估。</p>
<h2 id="演練節奏計畫不演練就會漂移">演練節奏：計畫不演練就會漂移</h2>
<p>DR 的能力會隨系統演進而悄悄失效——一份寫在 wiki、過去 12 個月沒演練過的 DR plan，基本上不可信，因為這 12 個月裡 production 一直在變、plan 早就跟現實漂移了。維持 DR 能力靠固定節奏的演練，不同類型有不同頻率：桌面推演（走一遍決策路由與角色分工）每季、局部 failover（切一個子系統、驗自動化腳本在 production 真的可執行）每半年、全區 failover（整區從災難回來、輸出 RTO/RPO 與資料一致性檢查）每年、資料還原演練每季。演練暴露的缺口要回寫進技術債追蹤——高優先的下個發布週期前修、次要的排入固定追蹤，不能演練完就散會。</p>
<h2 id="dr-與-chaos-的分工">DR 與 chaos 的分工</h2>
<p>DR 演練跟 chaos testing 容易混淆，但驗的是不同的事。chaos 驗「故障持續期間，服務能不能維持」——成功條件是穩態不被破壞、實驗結束系統還在運作；DR 驗「災難發生後，能不能回來」——成功條件是恢復路徑可執行、且符合 RTO/RPO，要經歷一次完整的失效加恢復循環。兩者的交集是 failover drill：chaos 關心切換期間退化多少，DR 關心切換完成後恢復的品質。要驗證高可用，兩者都需要——一個保證撐得住，一個保證回得來。</p>
<h2 id="下一步路由">下一步路由</h2>
<ul>
<li>RPO 的來源——同步 vs 非同步副本 → <a href="/blog/devops/operations/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/operations/06-high-availability/failover-mechanism/" data-link-title="Failover 機制" data-link-desc="設計單點掛掉自動切到替代路徑的機制時，釐清觸發靠探活、故障域要先劃定、恢復順序的循環等待風險、以及 rollback 與 roll-forward 怎麼選">Failover 機制</a></li>
<li>計畫內的暫停之後恢復一台主機：恢復工具不必避開已經故障的控制面，順序由每一段要用到前一段的產出、對外開放之前先裝好更新這兩個依賴決定 → <a href="/blog/devops/operations/09-host-lifecycle/suspend-and-resume-service/" data-link-title="服務暫停與恢復上線：只停服務、停止主機、終止主機到全部刪除各自保留的資源，暫停期間仍計費與仍被指向的資源，恢復前要查的漂移與恢復的順序" data-link-desc="一台主機上的服務要暫停一段時間再恢復：只停服務、停止主機、終止主機保留設定、全部刪除靠 repo 重建各自保留什麼與付出什麼，怎麼依保留的月費、重建的成本與漂移量選擇，暫停期間仍在計費的資源（含在作業系統裡 shutdown 不停止計費），仍被 DNS 與 CDN 指向的結果（Cloudflare 521、522，釋放 IP 之後的懸空 DNS），恢復前要重新確認的漂移，以及依元件依賴排出的恢復順序與驗證">服務暫停與恢復上線：只停服務、停止主機、終止主機到全部刪除各自保留的資源，暫停期間仍計費與仍被指向的資源，恢復前要查的漂移與恢復的順序</a>〈恢復的順序：依元件之間的依賴排列〉</li>
<li>這一切要付多少、值不值得 → <a href="/blog/devops/operations/06-high-availability/ha-cost/" data-link-title="高可用的成本" data-link-desc="判斷高可用值不值得時，用停機的商業代價衡量冗餘的 2x 成本、按可用性等級階梯評估投資、以及知道沒驗證的冗餘等於白付">高可用的成本</a></li>
<li>DR 與 rollback 演練的完整方法 → <a href="/blog/backend/06-reliability/dr-rollback-rehearsal/" data-link-title="6.7 DR 演練與 Rollback Rehearsal" data-link-desc="把回復路徑從紙面計畫變成定期可重播、可量測的驗證流程">backend DR 與 rollback 演練</a></li>
</ul>
]]></content:encoded></item><item><title>高可用的成本</title><link>https://tarrragon.github.io/blog/devops/operations/06-high-availability/ha-cost/</link><pubDate>Fri, 03 Jul 2026 00:00:00 +0800</pubDate><guid>https://tarrragon.github.io/blog/devops/operations/06-high-availability/ha-cost/</guid><description>&lt;p>高可用的成本核心是冗餘要多付一份資源，但多付多少取決於冗餘的形態，範圍從約 10% 到 100% 不等。最貴的一端是有狀態的熱備——一份 standby 跟主份同規格計費、平時完全閒置，等於把成本翻倍（2x）。最便宜的一端是無狀態機群的 N+1／N+M——一個 10 台的機群多加 1 台備援，只多約 10% 的開銷。所以「冗餘至少 2x」只對熱備成立，不能套到整套系統。這筆錢值不值得，不能用絕對數字判斷，要用「停機每小時的商業代價」衡量：一個停機一小時就損失巨大營收的服務，付冗餘換分鐘級 failover 很划算；一個停機幾小時無傷大雅的內部工具，付這筆冗餘就是浪費。高可用的設計目標是把可用性投資對齊停機的真實代價，而不是越高越好。&lt;/p>
&lt;h2 id="2x-的來源閒置的備援">2x 的來源：閒置的備援&lt;/h2>
&lt;p>冗餘的 2x 成本最直接的例子是資料庫的 multi-AZ——它的費用約是單一可用區的兩倍，因為那個 standby instance 按相同規格計費，卻不服務任何流量。這就是 active-passive 的閒置成本：備援存在、隨時準備接手，但平時純粹在燒錢等 failover。active-active 的冗餘資源閒置成本較低——那些資源平時就在分攤負載、沒閒著——但代價換到了資料一致性的協調成本上。更便宜的是無狀態機群的 N+1／N+M：機群本來就多台在分攤流量，多備一兩台的開銷攤到整個機群、比例很小（&lt;a href="https://tarrragon.github.io/blog/devops/operations/06-high-availability/redundancy-patterns/" data-link-title="冗餘設計模式" data-link-desc="在 active-passive、active-active、multi-region 之間選冗餘模式時，用資料同步方式與 standby 是否服務流量來區分，並知道冗餘不等於備份">冗餘設計模式&lt;/a> 有這個形態的說明）。所以 2x 的實際倍數由「這份冗餘是整份閒置的熱備、還是機群裡多備的幾台」決定，而不是一個固定數字：閒置的熱備付全額閒置成本，機群式的備援只攤到小比例開銷。&lt;/p>
&lt;h2 id="用停機代價衡量值不值得">用停機代價衡量值不值得&lt;/h2>
&lt;p>判斷冗餘值不值得，用的是過度配置的經濟學——過度配置的成本好算、配置不足的代價難算，兩者的平衡點就是該投多少，完整的算法在 &lt;a href="https://tarrragon.github.io/blog/devops/operations/05-capacity-planning/cost-model/" data-link-title="成本模型" data-link-desc="把容量規劃的資源翻成錢時，釐清 on-demand、reserved、spot 三種計費模式的取捨、怎麼算單位請求成本、以及過度與不足配置各自的經濟代價">模組五 成本模型&lt;/a> 展開過。套到高可用上，這個平衡點由停機代價定：關鍵服務的停機代價極高——電商每分鐘宕機對應可估算的營收損失——所以值得付 2x 甚至更多；非關鍵服務停機代價低，貼近最低配置跑就好。同一套判斷標準，關鍵服務算出來要厚冗餘、非關鍵算出來可以薄，差別在停機的代價不同。&lt;/p>
&lt;h2 id="可用性等級是一道成本階梯">可用性等級是一道成本階梯&lt;/h2>
&lt;p>可用性是一道階梯，而不是連續的旋鈕——每往上一級，成本與複雜度同步階梯上升。單一可用區是一級、跨可用區（multi-AZ）是一級、跨區域（multi-region）又是一級。多數服務的合理路徑是先把單一區域的 multi-AZ 加備份做扎實，再評估要不要跨區域，依據是業務對「整個區域級故障」的容忍度。&lt;/p>
&lt;p>跨區域這一級的決策特別要注意：它通常是合約 SLA 驅動的、不是技術判斷驅動的。一個 B2B SaaS 在合約裡承諾了某個可用性等級，跨區域投資才容易成立；純技術上「想更穩」很少足以正當化跨區域的成本與複雜度。可用性的頂級是有代價的錨——有平台跨 15 個區域做到 99.999%（一年停機約 5 分鐘），那個數字背後是十幾個區域各自維護的基礎設施。要不要爬到那一級，看的是合約與業務、不是工程的完美主義。&lt;/p>
&lt;h2 id="冗餘成本要有護欄">冗餘成本要有護欄&lt;/h2>
&lt;p>為可用性花錢也會失控，要有護欄。最典型的護欄是自動擴縮的成本上限——它是財務上的斷路器（&lt;a href="https://tarrragon.github.io/blog/devops/operations/05-capacity-planning/cost-model/" data-link-title="成本模型" data-link-desc="把容量規劃的資源翻成錢時，釐清 on-demand、reserved、spot 三種計費模式的取捨、怎麼算單位請求成本、以及過度與不足配置各自的經濟代價">模組五 成本模型&lt;/a> 講過），設無限大就等著一次異常把帳單炸掉。高可用的投入同理：冗餘、備援、跨區複製每一項都要有成本上限，否則「為了更穩」會變成一個無底洞。可用性投資要跟一個明確的成本天花板綁在一起，超過就回頭重新評估這一級到底值不值得。&lt;/p>
&lt;h2 id="沒驗證的冗餘等於白付">沒驗證的冗餘等於白付&lt;/h2>
&lt;p>最後一筆容易漏算的成本是驗證。冗餘、DR、failover 都要靠演練驗證才算數，而演練要投入工程時間——這是高可用成本的一部分，不是額外選項。一個沒被 drill 驗證過的 multi-AZ、一份沒被 restore 過的 backup，是紙面上的冗餘：帳單上付了 2x，但真出事時它不一定接得住，等於白付了那筆冗餘成本。算高可用的總成本，要把「持續驗證的工程投入」算進去——冗餘的錢加上驗證的工，才是它真正的價格。省掉驗證的那份冗餘，是最貴的一種，因為它讓人以為有保障、實際沒有。&lt;/p>
&lt;h2 id="下一步路由">下一步路由&lt;/h2>
&lt;ul>
&lt;li>過度配置的經濟學、autoscaler 的成本斷路器 → &lt;a href="https://tarrragon.github.io/blog/devops/operations/05-capacity-planning/cost-model/" data-link-title="成本模型" data-link-desc="把容量規劃的資源翻成錢時，釐清 on-demand、reserved、spot 三種計費模式的取捨、怎麼算單位請求成本、以及過度與不足配置各自的經濟代價">模組五 成本模型&lt;/a>&lt;/li>
&lt;li>冗餘怎麼擺、2x 從哪來 → &lt;a href="https://tarrragon.github.io/blog/devops/operations/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/operations/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/devops/operations/08-cost-management/" data-link-title="模組八：成本管理" data-link-desc="雲端帳單怎麼不失控 — reserved instance、spot instance、right-sizing 與成本監控告警；預算門檻、配額與停損層級的推算在本模組，各家的建置篇目前只有 GCP，放在雲端業者模組">模組八 成本管理&lt;/a>&lt;/li>
&lt;/ul></description><content:encoded><![CDATA[<p>高可用的成本核心是冗餘要多付一份資源，但多付多少取決於冗餘的形態，範圍從約 10% 到 100% 不等。最貴的一端是有狀態的熱備——一份 standby 跟主份同規格計費、平時完全閒置，等於把成本翻倍（2x）。最便宜的一端是無狀態機群的 N+1／N+M——一個 10 台的機群多加 1 台備援，只多約 10% 的開銷。所以「冗餘至少 2x」只對熱備成立，不能套到整套系統。這筆錢值不值得，不能用絕對數字判斷，要用「停機每小時的商業代價」衡量：一個停機一小時就損失巨大營收的服務，付冗餘換分鐘級 failover 很划算；一個停機幾小時無傷大雅的內部工具，付這筆冗餘就是浪費。高可用的設計目標是把可用性投資對齊停機的真實代價，而不是越高越好。</p>
<h2 id="2x-的來源閒置的備援">2x 的來源：閒置的備援</h2>
<p>冗餘的 2x 成本最直接的例子是資料庫的 multi-AZ——它的費用約是單一可用區的兩倍，因為那個 standby instance 按相同規格計費，卻不服務任何流量。這就是 active-passive 的閒置成本：備援存在、隨時準備接手，但平時純粹在燒錢等 failover。active-active 的冗餘資源閒置成本較低——那些資源平時就在分攤負載、沒閒著——但代價換到了資料一致性的協調成本上。更便宜的是無狀態機群的 N+1／N+M：機群本來就多台在分攤流量，多備一兩台的開銷攤到整個機群、比例很小（<a href="/blog/devops/operations/06-high-availability/redundancy-patterns/" data-link-title="冗餘設計模式" data-link-desc="在 active-passive、active-active、multi-region 之間選冗餘模式時，用資料同步方式與 standby 是否服務流量來區分，並知道冗餘不等於備份">冗餘設計模式</a> 有這個形態的說明）。所以 2x 的實際倍數由「這份冗餘是整份閒置的熱備、還是機群裡多備的幾台」決定，而不是一個固定數字：閒置的熱備付全額閒置成本，機群式的備援只攤到小比例開銷。</p>
<h2 id="用停機代價衡量值不值得">用停機代價衡量值不值得</h2>
<p>判斷冗餘值不值得，用的是過度配置的經濟學——過度配置的成本好算、配置不足的代價難算，兩者的平衡點就是該投多少，完整的算法在 <a href="/blog/devops/operations/05-capacity-planning/cost-model/" data-link-title="成本模型" data-link-desc="把容量規劃的資源翻成錢時，釐清 on-demand、reserved、spot 三種計費模式的取捨、怎麼算單位請求成本、以及過度與不足配置各自的經濟代價">模組五 成本模型</a> 展開過。套到高可用上，這個平衡點由停機代價定：關鍵服務的停機代價極高——電商每分鐘宕機對應可估算的營收損失——所以值得付 2x 甚至更多；非關鍵服務停機代價低，貼近最低配置跑就好。同一套判斷標準，關鍵服務算出來要厚冗餘、非關鍵算出來可以薄，差別在停機的代價不同。</p>
<h2 id="可用性等級是一道成本階梯">可用性等級是一道成本階梯</h2>
<p>可用性是一道階梯，而不是連續的旋鈕——每往上一級，成本與複雜度同步階梯上升。單一可用區是一級、跨可用區（multi-AZ）是一級、跨區域（multi-region）又是一級。多數服務的合理路徑是先把單一區域的 multi-AZ 加備份做扎實，再評估要不要跨區域，依據是業務對「整個區域級故障」的容忍度。</p>
<p>跨區域這一級的決策特別要注意：它通常是合約 SLA 驅動的、不是技術判斷驅動的。一個 B2B SaaS 在合約裡承諾了某個可用性等級，跨區域投資才容易成立；純技術上「想更穩」很少足以正當化跨區域的成本與複雜度。可用性的頂級是有代價的錨——有平台跨 15 個區域做到 99.999%（一年停機約 5 分鐘），那個數字背後是十幾個區域各自維護的基礎設施。要不要爬到那一級，看的是合約與業務、不是工程的完美主義。</p>
<h2 id="冗餘成本要有護欄">冗餘成本要有護欄</h2>
<p>為可用性花錢也會失控，要有護欄。最典型的護欄是自動擴縮的成本上限——它是財務上的斷路器（<a href="/blog/devops/operations/05-capacity-planning/cost-model/" data-link-title="成本模型" data-link-desc="把容量規劃的資源翻成錢時，釐清 on-demand、reserved、spot 三種計費模式的取捨、怎麼算單位請求成本、以及過度與不足配置各自的經濟代價">模組五 成本模型</a> 講過），設無限大就等著一次異常把帳單炸掉。高可用的投入同理：冗餘、備援、跨區複製每一項都要有成本上限，否則「為了更穩」會變成一個無底洞。可用性投資要跟一個明確的成本天花板綁在一起，超過就回頭重新評估這一級到底值不值得。</p>
<h2 id="沒驗證的冗餘等於白付">沒驗證的冗餘等於白付</h2>
<p>最後一筆容易漏算的成本是驗證。冗餘、DR、failover 都要靠演練驗證才算數，而演練要投入工程時間——這是高可用成本的一部分，不是額外選項。一個沒被 drill 驗證過的 multi-AZ、一份沒被 restore 過的 backup，是紙面上的冗餘：帳單上付了 2x，但真出事時它不一定接得住，等於白付了那筆冗餘成本。算高可用的總成本，要把「持續驗證的工程投入」算進去——冗餘的錢加上驗證的工，才是它真正的價格。省掉驗證的那份冗餘，是最貴的一種，因為它讓人以為有保障、實際沒有。</p>
<h2 id="下一步路由">下一步路由</h2>
<ul>
<li>過度配置的經濟學、autoscaler 的成本斷路器 → <a href="/blog/devops/operations/05-capacity-planning/cost-model/" data-link-title="成本模型" data-link-desc="把容量規劃的資源翻成錢時，釐清 on-demand、reserved、spot 三種計費模式的取捨、怎麼算單位請求成本、以及過度與不足配置各自的經濟代價">模組五 成本模型</a></li>
<li>冗餘怎麼擺、2x 從哪來 → <a href="/blog/devops/operations/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/operations/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/devops/operations/08-cost-management/" data-link-title="模組八：成本管理" data-link-desc="雲端帳單怎麼不失控 — reserved instance、spot instance、right-sizing 與成本監控告警；預算門檻、配額與停損層級的推算在本模組，各家的建置篇目前只有 GCP，放在雲端業者模組">模組八 成本管理</a></li>
</ul>
]]></content:encoded></item><item><title>小型服務的兩到三台主機配置：第二台與第三台主機的用法、監控主機的位置與連線、兩台主機互相監看，以及雲端業者負責的範圍</title><link>https://tarrragon.github.io/blog/devops/operations/06-high-availability/small-service-host-layout/</link><pubDate>Wed, 14 Oct 2026 00:00:00 +0800</pubDate><guid>https://tarrragon.github.io/blog/devops/operations/06-high-availability/small-service-host-layout/</guid><description>&lt;p>一個小型服務（一組應用程式、一個資料庫、一個快取，由一個小團隊維運）從一台主機擴充到兩到三台時，每一台主機放什麼、每一種分法換到什麼，以及哪些故障與攻擊要由雲端業者或入口的設定處理，是這一篇的範圍。內容是設計與規劃：監控主機跨業者讀取服務主機、兩台主機互相監看的配置，本篇沒有在兩台實體主機上部署驗證，這兩部分寫的是要決定的事與它們的前提，沒有附操作指令。單一主機上監控看不到的故障見 &lt;a href="https://tarrragon.github.io/blog/backend/04-observability/single-host-monitoring-outside-view/" data-link-title="4.28 單台主機的監控盲區與失效域以外的觀察者：主機停機、使用者路徑中斷與告警鏈中斷，心跳監看與外部探測各自回答的問題與位置，以及與內部探測並排的判讀" data-link-desc="服務與監控放在同一台主機時監控結構上看不到的故障：主機整台停掉、使用者到主機的路徑中斷、告警鏈停掉與通知送不出去；從失效域以外送出訊號的心跳監看與外部探測各自回答的問題與成立條件，觀察者由第三方服務、另一個失效域的主機（含兩台主機互相監看）或另一個業者的排程平台提供時的差別，以及心跳監看、外部探測與主機內部探測並排時的判讀">4.28 單台主機的監控盲區與失效域以外的觀察者&lt;/a>，冗餘的一般模式見 &lt;a href="https://tarrragon.github.io/blog/devops/operations/06-high-availability/redundancy-patterns/" data-link-title="冗餘設計模式" data-link-desc="在 active-passive、active-active、multi-region 之間選冗餘模式時，用資料同步方式與 standby 是否服務流量來區分，並知道冗餘不等於備份">冗餘設計模式&lt;/a>。&lt;/p>
&lt;h2 id="一台主機承擔的風險">一台主機承擔的風險&lt;/h2>
&lt;p>一台主機上跑著入口、應用程式、資料庫、快取與整組監控時，所有元件共用同一個&lt;a href="https://tarrragon.github.io/blog/backend/knowledge-cards/failure-domain/" data-link-title="Failure Domain（失效域）" data-link-desc="判斷兩個元件會不會因為同一件事一起停掉、備援或監控是否獨立於被保護的對象時，查它們共用了哪些會失效的依賴">失效域&lt;/a>（failure domain），風險有三種。&lt;strong>中斷沒人通知&lt;/strong>：主機停掉時服務中斷，而負責通知的監控同時停掉，要等使用者回報才知道。&lt;strong>監控與服務搶資源&lt;/strong>：主機過載時，應用程式、資料庫與監控搶同一組 CPU 與記憶體，監控量到的延遲混進它自己的等待（見 &lt;a href="https://tarrragon.github.io/blog/backend/04-observability/host-overload-alerting/" data-link-title="4.27 主機過載時的監控告警：可用與變慢分開判斷、依原因抑制、監控自身的等待" data-link-desc="多個服務共用一台主機而主機過載時，各服務的探測與告警會一起失敗：可用性與延遲分成兩個判斷的寫法、間歇的條件怎麼持續成立、以主機飽和抑制各服務變慢的規則與它的取捨、以合成告警驗證抑制、抑制藏起各服務受影響程度的差別、探測與 Prometheus 自己也在等 CPU 時的訊號，以及讓監控不比服務先失效的資源隔離；以一次開發環境的過載為例">4.27 主機過載時的監控告警&lt;/a>）。&lt;strong>資料與備份一起消失&lt;/strong>：資料與它的備份放在同一台主機的磁碟上時，磁碟損壞或帳號被停權會讓兩者一起消失。&lt;/p>
&lt;p>資料與備份一起消失是三種裡唯一不可逆的，也不需要第二台主機：備份放到另一個業者的物件儲存或另一個帳號，就不再與資料一起消失（備份與資料放在同一個帳號時，帳號被停權、或存取憑證外洩後被人刪除，兩者一起消失），所以它排在加主機之前做（備份的驗證見 &lt;a href="https://tarrragon.github.io/blog/devops/going-live/backup-restore-basics/" data-link-title="備份與還原的地基" data-link-desc="有了線上資料、知道「要備份」但不確定備什麼、多久一次、以及為什麼「沒測過還原的備份等於沒有」時回來讀 — 備份的地基認識">備份與還原的地基&lt;/a>）。分開帳號擋的是資料所在帳號的憑證外洩；寫入備份的那把存取金鑰仍放在服務主機上，它外洩之後備份會不會被刪除或覆寫，見 &lt;a href="https://tarrragon.github.io/blog/backend/07-security-data-protection/cross-network-connection-security/#%e9%9b%b2%e7%ab%af%e5%b0%8d%e9%9b%b2%e7%ab%af%e8%88%87%e7%95%b0%e5%9c%b0%e5%82%99%e4%bb%bd%e6%b2%92%e6%9c%89%e5%85%b1%e7%94%a8%e7%a7%81%e7%b6%b2%e6%99%82%e7%9a%84%e6%8e%a5%e6%b3%95" data-link-title="7.43 兩個網路之間的連線安全：可達範圍、連線方向與流入的資料、被入侵端改不到的限制、應用層認證、監控主機的位置、金鑰與控制平面、異地備份的寫入憑證與連線紀錄" data-link-desc="地端主機與雲端主機、或兩個雲端業者的主機以 VPN 或存取金鑰接起來之後的安全設計與評估：連線清單上各台連得到什麼、每一台各假設一次被入侵、限制要放在被入侵端沒有寫入路徑的地方、連線的發起方向與流入的資料、VPN 之內的應用層認證、監控主機與管理者裝置的位置、WireGuard 與 Tailscale 的金鑰與控制平面、異地備份的寫入憑證，以及連線本身的紀錄">7.43 兩個網路之間的連線安全&lt;/a>。第二台主機處理的是中斷沒人通知、監控與服務搶資源，處理哪一種取決於它放什麼。&lt;/p>
&lt;h2 id="第二台主機的用法給監控給應用程式的副本或給資料庫">第二台主機的用法：給監控、給應用程式的副本或給資料庫&lt;/h2>
&lt;p>&lt;strong>給監控。&lt;/strong> Prometheus、Alertmanager 與 Grafana 搬到第二台，服務主機只留 &lt;a href="https://tarrragon.github.io/blog/backend/knowledge-cards/prometheus-exporter/" data-link-title="Prometheus Exporter（指標轉接程式）" data-link-desc="要監控一個不會自己輸出 Prometheus 指標的系統（主機、容器、資料庫、快取、Nginx）時，查 exporter 做什麼、它和應用程式自己開的 /metrics 差在哪，以及 exporter 讀得到資料卻缺標籤、或者讀不到它所在層以外的機器時怎麼發現">exporter&lt;/a>（輸出指標給 Prometheus 讀取的程式）。原本跑在同一台的自架通知服務（ntfy、郵件轉送）一起搬過去，或改用外部的服務；留在服務主機上的話，「服務主機停了」這則告警要經過那台已經停掉的主機。服務主機停掉時，監控主機讀不到它的指標而發出告警；監控主機停掉時，服務照常運作，由服務主機上的心跳監看程式發現（見〈兩台主機互相監看〉）。服務本身的可用性沒有提高，主機停掉時服務照樣中斷；換到的是中斷有人通知，以及監控不再與服務搶資源。應用程式不必改，監控主機的資源需求也小（指標量的估算見 &lt;a href="https://tarrragon.github.io/blog/backend/04-observability/vendors/prometheus/capacity-failure-modes/" data-link-title="Prometheus 容量規劃與故障模式" data-link-desc="說明 Prometheus 單機容量邊界、cardinality 與 retention 的資源模型、常見故障模式與判讀方式">Prometheus 容量規劃與故障模式&lt;/a>）。搬的時候要決定既有的指標歷史帶不帶過去：不帶的話新主機從零累積，搬移前後的趨勢在面板上接不起來；要帶的話把 Prometheus 的資料目錄一起搬，停掉舊的 Prometheus 再複製，避免複製到寫到一半的資料。&lt;/p>
&lt;p>&lt;strong>給應用程式的副本。&lt;/strong> 兩台主機各跑一份應用程式，前面以&lt;a href="https://tarrragon.github.io/blog/backend/knowledge-cards/load-balancer/" data-link-title="Load Balancer" data-link-desc="說明流量如何分散、排空與導向健康節點">負載平衡器&lt;/a>分流，一台停掉時另一台接手。換到的是服務的可用性，前提有四個：應用程式是無狀態的（session 不存在單台主機的記憶體或磁碟裡，見 &lt;a href="https://tarrragon.github.io/blog/devops/operations/02-horizontal-scaling/stateless-design/" data-link-title="Stateless 設計原則" data-link-desc="要把服務改成能水平擴展的無狀態設計時，釐清什麼算「本機狀態」、哪些常見寫法會破壞無狀態、隱式狀態怎麼抓、以及定時 job 這種無狀態例外怎麼處理">無狀態設計&lt;/a>）；資料庫不在任何一台應用主機上，否則放著資料庫的那一台停掉時，另一台的應用程式也沒有資料可讀；負載平衡器本身不是單點；應用程式內建的排程工作（清理過期的短網址、寄信、結算）只在一台執行，否則兩台各跑一份，副作用跟著重複，做法是加鎖、選出一台負責，或把排程工作獨立出來；固定指定一台時，那一台停掉排程就停了，以排程工作的心跳發現（見 &lt;a href="https://tarrragon.github.io/blog/backend/04-observability/single-host-monitoring-outside-view/" data-link-title="4.28 單台主機的監控盲區與失效域以外的觀察者：主機停機、使用者路徑中斷與告警鏈中斷，心跳監看與外部探測各自回答的問題與位置，以及與內部探測並排的判讀" data-link-desc="服務與監控放在同一台主機時監控結構上看不到的故障：主機整台停掉、使用者到主機的路徑中斷、告警鏈停掉與通知送不出去；從失效域以外送出訊號的心跳監看與外部探測各自回答的問題與成立條件，觀察者由第三方服務、另一個失效域的主機（含兩台主機互相監看）或另一個業者的排程平台提供時的差別，以及心跳監看、外部探測與主機內部探測並排時的判讀">4.28 單台主機的監控盲區與失效域以外的觀察者&lt;/a> 的〈心跳監看：監控與送出心跳的那條路還在不在運作〉）。無狀態這一條違反時，平時看不出來：負載平衡器若以 &lt;a href="https://tarrragon.github.io/blog/backend/knowledge-cards/sticky-session/" data-link-title="Sticky Session" data-link-desc="說明同一 client 如何在一段時間內持續命中同一個後端實例">sticky session&lt;/a> 把同一個使用者固定送到同一台，兩台都在時每個人都正常；直到一台停掉的那一刻，那台上的使用者一起被登出、上傳到一半的檔案一起消失，而這是這個配置第一次真正派上用場的時候。資料庫因此要搬到託管服務或第三台主機，這個配置需要兩台應用主機加上另外放置的資料庫。&lt;/p>
&lt;p>&lt;strong>給資料庫。&lt;/strong> 資料庫搬到第二台，應用程式與資料庫各自有一台主機的資源。換到的是效能的隔離：資料庫的大查詢不再拖慢轉址這類延遲敏感的請求，應用程式與資料庫的容量也能分開調整。可用性沒有提高，反而多了一個會讓服務中斷的主機：兩台任一台停掉，服務都中斷。&lt;/p>
&lt;p>目標只有「中斷有人通知」時，不需要第二台主機：第三方的心跳監看與外部探測服務幾乎不花錢就做得到，挑選與接法見 &lt;a href="https://tarrragon.github.io/blog/backend/04-observability/vendors/prometheus/external-heartbeat-and-probe-services/" data-link-title="第三方心跳監看與外部探測服務：挑選條件、healthchecks 的 ping 與 /fail、Alertmanager 的接法與演練" data-link-desc="以第三方服務當作監控主機失效域以外的觀察者：心跳監看服務的挑選條件與送出的告警資料留在哪裡，healthchecks 的 ping 網址、週期與寬限、/fail 與自架和託管版的回應差異，Alertmanager 送心跳與送失敗通知的 receiver 與路由順序、驗收與暫停，停掉 Alertmanager 的演練，以及外部探測服務的挑選條件">第三方心跳監看與外部探測服務&lt;/a>。第二台給監控多換到的是三件事：監控不再與服務搶資源、監控資料與告警內容留在自己手上、心跳的接收端不依賴第三方的服務。通知的寄送與第三個位置的外部探測仍然依賴第三方：用來分辨兩台之間連線中斷的外部探測要放在兩台以外（見〈監控主機與服務主機之間的連線與連線中斷的誤判〉）。所以小型服務在要擴充主機時，第二台先給監控：中斷沒人通知與監控搶資源在一台主機的階段就存在，給監控的第二台同時處理這兩種風險，也不需要改應用程式；應用程式的副本要先處理無狀態化與資料庫的位置，資料庫的分離處理的是效能而不是可用性。停機代價高、主機故障又頻繁的服務，例外地先做應用程式的副本，判斷方式見 &lt;a href="https://tarrragon.github.io/blog/devops/operations/06-high-availability/ha-cost/" data-link-title="高可用的成本" data-link-desc="判斷高可用值不值得時，用停機的商業代價衡量冗餘的 2x 成本、按可用性等級階梯評估投資、以及知道沒驗證的冗餘等於白付">高可用的成本&lt;/a>。&lt;/p>
&lt;h2 id="監控主機的位置另一個業者或地端">監控主機的位置：另一個業者或地端&lt;/h2>
&lt;p>監控主機要與服務主機分屬不同的失效域。兩台虛擬機租在同一個業者、同一個區域時，業者那個區域的網路故障或帳號被停權會讓兩台一起受影響；所以監控主機放在另一個雲端業者，或放在地端（公司或家裡長時間開著的一台主機）。&lt;a href="https://tarrragon.github.io/blog/backend/04-observability/vendors/prometheus/multi-host-scraping/" data-link-title="多台主機的指標收集：讀取架構、主機標籤、目標清單、監控主機的位置與主機消失的偵測" data-link-desc="服務分到多台主機之後，Prometheus 怎麼讀到每一台：exporter 的部署位置與連接埠、中央直接讀取與各主機先收再推送的架構、代表主機的 host 標籤加在哪裡、目標清單由什麼產生，主機停掉與主機從清單上消失各自怎麼偵測，以及監控元件放在哪一台、compose 檔怎麼依主機角色拆開；附在單機上模擬第二台主機的驗證">多台主機的指標收集&lt;/a> 的〈監控主機放在哪裡〉處理的是同一個私有網路裡分出一台監控主機的情形，本篇多加的是失效域的條件。&lt;/p>
&lt;p>監控是內部服務，地端是合理的位置：Grafana 只給團隊看，連線經由 SSH 或 VPN（存取方式見 &lt;a href="https://tarrragon.github.io/blog/backend/04-observability/vendors/prometheus/grafana-external-access/" data-link-title="Grafana 的對外存取：SSH 通道或 VPN、經由應用入口轉送的問題、監控主機上的反向代理，與登入保護和認證的位置" data-link-desc="Grafana 只綁本機之後，讓其他人看到它的做法：看的人能不能經由 SSH 或 VPN 連進來、有沒有固定的來源網段時各自的存取方式，SSH 通道的連法，應用入口 Nginx 加上 Grafana 的轉送之後的兩個問題，監控主機上專用反向代理的 TLS、WebSocket、GF_SERVER_ROOT_URL 與來源限制，以及 Grafana 登入失敗的帳號鎖定與認證放置">Grafana 的對外存取&lt;/a>），不必對網際網路開放 Grafana。地端主機的代價是它自己的可靠度：停電、網路斷線、機器重開時監控就停了，停掉的那段時間沒有指標。這段時間由服務主機上的心跳監看程式發現；監控資料的連續性要求高時，改租另一個業者的小型 VPS。&lt;/p>
&lt;h2 id="監控主機與服務主機之間的連線與連線中斷的誤判">監控主機與服務主機之間的連線與連線中斷的誤判&lt;/h2>
&lt;p>Prometheus 主動讀取各主機的 exporter，所以監控主機要連得到服務主機上的 exporter 連接埠。這些連接埠不對網際網路開放：exporter 預設沒有認證，輸出的指標透露主機的資源、服務的名稱與版本。同一個雲端業者內，exporter 綁在私有網路的位址上（&lt;a href="https://tarrragon.github.io/blog/backend/04-observability/vendors/prometheus/multi-host-scraping/" data-link-title="多台主機的指標收集：讀取架構、主機標籤、目標清單、監控主機的位置與主機消失的偵測" data-link-desc="服務分到多台主機之後，Prometheus 怎麼讀到每一台：exporter 的部署位置與連接埠、中央直接讀取與各主機先收再推送的架構、代表主機的 host 標籤加在哪裡、目標清單由什麼產生，主機停掉與主機從清單上消失各自怎麼偵測，以及監控元件放在哪一台、compose 檔怎麼依主機角色拆開；附在單機上模擬第二台主機的驗證">多台主機的指標收集&lt;/a> 以 &lt;code>EXPORTER_BIND_ADDR&lt;/code> 設定）；跨業者或跨地端時沒有共用的私有網路，要在兩台之間建一條 VPN，例如 WireGuard 或 Tailscale（運作方式見 &lt;a href="https://tarrragon.github.io/blog/linux/tools/remote/tailscale-tailnet-and-relay/" data-link-title="Tailscale 深入：tailnet、MagicDNS、直連與 DERP 中繼" data-link-desc="要用 Tailscale 讓散在不同網路的機器互連、遇到連得到但延遲高、或想讀懂 tailscale status 的 relay / direct 標示時回來讀">Tailscale 深入&lt;/a>），exporter 改綁在 VPN 介面的位址上。VPN 預設兩個方向都互通，雲端主機被入侵時攻擊者也能經由它連回地端；隧道兩端各自連得到什麼、限制要放在哪一端，見 &lt;a href="https://tarrragon.github.io/blog/backend/07-security-data-protection/cross-network-connection-security/" data-link-title="7.43 兩個網路之間的連線安全：可達範圍、連線方向與流入的資料、被入侵端改不到的限制、應用層認證、監控主機的位置、金鑰與控制平面、異地備份的寫入憑證與連線紀錄" data-link-desc="地端主機與雲端主機、或兩個雲端業者的主機以 VPN 或存取金鑰接起來之後的安全設計與評估：連線清單上各台連得到什麼、每一台各假設一次被入侵、限制要放在被入侵端沒有寫入路徑的地方、連線的發起方向與流入的資料、VPN 之內的應用層認證、監控主機與管理者裝置的位置、WireGuard 與 Tailscale 的金鑰與控制平面、異地備份的寫入憑證，以及連線本身的紀錄">7.43 兩個網路之間的連線安全&lt;/a>。&lt;/p></description><content:encoded><![CDATA[<p>一個小型服務（一組應用程式、一個資料庫、一個快取，由一個小團隊維運）從一台主機擴充到兩到三台時，每一台主機放什麼、每一種分法換到什麼，以及哪些故障與攻擊要由雲端業者或入口的設定處理，是這一篇的範圍。內容是設計與規劃：監控主機跨業者讀取服務主機、兩台主機互相監看的配置，本篇沒有在兩台實體主機上部署驗證，這兩部分寫的是要決定的事與它們的前提，沒有附操作指令。單一主機上監控看不到的故障見 <a href="/blog/backend/04-observability/single-host-monitoring-outside-view/" data-link-title="4.28 單台主機的監控盲區與失效域以外的觀察者：主機停機、使用者路徑中斷與告警鏈中斷，心跳監看與外部探測各自回答的問題與位置，以及與內部探測並排的判讀" data-link-desc="服務與監控放在同一台主機時監控結構上看不到的故障：主機整台停掉、使用者到主機的路徑中斷、告警鏈停掉與通知送不出去；從失效域以外送出訊號的心跳監看與外部探測各自回答的問題與成立條件，觀察者由第三方服務、另一個失效域的主機（含兩台主機互相監看）或另一個業者的排程平台提供時的差別，以及心跳監看、外部探測與主機內部探測並排時的判讀">4.28 單台主機的監控盲區與失效域以外的觀察者</a>，冗餘的一般模式見 <a href="/blog/devops/operations/06-high-availability/redundancy-patterns/" data-link-title="冗餘設計模式" data-link-desc="在 active-passive、active-active、multi-region 之間選冗餘模式時，用資料同步方式與 standby 是否服務流量來區分，並知道冗餘不等於備份">冗餘設計模式</a>。</p>
<h2 id="一台主機承擔的風險">一台主機承擔的風險</h2>
<p>一台主機上跑著入口、應用程式、資料庫、快取與整組監控時，所有元件共用同一個<a href="/blog/backend/knowledge-cards/failure-domain/" data-link-title="Failure Domain（失效域）" data-link-desc="判斷兩個元件會不會因為同一件事一起停掉、備援或監控是否獨立於被保護的對象時，查它們共用了哪些會失效的依賴">失效域</a>（failure domain），風險有三種。<strong>中斷沒人通知</strong>：主機停掉時服務中斷，而負責通知的監控同時停掉，要等使用者回報才知道。<strong>監控與服務搶資源</strong>：主機過載時，應用程式、資料庫與監控搶同一組 CPU 與記憶體，監控量到的延遲混進它自己的等待（見 <a href="/blog/backend/04-observability/host-overload-alerting/" data-link-title="4.27 主機過載時的監控告警：可用與變慢分開判斷、依原因抑制、監控自身的等待" data-link-desc="多個服務共用一台主機而主機過載時，各服務的探測與告警會一起失敗：可用性與延遲分成兩個判斷的寫法、間歇的條件怎麼持續成立、以主機飽和抑制各服務變慢的規則與它的取捨、以合成告警驗證抑制、抑制藏起各服務受影響程度的差別、探測與 Prometheus 自己也在等 CPU 時的訊號，以及讓監控不比服務先失效的資源隔離；以一次開發環境的過載為例">4.27 主機過載時的監控告警</a>）。<strong>資料與備份一起消失</strong>：資料與它的備份放在同一台主機的磁碟上時，磁碟損壞或帳號被停權會讓兩者一起消失。</p>
<p>資料與備份一起消失是三種裡唯一不可逆的，也不需要第二台主機：備份放到另一個業者的物件儲存或另一個帳號，就不再與資料一起消失（備份與資料放在同一個帳號時，帳號被停權、或存取憑證外洩後被人刪除，兩者一起消失），所以它排在加主機之前做（備份的驗證見 <a href="/blog/devops/going-live/backup-restore-basics/" data-link-title="備份與還原的地基" data-link-desc="有了線上資料、知道「要備份」但不確定備什麼、多久一次、以及為什麼「沒測過還原的備份等於沒有」時回來讀 — 備份的地基認識">備份與還原的地基</a>）。分開帳號擋的是資料所在帳號的憑證外洩；寫入備份的那把存取金鑰仍放在服務主機上，它外洩之後備份會不會被刪除或覆寫，見 <a href="/blog/backend/07-security-data-protection/cross-network-connection-security/#%e9%9b%b2%e7%ab%af%e5%b0%8d%e9%9b%b2%e7%ab%af%e8%88%87%e7%95%b0%e5%9c%b0%e5%82%99%e4%bb%bd%e6%b2%92%e6%9c%89%e5%85%b1%e7%94%a8%e7%a7%81%e7%b6%b2%e6%99%82%e7%9a%84%e6%8e%a5%e6%b3%95" data-link-title="7.43 兩個網路之間的連線安全：可達範圍、連線方向與流入的資料、被入侵端改不到的限制、應用層認證、監控主機的位置、金鑰與控制平面、異地備份的寫入憑證與連線紀錄" data-link-desc="地端主機與雲端主機、或兩個雲端業者的主機以 VPN 或存取金鑰接起來之後的安全設計與評估：連線清單上各台連得到什麼、每一台各假設一次被入侵、限制要放在被入侵端沒有寫入路徑的地方、連線的發起方向與流入的資料、VPN 之內的應用層認證、監控主機與管理者裝置的位置、WireGuard 與 Tailscale 的金鑰與控制平面、異地備份的寫入憑證，以及連線本身的紀錄">7.43 兩個網路之間的連線安全</a>。第二台主機處理的是中斷沒人通知、監控與服務搶資源，處理哪一種取決於它放什麼。</p>
<h2 id="第二台主機的用法給監控給應用程式的副本或給資料庫">第二台主機的用法：給監控、給應用程式的副本或給資料庫</h2>
<p><strong>給監控。</strong> Prometheus、Alertmanager 與 Grafana 搬到第二台，服務主機只留 <a href="/blog/backend/knowledge-cards/prometheus-exporter/" data-link-title="Prometheus Exporter（指標轉接程式）" data-link-desc="要監控一個不會自己輸出 Prometheus 指標的系統（主機、容器、資料庫、快取、Nginx）時，查 exporter 做什麼、它和應用程式自己開的 /metrics 差在哪，以及 exporter 讀得到資料卻缺標籤、或者讀不到它所在層以外的機器時怎麼發現">exporter</a>（輸出指標給 Prometheus 讀取的程式）。原本跑在同一台的自架通知服務（ntfy、郵件轉送）一起搬過去，或改用外部的服務；留在服務主機上的話，「服務主機停了」這則告警要經過那台已經停掉的主機。服務主機停掉時，監控主機讀不到它的指標而發出告警；監控主機停掉時，服務照常運作，由服務主機上的心跳監看程式發現（見〈兩台主機互相監看〉）。服務本身的可用性沒有提高，主機停掉時服務照樣中斷；換到的是中斷有人通知，以及監控不再與服務搶資源。應用程式不必改，監控主機的資源需求也小（指標量的估算見 <a href="/blog/backend/04-observability/vendors/prometheus/capacity-failure-modes/" data-link-title="Prometheus 容量規劃與故障模式" data-link-desc="說明 Prometheus 單機容量邊界、cardinality 與 retention 的資源模型、常見故障模式與判讀方式">Prometheus 容量規劃與故障模式</a>）。搬的時候要決定既有的指標歷史帶不帶過去：不帶的話新主機從零累積，搬移前後的趨勢在面板上接不起來；要帶的話把 Prometheus 的資料目錄一起搬，停掉舊的 Prometheus 再複製，避免複製到寫到一半的資料。</p>
<p><strong>給應用程式的副本。</strong> 兩台主機各跑一份應用程式，前面以<a href="/blog/backend/knowledge-cards/load-balancer/" data-link-title="Load Balancer" data-link-desc="說明流量如何分散、排空與導向健康節點">負載平衡器</a>分流，一台停掉時另一台接手。換到的是服務的可用性，前提有四個：應用程式是無狀態的（session 不存在單台主機的記憶體或磁碟裡，見 <a href="/blog/devops/operations/02-horizontal-scaling/stateless-design/" data-link-title="Stateless 設計原則" data-link-desc="要把服務改成能水平擴展的無狀態設計時，釐清什麼算「本機狀態」、哪些常見寫法會破壞無狀態、隱式狀態怎麼抓、以及定時 job 這種無狀態例外怎麼處理">無狀態設計</a>）；資料庫不在任何一台應用主機上，否則放著資料庫的那一台停掉時，另一台的應用程式也沒有資料可讀；負載平衡器本身不是單點；應用程式內建的排程工作（清理過期的短網址、寄信、結算）只在一台執行，否則兩台各跑一份，副作用跟著重複，做法是加鎖、選出一台負責，或把排程工作獨立出來；固定指定一台時，那一台停掉排程就停了，以排程工作的心跳發現（見 <a href="/blog/backend/04-observability/single-host-monitoring-outside-view/" data-link-title="4.28 單台主機的監控盲區與失效域以外的觀察者：主機停機、使用者路徑中斷與告警鏈中斷，心跳監看與外部探測各自回答的問題與位置，以及與內部探測並排的判讀" data-link-desc="服務與監控放在同一台主機時監控結構上看不到的故障：主機整台停掉、使用者到主機的路徑中斷、告警鏈停掉與通知送不出去；從失效域以外送出訊號的心跳監看與外部探測各自回答的問題與成立條件，觀察者由第三方服務、另一個失效域的主機（含兩台主機互相監看）或另一個業者的排程平台提供時的差別，以及心跳監看、外部探測與主機內部探測並排時的判讀">4.28 單台主機的監控盲區與失效域以外的觀察者</a> 的〈心跳監看：監控與送出心跳的那條路還在不在運作〉）。無狀態這一條違反時，平時看不出來：負載平衡器若以 <a href="/blog/backend/knowledge-cards/sticky-session/" data-link-title="Sticky Session" data-link-desc="說明同一 client 如何在一段時間內持續命中同一個後端實例">sticky session</a> 把同一個使用者固定送到同一台，兩台都在時每個人都正常；直到一台停掉的那一刻，那台上的使用者一起被登出、上傳到一半的檔案一起消失，而這是這個配置第一次真正派上用場的時候。資料庫因此要搬到託管服務或第三台主機，這個配置需要兩台應用主機加上另外放置的資料庫。</p>
<p><strong>給資料庫。</strong> 資料庫搬到第二台，應用程式與資料庫各自有一台主機的資源。換到的是效能的隔離：資料庫的大查詢不再拖慢轉址這類延遲敏感的請求，應用程式與資料庫的容量也能分開調整。可用性沒有提高，反而多了一個會讓服務中斷的主機：兩台任一台停掉，服務都中斷。</p>
<p>目標只有「中斷有人通知」時，不需要第二台主機：第三方的心跳監看與外部探測服務幾乎不花錢就做得到，挑選與接法見 <a href="/blog/backend/04-observability/vendors/prometheus/external-heartbeat-and-probe-services/" data-link-title="第三方心跳監看與外部探測服務：挑選條件、healthchecks 的 ping 與 /fail、Alertmanager 的接法與演練" data-link-desc="以第三方服務當作監控主機失效域以外的觀察者：心跳監看服務的挑選條件與送出的告警資料留在哪裡，healthchecks 的 ping 網址、週期與寬限、/fail 與自架和託管版的回應差異，Alertmanager 送心跳與送失敗通知的 receiver 與路由順序、驗收與暫停，停掉 Alertmanager 的演練，以及外部探測服務的挑選條件">第三方心跳監看與外部探測服務</a>。第二台給監控多換到的是三件事：監控不再與服務搶資源、監控資料與告警內容留在自己手上、心跳的接收端不依賴第三方的服務。通知的寄送與第三個位置的外部探測仍然依賴第三方：用來分辨兩台之間連線中斷的外部探測要放在兩台以外（見〈監控主機與服務主機之間的連線與連線中斷的誤判〉）。所以小型服務在要擴充主機時，第二台先給監控：中斷沒人通知與監控搶資源在一台主機的階段就存在，給監控的第二台同時處理這兩種風險，也不需要改應用程式；應用程式的副本要先處理無狀態化與資料庫的位置，資料庫的分離處理的是效能而不是可用性。停機代價高、主機故障又頻繁的服務，例外地先做應用程式的副本，判斷方式見 <a href="/blog/devops/operations/06-high-availability/ha-cost/" data-link-title="高可用的成本" data-link-desc="判斷高可用值不值得時，用停機的商業代價衡量冗餘的 2x 成本、按可用性等級階梯評估投資、以及知道沒驗證的冗餘等於白付">高可用的成本</a>。</p>
<h2 id="監控主機的位置另一個業者或地端">監控主機的位置：另一個業者或地端</h2>
<p>監控主機要與服務主機分屬不同的失效域。兩台虛擬機租在同一個業者、同一個區域時，業者那個區域的網路故障或帳號被停權會讓兩台一起受影響；所以監控主機放在另一個雲端業者，或放在地端（公司或家裡長時間開著的一台主機）。<a href="/blog/backend/04-observability/vendors/prometheus/multi-host-scraping/" data-link-title="多台主機的指標收集：讀取架構、主機標籤、目標清單、監控主機的位置與主機消失的偵測" data-link-desc="服務分到多台主機之後，Prometheus 怎麼讀到每一台：exporter 的部署位置與連接埠、中央直接讀取與各主機先收再推送的架構、代表主機的 host 標籤加在哪裡、目標清單由什麼產生，主機停掉與主機從清單上消失各自怎麼偵測，以及監控元件放在哪一台、compose 檔怎麼依主機角色拆開；附在單機上模擬第二台主機的驗證">多台主機的指標收集</a> 的〈監控主機放在哪裡〉處理的是同一個私有網路裡分出一台監控主機的情形，本篇多加的是失效域的條件。</p>
<p>監控是內部服務，地端是合理的位置：Grafana 只給團隊看，連線經由 SSH 或 VPN（存取方式見 <a href="/blog/backend/04-observability/vendors/prometheus/grafana-external-access/" data-link-title="Grafana 的對外存取：SSH 通道或 VPN、經由應用入口轉送的問題、監控主機上的反向代理，與登入保護和認證的位置" data-link-desc="Grafana 只綁本機之後，讓其他人看到它的做法：看的人能不能經由 SSH 或 VPN 連進來、有沒有固定的來源網段時各自的存取方式，SSH 通道的連法，應用入口 Nginx 加上 Grafana 的轉送之後的兩個問題，監控主機上專用反向代理的 TLS、WebSocket、GF_SERVER_ROOT_URL 與來源限制，以及 Grafana 登入失敗的帳號鎖定與認證放置">Grafana 的對外存取</a>），不必對網際網路開放 Grafana。地端主機的代價是它自己的可靠度：停電、網路斷線、機器重開時監控就停了，停掉的那段時間沒有指標。這段時間由服務主機上的心跳監看程式發現；監控資料的連續性要求高時，改租另一個業者的小型 VPS。</p>
<h2 id="監控主機與服務主機之間的連線與連線中斷的誤判">監控主機與服務主機之間的連線與連線中斷的誤判</h2>
<p>Prometheus 主動讀取各主機的 exporter，所以監控主機要連得到服務主機上的 exporter 連接埠。這些連接埠不對網際網路開放：exporter 預設沒有認證，輸出的指標透露主機的資源、服務的名稱與版本。同一個雲端業者內，exporter 綁在私有網路的位址上（<a href="/blog/backend/04-observability/vendors/prometheus/multi-host-scraping/" data-link-title="多台主機的指標收集：讀取架構、主機標籤、目標清單、監控主機的位置與主機消失的偵測" data-link-desc="服務分到多台主機之後，Prometheus 怎麼讀到每一台：exporter 的部署位置與連接埠、中央直接讀取與各主機先收再推送的架構、代表主機的 host 標籤加在哪裡、目標清單由什麼產生，主機停掉與主機從清單上消失各自怎麼偵測，以及監控元件放在哪一台、compose 檔怎麼依主機角色拆開；附在單機上模擬第二台主機的驗證">多台主機的指標收集</a> 以 <code>EXPORTER_BIND_ADDR</code> 設定）；跨業者或跨地端時沒有共用的私有網路，要在兩台之間建一條 VPN，例如 WireGuard 或 Tailscale（運作方式見 <a href="/blog/linux/tools/remote/tailscale-tailnet-and-relay/" data-link-title="Tailscale 深入：tailnet、MagicDNS、直連與 DERP 中繼" data-link-desc="要用 Tailscale 讓散在不同網路的機器互連、遇到連得到但延遲高、或想讀懂 tailscale status 的 relay / direct 標示時回來讀">Tailscale 深入</a>），exporter 改綁在 VPN 介面的位址上。VPN 預設兩個方向都互通，雲端主機被入侵時攻擊者也能經由它連回地端；隧道兩端各自連得到什麼、限制要放在哪一端，見 <a href="/blog/backend/07-security-data-protection/cross-network-connection-security/" data-link-title="7.43 兩個網路之間的連線安全：可達範圍、連線方向與流入的資料、被入侵端改不到的限制、應用層認證、監控主機的位置、金鑰與控制平面、異地備份的寫入憑證與連線紀錄" data-link-desc="地端主機與雲端主機、或兩個雲端業者的主機以 VPN 或存取金鑰接起來之後的安全設計與評估：連線清單上各台連得到什麼、每一台各假設一次被入侵、限制要放在被入侵端沒有寫入路徑的地方、連線的發起方向與流入的資料、VPN 之內的應用層認證、監控主機與管理者裝置的位置、WireGuard 與 Tailscale 的金鑰與控制平面、異地備份的寫入憑證，以及連線本身的紀錄">7.43 兩個網路之間的連線安全</a>。</p>
<p>地端在 NAT 後面、對外 IP 會變動時，由地端主動建立 VPN：WireGuard 在地端那一側設定 <code>PersistentKeepalive</code>、主動連到雲端主機，雲端主機在業者的防火牆或安全群組開放一個 UDP 連接埠給它；Tailscale 由它的 NAT 穿越與中繼伺服器建立連線，兩端都不必開放連接埠。隧道建立之後兩個方向都連得到，所以 Prometheus 從監控主機讀取，或服務主機以 remote write 把指標推到監控主機，在網路上都走得通，兩者的取捨見〈多台主機的指標收集〉的〈指標回到中央的架構：中央直接讀取與各主機推送〉。安全上兩者的差別在誰要接受對方發起的連線：讀取時地端只發起連線，推送時地端要開放接收端點，見 <a href="/blog/backend/07-security-data-protection/cross-network-connection-security/#%e5%9c%b0%e7%ab%af%e7%9b%a3%e6%8e%a7%e6%83%85%e5%a2%83%e9%9c%80%e8%a6%81%e7%9a%84%e9%80%a3%e7%b7%9a%e7%99%bc%e8%b5%b7%e6%96%b9%e5%90%91%e8%88%87%e6%b5%81%e5%85%a5%e7%9a%84%e8%b3%87%e6%96%99" data-link-title="7.43 兩個網路之間的連線安全：可達範圍、連線方向與流入的資料、被入侵端改不到的限制、應用層認證、監控主機的位置、金鑰與控制平面、異地備份的寫入憑證與連線紀錄" data-link-desc="地端主機與雲端主機、或兩個雲端業者的主機以 VPN 或存取金鑰接起來之後的安全設計與評估：連線清單上各台連得到什麼、每一台各假設一次被入侵、限制要放在被入侵端沒有寫入路徑的地方、連線的發起方向與流入的資料、VPN 之內的應用層認證、監控主機與管理者裝置的位置、WireGuard 與 Tailscale 的金鑰與控制平面、異地備份的寫入憑證，以及連線本身的紀錄">7.43 兩個網路之間的連線安全</a>。</p>
<p>跨網路讀取多了一種誤判：兩地之間的 VPN 斷掉時，監控主機讀不到服務主機，在監控看來與服務主機停了相同，<code>up</code>（Prometheus 記錄每個讀取對象是否讀取成功的序列）變成 0，主機停機的告警發出。分辨連線中斷與服務主機停機要靠第三個位置的觀察者：從另一個網路對服務的公開網址發請求的外部探測，放在服務主機與監控主機以外（通常是第三方的外部探測服務）。外部探測成功而監控讀不到，指向兩地之間的連線；兩者都失敗，指向服務主機。這個配置裡量使用者路徑的也是這個外部探測：監控主機經由 VPN 讀取，不走使用者用的公開網址（見 <a href="/blog/backend/04-observability/single-host-monitoring-outside-view/" data-link-title="4.28 單台主機的監控盲區與失效域以外的觀察者：主機停機、使用者路徑中斷與告警鏈中斷，心跳監看與外部探測各自回答的問題與位置，以及與內部探測並排的判讀" data-link-desc="服務與監控放在同一台主機時監控結構上看不到的故障：主機整台停掉、使用者到主機的路徑中斷、告警鏈停掉與通知送不出去；從失效域以外送出訊號的心跳監看與外部探測各自回答的問題與成立條件，觀察者由第三方服務、另一個失效域的主機（含兩台主機互相監看）或另一個業者的排程平台提供時的差別，以及心跳監看、外部探測與主機內部探測並排時的判讀">4.28 單台主機的監控盲區與失效域以外的觀察者</a> 的〈外部探測：使用者看到的結果〉）。主機停機告警的說明因此寫上「也可能是監控主機連不過去」，值班的人收到時就知道有這兩種成因。</p>
<h2 id="兩台主機互相監看">兩台主機互相監看</h2>
<p>監控主機發現服務主機停掉；監控主機自己停掉時，要由服務主機發現。服務主機上跑一個心跳監看程式（<a href="/blog/backend/knowledge-cards/dead-mans-switch/" data-link-title="Dead Man&#39;s Switch（心跳監看）" data-link-desc="需要知道監控或排程工作自己停掉了、而它停掉時發不出任何告警時，以「時限內沒收到訊號就通知」反過來判斷">dead man&rsquo;s switch</a>，例如自架的 healthchecks，或一個記下最後一次心跳、超過週期加寬限就通知的小程式），接收監控主機上 Alertmanager 送出的 Watchdog 心跳。自架 healthchecks 時，ping 網址、<code>/fail</code>、Alertmanager 的路由與暫停的用法與第三方版相同，見 <a href="/blog/backend/04-observability/vendors/prometheus/external-heartbeat-and-probe-services/" data-link-title="第三方心跳監看與外部探測服務：挑選條件、healthchecks 的 ping 與 /fail、Alertmanager 的接法與演練" data-link-desc="以第三方服務當作監控主機失效域以外的觀察者：心跳監看服務的挑選條件與送出的告警資料留在哪裡，healthchecks 的 ping 網址、週期與寬限、/fail 與自架和託管版的回應差異，Alertmanager 送心跳與送失敗通知的 receiver 與路由順序、驗收與暫停，停掉 Alertmanager 的演練，以及外部探測服務的挑選條件">第三方心跳監看與外部探測服務</a>，網址換成服務主機的 VPN 位址。任一台停掉，另一台都會發現，心跳監看不必用第三方服務。</p>
<p>心跳監看本身的條件（見 <a href="/blog/backend/04-observability/single-host-monitoring-outside-view/" data-link-title="4.28 單台主機的監控盲區與失效域以外的觀察者：主機停機、使用者路徑中斷與告警鏈中斷，心跳監看與外部探測各自回答的問題與位置，以及與內部探測並排的判讀" data-link-desc="服務與監控放在同一台主機時監控結構上看不到的故障：主機整台停掉、使用者到主機的路徑中斷、告警鏈停掉與通知送不出去；從失效域以外送出訊號的心跳監看與外部探測各自回答的問題與成立條件，觀察者由第三方服務、另一個失效域的主機（含兩台主機互相監看）或另一個業者的排程平台提供時的差別，以及心跳監看、外部探測與主機內部探測並排時的判讀">4.28 單台主機的監控盲區與失效域以外的觀察者</a> 的〈心跳監看：監控與送出心跳的那條路還在不在運作〉，例如送出間隔小於週期加寬限）之外，互相監看另外要滿足三個條件：</p>
<ul>
<li><strong>心跳的路徑也走 VPN。</strong> 監看程式的接收端點不對網際網路開放；知道心跳網址的人可以送出假的心跳，也可以送出假的失敗。代價是 VPN 斷線時這裡也會誤報：監看程式收不到心跳，寄出「監控主機停了」，同時監控主機讀不到服務主機，發出「服務主機停了」。兩邊的停機通知同時出現，指向的是兩地之間的連線；兩台都停掉時，第三方的外部探測也會失敗，外部探測成功就是連線的問題。</li>
<li><strong>監看程式的通知不經過監控主機。</strong> 它直接寄 email（經由業者的郵件服務或一個寄送系統通知信的郵件服務，transactional email），或送到另一個推播服務，不送給監控主機上的 Alertmanager 或 ntfy。監控主機停掉時，經過它的通知一起停。</li>
<li><strong>監看程式自己有人盯著。</strong> 它停掉時不會有任何訊號。它跑在服務主機上，監控主機以 blackbox_exporter 這類探測程式對它的網頁發 HTTP 請求，它停掉時由監控主機的告警通知；Prometheus 讀取 exporter 的方式讀的是指標格式，讀不了一般的網頁或健康端點。這條告警要同時涵蓋探測程式自己讀不到的情形：只寫 <code>probe_success == 0</code> 時，blackbox_exporter 自己停掉，這個序列跟著消失，告警不會成立，所以另外以 <code>up == 0</code>（或序列消失）告警。</li>
</ul>
<p>剩下的風險是兩台同時停掉，這時沒有任何一方送得出通知。兩台在不同的業者時，同時停掉的機會小；兩台主機共用的依賴會讓這種情形比預期常見，例如兩台的通知都經由同一個郵件服務寄出、兩台的網域都在同一個 DNS 業者。兩台是否分屬不同失效域，看逐項比對依賴之後還剩下哪些共用項（比對方式見 <a href="/blog/backend/knowledge-cards/failure-domain/" data-link-title="Failure Domain（失效域）" data-link-desc="判斷兩個元件會不會因為同一件事一起停掉、備援或監控是否獨立於被保護的對象時，查它們共用了哪些會失效的依賴">Failure Domain</a> 的〈判讀方式〉）。要涵蓋兩台同時停掉，〈監控主機與服務主機之間的連線與連線中斷的誤判〉裡用來分辨連線中斷的第三方外部探測服務，同時就是兩台主機以外的觀察者。</p>
<h2 id="第三台主機的用法給資料庫或兩台應用主機搭配託管資料庫">第三台主機的用法：給資料庫，或兩台應用主機搭配託管資料庫</h2>
<p><strong>應用主機、資料庫主機與監控主機。</strong> 第三台給資料庫，應用程式與資料庫各一台，兩台在同一個業者、同一個區域，以私有網路連線；監控主機維持在另一個業者或地端。這個配置處理資源競爭，可用性與只有服務主機加監控主機時相同：應用主機或資料庫主機任一台停掉，服務中斷。適合的情形是監控已經分出去、而效能問題來自應用程式與資料庫搶資源。</p>
<p><strong>兩台應用主機加監控主機。</strong> 兩台各跑一份應用程式，前面放業者的負載平衡器，監控主機在另一個失效域。資料庫不能放在任何一台應用主機上，所以要用業者的託管資料庫（自架與託管的取捨見 <a href="/blog/devops/going-live/self-host-vs-managed-db/" data-link-title="自架還是託管：以資料庫為例" data-link-desc="在 VPS 上自己跑一個 DB container 很便宜、看到 RDS / Cloud SQL 一個月要幾十鎂而猶豫時回來讀 — 成本差在哪、差價其實在買什麼">自架還是託管：以資料庫為例</a>）。這個配置提高可用性：一台應用主機停掉時服務照常，監控主機發出告警，通知值班的人有一台應用主機停了。代價是託管資料庫的費用，以及應用程式要先做到無狀態、排程工作只在一台執行。兩台應用主機放在同一個業者的不同可用區，才不會因為同一個機房的故障一起停；它們仍共用同一個帳號、業者的負載平衡器、同一條部署管線（一次壞掉的部署同時打到兩台，見 <a href="/blog/backend/knowledge-cards/correlated-failure/" data-link-title="Correlated Failure" data-link-desc="以為獨立的多個元件共享一個隱藏的失效觸發器、在同一時刻一起壞；冗餘副本、觀測系統、跨區部署都可能共命運">Correlated Failure</a>）與同一組 DNS，這幾項是可用區分開之後剩下的共用依賴；託管資料庫本身也落在某個可用區，只開在單一可用區時，那個機房故障仍會讓服務中斷，跨可用區的設定與費用查自己那一家的文件。active-passive（備援平時不接流量）與 active-active（兩份同時接流量）的選擇見 <a href="/blog/devops/operations/06-high-availability/redundancy-patterns/" data-link-title="冗餘設計模式" data-link-desc="在 active-passive、active-active、multi-region 之間選冗餘模式時，用資料同步方式與 standby 是否服務流量來區分，並知道冗餘不等於備份">冗餘設計模式</a>。</p>
<p>不論第三台怎麼用，備份都維持在應用與資料庫的失效域以外（見〈一台主機承擔的風險〉）：資料庫搬到第三台或託管服務之後，備份的來源跟著換，備份的目的地仍是另一個業者或另一個帳號。</p>
<h2 id="雲端業者負責的範圍與自己負責的範圍">雲端業者負責的範圍與自己負責的範圍</h2>
<p>主機數處理的是主機層的故障：一台停掉時另一台接手、監控不與服務一起停。業者對硬體與電力的故障處理到「讓虛擬機恢復」為止：在另一台實體機上重新啟動虛擬機，中間的停機仍由使用者處理：要不中斷就要另一台實體機上的副本（機房層級的故障要放在另一個可用區），那正是第二台主機給應用程式的副本時換到的保護（可用區見〈第三台主機的用法：給資料庫，或兩台應用主機搭配託管資料庫〉）。應用層的攻擊則是加主機也換不到保護的一類：它打在每一台都相同的入口上，主機再多也一樣進得來。這兩類由雲端業者與使用者之間的<a href="/blog/backend/knowledge-cards/shared-responsibility-model/" data-link-title="Shared Responsibility Model（責任分擔模型）" data-link-desc="把服務放上雲端之後，要分清哪些故障與攻擊由業者處理、哪些仍然是自己的工作時，查業者與使用者之間的責任分界">責任分擔模型</a>（shared responsibility model）分工：業者處理所有客戶共用的部分，依應用而不同的部分留給使用者。</p>
<table>
  <thead>
      <tr>
          <th>項目</th>
          <th>業者處理的部分</th>
          <th>使用者處理的部分</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>實體機房、硬體、電力</td>
          <td>硬體故障時把虛擬機搬到其他實體機重新啟動</td>
          <td>服務能自己啟動回來（容器的重啟策略、開機自動啟動）；恢復期間的中斷靠另一台實體機上的副本；本機磁碟的資料是否保留依業者與磁碟種類而定，查自己那一家</td>
      </tr>
      <tr>
          <td>網路層的大流量攻擊（L3/L4 的 DDoS）</td>
          <td>主要的雲端業者在網路邊緣提供基本防護（例如 AWS Shield Standard 對所有客戶生效）</td>
          <td>查清楚自己那一家超過防護容量時怎麼處置（部分業者會把被攻擊的 IP 暫時移出網路）；需要更強的防護時另外購買或加一層 CDN</td>
      </tr>
      <tr>
          <td>應用層的攻擊（HTTP 洪水、掃描、撞密碼 credential stuffing）</td>
          <td>預設不處理</td>
          <td>入口的限流、CDN 與 <a href="/blog/backend/knowledge-cards/waf/" data-link-title="WAF" data-link-desc="說明 Web Application Firewall 如何在入口層過濾常見攻擊與濫用">WAF</a>、應用程式本身的偵測</td>
      </tr>
      <tr>
          <td>流量突增</td>
          <td>用了自動擴充群組或託管服務時，依使用者設定的策略擴充</td>
          <td>設定擴充的策略與上下限；單台虛擬機不會自己變大，沒有擴充時要預留容量</td>
      </tr>
      <tr>
          <td>作業系統、應用程式、設定、資料、帳號（付款、權限、停權的風險）與金鑰</td>
          <td>不處理</td>
          <td>全部</td>
      </tr>
  </tbody>
</table>
<p>表裡「服務能自己啟動回來」這一項，業者在硬體維護後重新啟動虛擬機時要成立，主機裝了核心更新、排程自動重開機時也要成立。要確認的是服務的 unit 處在 enabled、容器設了 restart policy、主機防火牆的規則寫進了永久設定，最可靠的確認是在有人在場的維護時段手動重開一次，見 <a href="/blog/devops/operations/09-host-lifecycle/long-running-host-maintenance/" data-link-title="長期上線主機的維護項目：會累積的資料、定期讀的 log、對外入口的盤點、安全更新、會到期的設定與檢查間隔的推算" data-link-desc="單台 Linux 主機（VPS、雲端主機）長期上線時，沒有人操作也會改變的狀態與維護對它們做的事：log 與資料的寫入者和清理機制（logrotate、journald、容器 log）、磁碟寫滿時各元件的反應、每份 log 要讀的欄位、入口在主機與雲端各層的盤點（ss）、各條更新管道的安全更新與重開機（dnf-automatic、unattended-upgrades、needs-restarting）、會到期與會改變的設定、檢查間隔的推算，以及接手一台已上線的主機時先處理哪幾項">長期上線主機的維護項目：會累積的資料、定期讀的 log、對外入口的盤點、安全更新、會到期的設定與檢查間隔的推算</a>〈會老化的軟體：各條更新管道與更新後的重開機〉。</p>
<p>網路層攻擊的處置（流量清洗、邊緣網路）見 <a href="/blog/backend/09-performance-capacity/unplanned-traffic-surge/" data-link-title="9.15 無預警瞬時大流量：流量來源辨識、擴展緩衝、請求優先等級、准入控制、體積型攻擊與退路" data-link-desc="沒有準備窗口的瞬時大流量（突發流量、流量暴增）怎麼承接：依流量形狀分辨真人需求、應用層的濫用流量、體積型攻擊（DDoS），自動擴展的反應時間換算成緩衝，入口標記請求優先等級與負載卸除的順序，等候室與事前註冊這類准入控制，把體積型攻擊交給更大的邊緣網路，以及擴展跟不上時的退路">9.15 無預警瞬時大流量</a> 的〈體積型攻擊（DDoS）的處置：流量清洗與邊緣網路〉。以短網址服務為例，最可能遇到的攻擊是以正常的 HTTPS 請求大量掃描短碼、對轉址路徑灌請求。這些請求在網路層與一般使用者相同，業者的網路層防護不會攔下，要由入口的限流與掃描偵測處理；前面加一層 CDN 或 WAF，是把應用層的第一道過濾交給 CDN 業者，規則仍然要自己設定。各業者的防護範圍與處置方式寫在各自的服務條款與文件裡，選用前查自己那一家。</p>
<h2 id="延伸閱讀主機只有一台時觀察者改由第三方提供時exporter-的接法與冗餘的選擇">延伸閱讀：主機只有一台時、觀察者改由第三方提供時、exporter 的接法與冗餘的選擇</h2>
<ul>
<li>還沒有第二台主機、服務與監控在同一台時看不到哪些故障，心跳監看、外部探測與主機內部探測並排時怎麼判讀，見 <a href="/blog/backend/04-observability/single-host-monitoring-outside-view/" data-link-title="4.28 單台主機的監控盲區與失效域以外的觀察者：主機停機、使用者路徑中斷與告警鏈中斷，心跳監看與外部探測各自回答的問題與位置，以及與內部探測並排的判讀" data-link-desc="服務與監控放在同一台主機時監控結構上看不到的故障：主機整台停掉、使用者到主機的路徑中斷、告警鏈停掉與通知送不出去；從失效域以外送出訊號的心跳監看與外部探測各自回答的問題與成立條件，觀察者由第三方服務、另一個失效域的主機（含兩台主機互相監看）或另一個業者的排程平台提供時的差別，以及心跳監看、外部探測與主機內部探測並排時的判讀">4.28 單台主機的監控盲區與失效域以外的觀察者</a>。</li>
<li>心跳監看或外部探測改由第三方服務提供時，挑選條件與 Alertmanager 的接法，見 <a href="/blog/backend/04-observability/vendors/prometheus/external-heartbeat-and-probe-services/" data-link-title="第三方心跳監看與外部探測服務：挑選條件、healthchecks 的 ping 與 /fail、Alertmanager 的接法與演練" data-link-desc="以第三方服務當作監控主機失效域以外的觀察者：心跳監看服務的挑選條件與送出的告警資料留在哪裡，healthchecks 的 ping 網址、週期與寬限、/fail 與自架和託管版的回應差異，Alertmanager 送心跳與送失敗通知的 receiver 與路由順序、驗收與暫停，停掉 Alertmanager 的演練，以及外部探測服務的挑選條件">第三方心跳監看與外部探測服務</a>；自架 healthchecks 時同一篇的 ping 網址、<code>/fail</code> 與暫停也適用。</li>
<li>監控主機與服務主機之間的 VPN 要開到多寬、限制放在哪一端才在雲端主機被入侵之後仍然成立、異地備份的存取金鑰要拿掉哪些權限，見 <a href="/blog/backend/07-security-data-protection/cross-network-connection-security/" data-link-title="7.43 兩個網路之間的連線安全：可達範圍、連線方向與流入的資料、被入侵端改不到的限制、應用層認證、監控主機的位置、金鑰與控制平面、異地備份的寫入憑證與連線紀錄" data-link-desc="地端主機與雲端主機、或兩個雲端業者的主機以 VPN 或存取金鑰接起來之後的安全設計與評估：連線清單上各台連得到什麼、每一台各假設一次被入侵、限制要放在被入侵端沒有寫入路徑的地方、連線的發起方向與流入的資料、VPN 之內的應用層認證、監控主機與管理者裝置的位置、WireGuard 與 Tailscale 的金鑰與控制平面、異地備份的寫入憑證，以及連線本身的紀錄">7.43 兩個網路之間的連線安全</a>。</li>
<li>監控主機已經分出去、要把各主機的 exporter 接上時，綁定位址、目標清單、主機標籤與主機消失的偵測，見 <a href="/blog/backend/04-observability/vendors/prometheus/multi-host-scraping/" data-link-title="多台主機的指標收集：讀取架構、主機標籤、目標清單、監控主機的位置與主機消失的偵測" data-link-desc="服務分到多台主機之後，Prometheus 怎麼讀到每一台：exporter 的部署位置與連接埠、中央直接讀取與各主機先收再推送的架構、代表主機的 host 標籤加在哪裡、目標清單由什麼產生，主機停掉與主機從清單上消失各自怎麼偵測，以及監控元件放在哪一台、compose 檔怎麼依主機角色拆開；附在單機上模擬第二台主機的驗證">多台主機的指標收集</a>。</li>
<li>決定做應用程式的副本之後，要選 active-passive 還是 active-active、資料怎麼同步，見 <a href="/blog/devops/operations/06-high-availability/redundancy-patterns/" data-link-title="冗餘設計模式" data-link-desc="在 active-passive、active-active、multi-region 之間選冗餘模式時，用資料同步方式與 standby 是否服務流量來區分，並知道冗餘不等於備份">冗餘設計模式</a>；每多一台要花多少、值不值得，見 <a href="/blog/devops/operations/06-high-availability/ha-cost/" data-link-title="高可用的成本" data-link-desc="判斷高可用值不值得時，用停機的商業代價衡量冗餘的 2x 成本、按可用性等級階梯評估投資、以及知道沒驗證的冗餘等於白付">高可用的成本</a>。</li>
</ul>
]]></content:encoded></item></channel></rss>