<?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>Failure-Domain on Tarragon</title><link>https://tarrragon.github.io/blog/tags/failure-domain/</link><description>Recent content in Failure-Domain on Tarragon</description><generator>Hugo -- gohugo.io</generator><language>zh-TW</language><copyright>Tarragon (CC BY 4.0)</copyright><lastBuildDate>Wed, 14 Oct 2026 00:00:00 +0800</lastBuildDate><atom:link href="https://tarrragon.github.io/blog/tags/failure-domain/index.xml" rel="self" type="application/rss+xml"/><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><item><title>4.28 單台主機的監控盲區與失效域以外的觀察者：主機停機、使用者路徑中斷與告警鏈中斷，心跳監看與外部探測各自回答的問題與位置，以及與內部探測並排的判讀</title><link>https://tarrragon.github.io/blog/backend/04-observability/single-host-monitoring-outside-view/</link><pubDate>Wed, 14 Oct 2026 00:00:00 +0800</pubDate><guid>https://tarrragon.github.io/blog/backend/04-observability/single-host-monitoring-outside-view/</guid><description>&lt;p>這一篇整理服務與監控放在同一台主機（或同一個失效域）時，監控結構上判斷不了的故障，以及從失效域以外送出訊號的方式。觀測與被觀測系統一起退化的一般機制在 &lt;a href="https://tarrragon.github.io/blog/backend/04-observability/observability-shared-fate/" data-link-title="4.25 觀測共命運失效：工具退化時的訊號與人層設計" data-link-desc="觀測系統跟被觀測系統共享失效域、在最需要時一起退化；out-of-band 訊號、優雅降級、以及工具盲飛時客服與工程師怎麼還能應對">4.25 觀測共命運失效：工具退化時的訊號與人層設計&lt;/a>，這一篇處理其中最小的情形：只有一台主機。第三方服務的挑選與接法見 &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/small-service-host-layout/" data-link-title="小型服務的兩到三台主機配置：第二台與第三台主機的用法、監控主機的位置與連線、兩台主機互相監看，以及雲端業者負責的範圍" data-link-desc="一台主機的服務擴充到兩到三台時，每一台放什麼：第二台給監控、給應用程式的副本或給資料庫各自換到什麼與前提，與第三方心跳監看服務的比較，監控主機放在另一個業者或地端時經 VPN 讀取、連線中斷的誤判，兩台主機互相監看的條件，第三台給資料庫或兩台應用主機搭配託管資料庫，備份的位置，以及加主機也換不到、由雲端業者或入口設定處理的故障與攻擊">小型服務的兩到三台主機配置&lt;/a>。在 &lt;a href="https://tarrragon.github.io/blog/backend/04-observability/monitoring-layers/" data-link-title="4.0 服務端監控的分層：容器與程序的自檢、服務網路內的探測、元件指標、應用層訊號、告警規則與分送、告警鏈的監看與使用者路徑的合成監控" data-link-desc="以每一層監控檢查的對象、看不到的範圍與接手的那一層，把服務端監控串成一條監控鏈，以及拿它盤點一個服務時怎麼判讀缺口的性質（檢查範圍、位置、讀取與訊號失真），涵蓋自架主機、Kubernetes 與雲端託管的情形；使用者路徑那一層另寫合成監控與真實使用者監測的差別，以及盤點時各種缺口的補法">4.0 服務端監控的分層&lt;/a> 的分法裡，主機停機與告警鏈停掉是位置盲區（觀察者跟著被觀察的對象一起停），使用者路徑中斷是服務網路內探測的檢查範圍盲區（公開入口不在它的檢查範圍裡），通知送不出去是讀取缺口，由送失敗的訊號偵測，各層的接手關係見那一篇；本篇的外部探測就是那一篇的使用者路徑合成監控（&lt;a href="https://tarrragon.github.io/blog/backend/knowledge-cards/synthetic-monitoring/" data-link-title="Synthetic Monitoring（合成監控）" data-link-desc="要知道使用者從外面連不連得到服務、或分不清某個「外部探測」從哪裡發出時，查合成監控以排程的請求模擬使用者的做法、探測端的位置怎麼決定它量得到什麼，以及它與真實使用者監測的差別">Synthetic Monitoring&lt;/a>），主機內部探測是服務網路內的探測。&lt;/p>
&lt;h2 id="監控與服務共用失效域時看不到的故障主機停機使用者路徑中斷與告警鏈中斷">監控與服務共用失效域時看不到的故障：主機停機、使用者路徑中斷與告警鏈中斷&lt;/h2>
&lt;p>監控要判斷一件事，有兩個條件：監控自己的程序在運作，以及它所在的位置看得到那件事。同一台主機上的 Prometheus 讀得到主機與容器的資源、每個服務的指標，也能從主機內部對各服務發探測請求，這些都在它的位置看得到。它與服務共用同一個&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;/p>
&lt;p>&lt;strong>主機整台停掉。&lt;/strong> 當機、斷電、雲端業者的維護重開、帳號因為付款失敗被停權，Prometheus 與 Alertmanager 跟著服務一起停。通知端的結果是什麼都沒收到，而「什麼都沒收到」與「一切正常」在收件匣裡看起來相同。&lt;/p>
&lt;p>&lt;strong>使用者到主機的路徑中斷。&lt;/strong> 網域過期、DNS 設定改錯、TLS 憑證過期、雲端業者的網路故障、防火牆規則擋掉外部連線，主機內部的服務都在運作，而使用者連不進來。主機內部的探測走的是容器網路或 &lt;code>127.0.0.1&lt;/code>，不經過 DNS、不經過公開的網路入口與 TLS，所以照樣回報成功。以 &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> 那個短網址服務為例，它的探測程式 Gatus 跑在同一個 Compose 專案裡，連的是服務名稱，量到的是「容器之間通不通」，不是「使用者連不連得到」。&lt;/p>
&lt;p>&lt;strong>告警鏈中斷。&lt;/strong> 規則照常成立，而告警送不到人手上，分成兩種。&lt;strong>告警鏈停掉&lt;/strong>：Alertmanager 停了、規則檔沒有載入、Prometheus 連不到 Alertmanager。&lt;strong>通知送不出去&lt;/strong>：Alertmanager 在運作，而某一條通知管道的網址打錯、外部的推播服務拒收。通知送不出去時，Alertmanager 會留下失敗的計數，Prometheus 可以把它寫成告警（見 &lt;a href="https://tarrragon.github.io/blog/backend/04-observability/vendors/prometheus/alertmanager-notification-channels/" data-link-title="Alertmanager 的通知管道：路由樹與分組、webhook 與 ntfy、email 與 Slack、私密網址的檔案、心跳與通知送不出去的偵測" data-link-desc="Alertmanager 從只在網頁上看告警，到依嚴重度送到手機與信箱：路由樹怎麼決定一則告警送到哪裡、分組與 group_wait、group_interval、repeat_interval 各控制什麼，以 webhook 接 ntfy 推播與它的訊息範本，email 與 Slack 的設定，私密網址為什麼要放在檔案裡（設定檔不展開環境變數），以及 Watchdog 心跳與通知送不出去時的偵測">Alertmanager 的通知管道&lt;/a> 的〈通知送不出去的偵測〉）；而這條告警本身也要經過某一條通知管道，唯一的管道壞掉時它同樣送不出去。&lt;/p>
&lt;p>主機停機與告警鏈中斷，是監控與它要判斷的對象一起停掉，或監控的告警出不去；使用者路徑中斷，是監控所在的位置不在使用者的路徑上。這兩類成因都不是在同一台主機上把監控做得更可靠（多跑一份 Prometheus、加大資源）解決得了的，因為多出來的那一份同樣在這台主機上、同樣不在使用者的路徑上；要的是一個位置在主機失效域以外、而且能照使用者路徑發請求的觀察者，下文稱為失效域以外的觀察者。它送出的訊號稱為頻外訊號（&lt;a href="https://tarrragon.github.io/blog/backend/knowledge-cards/out-of-band-signal/" data-link-title="Out-of-Band Signal（頻外訊號）" data-link-desc="觀測系統本身也可能在事故中失能時、判斷該從哪個獨立通道取得系統存活狀態">out-of-band signal&lt;/a>，簡體中文資料常寫作「帶外」）。&lt;/p>
&lt;p>主機過載是另一種情形：Prometheus 與 Gatus 都還在運作，而它們自己也在等 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> 的〈探測程式與 Prometheus 在過載主機上的 CPU 等待〉。&lt;/p>
&lt;h2 id="頻外訊號心跳監看與外部探測">頻外訊號：心跳監看與外部探測&lt;/h2>
&lt;p>失效域以外的觀察者送出的頻外訊號有心跳監看與外部探測，兩者經過的路徑不同，所以各回答一個問題、彼此不能取代：心跳走的是監控本身送出告警的那條路，外部探測走的是使用者到服務的那條路。送出的方向也不同：心跳由被觀察的一方送出，觀察者在它缺席時通知；外部探測由觀察者主動發出請求，看回應。&lt;/p>
&lt;h3 id="心跳監看監控與送出心跳的那條路還在不在運作">心跳監看：監控與送出心跳的那條路還在不在運作&lt;/h3>
&lt;p>&lt;a href="https://tarrragon.github.io/blog/backend/knowledge-cards/dead-mans-switch/" data-link-title="Dead Man&amp;#39;s Switch（心跳監看）" data-link-desc="需要知道監控或排程工作自己停掉了、而它停掉時發不出任何告警時，以「時限內沒收到訊號就通知」反過來判斷">心跳監看&lt;/a>（dead man&amp;rsquo;s switch）把判斷反過來：監控持續對外送出「我還在」，觀察者在約定的時限內沒收到就通知。時限由兩個值組成：週期（period，預期的心跳間隔）與寬限（grace time，容許的延遲），距離最後一次心跳超過兩者的總和就判定中斷。Prometheus 上的做法是一條永遠成立的告警規則（&lt;code>Watchdog&lt;/code>），Alertmanager 定時把它經由一個專用的 receiver 送到觀察者的網址。主機整台停掉、主機對外的連線斷掉，以及告警鏈停掉的各種情形（Alertmanager 停了、規則檔沒有載入、Prometheus 連不到 Alertmanager、&lt;code>Watchdog&lt;/code> 的路由設錯），心跳都會中斷。中斷的時間點大多在週期加寬限之後；停掉的是 Prometheus 時再晚一段：Prometheus 送給 Alertmanager 的告警帶著結束時間，Prometheus 停掉之後，Alertmanager 在這個結束時間之前照常重送心跳，依 Prometheus 的原始碼這段重送期約是 4 個評估週期（評估週期短於 1 分鐘時以 1 分鐘計），這裡沒有實測。&lt;/p>
&lt;p>心跳只走送到觀察者的那一個 receiver，所以它不涵蓋通知送不出去的那一種：ntfy 的網址打錯、推播服務拒收時，心跳照常送達。這一種由通知送不出去的偵測發現，送到心跳監看服務上另一個專用檢查項目的回報失敗端點，設定見 &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> 的〈Alertmanager 的 receiver 與路由：心跳與送失敗的通知〉。心跳監看也不回答使用者連不連得到服務：主機照常運作、監控照常送心跳時，DNS 改錯讓使用者全部連不進來，心跳監看看不出任何異常。心跳也分不出故障與入侵：監控主機被入侵時，攻擊者可以用它存著的心跳網址自己送心跳，判讀見 &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>
&lt;p>成立的條件有三個。觀察者在送出心跳那台主機（跑 Alertmanager 的那一台）的失效域以外：跑在同一台主機上的觀察者，主機停掉時跟著停。觀察者的通知管道不依賴那台主機，也不寄到被監看服務網域底下的信箱：觀察者也透過那台主機上的推播服務通知時，心跳中斷的通知會走那條已經停掉的路；被監看服務的網域過期時，寄到那個網域的所有通知會一起收不到，觀察者的通知不能也在其中。Alertmanager 實際送出心跳的最長間隔（&lt;code>repeat_interval&lt;/code> 加一個 &lt;code>group_interval&lt;/code>，因為 Alertmanager 只在 &lt;code>group_interval&lt;/code> 的時間點檢查要不要重送）要小於觀察者設定的週期加寬限，參數的寫法見 &lt;a href="https://tarrragon.github.io/blog/backend/04-observability/vendors/prometheus/alertmanager-notification-channels/" data-link-title="Alertmanager 的通知管道：路由樹與分組、webhook 與 ntfy、email 與 Slack、私密網址的檔案、心跳與通知送不出去的偵測" data-link-desc="Alertmanager 從只在網頁上看告警，到依嚴重度送到手機與信箱：路由樹怎麼決定一則告警送到哪裡、分組與 group_wait、group_interval、repeat_interval 各控制什麼，以 webhook 接 ntfy 推播與它的訊息範本，email 與 Slack 的設定，私密網址為什麼要放在檔案裡（設定檔不展開環境變數），以及 Watchdog 心跳與通知送不出去時的偵測">Alertmanager 的通知管道&lt;/a> 的〈Watchdog：告警鏈本身的心跳〉。&lt;/p></description><content:encoded><![CDATA[<p>這一篇整理服務與監控放在同一台主機（或同一個失效域）時，監控結構上判斷不了的故障，以及從失效域以外送出訊號的方式。觀測與被觀測系統一起退化的一般機制在 <a href="/blog/backend/04-observability/observability-shared-fate/" data-link-title="4.25 觀測共命運失效：工具退化時的訊號與人層設計" data-link-desc="觀測系統跟被觀測系統共享失效域、在最需要時一起退化；out-of-band 訊號、優雅降級、以及工具盲飛時客服與工程師怎麼還能應對">4.25 觀測共命運失效：工具退化時的訊號與人層設計</a>，這一篇處理其中最小的情形：只有一台主機。第三方服務的挑選與接法見 <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/small-service-host-layout/" data-link-title="小型服務的兩到三台主機配置：第二台與第三台主機的用法、監控主機的位置與連線、兩台主機互相監看，以及雲端業者負責的範圍" data-link-desc="一台主機的服務擴充到兩到三台時，每一台放什麼：第二台給監控、給應用程式的副本或給資料庫各自換到什麼與前提，與第三方心跳監看服務的比較，監控主機放在另一個業者或地端時經 VPN 讀取、連線中斷的誤判，兩台主機互相監看的條件，第三台給資料庫或兩台應用主機搭配託管資料庫，備份的位置，以及加主機也換不到、由雲端業者或入口設定處理的故障與攻擊">小型服務的兩到三台主機配置</a>。在 <a href="/blog/backend/04-observability/monitoring-layers/" data-link-title="4.0 服務端監控的分層：容器與程序的自檢、服務網路內的探測、元件指標、應用層訊號、告警規則與分送、告警鏈的監看與使用者路徑的合成監控" data-link-desc="以每一層監控檢查的對象、看不到的範圍與接手的那一層，把服務端監控串成一條監控鏈，以及拿它盤點一個服務時怎麼判讀缺口的性質（檢查範圍、位置、讀取與訊號失真），涵蓋自架主機、Kubernetes 與雲端託管的情形；使用者路徑那一層另寫合成監控與真實使用者監測的差別，以及盤點時各種缺口的補法">4.0 服務端監控的分層</a> 的分法裡，主機停機與告警鏈停掉是位置盲區（觀察者跟著被觀察的對象一起停），使用者路徑中斷是服務網路內探測的檢查範圍盲區（公開入口不在它的檢查範圍裡），通知送不出去是讀取缺口，由送失敗的訊號偵測，各層的接手關係見那一篇；本篇的外部探測就是那一篇的使用者路徑合成監控（<a href="/blog/backend/knowledge-cards/synthetic-monitoring/" data-link-title="Synthetic Monitoring（合成監控）" data-link-desc="要知道使用者從外面連不連得到服務、或分不清某個「外部探測」從哪裡發出時，查合成監控以排程的請求模擬使用者的做法、探測端的位置怎麼決定它量得到什麼，以及它與真實使用者監測的差別">Synthetic Monitoring</a>），主機內部探測是服務網路內的探測。</p>
<h2 id="監控與服務共用失效域時看不到的故障主機停機使用者路徑中斷與告警鏈中斷">監控與服務共用失效域時看不到的故障：主機停機、使用者路徑中斷與告警鏈中斷</h2>
<p>監控要判斷一件事，有兩個條件：監控自己的程序在運作，以及它所在的位置看得到那件事。同一台主機上的 Prometheus 讀得到主機與容器的資源、每個服務的指標，也能從主機內部對各服務發探測請求，這些都在它的位置看得到。它與服務共用同一個<a href="/blog/backend/knowledge-cards/failure-domain/" data-link-title="Failure Domain（失效域）" data-link-desc="判斷兩個元件會不會因為同一件事一起停掉、備援或監控是否獨立於被保護的對象時，查它們共用了哪些會失效的依賴">失效域</a>（failure domain）：同一台主機、同一個網路出口、同一個雲端帳號。下面三種故障，監控在自己的位置上看不到，或看到了也送不出告警：</p>
<p><strong>主機整台停掉。</strong> 當機、斷電、雲端業者的維護重開、帳號因為付款失敗被停權，Prometheus 與 Alertmanager 跟著服務一起停。通知端的結果是什麼都沒收到，而「什麼都沒收到」與「一切正常」在收件匣裡看起來相同。</p>
<p><strong>使用者到主機的路徑中斷。</strong> 網域過期、DNS 設定改錯、TLS 憑證過期、雲端業者的網路故障、防火牆規則擋掉外部連線，主機內部的服務都在運作，而使用者連不進來。主機內部的探測走的是容器網路或 <code>127.0.0.1</code>，不經過 DNS、不經過公開的網路入口與 TLS，所以照樣回報成功。以 <a href="/blog/backend/04-observability/host-overload-alerting/" data-link-title="4.27 主機過載時的監控告警：可用與變慢分開判斷、依原因抑制、監控自身的等待" data-link-desc="多個服務共用一台主機而主機過載時，各服務的探測與告警會一起失敗：可用性與延遲分成兩個判斷的寫法、間歇的條件怎麼持續成立、以主機飽和抑制各服務變慢的規則與它的取捨、以合成告警驗證抑制、抑制藏起各服務受影響程度的差別、探測與 Prometheus 自己也在等 CPU 時的訊號，以及讓監控不比服務先失效的資源隔離；以一次開發環境的過載為例">4.27 主機過載時的監控告警</a> 那個短網址服務為例，它的探測程式 Gatus 跑在同一個 Compose 專案裡，連的是服務名稱，量到的是「容器之間通不通」，不是「使用者連不連得到」。</p>
<p><strong>告警鏈中斷。</strong> 規則照常成立，而告警送不到人手上，分成兩種。<strong>告警鏈停掉</strong>：Alertmanager 停了、規則檔沒有載入、Prometheus 連不到 Alertmanager。<strong>通知送不出去</strong>：Alertmanager 在運作，而某一條通知管道的網址打錯、外部的推播服務拒收。通知送不出去時，Alertmanager 會留下失敗的計數，Prometheus 可以把它寫成告警（見 <a href="/blog/backend/04-observability/vendors/prometheus/alertmanager-notification-channels/" data-link-title="Alertmanager 的通知管道：路由樹與分組、webhook 與 ntfy、email 與 Slack、私密網址的檔案、心跳與通知送不出去的偵測" data-link-desc="Alertmanager 從只在網頁上看告警，到依嚴重度送到手機與信箱：路由樹怎麼決定一則告警送到哪裡、分組與 group_wait、group_interval、repeat_interval 各控制什麼，以 webhook 接 ntfy 推播與它的訊息範本，email 與 Slack 的設定，私密網址為什麼要放在檔案裡（設定檔不展開環境變數），以及 Watchdog 心跳與通知送不出去時的偵測">Alertmanager 的通知管道</a> 的〈通知送不出去的偵測〉）；而這條告警本身也要經過某一條通知管道，唯一的管道壞掉時它同樣送不出去。</p>
<p>主機停機與告警鏈中斷，是監控與它要判斷的對象一起停掉，或監控的告警出不去；使用者路徑中斷，是監控所在的位置不在使用者的路徑上。這兩類成因都不是在同一台主機上把監控做得更可靠（多跑一份 Prometheus、加大資源）解決得了的，因為多出來的那一份同樣在這台主機上、同樣不在使用者的路徑上；要的是一個位置在主機失效域以外、而且能照使用者路徑發請求的觀察者，下文稱為失效域以外的觀察者。它送出的訊號稱為頻外訊號（<a href="/blog/backend/knowledge-cards/out-of-band-signal/" data-link-title="Out-of-Band Signal（頻外訊號）" data-link-desc="觀測系統本身也可能在事故中失能時、判斷該從哪個獨立通道取得系統存活狀態">out-of-band signal</a>，簡體中文資料常寫作「帶外」）。</p>
<p>主機過載是另一種情形：Prometheus 與 Gatus 都還在運作，而它們自己也在等 CPU，量到的延遲混進了監控本身的等待，判讀見 <a href="/blog/backend/04-observability/host-overload-alerting/" data-link-title="4.27 主機過載時的監控告警：可用與變慢分開判斷、依原因抑制、監控自身的等待" data-link-desc="多個服務共用一台主機而主機過載時，各服務的探測與告警會一起失敗：可用性與延遲分成兩個判斷的寫法、間歇的條件怎麼持續成立、以主機飽和抑制各服務變慢的規則與它的取捨、以合成告警驗證抑制、抑制藏起各服務受影響程度的差別、探測與 Prometheus 自己也在等 CPU 時的訊號，以及讓監控不比服務先失效的資源隔離；以一次開發環境的過載為例">4.27 主機過載時的監控告警</a> 的〈探測程式與 Prometheus 在過載主機上的 CPU 等待〉。</p>
<h2 id="頻外訊號心跳監看與外部探測">頻外訊號：心跳監看與外部探測</h2>
<p>失效域以外的觀察者送出的頻外訊號有心跳監看與外部探測，兩者經過的路徑不同，所以各回答一個問題、彼此不能取代：心跳走的是監控本身送出告警的那條路，外部探測走的是使用者到服務的那條路。送出的方向也不同：心跳由被觀察的一方送出，觀察者在它缺席時通知；外部探測由觀察者主動發出請求，看回應。</p>
<h3 id="心跳監看監控與送出心跳的那條路還在不在運作">心跳監看：監控與送出心跳的那條路還在不在運作</h3>
<p><a href="/blog/backend/knowledge-cards/dead-mans-switch/" data-link-title="Dead Man&#39;s Switch（心跳監看）" data-link-desc="需要知道監控或排程工作自己停掉了、而它停掉時發不出任何告警時，以「時限內沒收到訊號就通知」反過來判斷">心跳監看</a>（dead man&rsquo;s switch）把判斷反過來：監控持續對外送出「我還在」，觀察者在約定的時限內沒收到就通知。時限由兩個值組成：週期（period，預期的心跳間隔）與寬限（grace time，容許的延遲），距離最後一次心跳超過兩者的總和就判定中斷。Prometheus 上的做法是一條永遠成立的告警規則（<code>Watchdog</code>），Alertmanager 定時把它經由一個專用的 receiver 送到觀察者的網址。主機整台停掉、主機對外的連線斷掉，以及告警鏈停掉的各種情形（Alertmanager 停了、規則檔沒有載入、Prometheus 連不到 Alertmanager、<code>Watchdog</code> 的路由設錯），心跳都會中斷。中斷的時間點大多在週期加寬限之後；停掉的是 Prometheus 時再晚一段：Prometheus 送給 Alertmanager 的告警帶著結束時間，Prometheus 停掉之後，Alertmanager 在這個結束時間之前照常重送心跳，依 Prometheus 的原始碼這段重送期約是 4 個評估週期（評估週期短於 1 分鐘時以 1 分鐘計），這裡沒有實測。</p>
<p>心跳只走送到觀察者的那一個 receiver，所以它不涵蓋通知送不出去的那一種：ntfy 的網址打錯、推播服務拒收時，心跳照常送達。這一種由通知送不出去的偵測發現，送到心跳監看服務上另一個專用檢查項目的回報失敗端點，設定見 <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> 的〈Alertmanager 的 receiver 與路由：心跳與送失敗的通知〉。心跳監看也不回答使用者連不連得到服務：主機照常運作、監控照常送心跳時，DNS 改錯讓使用者全部連不進來，心跳監看看不出任何異常。心跳也分不出故障與入侵：監控主機被入侵時，攻擊者可以用它存著的心跳網址自己送心跳，判讀見 <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>成立的條件有三個。觀察者在送出心跳那台主機（跑 Alertmanager 的那一台）的失效域以外：跑在同一台主機上的觀察者，主機停掉時跟著停。觀察者的通知管道不依賴那台主機，也不寄到被監看服務網域底下的信箱：觀察者也透過那台主機上的推播服務通知時，心跳中斷的通知會走那條已經停掉的路；被監看服務的網域過期時，寄到那個網域的所有通知會一起收不到，觀察者的通知不能也在其中。Alertmanager 實際送出心跳的最長間隔（<code>repeat_interval</code> 加一個 <code>group_interval</code>，因為 Alertmanager 只在 <code>group_interval</code> 的時間點檢查要不要重送）要小於觀察者設定的週期加寬限，參數的寫法見 <a href="/blog/backend/04-observability/vendors/prometheus/alertmanager-notification-channels/" data-link-title="Alertmanager 的通知管道：路由樹與分組、webhook 與 ntfy、email 與 Slack、私密網址的檔案、心跳與通知送不出去的偵測" data-link-desc="Alertmanager 從只在網頁上看告警，到依嚴重度送到手機與信箱：路由樹怎麼決定一則告警送到哪裡、分組與 group_wait、group_interval、repeat_interval 各控制什麼，以 webhook 接 ntfy 推播與它的訊息範本，email 與 Slack 的設定，私密網址為什麼要放在檔案裡（設定檔不展開環境變數），以及 Watchdog 心跳與通知送不出去時的偵測">Alertmanager 的通知管道</a> 的〈Watchdog：告警鏈本身的心跳〉。</p>
<p>沒有 Prometheus 的主機也能送心跳：以 systemd 的計時器定時對心跳監看服務送請求，做法見 <a href="/blog/linux/debug/service-failure-monitoring/" data-link-title="服務掛了怎麼自動知道：從肉眼盯到主動告警" data-link-desc="不想每次都手動 systemctl 檢查服務死活、想讓機器在 service 掛掉時主動推播通知、或擔心整台機器當掉沒人知道時回來讀">服務掛了怎麼自動知道</a> 的〈第三層：整台機器死掉怎麼辦（監控自己的盲點）〉。排程工作（備份、匯出）同樣可以在跑完時自己送一次心跳，那時心跳回答的是「工作有沒有跑完」。</p>
<h3 id="外部探測使用者看到的結果">外部探測：使用者看到的結果</h3>
<p>這一篇的外部探測指從服務主機的失效域以外，在使用者連線出發的那一側網路照使用者的路徑對服務發請求：公開服務的使用者從公開的網際網路來，探測就解析公開的網域、經過 HTTPS 與公開的入口，檢查回應的狀態碼與內容（也叫 synthetic monitoring 或 blackbox 探測，多地區探測的做法見 <a href="/blog/backend/04-observability/client-side-monitoring/" data-link-title="4.10 Client-side / Synthetic / RUM" data-link-desc="補 server-side 看不到的 user perceived 訊號">4.10 Client-side / Synthetic / RUM</a> 的〈Synthetic Monitoring〉）；只在公司內網或 VPN 裡提供的服務，探測端要放在那個網路裡。站內 <a href="/blog/devops/operations/04-service-health/multi-container-monitoring/" data-link-title="多容器服務的存活監看：容器健康檢查、外部探測與指令列查詢的分工" data-link-desc="說明一組用 Compose 跑的多容器服務怎麼回答「每個服務還活著嗎」：容器健康檢查、從另一個容器發請求的外部探測、SSH 進主機時用的查詢腳本各自看得到與看不到的範圍，外部探測工具（Gatus、Uptime Kuma）的選擇、TCP 檢查與經過負載平衡的檢查的限制，以及監看工具自己掛掉時怎麼發現">多容器服務的存活監看</a> 的外部探測是從同一台主機上另一個容器發出的，「外部」是相對於服務的程序；它在服務程序卡住時有用，而主機停掉時跟著停，不是這裡要的觀察者。</p>
<p>外部探測回答的是使用者連不連得到、回應對不對，涵蓋主機整台停掉與使用者路徑中斷。它不回答監控還在不在運作：服務照常回應、Alertmanager 已經停了一整天，外部探測全部成功。</p>
<p>成立的條件是探測的位置與路徑：探測端在使用者所在的那一側網路、服務主機的失效域以外，請求打的是使用者用的網址，而不是主機的 IP 或內部的服務名稱；失敗通知同樣不寄到被監看服務網域底下的信箱。判斷成功的方式也要選對，只看狀態碼時入口回一個錯誤頁也可能是 200，比對回應內容的做法見 <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> 的〈外部探測服務的挑選條件〉。</p>
<h2 id="觀察者的位置第三方服務另一個失效域的主機含互相監看與另一個業者的排程平台">觀察者的位置：第三方服務、另一個失效域的主機（含互相監看）與另一個業者的排程平台</h2>
<p>心跳監看與外部探測要避開的失效域不同：心跳監看的觀察者要避開送出心跳那台主機（跑 Alertmanager 的那一台）的失效域；外部探測量使用者路徑時要避開服務主機的失效域，兩台主機時用來分辨連線中斷的那一個另外要避開監控主機（見本節最後的清單）。只有一台主機時，跑 Alertmanager 的主機就是服務主機，兩種觀察者要避開的是同一台；監控搬到另一台主機之後，兩者分開。這個位置有幾種來源。</p>
<p><strong>第三方服務。</strong> 心跳監看與外部探測都有現成的託管服務，它們跑在別人的機房與網路上。業者維運的意思是業者自己知道服務停了，購買服務的一方並不會因此收到通知：檢查項目被刪除、業者自己停擺，心跳都只是不再被看著。購買服務的一方能做的是定期演練（見〈心跳監看、外部探測與內部探測並排時的判讀〉的演練那一段），以及訂閱業者的狀態頁。代價是告警的內容（標籤、主機名）與被監看服務的公開網址會送到第三方，以及多了一個要管理的帳號與私密網址。</p>
<p><strong>另一個失效域的主機。</strong> 心跳監看的邏輯不複雜（記下最後一次心跳的時間，距離它超過週期與寬限的總和就通知），開源的心跳監看服務也可以自架。自架的觀察者成立的前提有兩個。第一，觀察者所在的主機與它要避開的那台主機不共用失效域：換一個雲端業者，或一台在雲端、一台在地端，是分開的起點；分開之後還要逐項比對兩台仍共用的依賴（付款方式與帳號、通知用的郵件服務、DNS 業者），比對方式見 <a href="/blog/backend/knowledge-cards/failure-domain/" data-link-title="Failure Domain（失效域）" data-link-desc="判斷兩個元件會不會因為同一件事一起停掉、備援或監控是否獨立於被保護的對象時，查它們共用了哪些會失效的依賴">Failure Domain</a> 的〈判讀方式〉。第二，觀察者自己停掉時有人知道，這又分成兩種情形。<strong>主機停掉</strong>：只多租一台主機專門跑觀察者、監控仍留在服務主機上時，由服務主機上的 Prometheus 探測那一台；監控搬到第二台時，由<strong>互相監看</strong>處理，服務主機上跑心跳監看程式，接收監控主機送出的心跳，監控主機讀取服務主機的指標（讀不到時，監控主機上那個讀取對象的 <code>up</code> 變成 0，這也是一種由觀察者主動發出的訊號），服務主機停掉時由監控主機上的 Alertmanager 通知值班的人，任一台主機停掉，另一台都會發現。<strong>監看程式這個程序停掉、主機照常運作</strong>：由監控主機對它發探測。兩邊的通知管道也要彼此獨立：服務主機上的監看程式直接寄 email 或走另一個推播服務，不經過監控主機上的 Alertmanager。心跳的接收端點不對外開放、監看程式怎麼被探測、兩台同時停掉的風險，見 <a href="/blog/devops/operations/06-high-availability/small-service-host-layout/" data-link-title="小型服務的兩到三台主機配置：第二台與第三台主機的用法、監控主機的位置與連線、兩台主機互相監看，以及雲端業者負責的範圍" data-link-desc="一台主機的服務擴充到兩到三台時，每一台放什麼：第二台給監控、給應用程式的副本或給資料庫各自換到什麼與前提，與第三方心跳監看服務的比較，監控主機放在另一個業者或地端時經 VPN 讀取、連線中斷的誤判，兩台主機互相監看的條件，第三台給資料庫或兩台應用主機搭配託管資料庫，備份的位置，以及加主機也換不到、由雲端業者或入口設定處理的故障與攻擊">小型服務的兩到三台主機配置</a> 的〈兩台主機互相監看〉。</p>
<p><strong>另一個業者的排程平台。</strong> 自己寫的觀察者不一定要跑在一台主機上，也可以是另一個業者的排程或無伺服器平台上、以組織自己的帳號執行的程式。它與主機的故障分屬不同失效域，帳號、付款方式與通知管道仍要逐項比對；資料留在自己的帳號裡，而那個業者也是要多管理的一個帳號。這種觀察者要能接收心跳並保存最後一次心跳的時間，它自己停掉時，可以由主機上的 Prometheus 定時探測它來發現；本篇沒有實作這一種。</p>
<p>兩種頻外訊號的位置分開選：</p>
<ul>
<li><strong>心跳監看</strong>：手上有一台與跑 Alertmanager 那台主機不共用失效域、它停掉時也會被發現的主機，就放在那台，告警內容留在自己手上，也不必多管理一個第三方的帳號；沒有，就用第三方服務，或另一個業者的排程平台。告警內容不能離開組織時，第三方的心跳服務也還有一種用法：Alertmanager 的 webhook 一律送整份告警 JSON，改由主機上的排程確認 <code>Watchdog</code> 還在之後對 ping 網址送一個不帶本文的請求，送到第三方的就只剩「還在」這個訊號。這條路繞過了 Alertmanager 送出告警的那一段，所以心跳不再涵蓋 Alertmanager 的送出；本篇沒有實作這種送法。</li>
<li><strong>外部探測</strong>：量使用者路徑時放在服務主機的失效域以外，通常是第三方的外部探測服務；只有一台主機時就滿足了。兩台主機互相監看時，還要有一個探測負責分辨「兩台之間的連線斷了」與「服務主機停了」：監控主機讀不到服務主機時，兩者看起來相同。只是兩台之間的 VPN 斷掉時，監控主機對服務公開網址發的探測走網際網路、不走 VPN，照樣成功，已經分辨得出來（監控主機的流量若被 VPN 改走隧道，這一點就不成立）；兩地之間的網路路徑一起斷掉時，放在監控主機上的探測端與讀取一起失敗，值班的人會把它判成服務主機停了。所以這一個探測放在服務主機與監控主機兩者的失效域以外，它也是兩台同時停掉時唯一還看得到的觀察者。</li>
</ul>
<h2 id="心跳監看外部探測與內部探測並排時的判讀">心跳監看、外部探測與內部探測並排時的判讀</h2>
<p>心跳監看、外部探測與主機內部對同一功能的探測各自站在不同的位置，故障發生時三者的組合指向不同段的失效。下表以單台主機加第三方服務的配置為準，並假設沒有收到送失敗通知的那個檢查項目寄來的通知。主機內部探測要打外部探測檢查的那一個功能，而且直接打應用程式、不經過反向代理（例如外部探測打一條測試短網址，內部也直接對應用程式要同一條短網址）；只看「有沒有任何告警成立」分不出失效在服務還是在路徑，而 4.27 那個範例的 Gatus 探的是健康端點，與外部探測不是同一個功能，要另外加這一條。內部探測若經過反向代理，入口元件的故障會落在「服務本身」那一列。</p>
<table>
  <thead>
      <tr>
          <th>心跳監看</th>
          <th>外部探測</th>
          <th>主機內部對同一功能的探測</th>
          <th>指向的失效</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>正常</td>
          <td>正常</td>
          <td>成功</td>
          <td>沒有失效：服務對外可用，監控在運作；其他內部告警（資源、某個服務）照常判讀</td>
      </tr>
      <tr>
          <td>正常</td>
          <td>正常</td>
          <td>失敗</td>
          <td>內部探測自己的路徑或探測程式（容器網路、服務名稱解析、探測程式過載），或外部探測打到 CDN 的快取而源站已經壞了</td>
      </tr>
      <tr>
          <td>正常</td>
          <td>失敗</td>
          <td>失敗</td>
          <td>服務本身：外部與內部兩個位置都看到同一個功能失敗，失效在應用程式、資料庫這一側</td>
      </tr>
      <tr>
          <td>正常</td>
          <td>失敗</td>
          <td>成功</td>
          <td>主機內部探測沒有經過的那段路徑：主機以外的網域註冊、DNS、業者網路、防火牆或安全群組，以及主機上的入口元件（反向代理、TLS 憑證的自動續期、tunnel 的連接程式）；入口元件的紀錄在主機上</td>
      </tr>
      <tr>
          <td>中斷</td>
          <td>正常</td>
          <td>不可信</td>
          <td>監控或心跳送出的那條路：Prometheus、Alertmanager、規則與路由、送心跳的 receiver、主機對心跳監看服務的對外連線；服務仍在對外服務</td>
      </tr>
      <tr>
          <td>中斷</td>
          <td>失敗</td>
          <td>不可信</td>
          <td>主機整台或它的網路</td>
      </tr>
  </tbody>
</table>
<p>心跳中斷的兩列，主機內部探測的結果靠監控送出，監控停了或送不出去時結果到不了人手上，所以這一欄不能拿來判斷，這段時間沒有收到內部告警也不代表服務正常。表上沒有通知送不出去的那一種：三欄都可以是正常，訊號是送失敗通知的那個專用檢查項目寄來的 <code>DOWN</code>（檢查項目的名稱就指出是送失敗通知），它本身指出了失效所在。兩台主機互相監看時，心跳欄看的是服務主機上的監看程式有沒有收到監控主機送來的心跳：服務主機整台停掉時，監看程式跟著停，心跳欄不會有任何通知，主機停機的告警由監控主機發出；兩地之間的連線斷掉時，兩邊各自發出對方停機的通知，而外部探測成功。</p>
<p>只有主機內部的監控時，所有判斷都來自主機內部，排查從登入主機看程序與日誌開始。多了失效域以外的觀察者之後，各觀察者看到的組合先指出失效在哪一段，再決定下一步：指向服務本身時，照內部告警與應用程式的日誌查；指向路徑時，先查主機上入口元件的紀錄（反向代理的日誌、憑證續期的紀錄），沒有異常再往主機外查 DNS、網域與業者的狀態頁；指向主機整台或它的網路時，從主機外一層層確認哪裡斷，見 <a href="/blog/linux/debug/machine-unreachable/" data-link-title="機器連不到或起不來" data-link-desc="遠端機器突然 SSH 連不上、虛擬機開不了機、或懷疑磁碟滿引發連鎖故障時，從主機側與網路層的權威狀態往下定位是哪一環斷了">機器連不到或起不來</a>；指向監控本身時，查 Prometheus 與 Alertmanager 的程序狀態（見 <a href="/blog/linux/debug/process-service-state-diagnosis/" data-link-title="程序、服務與狀態怎麼判" data-link-desc="要判斷一個程式活著沒、某個系統服務現在由誰提供、桌面 session 有沒有被鎖、或終端機多工器的 session 還在不在時，用對的權威來源而不是靠畫面或猜的名字">程序、服務與狀態怎麼判</a>），再查規則、路由與主機對心跳監看服務的對外連線。</p>
<p>心跳監看與外部探測的失敗通知平時不會發出，所以接好之後要演練，而且要定期再演練，因為第三方那邊的檢查項目被刪除時同樣沒有任何訊號。兩種演練各自隔離一段路徑：停掉 Alertmanager 讓告警鏈中斷，確認心跳監看在週期加寬限之後通知；在外部探測服務上把探測的目標網址暫時改成不存在的路徑，不必停掉服務就模擬出使用者路徑的失敗，確認外部探測的失敗通知會到。演練完重新啟動 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> 的〈心跳中斷的演練〉；演練的範圍、安全邊界與成功標準怎麼定，見 <a href="/blog/backend/knowledge-cards/game-day/" data-link-title="Game Day" data-link-desc="說明事故演練如何驗證流程、工具與團隊協作">Game Day</a>，驗證備援的一般原則見 <a href="/blog/backend/04-observability/observability-shared-fate/" data-link-title="4.25 觀測共命運失效：工具退化時的訊號與人層設計" data-link-desc="觀測系統跟被觀測系統共享失效域、在最需要時一起退化；out-of-band 訊號、優雅降級、以及工具盲飛時客服與工程師怎麼還能應對">4.25 觀測共命運失效</a> 的〈驗證備援：不測的備援是薛丁格的備援〉。</p>
<h2 id="延伸閱讀觀察者改由第三方提供主機變成兩台失效範圍擴大到觀測系統與主機過載">延伸閱讀：觀察者改由第三方提供、主機變成兩台、失效範圍擴大到觀測系統與主機過載</h2>
<ul>
<li>觀察者改由第三方服務提供時，要挑的條件（服務的位置、通知管道、告警資料留在哪裡）、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>。</li>
<li>主機從一台變成兩台時，監控搬到另一個失效域、兩台之間的 VPN 與互相監看、雲端業者處理與不處理的故障，見 <a href="/blog/devops/operations/06-high-availability/small-service-host-layout/" data-link-title="小型服務的兩到三台主機配置：第二台與第三台主機的用法、監控主機的位置與連線、兩台主機互相監看，以及雲端業者負責的範圍" data-link-desc="一台主機的服務擴充到兩到三台時，每一台放什麼：第二台給監控、給應用程式的副本或給資料庫各自換到什麼與前提，與第三方心跳監看服務的比較，監控主機放在另一個業者或地端時經 VPN 讀取、連線中斷的誤判，兩台主機互相監看的條件，第三台給資料庫或兩台應用主機搭配託管資料庫，備份的位置，以及加主機也換不到、由雲端業者或入口設定處理的故障與攻擊">小型服務的兩到三台主機配置</a>。</li>
<li>失效的範圍從一台主機擴大到觀測系統本身時，依賴耦合、反噬與供應商單點三種機制，狀態頁的失效域隔離與人在盲飛時的應對，見 <a href="/blog/backend/04-observability/observability-shared-fate/" data-link-title="4.25 觀測共命運失效：工具退化時的訊號與人層設計" data-link-desc="觀測系統跟被觀測系統共享失效域、在最需要時一起退化；out-of-band 訊號、優雅降級、以及工具盲飛時客服與工程師怎麼還能應對">4.25 觀測共命運失效</a>。</li>
<li>主機沒有停而是過載時，監控自己也在等 CPU 的訊號與資源隔離，見 <a href="/blog/backend/04-observability/host-overload-alerting/" data-link-title="4.27 主機過載時的監控告警：可用與變慢分開判斷、依原因抑制、監控自身的等待" data-link-desc="多個服務共用一台主機而主機過載時，各服務的探測與告警會一起失敗：可用性與延遲分成兩個判斷的寫法、間歇的條件怎麼持續成立、以主機飽和抑制各服務變慢的規則與它的取捨、以合成告警驗證抑制、抑制藏起各服務受影響程度的差別、探測與 Prometheus 自己也在等 CPU 時的訊號，以及讓監控不比服務先失效的資源隔離；以一次開發環境的過載為例">4.27 主機過載時的監控告警</a>。</li>
</ul>
]]></content:encoded></item><item><title>Failure Domain（失效域）</title><link>https://tarrragon.github.io/blog/backend/knowledge-cards/failure-domain/</link><pubDate>Wed, 14 Oct 2026 00:00:00 +0800</pubDate><guid>https://tarrragon.github.io/blog/backend/knowledge-cards/failure-domain/</guid><description>&lt;p>失效域（failure domain，也寫作 fault domain、故障域）是一組會因為同一類原因一起停掉的元件：對主機故障而言是同一台主機上的程序，對機房斷電而言是同一個機房裡的主機，對帳號停權而言是同一個雲端帳號底下的資源。Oracle Cloud 把可用區內的一組硬體直接命名為 fault domain，建立主機時可以指定，見 &lt;a href="https://tarrragon.github.io/blog/devops/infra/knowledge-cards/fault-domain/" data-link-title="Fault Domain（故障域）" data-link-desc="建立 Oracle Cloud 主機時看到 fault domain 欄位、要讓同一個服務的幾台主機不落在同一組實體硬體上，或所在區域只有一個可用區、要找可用區以外的隔離手段時，查故障域的範圍、它防的事件與各家對應的放置政策">Fault Domain（故障域）&lt;/a>。判斷的單位是&lt;strong>共用的依賴&lt;/strong>——兩個元件共用一個會失效的依賴（主機、電源、網路、帳號、DNS），對那一類失效就落在同一個失效域，備援與監控是否獨立都以這件事判斷。任何兩台主機都會共用某些依賴，所以「兩者是不是不同的失效域」要指明是對哪一類失效。以為獨立而其實共用觸發點的情形見 &lt;a href="https://tarrragon.github.io/blog/backend/knowledge-cards/correlated-failure/" data-link-title="Correlated Failure" data-link-desc="以為獨立的多個元件共享一個隱藏的失效觸發器、在同一時刻一起壞；冗餘副本、觀測系統、跨區部署都可能共命運">Correlated Failure&lt;/a>。&lt;/p>
&lt;h2 id="概念位置">概念位置&lt;/h2>
&lt;p>失效域是冗餘與監控設計的單位。兩台主機放在同一個機房，機房斷電時一起停，冗餘只防得了單台主機的故障；監控與服務跑在同一台主機，主機停掉時監控跟著停，發不出告警。所以判斷一個備援或一個觀察者有沒有用，先問它與被保護、被觀察的對象共用了哪些依賴。觀察者落在失效域以外時，它送出的訊號稱為 &lt;a href="https://tarrragon.github.io/blog/backend/knowledge-cards/out-of-band-signal/" data-link-title="Out-of-Band Signal（頻外訊號）" data-link-desc="觀測系統本身也可能在事故中失能時、判斷該從哪個獨立通道取得系統存活狀態">Out-of-Band Signal&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> 看的是同一件事的兩端：失效域問「哪些元件會一起停」，影響範圍問「它們停掉時哪些使用者與功能受影響」。&lt;/p>
&lt;p>實體的依賴有由內而外的層次：程序、主機、機房（雲端的可用區）、區域、業者（業者全域的控制平面）。越往外的層，一次停掉的元件越多，發生的頻率通常也越低；在越外層把元件分開（不同主機、不同機房、不同區域），成本越高。帳號與計費、TLS 憑證、網域與 DNS、部署管線這類依賴不在這條序列上，它們橫跨各層：兩台在不同區域的主機，仍可能因為同一個帳號被停權、同一個網域過期而一起停。&lt;/p>
&lt;h2 id="可觀察訊號與例子">可觀察訊號與例子&lt;/h2>
&lt;p>服務與 Prometheus、Alertmanager 放在同一台雲端主機上：主機被業者維護重開、或帳號被停權時，所有元件一起停，通知端什麼都沒收到，與「一切正常」看起來一樣。把 Alertmanager 的&lt;a href="https://tarrragon.github.io/blog/backend/knowledge-cards/dead-mans-switch/" data-link-title="Dead Man&amp;#39;s Switch（心跳監看）" data-link-desc="需要知道監控或排程工作自己停掉了、而它停掉時發不出任何告警時，以「時限內沒收到訊號就通知」反過來判斷">心跳&lt;/a>送到另一個雲端業者上的監看服務，心跳中斷由那一邊通知，這條通知路徑就不在主機的失效域裡。&lt;/p>
&lt;p>共用的依賴常常藏在設定裡：兩台「分開」的主機掛著同一個網路檔案系統、讀同一份祕密管理服務、用同一個 DNS 業者，三者任一個停掉，兩台一起受影響。狀態頁與主站共用 DNS 是同一種情形（見 &lt;a href="https://tarrragon.github.io/blog/backend/knowledge-cards/status-page/" data-link-title="Status Page" data-link-desc="說明事故期間對外狀態頁如何承接可用性承諾">Status Page&lt;/a>）。&lt;/p>
&lt;h2 id="判讀方式">判讀方式&lt;/h2>
&lt;p>判斷兩個元件的失效域分開到什麼程度，逐項列出它們各自的依賴（主機、網路、電源、雲端帳號與付款方式、DNS、TLS 憑證、部署管線，以及通知管道：寄送通知的服務、收件信箱的網域、推播服務），共用的每一項都是一起停掉的原因。判讀的產出是剩下的共用依賴清單，以及每一項的處置。接不接受依兩件事判斷：這一項失效的頻率，以及兩者一起停掉的代價（停機代價怎麼估見 &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;a href="https://tarrragon.github.io/blog/devops/operations/06-high-availability/small-service-host-layout/" data-link-title="小型服務的兩到三台主機配置：第二台與第三台主機的用法、監控主機的位置與連線、兩台主機互相監看，以及雲端業者負責的範圍" data-link-desc="一台主機的服務擴充到兩到三台時，每一台放什麼：第二台給監控、給應用程式的副本或給資料庫各自換到什麼與前提，與第三方心跳監看服務的比較，監控主機放在另一個業者或地端時經 VPN 讀取、連線中斷的誤判，兩台主機互相監看的條件，第三台給資料庫或兩台應用主機搭配託管資料庫，備份的位置，以及加主機也換不到、由雲端業者或入口設定處理的故障與攻擊">小型服務的兩到三台主機配置&lt;/a>。&lt;/p></description><content:encoded><![CDATA[<p>失效域（failure domain，也寫作 fault domain、故障域）是一組會因為同一類原因一起停掉的元件：對主機故障而言是同一台主機上的程序，對機房斷電而言是同一個機房裡的主機，對帳號停權而言是同一個雲端帳號底下的資源。Oracle Cloud 把可用區內的一組硬體直接命名為 fault domain，建立主機時可以指定，見 <a href="/blog/devops/infra/knowledge-cards/fault-domain/" data-link-title="Fault Domain（故障域）" data-link-desc="建立 Oracle Cloud 主機時看到 fault domain 欄位、要讓同一個服務的幾台主機不落在同一組實體硬體上，或所在區域只有一個可用區、要找可用區以外的隔離手段時，查故障域的範圍、它防的事件與各家對應的放置政策">Fault Domain（故障域）</a>。判斷的單位是<strong>共用的依賴</strong>——兩個元件共用一個會失效的依賴（主機、電源、網路、帳號、DNS），對那一類失效就落在同一個失效域，備援與監控是否獨立都以這件事判斷。任何兩台主機都會共用某些依賴，所以「兩者是不是不同的失效域」要指明是對哪一類失效。以為獨立而其實共用觸發點的情形見 <a href="/blog/backend/knowledge-cards/correlated-failure/" data-link-title="Correlated Failure" data-link-desc="以為獨立的多個元件共享一個隱藏的失效觸發器、在同一時刻一起壞；冗餘副本、觀測系統、跨區部署都可能共命運">Correlated Failure</a>。</p>
<h2 id="概念位置">概念位置</h2>
<p>失效域是冗餘與監控設計的單位。兩台主機放在同一個機房，機房斷電時一起停，冗餘只防得了單台主機的故障；監控與服務跑在同一台主機，主機停掉時監控跟著停，發不出告警。所以判斷一個備援或一個觀察者有沒有用，先問它與被保護、被觀察的對象共用了哪些依賴。觀察者落在失效域以外時，它送出的訊號稱為 <a href="/blog/backend/knowledge-cards/out-of-band-signal/" data-link-title="Out-of-Band Signal（頻外訊號）" data-link-desc="觀測系統本身也可能在事故中失能時、判斷該從哪個獨立通道取得系統存活狀態">Out-of-Band Signal</a>。失效域與 <a href="/blog/backend/knowledge-cards/blast-radius/" data-link-title="Blast Radius" data-link-desc="說明事故影響面如何估算與隔離">Blast Radius</a> 看的是同一件事的兩端：失效域問「哪些元件會一起停」，影響範圍問「它們停掉時哪些使用者與功能受影響」。</p>
<p>實體的依賴有由內而外的層次：程序、主機、機房（雲端的可用區）、區域、業者（業者全域的控制平面）。越往外的層，一次停掉的元件越多，發生的頻率通常也越低；在越外層把元件分開（不同主機、不同機房、不同區域），成本越高。帳號與計費、TLS 憑證、網域與 DNS、部署管線這類依賴不在這條序列上，它們橫跨各層：兩台在不同區域的主機，仍可能因為同一個帳號被停權、同一個網域過期而一起停。</p>
<h2 id="可觀察訊號與例子">可觀察訊號與例子</h2>
<p>服務與 Prometheus、Alertmanager 放在同一台雲端主機上：主機被業者維護重開、或帳號被停權時，所有元件一起停，通知端什麼都沒收到，與「一切正常」看起來一樣。把 Alertmanager 的<a href="/blog/backend/knowledge-cards/dead-mans-switch/" data-link-title="Dead Man&#39;s Switch（心跳監看）" data-link-desc="需要知道監控或排程工作自己停掉了、而它停掉時發不出任何告警時，以「時限內沒收到訊號就通知」反過來判斷">心跳</a>送到另一個雲端業者上的監看服務，心跳中斷由那一邊通知，這條通知路徑就不在主機的失效域裡。</p>
<p>共用的依賴常常藏在設定裡：兩台「分開」的主機掛著同一個網路檔案系統、讀同一份祕密管理服務、用同一個 DNS 業者，三者任一個停掉，兩台一起受影響。狀態頁與主站共用 DNS 是同一種情形（見 <a href="/blog/backend/knowledge-cards/status-page/" data-link-title="Status Page" data-link-desc="說明事故期間對外狀態頁如何承接可用性承諾">Status Page</a>）。</p>
<h2 id="判讀方式">判讀方式</h2>
<p>判斷兩個元件的失效域分開到什麼程度，逐項列出它們各自的依賴（主機、網路、電源、雲端帳號與付款方式、DNS、TLS 憑證、部署管線，以及通知管道：寄送通知的服務、收件信箱的網域、推播服務），共用的每一項都是一起停掉的原因。判讀的產出是剩下的共用依賴清單，以及每一項的處置。接不接受依兩件事判斷：這一項失效的頻率，以及兩者一起停掉的代價（停機代價怎麼估見 <a href="/blog/devops/operations/06-high-availability/ha-cost/" data-link-title="高可用的成本" data-link-desc="判斷高可用值不值得時，用停機的商業代價衡量冗餘的 2x 成本、按可用性等級階梯評估投資、以及知道沒驗證的冗餘等於白付">高可用的成本</a>）。處置有三種：接受並寫明理由；把兩者分開；分不開時（例如兩台主機都服務同一個網域），改放一個在那一項以外的觀察者，讓它一起停掉時至少有人知道。列在紙上的依賴不一定完整：共用的依賴常在停掉其中一個元件時才浮現（另一個跟著出錯，或觀察者沒有發出通知），所以分到不同失效域之後的判斷，以實際停掉其中一個的結果為準。小型服務怎麼用兩到三台主機分開失效域，見 <a href="/blog/devops/operations/06-high-availability/small-service-host-layout/" data-link-title="小型服務的兩到三台主機配置：第二台與第三台主機的用法、監控主機的位置與連線、兩台主機互相監看，以及雲端業者負責的範圍" data-link-desc="一台主機的服務擴充到兩到三台時，每一台放什麼：第二台給監控、給應用程式的副本或給資料庫各自換到什麼與前提，與第三方心跳監看服務的比較，監控主機放在另一個業者或地端時經 VPN 讀取、連線中斷的誤判，兩台主機互相監看的條件，第三台給資料庫或兩台應用主機搭配託管資料庫，備份的位置，以及加主機也換不到、由雲端業者或入口設定處理的故障與攻擊">小型服務的兩到三台主機配置</a>。</p>
]]></content:encoded></item></channel></rss>