<?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>Noisy-Neighbor on Tarragon</title><link>https://tarrragon.github.io/blog/tags/noisy-neighbor/</link><description>Recent content in Noisy-Neighbor on Tarragon</description><generator>Hugo -- gohugo.io</generator><language>zh-TW</language><copyright>Tarragon (CC BY 4.0)</copyright><lastBuildDate>Mon, 12 Oct 2026 00:00:00 +0800</lastBuildDate><atom:link href="https://tarrragon.github.io/blog/tags/noisy-neighbor/index.xml" rel="self" type="application/rss+xml"/><item><title>共用主機的資源競爭：容量估算、故障範圍、隔離層級與監控的位置</title><link>https://tarrragon.github.io/blog/devops/operations/05-capacity-planning/shared-host-contention/</link><pubDate>Mon, 12 Oct 2026 00:00:00 +0800</pubDate><guid>https://tarrragon.github.io/blog/devops/operations/05-capacity-planning/shared-host-contention/</guid><description>&lt;p>多個工作負載共用同一份硬體資源，是部署與容量規劃的一個設計條件；這篇整理它在容量估算、故障範圍、隔離與監控上各要考慮什麼。共用有三種常見的形態：一台主機上用 Docker Compose 跑整個系統（應用程式、資料庫、快取與監控都在一起）、雲端的虛擬機與其他租戶共用同一台實體機，以及開發用的筆電上 Docker 的虛擬機與其他程式共用 CPU 與磁碟。三者的共同點是：某一個工作負載用掉的資源，會從其他工作負載能用的那一份裡扣掉，而被扣掉的那一方沒有做錯任何事。這個現象叫 &lt;a href="https://tarrragon.github.io/blog/backend/knowledge-cards/noisy-neighbor/" data-link-title="Noisy Neighbor（共用資源的鄰居干擾）" data-link-desc="服務沒有改動、自己的用量也不高卻整體變慢，或者同一台主機、同一台實體機上的其他工作負載一忙就跟著慢時，查共用資源的競爭從哪裡來、為什麼服務自己的監控看不到，以及隔離由淺到深有哪些做法">Noisy Neighbor&lt;/a>。本篇處理整台主機層級的取捨，單一容器的 CPU 與記憶體限制怎麼設另見 &lt;a href="https://tarrragon.github.io/blog/devops/operations/05-capacity-planning/container-resource-design/" data-link-title="容器化資源設計" data-link-desc="把容量規劃落到容器上時，怎麼定 memory 與 CPU 限制不觸發 OOMKill 或 throttle、以及 overlay filesystem 對高頻寫入的 I/O 影響">容器化資源設計&lt;/a>。&lt;/p>
&lt;h2 id="一次開發環境共用主機過載的量測">一次開發環境共用主機過載的量測&lt;/h2>
&lt;p>一個短網址服務的開發環境在同一台虛擬機裡跑入口 Nginx、兩個後端、PostgreSQL、Valkey 與監控，虛擬機由 macOS 上的 OrbStack 提供。Mac 上其他程式把 &lt;a href="https://tarrragon.github.io/blog/backend/knowledge-cards/load-average/" data-link-title="Load Average（負載平均）" data-link-desc="看到 uptime 或 node_load1 的數字、要判斷主機是不是在排隊時，查 load average 算的是什麼、除以核心數怎麼讀、Linux 為什麼把等磁碟的行程也算進去，以及在虛擬機與容器裡量到的值代表誰">load average&lt;/a>（在跑或在等 CPU 的平均行程數，除以核心數大於 1 代表有行程在排隊）推到 55 到 78、持續數小時的那段時間，這台 8 顆核心的 Mac 上：&lt;/p>
&lt;ul>
&lt;li>&lt;strong>所有工作都變慢&lt;/strong>：PostgreSQL 產生 200 萬個數字的查詢要 4 秒，同一個查詢在 Mac 沒被佔用時約一百多毫秒，相差二、三十倍；1.2 萬列的批次寫入要十幾秒。這個比較量的正是主機造成的差距。&lt;/li>
&lt;li>&lt;strong>各服務受影響的程度不同&lt;/strong>：外部探測要求回應時間低於 500 ms，Go 後端達標的比例是 92.5%、最慢 2.1 秒；Laravel 後端只有 49%、最慢 6.0 秒，未達標的全是慢、沒有錯誤（探測的回應時間也含探測程式自己的等待，見 4.27）。&lt;/li>
&lt;/ul>
&lt;p>同一段時間，監控自己讀取各 &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> 的耗時也逼近逾時，而虛擬機裡的 load 除以核心數最高只有 1.28，從虛擬機的數字判斷不出 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;/p>
&lt;h2 id="容量估算共用主機時分得到的資源量">容量估算：共用主機時分得到的資源量&lt;/h2>
&lt;p>容量估算把「每秒多少請求」換成「需要多少 CPU、記憶體與連線」，前提是這些資源在需要的時候拿得到。共用主機時，拿得到的量由其他工作負載決定：&lt;/p>
&lt;ul>
&lt;li>&lt;strong>同一台主機上的其他服務&lt;/strong>：資料庫的重查詢、批次工作、監控本身的讀取，和線上的請求搶 CPU 與磁碟。估算時要把它們的尖峰時段疊在一起看，而不是各自算平均。&lt;/li>
&lt;li>&lt;strong>同一台實體機上的其他租戶&lt;/strong>：雲端的虛擬機分到的 CPU 時間會被虛擬化層（hypervisor）分給別的虛擬機，Linux 虛擬機裡的 steal 時間（&lt;code>/proc/stat&lt;/code> 的 steal，&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 讀得到資料卻缺標籤、或者讀不到它所在層以外的機器時怎麼發現">node_exporter&lt;/a> 的 &lt;code>node_cpu_seconds_total{mode=&amp;quot;steal&amp;quot;}&lt;/code>）記錄這段被拿走的時間。&lt;/li>
&lt;li>&lt;strong>雲端機型自己的 CPU 額度&lt;/strong>：可突發型的機型（例如 AWS 的 T 系列）另有 CPU 額度：standard 模式下額度用完只剩基準效能；unlimited 模式（T3、T3a、T4g 等的預設）可以繼續突發，超出基準的部分另外計費。額度剩多少看雲端自己的監控（AWS 是 CloudWatch 的 &lt;code>CPUCreditBalance&lt;/code> 與 &lt;code>CPUSurplusCreditBalance&lt;/code>），虛擬機裡的 node_exporter 看不到它。&lt;/li>
&lt;li>&lt;strong>開發環境&lt;/strong>：筆電上的其他程式。這一層無法控制，所以在筆電上量到的數字只代表那一刻的那台機器。&lt;/li>
&lt;/ul>
&lt;p>所以量到的數字含有主機當下的負載：同一個服務在主機安靜時與過載時量到的上限，差的是主機而不是服務，拿來比較服務本身的表現（兩個版本、兩種設定）時兩者不能互相比較。量測紀錄因此附上當時主機的 load、核心數與可用磁碟，而且要在主機本身看，不是在 Docker 的虛擬機裡（macOS 用 &lt;code>uptime&lt;/code>、&lt;code>sysctl -n hw.ncpu&lt;/code>、&lt;code>df -h&lt;/code>，Linux 用 &lt;code>uptime&lt;/code>、&lt;code>nproc&lt;/code>、&lt;code>df -h&lt;/code>）；虛擬機裡的數字為什麼不能用，見 &lt;a href="https://tarrragon.github.io/blog/backend/04-observability/host-traffic-resource-monitoring/" data-link-title="4.26 單機容器服務的流量與資源監控：各層的訊號、Prometheus 與 exporter、監控所在層的盲區" data-link-desc="健康檢查之外的流量與資源監控：入口、應用程式、容器、主機與資料庫等服務內部各層的訊號從哪裡收、用哪一個 exporter，Prometheus 加 exporter、單一 agent、開箱即用工具與臨時查看指令的取捨，單次取樣與時間窗的差別，監控裝在虛擬機裡時看不到主機的 CPU 負載、看到的磁碟要分清是哪一顆，以及每接上一個來源的驗收與偵測容器停止的寫法；cAdvisor 與 node_exporter 在 OrbStack 上實測過">4.26 單機容器服務的流量與資源監控&lt;/a>〈監控所在層看不到的範圍：虛擬機與主機〉。主機的 load 除以核心數或磁碟使用率超過事先定好的門檻時，量到的數字不拿去和其他時間比較服務的表現，採用的門檻也寫進紀錄。主機狀態要在量測期間持續記錄，不只在開始前看一次；壓測工具跑在同一台主機上時，它用的 CPU 也從服務那一份扣掉。單次取樣的數字本身也會跳動，判讀方式見 4.26〈單次取樣與時間窗〉。&lt;/p>
&lt;h2 id="故障範圍同一台主機上服務的相關失效">故障範圍：同一台主機上服務的相關失效&lt;/h2>
&lt;p>共用同一台主機的服務，失效是相關的：主機的 CPU、記憶體、磁碟或網路任一樣耗盡，上面全部的服務一起受影響；主機重開或磁碟寫滿，全部一起停。&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="判斷兩個元件會不會因為同一件事一起停掉、備援或監控是否獨立於被保護的對象時，查它們共用了哪些會失效的依賴">失效域&lt;/a>。實例是同一個開發環境稍早的一次：Mac 的磁碟剩不到 1 GB 時，OrbStack 的虛擬機連同裡面全部的容器被停掉了三次。&lt;/p></description><content:encoded><![CDATA[<p>多個工作負載共用同一份硬體資源，是部署與容量規劃的一個設計條件；這篇整理它在容量估算、故障範圍、隔離與監控上各要考慮什麼。共用有三種常見的形態：一台主機上用 Docker Compose 跑整個系統（應用程式、資料庫、快取與監控都在一起）、雲端的虛擬機與其他租戶共用同一台實體機，以及開發用的筆電上 Docker 的虛擬機與其他程式共用 CPU 與磁碟。三者的共同點是：某一個工作負載用掉的資源，會從其他工作負載能用的那一份裡扣掉，而被扣掉的那一方沒有做錯任何事。這個現象叫 <a href="/blog/backend/knowledge-cards/noisy-neighbor/" data-link-title="Noisy Neighbor（共用資源的鄰居干擾）" data-link-desc="服務沒有改動、自己的用量也不高卻整體變慢，或者同一台主機、同一台實體機上的其他工作負載一忙就跟著慢時，查共用資源的競爭從哪裡來、為什麼服務自己的監控看不到，以及隔離由淺到深有哪些做法">Noisy Neighbor</a>。本篇處理整台主機層級的取捨，單一容器的 CPU 與記憶體限制怎麼設另見 <a href="/blog/devops/operations/05-capacity-planning/container-resource-design/" data-link-title="容器化資源設計" data-link-desc="把容量規劃落到容器上時，怎麼定 memory 與 CPU 限制不觸發 OOMKill 或 throttle、以及 overlay filesystem 對高頻寫入的 I/O 影響">容器化資源設計</a>。</p>
<h2 id="一次開發環境共用主機過載的量測">一次開發環境共用主機過載的量測</h2>
<p>一個短網址服務的開發環境在同一台虛擬機裡跑入口 Nginx、兩個後端、PostgreSQL、Valkey 與監控，虛擬機由 macOS 上的 OrbStack 提供。Mac 上其他程式把 <a href="/blog/backend/knowledge-cards/load-average/" data-link-title="Load Average（負載平均）" data-link-desc="看到 uptime 或 node_load1 的數字、要判斷主機是不是在排隊時，查 load average 算的是什麼、除以核心數怎麼讀、Linux 為什麼把等磁碟的行程也算進去，以及在虛擬機與容器裡量到的值代表誰">load average</a>（在跑或在等 CPU 的平均行程數，除以核心數大於 1 代表有行程在排隊）推到 55 到 78、持續數小時的那段時間，這台 8 顆核心的 Mac 上：</p>
<ul>
<li><strong>所有工作都變慢</strong>：PostgreSQL 產生 200 萬個數字的查詢要 4 秒，同一個查詢在 Mac 沒被佔用時約一百多毫秒，相差二、三十倍；1.2 萬列的批次寫入要十幾秒。這個比較量的正是主機造成的差距。</li>
<li><strong>各服務受影響的程度不同</strong>：外部探測要求回應時間低於 500 ms，Go 後端達標的比例是 92.5%、最慢 2.1 秒；Laravel 後端只有 49%、最慢 6.0 秒，未達標的全是慢、沒有錯誤（探測的回應時間也含探測程式自己的等待，見 4.27）。</li>
</ul>
<p>同一段時間，監控自己讀取各 <a href="/blog/backend/knowledge-cards/prometheus-exporter/" data-link-title="Prometheus Exporter（指標轉接程式）" data-link-desc="要監控一個不會自己輸出 Prometheus 指標的系統（主機、容器、資料庫、快取、Nginx）時，查 exporter 做什麼、它和應用程式自己開的 /metrics 差在哪，以及 exporter 讀得到資料卻缺標籤、或者讀不到它所在層以外的機器時怎麼發現">exporter</a> 的耗時也逼近逾時，而虛擬機裡的 load 除以核心數最高只有 1.28，從虛擬機的數字判斷不出 CPU 在排隊；這一面的量測與告警寫法見 <a href="/blog/backend/04-observability/host-overload-alerting/" data-link-title="4.27 主機過載時的監控告警：可用與變慢分開判斷、依原因抑制、監控自身的等待" data-link-desc="多個服務共用一台主機而主機過載時，各服務的探測與告警會一起失敗：可用性與延遲分成兩個判斷的寫法、間歇的條件怎麼持續成立、以主機飽和抑制各服務變慢的規則與它的取捨、以合成告警驗證抑制、抑制藏起各服務受影響程度的差別、探測與 Prometheus 自己也在等 CPU 時的訊號，以及讓監控不比服務先失效的資源隔離；以一次開發環境的過載為例">4.27 主機過載時的監控告警</a>。容量拿不準、服務一起出事，是下面兩節的題目。</p>
<h2 id="容量估算共用主機時分得到的資源量">容量估算：共用主機時分得到的資源量</h2>
<p>容量估算把「每秒多少請求」換成「需要多少 CPU、記憶體與連線」，前提是這些資源在需要的時候拿得到。共用主機時，拿得到的量由其他工作負載決定：</p>
<ul>
<li><strong>同一台主機上的其他服務</strong>：資料庫的重查詢、批次工作、監控本身的讀取，和線上的請求搶 CPU 與磁碟。估算時要把它們的尖峰時段疊在一起看，而不是各自算平均。</li>
<li><strong>同一台實體機上的其他租戶</strong>：雲端的虛擬機分到的 CPU 時間會被虛擬化層（hypervisor）分給別的虛擬機，Linux 虛擬機裡的 steal 時間（<code>/proc/stat</code> 的 steal，<a href="/blog/backend/knowledge-cards/prometheus-exporter/" data-link-title="Prometheus Exporter（指標轉接程式）" data-link-desc="要監控一個不會自己輸出 Prometheus 指標的系統（主機、容器、資料庫、快取、Nginx）時，查 exporter 做什麼、它和應用程式自己開的 /metrics 差在哪，以及 exporter 讀得到資料卻缺標籤、或者讀不到它所在層以外的機器時怎麼發現">node_exporter</a> 的 <code>node_cpu_seconds_total{mode=&quot;steal&quot;}</code>）記錄這段被拿走的時間。</li>
<li><strong>雲端機型自己的 CPU 額度</strong>：可突發型的機型（例如 AWS 的 T 系列）另有 CPU 額度：standard 模式下額度用完只剩基準效能；unlimited 模式（T3、T3a、T4g 等的預設）可以繼續突發，超出基準的部分另外計費。額度剩多少看雲端自己的監控（AWS 是 CloudWatch 的 <code>CPUCreditBalance</code> 與 <code>CPUSurplusCreditBalance</code>），虛擬機裡的 node_exporter 看不到它。</li>
<li><strong>開發環境</strong>：筆電上的其他程式。這一層無法控制，所以在筆電上量到的數字只代表那一刻的那台機器。</li>
</ul>
<p>所以量到的數字含有主機當下的負載：同一個服務在主機安靜時與過載時量到的上限，差的是主機而不是服務，拿來比較服務本身的表現（兩個版本、兩種設定）時兩者不能互相比較。量測紀錄因此附上當時主機的 load、核心數與可用磁碟，而且要在主機本身看，不是在 Docker 的虛擬機裡（macOS 用 <code>uptime</code>、<code>sysctl -n hw.ncpu</code>、<code>df -h</code>，Linux 用 <code>uptime</code>、<code>nproc</code>、<code>df -h</code>）；虛擬機裡的數字為什麼不能用，見 <a href="/blog/backend/04-observability/host-traffic-resource-monitoring/" data-link-title="4.26 單機容器服務的流量與資源監控：各層的訊號、Prometheus 與 exporter、監控所在層的盲區" data-link-desc="健康檢查之外的流量與資源監控：入口、應用程式、容器、主機與資料庫等服務內部各層的訊號從哪裡收、用哪一個 exporter，Prometheus 加 exporter、單一 agent、開箱即用工具與臨時查看指令的取捨，單次取樣與時間窗的差別，監控裝在虛擬機裡時看不到主機的 CPU 負載、看到的磁碟要分清是哪一顆，以及每接上一個來源的驗收與偵測容器停止的寫法；cAdvisor 與 node_exporter 在 OrbStack 上實測過">4.26 單機容器服務的流量與資源監控</a>〈監控所在層看不到的範圍：虛擬機與主機〉。主機的 load 除以核心數或磁碟使用率超過事先定好的門檻時，量到的數字不拿去和其他時間比較服務的表現，採用的門檻也寫進紀錄。主機狀態要在量測期間持續記錄，不只在開始前看一次；壓測工具跑在同一台主機上時，它用的 CPU 也從服務那一份扣掉。單次取樣的數字本身也會跳動，判讀方式見 4.26〈單次取樣與時間窗〉。</p>
<h2 id="故障範圍同一台主機上服務的相關失效">故障範圍：同一台主機上服務的相關失效</h2>
<p>共用同一台主機的服務，失效是相關的：主機的 CPU、記憶體、磁碟或網路任一樣耗盡，上面全部的服務一起受影響；主機重開或磁碟寫滿，全部一起停。<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="判斷兩個元件會不會因為同一件事一起停掉、備援或監控是否獨立於被保護的對象時，查它們共用了哪些會失效的依賴">失效域</a>。實例是同一個開發環境稍早的一次：Mac 的磁碟剩不到 1 GB 時，OrbStack 的虛擬機連同裡面全部的容器被停掉了三次。</p>
<p>這帶出部署時要決定的幾件事：</p>
<ul>
<li><strong>哪些服務適合放在一起</strong>：延遲敏感的線上請求與吃滿 CPU 的批次工作（重算報表、匯出）放在一起時，批次工作的尖峰就是線上請求的延遲尖峰。分開放，或至少用限制與權重讓線上請求優先。</li>
<li><strong>資料庫與應用程式要不要同機</strong>：同機省下網路延遲與一台機器的成本，代價在記憶體。主機的記憶體耗盡時，Linux 的 <a href="/blog/linux/dotfile/knowledge-cards/oom-exit-code-137/" data-link-title="OOM Killer and Exit Code 137（OOM killer 與退出碼 137）" data-link-desc="程序或 container 被無預警砍掉、退出碼是 137、或編譯 / 測試在記憶體吃緊時突然死掉、要判斷是不是記憶體不足時回來讀">OOM killer</a> 依各行程常駐的記憶體（與可調的 <code>oom_score_adj</code>）挑一個結束，佔用最多的最先被挑中；資料常駐記憶體的 Redis、Valkey，或 <code>shared_buffers</code> 調大的 PostgreSQL，常是佔用最多的那一個（PostgreSQL 多數的快取在作業系統的 page cache，不算進去）。所以應用程式的記憶體暴增時，被結束的可能是資料庫或快取；PostgreSQL 的一個行程被結束，主行程會中斷所有連線、做損毀復原（crash recovery）之後才收得了新連線。給應用程式的容器設記憶體上限，暴增時被結束的就只會是那個容器；PostgreSQL 官方文件另建議把主行程的 <code>oom_score_adj</code> 調低。這時被終止的程序與負載增加的程序不是同一個，後端看到的是依賴失敗，見 <a href="/blog/backend/09-performance-capacity/overload-outcomes/" data-link-title="9.16 負載超過容量時服務的表現：變慢、請求失敗、無回應、程序終止，尖峰過去或應對切換之後仍持續的停在失效、擺盪與第二波湧入，以及應對選出的降級回應，各自的判斷標準、成因、應對與看得到它的監控層" data-link-desc="負載超過容量（過載）時，服務呈現的結果分成變慢、請求失敗（抵達後被拒與根本沒有抵達）、無回應、程序終止，以及尖峰過去、依賴恢復或應對切換之後仍持續的停在失效、擺盪與第二波湧入；每一種的判斷標準、通常的成因與應對，哪一種先出現由先耗盡的資源與等待是否設有上限決定，影響範圍怎麼隨時間擴大，服務端監控的各層各自看得到哪一種，降級回應怎麼計數，過載在資料上造成的重複寫入、接受後遺失與讀到舊資料，以及描述一次過載要寫出的項目">9.16 負載超過容量時服務的表現</a> 的〈程序終止：被系統結束、當機或反覆重啟〉。</li>
<li><strong>監控放在哪裡</strong>：監控與被監控的服務放在同一台主機時，主機出事的那一刻監控也跟著退化或停止，見〈監控的位置〉。</li>
</ul>
<h2 id="隔離的層級與代價">隔離的層級與代價</h2>
<p>隔離可以分成幾個層級，越往下隔離得越徹底，成本與管理負擔也越高：</p>
<table>
  <thead>
      <tr>
          <th>層級</th>
          <th>做法</th>
          <th>隔離得了</th>
          <th>隔離不了</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>同一台主機，不設限制</td>
          <td>Compose 的預設</td>
          <td>—</td>
          <td>任何一個服務吃滿資源，其他全部受影響</td>
      </tr>
      <tr>
          <td>同一台主機，設上限與權重</td>
          <td>容器的 CPU 上限（<code>--cpus</code>，<a href="/blog/backend/knowledge-cards/cgroup/" data-link-title="cgroup（控制群組）" data-link-desc="設定容器的 CPU 與記憶體上限、讀 cAdvisor 的指標、或查容器為什麼被暫停與結束時，查 cgroup 是什麼、v1 與 v2 的差別，以及 Docker 與 Kubernetes 的參數各自對應到它的哪個控制檔">cgroup</a> 的 <code>cpu.max</code>）、把容器釘在指定核心（<code>--cpuset-cpus</code>）、相對權重（<code>--cpu-shares</code>，<code>cpu.weight</code>）、記憶體上限</td>
          <td>單一服務吃掉全部 CPU 或記憶體</td>
          <td>磁碟讀寫與網路的爭用、主機本身的故障</td>
      </tr>
      <tr>
          <td>同一台主機，保留資源與優先權</td>
          <td>Kubernetes 的 requests 與 QoS（requests 等於 limits 的 Pod 屬於 Guaranteed，最後才被 OOM 結束）、<code>PriorityClass</code>（資源不夠排程時先排它，必要時驅逐低優先權的 Pod）；cgroup v2 的記憶體保留（<code>memory.min</code>、<code>memory.low</code>，Docker 的 <code>--memory-reservation</code>）；Compose 的 <code>oom_score_adj</code>；systemd 的 slice（把一組服務放進同一個 cgroup，給它權重或上限）</td>
          <td>主機記憶體吃緊時，重要的服務與監控的記憶體最後被回收、最後被結束</td>
          <td>主機本身的故障</td>
      </tr>
      <tr>
          <td>不同主機或虛擬機</td>
          <td>依角色分開部署（資料庫、應用程式、監控各自一台），Kubernetes 的 anti-affinity（排程時不讓指定的 Pod 落在同一個節點）</td>
          <td>一台主機的資源耗盡與故障</td>
          <td>同一台實體機上其他租戶的競爭（虛擬機時）</td>
      </tr>
      <tr>
          <td>專用的實體機</td>
          <td>雲端的 dedicated host、自己的機房</td>
          <td>其他租戶，含共用的 CPU 快取與記憶體頻寬</td>
          <td>同一個機櫃、同一個機房的共同故障</td>
      </tr>
  </tbody>
</table>
<p>機房與可用區層級的隔離見 <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>CPU 的硬上限有代價：碰到上限的容器會被暫停執行（CPU throttling），延遲因此升高而主機的 CPU 不一定滿（<a href="/blog/backend/knowledge-cards/resource-limit/" data-link-title="Resource Limit" data-link-desc="說明服務可使用的 CPU、memory 與相關資源上限如何影響行為">Resource Limit</a>）。單一容器的上限怎麼定見 <a href="/blog/devops/operations/05-capacity-planning/container-resource-design/" data-link-title="容器化資源設計" data-link-desc="把容量規劃落到容器上時，怎麼定 memory 與 CPU 限制不觸發 OOMKill 或 throttle、以及 overlay filesystem 對高頻寫入的 I/O 影響">容器化資源設計</a>〈CPU 限制：hard limit 還是相對權重〉，不設上限只設權重的取捨見 <a href="/blog/backend/05-deployment-platform/container-runtime/" data-link-title="5.1 container 與 runtime" data-link-desc="整理 image、resource limit 與啟動行為">5.1 container 與 runtime</a>〈CPU request 與 limit 的設定策略〉；核心依 <code>cpu.weight</code> 分配比例只在搶資源時生效，不會讓服務被暫停。</p>
<p>保留資源與優先權那一層在 CPU 上用的是同一個權重機制，它多出來的是記憶體耗盡時誰先被結束。這一層的觸發條件是：有服務沒設上限（監控元件常是這樣），或上限加總再加上主機自己的行程超過主機的記憶體，每個服務都沒超過自己的上限，主機一樣會耗盡記憶體；這時決定被結束順序的就是 QoS、優先權與 <code>oom_score_adj</code>，而 <code>memory.min</code>、<code>memory.low</code> 影響的是核心回收記憶體時先避開誰，不影響 OOM killer 挑誰結束。Kubernetes 上 kubelet 在節點記憶體或磁碟吃緊時會先依 QoS 驅逐 Pod，驅逐發生在核心的 OOM 之前。主機有 swap 時，耗盡的樣子常是全面變慢（不斷換頁），而不是某個行程被結束。</p>
<p>CPU 與記憶體的限制是成熟的做法；磁碟讀寫與網路頻寬的隔離（cgroup v2 的 <code>io.max</code>、<code>io.weight</code>）實際效果依磁碟與排程器而定，本篇沒有實測。磁碟爭用的樣子是：備份或大量匯入與資料庫的寫入同時進行時，資料庫每次提交都要等資料寫到磁碟上，寫入延遲跟著另一個服務的寫入量起伏，而兩邊的 CPU 用量都不高。所以高頻寫入的服務（資料庫、事件的寫入）在同一台主機上最容易互相拖累，也最常是第一個被分出去的。</p>
<p>選哪一個層級，看兩件事：一起出事的代價（故障範圍內的服務對使用者有多重要），以及拆開的成本（多一台機器、多一份部署與監控）。練習或早期的服務放在一台主機上是合理的起點，前提是知道哪些事會一起發生，並在它們開始發生時看得到。在一台主機上，「開始發生」長的是前面幾節的樣子：批次工作的時段線上請求的 p95 跟著上升、資料庫被 OOM killer 結束、磁碟寫滿讓全部服務一起停。前兩種先在同一台主機上補限制、權重或保留。磁碟寫滿先找出是誰寫滿的（日誌、映像、備份或資料庫本身），擴充磁碟或加上清理：Docker 預設的 json-file 日誌不會輪替，在 compose 設 <code>logging.options.max-size</code> 與 <code>max-file</code>；寫入量大的服務放在自己的檔案系統或設配額，寫滿時只影響它自己；同一個服務的寫入反覆把磁碟寫滿、或它的磁碟讀寫反覆拖慢資料庫，才是把它分到另一台主機的時候。限制、權重與保留都補了之後同一種情形仍反覆出現，也是分出去的時候。雲端虛擬機的 steal 時間長期偏高、換成非突發型機型也沒有改善時，才輪到專用的實體機。</p>
<h2 id="監控的位置">監控的位置</h2>
<p>裝在虛擬機裡的監控看不到虛擬機以外的競爭從哪裡來：Mac 上的其他程式完全看不到；實體機上的其他租戶只留下 <a href="/blog/backend/knowledge-cards/cpu-steal-time/" data-link-title="CPU Steal Time（被虛擬化層拿走的 CPU 時間）" data-link-desc="雲端虛擬機的服務沒有改動、CPU 用量也不高卻變慢時，查 steal time 記的是什麼、怎麼從 node_exporter 算出比例、什麼環境量不到它，以及升高時的處置">steal 時間</a>這一個間接訊號（見〈容量估算〉）。兩種情形在服務的指標上都長成全部服務同時變慢，而它們各自的用量都不高。各層的監控能看到什麼、主機的磁碟怎麼一起涵蓋，見 <a href="/blog/backend/04-observability/host-traffic-resource-monitoring/" data-link-title="4.26 單機容器服務的流量與資源監控：各層的訊號、Prometheus 與 exporter、監控所在層的盲區" data-link-desc="健康檢查之外的流量與資源監控：入口、應用程式、容器、主機與資料庫等服務內部各層的訊號從哪裡收、用哪一個 exporter，Prometheus 加 exporter、單一 agent、開箱即用工具與臨時查看指令的取捨，單次取樣與時間窗的差別，監控裝在虛擬機裡時看不到主機的 CPU 負載、看到的磁碟要分清是哪一顆，以及每接上一個來源的驗收與偵測容器停止的寫法；cAdvisor 與 node_exporter 在 OrbStack 上實測過">4.26 單機容器服務的流量與資源監控</a>。</p>
<p>監控和服務放在同一台主機時還會一起退化：探測與 Prometheus 自己也在等 CPU，量到的延遲包含它們自己的等待，讀取逾時會在資料裡留下空洞。所以正式環境至少要有一個訊號來自那台主機之外（另一個失效域的機器上的探測、外部的 uptime 服務；位置怎麼選見 <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/small-service-host-layout/" data-link-title="小型服務的兩到三台主機配置：第二台與第三台主機的用法、監控主機的位置與連線、兩台主機互相監看，以及雲端業者負責的範圍" data-link-desc="一台主機的服務擴充到兩到三台時，每一台放什麼：第二台給監控、給應用程式的副本或給資料庫各自換到什麼與前提，與第三方心跳監看服務的比較，監控主機放在另一個業者或地端時經 VPN 讀取、連線中斷的誤判，兩台主機互相監看的條件，第三台給資料庫或兩台應用主機搭配託管資料庫，備份的位置，以及加主機也換不到、由雲端業者或入口設定處理的故障與攻擊">小型服務的兩到三台主機配置</a>），這是 <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/host-overload-alerting/" data-link-title="4.27 主機過載時的監控告警：可用與變慢分開判斷、依原因抑制、監控自身的等待" data-link-desc="多個服務共用一台主機而主機過載時，各服務的探測與告警會一起失敗：可用性與延遲分成兩個判斷的寫法、間歇的條件怎麼持續成立、以主機飽和抑制各服務變慢的規則與它的取捨、以合成告警驗證抑制、抑制藏起各服務受影響程度的差別、探測與 Prometheus 自己也在等 CPU 時的訊號，以及讓監控不比服務先失效的資源隔離；以一次開發環境的過載為例">4.27 主機過載時的監控告警</a>。</p>
<h2 id="延伸閱讀單一容器的限制資源分艙與單點盤點">延伸閱讀：單一容器的限制、資源分艙與單點盤點</h2>
<ul>
<li>單一容器的記憶體與 CPU 限制怎麼從基準量推出來、CPU 用完配額而被暫停（throttling）時的症狀，見 <a href="/blog/devops/operations/05-capacity-planning/container-resource-design/" data-link-title="容器化資源設計" data-link-desc="把容量規劃落到容器上時，怎麼定 memory 與 CPU 限制不觸發 OOMKill 或 throttle、以及 overlay filesystem 對高頻寫入的 I/O 影響">容器化資源設計</a>。</li>
<li>本篇的隔離停在主機與容器這一層；同一個服務裡把連線池、執行緒依用途分開，讓一個依賴的故障不讓其他請求一起失敗，是同一個想法在應用層的做法，見 <a href="/blog/backend/knowledge-cards/bulkhead/" data-link-title="Bulkhead" data-link-desc="說明 bulkhead 如何用資源分艙限制故障擴散">Bulkhead</a> 與 <a href="/blog/devops/operations/03-traffic-management/bulkhead/" data-link-title="Bulkhead 隔離" data-link-desc="不同工作負載的資源池隔離 — 一個功能過載不拖垮其他功能的隔艙設計">Bulkhead 隔離</a>。</li>
<li>單點盤點的方法（逐條列出依賴、問每一條失效時誰受影響），見 <a href="/blog/devops/operations/06-high-availability/spof-inventory/" data-link-title="單點故障盤點" data-link-desc="要系統性找出哪些元件掛了整個系統就跟著掛時，用 pre-mortem 反推失敗路徑、依賴 budget 算可用性上限、以及按 blast radius 排序缺口">單點故障盤點</a>；「放在同一台主機」可以當成其中一條依賴列進去。</li>
</ul>
]]></content:encoded></item><item><title>Noisy Neighbor（共用資源的鄰居干擾）</title><link>https://tarrragon.github.io/blog/backend/knowledge-cards/noisy-neighbor/</link><pubDate>Mon, 12 Oct 2026 00:00:00 +0800</pubDate><guid>https://tarrragon.github.io/blog/backend/knowledge-cards/noisy-neighbor/</guid><description>&lt;p>Noisy neighbor 是多個工作負載共用同一份硬體資源時，其中一個用掉的資源從其他工作負載能用的那一份裡扣掉，使那些工作負載變慢或失敗的現象；被影響的一方沒有做錯任何事。本卡管的是硬體資源這一層，共用發生在幾個層：同一台主機上的多個容器（應用程式、資料庫、批次工作、監控）、同一台實體機上的多台虛擬機（雲端的其他租戶），以及開發用筆電上 Docker 的虛擬機與其他程式。它是 &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/bulkhead/" data-link-title="Bulkhead" data-link-desc="說明 bulkhead 如何用資源分艙限制故障擴散">Bulkhead&lt;/a> 與 &lt;a href="https://tarrragon.github.io/blog/backend/knowledge-cards/resource-limit/" data-link-title="Resource Limit" data-link-desc="說明服務可使用的 CPU、memory 與相關資源上限如何影響行為">Resource Limit&lt;/a>。同一個服務裡的多個租戶搶連線池、快取或佇列，是同一個現象在應用層的形態，隔離的做法見 Bulkhead。&lt;/p>
&lt;h2 id="概念位置">概念位置&lt;/h2>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>共用的層&lt;/th>
 &lt;th>被搶走的資源&lt;/th>
 &lt;th>從哪裡看得到&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>同一台主機的容器&lt;/td>
 &lt;td>CPU、記憶體、磁碟讀寫、網路&lt;/td>
 &lt;td>主機與每個容器的用量（node_exporter、cAdvisor），哪個容器在尖峰時用得最多&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>同一台實體機的虛擬機&lt;/td>
 &lt;td>CPU 時間、磁碟與網路頻寬&lt;/td>
 &lt;td>Linux 虛擬機的 &lt;a href="https://tarrragon.github.io/blog/backend/knowledge-cards/cpu-steal-time/" data-link-title="CPU Steal Time（被虛擬化層拿走的 CPU 時間）" data-link-desc="雲端虛擬機的服務沒有改動、CPU 用量也不高卻變慢時，查 steal time 記的是什麼、怎麼從 node_exporter 算出比例、什麼環境量不到它，以及升高時的處置">steal 時間&lt;/a>（&lt;code>node_cpu_seconds_total{mode=&amp;quot;steal&amp;quot;}&lt;/code>）&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>開發用筆電上的虛擬機&lt;/td>
 &lt;td>筆電的 CPU 與磁碟&lt;/td>
 &lt;td>CPU 負載只有筆電本身看得到（&lt;code>uptime&lt;/code>），筆電忙的時候虛擬機裡的 load 仍然很低；磁碟要看虛擬機有沒有掛進筆電的那一顆（OrbStack 以 virtiofs 掛入，node_exporter 看得到，剩餘比例正確而位元組數放大 256 倍）&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;p>被干擾的服務自己的監控通常看不到成因：它的 CPU 用量低、錯誤少，只有延遲高，成因在它與其他工作負載共用的那一份資源上，而且常在監控所在層之外。隔離由淺到深是同機設上限與權重（&lt;a href="https://tarrragon.github.io/blog/backend/knowledge-cards/resource-limit/" data-link-title="Resource Limit" data-link-desc="說明服務可使用的 CPU、memory 與相關資源上限如何影響行為">Resource Limit&lt;/a>）、同機保留資源與優先權、分到不同主機、專用實體機，各層級隔離得了與隔離不了什麼，見 &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;h2 id="可觀察訊號與例子">可觀察訊號與例子&lt;/h2>
