<?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>Scale-Down on Tarragon</title><link>https://tarrragon.github.io/blog/tags/scale-down/</link><description>Recent content in Scale-Down on Tarragon</description><generator>Hugo -- gohugo.io</generator><language>zh-TW</language><copyright>Tarragon (CC BY 4.0)</copyright><lastBuildDate>Fri, 03 Jul 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://tarrragon.github.io/blog/tags/scale-down/index.xml" rel="self" type="application/rss+xml"/><item><title>擴展的觸發與縮回</title><link>https://tarrragon.github.io/blog/devops/02-horizontal-scaling/scaling-triggers/</link><pubDate>Fri, 03 Jul 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/devops/02-horizontal-scaling/scaling-triggers/</guid><description>&lt;p>擴展的觸發與縮回，一個決定何時加實例、一個決定何時減實例，兩者的難度不對稱。擴容相對簡單——加一台機器、等它就緒、開始分流。縮回難得多，因為減一台實例前，要先把它身上的流量與在途工作安全移走，硬砍會中斷正在處理的請求。這一章講擴縮這個閉環，重點放在縮回這個常被忽略、也更容易出事的方向。什麼訊號代表系統飽和、該不該擴，是 &lt;a href="https://tarrragon.github.io/blog/devops/05-capacity-planning/scaling-inflection-point/" data-link-title="規模拐點判斷" data-link-desc="判斷什麼訊號代表該擴容、什麼代表可縮容、以及該往垂直還水平擴時，用飽和曲線的三段區間、膝點的早期訊號與 ramp-up 方法回來讀">規模拐點判斷&lt;/a> 的主題，這裡承接的是「確認要擴之後，這個擴縮怎麼運作」。&lt;/p>
&lt;h2 id="擴展前先窮盡低成本手段">擴展前先窮盡低成本手段&lt;/h2>
&lt;p>加實例是有成本的手段，不該是遇到壓力的第一反應。一個健康的擴展決策，會先窮盡零成本或低成本的手段，確認真的不夠了才擴機。以讀取變慢為例，加副本或加機器之前，先做過補索引、讓儀表板改讀預聚合的摘要表、把降採樣 job 調到避開高峰時段——這些預聚合類的手段常常是「加機器前」最有效的降載，做完可能就不需要擴了。擴展的觸發原則是按觀察到的真實瓶頸行動、不按預測搶跑，且在擴機之前先把便宜的優化用盡。&lt;/p>
&lt;h2 id="觸發訊號分層各層對應不同動作">觸發訊號分層，各層對應不同動作&lt;/h2>
&lt;p>擴展的觸發不是單一訊號、單一動作，成熟的系統分層應對。本站 collector 的 ingestion 就分四層防線，每層有各自的觸發條件與動作：源頭的 SDK 在超過粒度時自動降取樣、單機的背壓與限流在寫入接近滿載時擋、水平擴展在單機 CPU 或連線飽和時加實例、佇列解耦在突發流量超過整個 collector 群的即時處理能力時插入緩衝。訊號從源頭到基礎設施逐層升級，先用便宜的層擋，擋不住才動到貴的層。&lt;/p>
&lt;p>共享儲存的擴展也有量化的觸發訊號。collector 的 SQLite 後端撞到「&lt;code>database is locked&lt;/code> 每分鐘出現一次以上」或「聚合查詢超過 3 秒」，就是該換 PostgreSQL 的訊號；PostgreSQL 撐到每秒數萬筆持續寫入或需要自動降採樣，就是該換時間序列資料庫的訊號。這些訊號的共通原則還是那條：按觀察到的瓶頸切換，不按預測提前重構。&lt;/p>
&lt;h2 id="縮回要先-drain不能硬砍">縮回要先 drain，不能硬砍&lt;/h2>
&lt;p>縮回的核心難點是實例身上還有活。減一台實例前，要走跟關閉服務同一套收束流程：先把它從負載平衡的目標裡摘掉（停止送新流量）、等它手上的在途請求處理完、再真正終止。這跟 &lt;a href="https://tarrragon.github.io/blog/devops/04-service-health/graceful-shutdown/" data-link-title="Graceful shutdown" data-link-desc="設計服務收到停止信號後的收束流程時，釐清 SIGTERM 到 SIGKILL 的 grace period、退場的固定順序、以及不同 workload 的 drain 窗口要留多長">模組四 graceful shutdown&lt;/a> 是同一套機制——縮容其實就是一次有計畫的實例退場，退場的固定順序（摘流量、drain、終止）在那裡展開。硬砍一台正在處理請求的實例，那些請求全部中斷，用戶端看到的就是一批莫名其妙的失敗。&lt;/p>
&lt;p>縮回還有兩個容易出事的地方。一是縮太快造成容量不足——流量剛回落就急著縮，結果下一波又上來、新實例還沒起好。二是縮縮擴擴的抖動，訊號在門檻上下跳、實例反覆增減，這靠冷卻時間（cool-down）壓住：擴或縮之後強制等一段時間再判斷，不讓它對每個瞬間波動都反應。擴縮該選哪個訊號、冷卻時間怎麼配，在 &lt;a href="https://tarrragon.github.io/blog/devops/05-capacity-planning/scaling-inflection-point/" data-link-title="規模拐點判斷" data-link-desc="判斷什麼訊號代表該擴容、什麼代表可縮容、以及該往垂直還水平擴時，用飽和曲線的三段區間、膝點的早期訊號與 ramp-up 方法回來讀">規模拐點判斷&lt;/a> 的擴縮訊號段有完整對照。&lt;/p>
&lt;p>有一種源頭的縮回不靠減實例，而靠降載。collector 的背壓 buffer 滿了就回 429 加一個 &lt;code>Retry-After&lt;/code>，SDK 收到 429 自動把取樣率從 1.0 降到 0.5、再降到 0.1；等連續成功幾十次，再逐步回升到 1.0。這是一個閉環的自動降載與恢復——不加機器、直接在源頭把進來的量壓下去，撐過尖峰再放回來。對短暫的高峰，這種源頭降載比擴實例划算得多。&lt;/p>
&lt;h2 id="該擴還是該解耦">該擴、還是該解耦&lt;/h2>
&lt;p>擴展到某個點會遇到一個判斷：繼續加實例、還是改變架構。當 collector 群已經水平擴展、仍無法即時消化突發流量時，繼續加實例的邊際效益在下降，這時該考慮插入一個佇列解耦——collector 簡化成「接收、驗證、寫進佇列、回 202」，後面的 worker 按自己的速度消化積壓，把「即時處理」換成「保證不丟、慢慢處理」。但這個決策有反向的一面：如果只是短暫的高峰，佇列的維護成本可能高於它的收益，這時回到源頭用動態取樣降量更划算。佇列解耦的完整設計在 &lt;a href="https://tarrragon.github.io/blog/devops/07-burst-traffic/" data-link-title="模組七：突發流量應對" data-link-desc="行銷活動或新聞曝光帶來 10x-100x 流量時怎麼撐 — 突發分類、降級策略、queue 緩衝、規模分級應對">模組七 突發流量&lt;/a> 展開，這裡的判斷點是：加實例、源頭降載、佇列解耦是三個不同成本的選項，按尖峰是短暫還是持續來選。&lt;/p>
&lt;h2 id="下一步路由">下一步路由&lt;/h2>
&lt;ul>
&lt;li>什麼訊號代表系統進入飽和、該擴容 → &lt;a href="https://tarrragon.github.io/blog/devops/05-capacity-planning/scaling-inflection-point/" data-link-title="規模拐點判斷" data-link-desc="判斷什麼訊號代表該擴容、什麼代表可縮容、以及該往垂直還水平擴時，用飽和曲線的三段區間、膝點的早期訊號與 ramp-up 方法回來讀">規模拐點判斷&lt;/a>&lt;/li>
&lt;li>縮回的實例退場順序、drain 怎麼做 → &lt;a href="https://tarrragon.github.io/blog/devops/04-service-health/graceful-shutdown/" data-link-title="Graceful shutdown" data-link-desc="設計服務收到停止信號後的收束流程時，釐清 SIGTERM 到 SIGKILL 的 grace period、退場的固定順序、以及不同 workload 的 drain 窗口要留多長">模組四 Graceful shutdown&lt;/a>&lt;/li>
&lt;li>佇列解耦怎麼接、突發流量的完整應對 → &lt;a href="https://tarrragon.github.io/blog/devops/07-burst-traffic/" data-link-title="模組七：突發流量應對" data-link-desc="行銷活動或新聞曝光帶來 10x-100x 流量時怎麼撐 — 突發分類、降級策略、queue 緩衝、規模分級應對">模組七 突發流量&lt;/a>&lt;/li>
&lt;li>垂直還是水平——擴的方向怎麼選 → &lt;a href="https://tarrragon.github.io/blog/devops/02-horizontal-scaling/vertical-vs-horizontal/" data-link-title="垂直與水平擴展的判斷" data-link-desc="決定該加 CPU 還是加實例時，用「這個元件能不能做成無狀態」當判斷樞紐，並知道有狀態的節點該用垂直撐、讀路徑用副本擴、撐不住才分片">垂直與水平擴展的判斷&lt;/a>&lt;/li>
&lt;/ul></description><content:encoded><![CDATA[<p>擴展的觸發與縮回，一個決定何時加實例、一個決定何時減實例，兩者的難度不對稱。擴容相對簡單——加一台機器、等它就緒、開始分流。縮回難得多，因為減一台實例前，要先把它身上的流量與在途工作安全移走，硬砍會中斷正在處理的請求。這一章講擴縮這個閉環，重點放在縮回這個常被忽略、也更容易出事的方向。什麼訊號代表系統飽和、該不該擴，是 <a href="/blog/devops/05-capacity-planning/scaling-inflection-point/" data-link-title="規模拐點判斷" data-link-desc="判斷什麼訊號代表該擴容、什麼代表可縮容、以及該往垂直還水平擴時，用飽和曲線的三段區間、膝點的早期訊號與 ramp-up 方法回來讀">規模拐點判斷</a> 的主題，這裡承接的是「確認要擴之後，這個擴縮怎麼運作」。</p>
<h2 id="擴展前先窮盡低成本手段">擴展前先窮盡低成本手段</h2>
<p>加實例是有成本的手段，不該是遇到壓力的第一反應。一個健康的擴展決策，會先窮盡零成本或低成本的手段，確認真的不夠了才擴機。以讀取變慢為例，加副本或加機器之前，先做過補索引、讓儀表板改讀預聚合的摘要表、把降採樣 job 調到避開高峰時段——這些預聚合類的手段常常是「加機器前」最有效的降載，做完可能就不需要擴了。擴展的觸發原則是按觀察到的真實瓶頸行動、不按預測搶跑，且在擴機之前先把便宜的優化用盡。</p>
<h2 id="觸發訊號分層各層對應不同動作">觸發訊號分層，各層對應不同動作</h2>
<p>擴展的觸發不是單一訊號、單一動作，成熟的系統分層應對。本站 collector 的 ingestion 就分四層防線，每層有各自的觸發條件與動作：源頭的 SDK 在超過粒度時自動降取樣、單機的背壓與限流在寫入接近滿載時擋、水平擴展在單機 CPU 或連線飽和時加實例、佇列解耦在突發流量超過整個 collector 群的即時處理能力時插入緩衝。訊號從源頭到基礎設施逐層升級，先用便宜的層擋，擋不住才動到貴的層。</p>
<p>共享儲存的擴展也有量化的觸發訊號。collector 的 SQLite 後端撞到「<code>database is locked</code> 每分鐘出現一次以上」或「聚合查詢超過 3 秒」，就是該換 PostgreSQL 的訊號；PostgreSQL 撐到每秒數萬筆持續寫入或需要自動降採樣，就是該換時間序列資料庫的訊號。這些訊號的共通原則還是那條：按觀察到的瓶頸切換，不按預測提前重構。</p>
<h2 id="縮回要先-drain不能硬砍">縮回要先 drain，不能硬砍</h2>
<p>縮回的核心難點是實例身上還有活。減一台實例前，要走跟關閉服務同一套收束流程：先把它從負載平衡的目標裡摘掉（停止送新流量）、等它手上的在途請求處理完、再真正終止。這跟 <a href="/blog/devops/04-service-health/graceful-shutdown/" data-link-title="Graceful shutdown" data-link-desc="設計服務收到停止信號後的收束流程時，釐清 SIGTERM 到 SIGKILL 的 grace period、退場的固定順序、以及不同 workload 的 drain 窗口要留多長">模組四 graceful shutdown</a> 是同一套機制——縮容其實就是一次有計畫的實例退場，退場的固定順序（摘流量、drain、終止）在那裡展開。硬砍一台正在處理請求的實例，那些請求全部中斷，用戶端看到的就是一批莫名其妙的失敗。</p>
<p>縮回還有兩個容易出事的地方。一是縮太快造成容量不足——流量剛回落就急著縮，結果下一波又上來、新實例還沒起好。二是縮縮擴擴的抖動，訊號在門檻上下跳、實例反覆增減，這靠冷卻時間（cool-down）壓住：擴或縮之後強制等一段時間再判斷，不讓它對每個瞬間波動都反應。擴縮該選哪個訊號、冷卻時間怎麼配，在 <a href="/blog/devops/05-capacity-planning/scaling-inflection-point/" data-link-title="規模拐點判斷" data-link-desc="判斷什麼訊號代表該擴容、什麼代表可縮容、以及該往垂直還水平擴時，用飽和曲線的三段區間、膝點的早期訊號與 ramp-up 方法回來讀">規模拐點判斷</a> 的擴縮訊號段有完整對照。</p>
<p>有一種源頭的縮回不靠減實例，而靠降載。collector 的背壓 buffer 滿了就回 429 加一個 <code>Retry-After</code>，SDK 收到 429 自動把取樣率從 1.0 降到 0.5、再降到 0.1；等連續成功幾十次，再逐步回升到 1.0。這是一個閉環的自動降載與恢復——不加機器、直接在源頭把進來的量壓下去，撐過尖峰再放回來。對短暫的高峰，這種源頭降載比擴實例划算得多。</p>
<h2 id="該擴還是該解耦">該擴、還是該解耦</h2>
<p>擴展到某個點會遇到一個判斷：繼續加實例、還是改變架構。當 collector 群已經水平擴展、仍無法即時消化突發流量時，繼續加實例的邊際效益在下降，這時該考慮插入一個佇列解耦——collector 簡化成「接收、驗證、寫進佇列、回 202」，後面的 worker 按自己的速度消化積壓，把「即時處理」換成「保證不丟、慢慢處理」。但這個決策有反向的一面：如果只是短暫的高峰，佇列的維護成本可能高於它的收益，這時回到源頭用動態取樣降量更划算。佇列解耦的完整設計在 <a href="/blog/devops/07-burst-traffic/" data-link-title="模組七：突發流量應對" data-link-desc="行銷活動或新聞曝光帶來 10x-100x 流量時怎麼撐 — 突發分類、降級策略、queue 緩衝、規模分級應對">模組七 突發流量</a> 展開，這裡的判斷點是：加實例、源頭降載、佇列解耦是三個不同成本的選項，按尖峰是短暫還是持續來選。</p>
<h2 id="下一步路由">下一步路由</h2>
<ul>
<li>什麼訊號代表系統進入飽和、該擴容 → <a href="/blog/devops/05-capacity-planning/scaling-inflection-point/" data-link-title="規模拐點判斷" data-link-desc="判斷什麼訊號代表該擴容、什麼代表可縮容、以及該往垂直還水平擴時，用飽和曲線的三段區間、膝點的早期訊號與 ramp-up 方法回來讀">規模拐點判斷</a></li>
<li>縮回的實例退場順序、drain 怎麼做 → <a href="/blog/devops/04-service-health/graceful-shutdown/" data-link-title="Graceful shutdown" data-link-desc="設計服務收到停止信號後的收束流程時，釐清 SIGTERM 到 SIGKILL 的 grace period、退場的固定順序、以及不同 workload 的 drain 窗口要留多長">模組四 Graceful shutdown</a></li>
<li>佇列解耦怎麼接、突發流量的完整應對 → <a href="/blog/devops/07-burst-traffic/" data-link-title="模組七：突發流量應對" data-link-desc="行銷活動或新聞曝光帶來 10x-100x 流量時怎麼撐 — 突發分類、降級策略、queue 緩衝、規模分級應對">模組七 突發流量</a></li>
<li>垂直還是水平——擴的方向怎麼選 → <a href="/blog/devops/02-horizontal-scaling/vertical-vs-horizontal/" data-link-title="垂直與水平擴展的判斷" data-link-desc="決定該加 CPU 還是加實例時，用「這個元件能不能做成無狀態」當判斷樞紐，並知道有狀態的節點該用垂直撐、讀路徑用副本擴、撐不住才分片">垂直與水平擴展的判斷</a></li>
</ul>
]]></content:encoded></item></channel></rss>