&lt;ul>
&lt;li>&lt;strong>全部服務同時變慢，各自的用量都不高&lt;/strong>：成因在它們共用的那一份資源上，而且可能落在監控所在層之外（虛擬機外的實體機或筆電），各層的監控看得到什麼見 &lt;a href="https://tarrragon.github.io/blog/backend/04-observability/host-traffic-resource-monitoring/" data-link-title="4.26 單機容器服務的流量與資源監控：各層的訊號、Prometheus 與 exporter、監控所在層的盲區" data-link-desc="健康檢查之外的流量與資源監控：入口、應用程式、容器、主機與資料庫等服務內部各層的訊號從哪裡收、用哪一個 exporter，Prometheus 加 exporter、單一 agent、開箱即用工具與臨時查看指令的取捨，單次取樣與時間窗的差別，監控裝在虛擬機裡時看不到主機的 CPU 負載、看到的磁碟要分清是哪一顆，以及每接上一個來源的驗收與偵測容器停止的寫法；cAdvisor 與 node_exporter 在 OrbStack 上實測過">4.26 單機容器服務的流量與資源監控&lt;/a>。一台 8 核心的 Mac 被其他程式吃到 &lt;a href="https://tarrragon.github.io/blog/backend/knowledge-cards/load-average/" data-link-title="Load Average（負載平均）" data-link-desc="看到 uptime 或 node_load1 的數字、要判斷主機是不是在排隊時，查 load average 算的是什麼、除以核心數怎麼讀、Linux 為什麼把等磁碟的行程也算進去，以及在虛擬機與容器裡量到的值代表誰">load average&lt;/a> 55 以上時，Docker 虛擬機裡的 load 除以核心數在 0.33 到 1.28 之間，而容器裡的服務全面變慢，資料庫一個平常一百多毫秒的查詢要 4 秒。這時各服務的延遲告警會一起發出，以主機飽和的告警收斂它們、以及這條規則在虛擬機裡判斷不到外部原因的條件，見 &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;/li>
&lt;li>&lt;strong>只在某些時段變慢&lt;/strong>：與同一台主機上的批次工作、備份或另一個租戶的尖峰重疊。&lt;/li>
&lt;li>&lt;strong>受影響的程度因服務而異&lt;/strong>：同一次過載，同樣的探測條件下（回應碼 200 且 500 ms 以內），Go 後端達標的比例是 92.5%、Laravel 後端是 49%，未達標的全是慢、沒有錯誤；對 CPU 被搶比較敏感的服務先變慢。&lt;/li>
&lt;/ul>
&lt;h2 id="設計責任">設計責任&lt;/h2>
&lt;p>部署時寫下哪些工作負載共用同一份資源、它們的尖峰會不會重疊，延遲敏感的服務與吃資源的批次工作至少用限制與權重分開，同一台主機上的容器之間用 &lt;a href="https://tarrragon.github.io/blog/backend/knowledge-cards/resource-limit/" data-link-title="Resource Limit" data-link-desc="說明服務可使用的 CPU、memory 與相關資源上限如何影響行為">Resource Limit&lt;/a> 把各自能用的量分開。壓測與效能比較的數字要附上當時共用資源的負載，否則不同時間量到的數字不能互相比較。&lt;/p></description><content:encoded><![CDATA[<p>Noisy neighbor 是多個工作負載共用同一份硬體資源時，其中一個用掉的資源從其他工作負載能用的那一份裡扣掉，使那些工作負載變慢或失敗的現象；被影響的一方沒有做錯任何事。本卡管的是硬體資源這一層，共用發生在幾個層：同一台主機上的多個容器（應用程式、資料庫、批次工作、監控）、同一台實體機上的多台虛擬機（雲端的其他租戶），以及開發用筆電上 Docker 的虛擬機與其他程式。它是 <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/bulkhead/" data-link-title="Bulkhead" data-link-desc="說明 bulkhead 如何用資源分艙限制故障擴散">Bulkhead</a> 與 <a href="/blog/backend/knowledge-cards/resource-limit/" data-link-title="Resource Limit" data-link-desc="說明服務可使用的 CPU、memory 與相關資源上限如何影響行為">Resource Limit</a>。同一個服務裡的多個租戶搶連線池、快取或佇列，是同一個現象在應用層的形態，隔離的做法見 Bulkhead。</p>
<h2 id="概念位置">概念位置</h2>
<table>
  <thead>
      <tr>
          <th>共用的層</th>
          <th>被搶走的資源</th>
          <th>從哪裡看得到</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>同一台主機的容器</td>
          <td>CPU、記憶體、磁碟讀寫、網路</td>
          <td>主機與每個容器的用量（node_exporter、cAdvisor），哪個容器在尖峰時用得最多</td>
      </tr>
      <tr>
          <td>同一台實體機的虛擬機</td>
          <td>CPU 時間、磁碟與網路頻寬</td>
          <td>Linux 虛擬機的 <a href="/blog/backend/knowledge-cards/cpu-steal-time/" data-link-title="CPU Steal Time（被虛擬化層拿走的 CPU 時間）" data-link-desc="雲端虛擬機的服務沒有改動、CPU 用量也不高卻變慢時，查 steal time 記的是什麼、怎麼從 node_exporter 算出比例、什麼環境量不到它，以及升高時的處置">steal 時間</a>（<code>node_cpu_seconds_total{mode=&quot;steal&quot;}</code>）</td>
      </tr>
      <tr>
          <td>開發用筆電上的虛擬機</td>
          <td>筆電的 CPU 與磁碟</td>
          <td>CPU 負載只有筆電本身看得到（<code>uptime</code>），筆電忙的時候虛擬機裡的 load 仍然很低；磁碟要看虛擬機有沒有掛進筆電的那一顆（OrbStack 以 virtiofs 掛入，node_exporter 看得到，剩餘比例正確而位元組數放大 256 倍）</td>
      </tr>
  </tbody>
</table>
<p>被干擾的服務自己的監控通常看不到成因：它的 CPU 用量低、錯誤少，只有延遲高，成因在它與其他工作負載共用的那一份資源上，而且常在監控所在層之外。隔離由淺到深是同機設上限與權重（<a href="/blog/backend/knowledge-cards/resource-limit/" data-link-title="Resource Limit" data-link-desc="說明服務可使用的 CPU、memory 與相關資源上限如何影響行為">Resource Limit</a>）、同機保留資源與優先權、分到不同主機、專用實體機，各層級隔離得了與隔離不了什麼，見 <a href="/blog/devops/operations/05-capacity-planning/shared-host-contention/" data-link-title="共用主機的資源競爭：容量估算、故障範圍、隔離層級與監控的位置" data-link-desc="多個服務、資料庫與監控放在同一台主機（或同一台實體機上的多台虛擬機）時，資源競爭在容量估算、故障範圍、隔離的做法與監控的位置上各自要考慮什麼：共用發生在哪些層、量到的數字什麼時候能互相比較、哪些服務適合放在一起、從同機加限制到專用實體機的隔離層級與各層的觸發條件">共用主機的資源競爭</a>〈隔離的層級與代價〉。</p>
<h2 id="可觀察訊號與例子">可觀察訊號與例子</h2>
<ul>
<li><strong>全部服務同時變慢，各自的用量都不高</strong>：成因在它們共用的那一份資源上，而且可能落在監控所在層之外（虛擬機外的實體機或筆電），各層的監控看得到什麼見 <a href="/blog/backend/04-observability/host-traffic-resource-monitoring/" data-link-title="4.26 單機容器服務的流量與資源監控：各層的訊號、Prometheus 與 exporter、監控所在層的盲區" data-link-desc="健康檢查之外的流量與資源監控：入口、應用程式、容器、主機與資料庫等服務內部各層的訊號從哪裡收、用哪一個 exporter，Prometheus 加 exporter、單一 agent、開箱即用工具與臨時查看指令的取捨，單次取樣與時間窗的差別，監控裝在虛擬機裡時看不到主機的 CPU 負載、看到的磁碟要分清是哪一顆，以及每接上一個來源的驗收與偵測容器停止的寫法；cAdvisor 與 node_exporter 在 OrbStack 上實測過">4.26 單機容器服務的流量與資源監控</a>。一台 8 核心的 Mac 被其他程式吃到 <a href="/blog/backend/knowledge-cards/load-average/" data-link-title="Load Average（負載平均）" data-link-desc="看到 uptime 或 node_load1 的數字、要判斷主機是不是在排隊時，查 load average 算的是什麼、除以核心數怎麼讀、Linux 為什麼把等磁碟的行程也算進去，以及在虛擬機與容器裡量到的值代表誰">load average</a> 55 以上時，Docker 虛擬機裡的 load 除以核心數在 0.33 到 1.28 之間，而容器裡的服務全面變慢，資料庫一個平常一百多毫秒的查詢要 4 秒。這時各服務的延遲告警會一起發出，以主機飽和的告警收斂它們、以及這條規則在虛擬機裡判斷不到外部原因的條件，見 <a href="/blog/backend/04-observability/host-overload-alerting/" data-link-title="4.27 主機過載時的監控告警：可用與變慢分開判斷、依原因抑制、監控自身的等待" data-link-desc="多個服務共用一台主機而主機過載時，各服務的探測與告警會一起失敗：可用性與延遲分成兩個判斷的寫法、間歇的條件怎麼持續成立、以主機飽和抑制各服務變慢的規則與它的取捨、以合成告警驗證抑制、抑制藏起各服務受影響程度的差別、探測與 Prometheus 自己也在等 CPU 時的訊號，以及讓監控不比服務先失效的資源隔離；以一次開發環境的過載為例">4.27 主機過載時的監控告警</a>。</li>
<li><strong>只在某些時段變慢</strong>：與同一台主機上的批次工作、備份或另一個租戶的尖峰重疊。</li>
<li><strong>受影響的程度因服務而異</strong>：同一次過載，同樣的探測條件下（回應碼 200 且 500 ms 以內），Go 後端達標的比例是 92.5%、Laravel 後端是 49%，未達標的全是慢、沒有錯誤；對 CPU 被搶比較敏感的服務先變慢。</li>
</ul>
<h2 id="設計責任">設計責任</h2>
<p>部署時寫下哪些工作負載共用同一份資源、它們的尖峰會不會重疊，延遲敏感的服務與吃資源的批次工作至少用限制與權重分開，同一台主機上的容器之間用 <a href="/blog/backend/knowledge-cards/resource-limit/" data-link-title="Resource Limit" data-link-desc="說明服務可使用的 CPU、memory 與相關資源上限如何影響行為">Resource Limit</a> 把各自能用的量分開。壓測與效能比較的數字要附上當時共用資源的負載，否則不同時間量到的數字不能互相比較。</p>
]]></content:encoded></item></channel></rss>