vatt'ghern jaskier's ballads
本文 2 個互動圖表在手機上以重點摘要呈現,互動版請以桌面瀏覽器開啟。

多數自動擴縮只有一顆旋鈕:想守住 SLO 就多開機器、想省錢就少開,兩端永遠在拔河。Spandana 的做法是把它拆成兩顆——一顆掛在每台 VM 上、每個 request 都在動,只管死線;另一顆慢慢動,只管帳單。

SLO 死線攻防和省錢分開做——Spandana 怎麼讓雲端服務兩者不互相牽制

Spandana 是一篇雲端系統論文,處理一個運維每天在對付的矛盾:線上服務的流量在 sub-second 尺度上劇烈抖動,服務又被 strict SLO 綁著,於是最省事的保命做法就是多開機器、留一大塊 idle headroom 去吸收尖峰——SLO 是守住了,利用率跟帳單一起難看。論文摘要把主張講得很直接:既有的做法「fail to reconcile strict SLO compliance with low cost and high utilization under fine-grained load fluctuation」,而 Spandana「addresses this trade off by decoupling SLO enforcement from cost optimization」。翻成工程語言就是:不要讓「守 SLO」跟「省錢」搶同一份資源預算,把兩者拆成兩個獨立的控制問題,各自用最合適的時間尺度去解。

先把最反直覺的一個數字擺出來:76-86% 的 CPU 利用率。對一台跑批次、不在乎延遲的機器,這不稀奇;但這是一個被 strict SLO 綁著的線上服務的利用率。守延遲的服務為了留尖峰餘裕,利用率常年壓在很低的水位,看到七、八成還能守住 SLO,第一反應會是「這哪守得住」。整篇論文就是在回答這個「怎麼可能」——答案不在把某個元件調快,而在把守 SLO 這件事整個搬到另一個迴路去做。

下面這個互動小工具先把整個張力擺上檯面。橫軸是時間、縱軸是每秒進來的 request;那條會抖動的曲線是刻意合成的 sub-second 負載,不是論文的實測 trace。你能拖的只有一個變數——VM pool 的容量天花板。天花板以下的請求由 VM 服務(利用率),冒出天花板的那截被 controller 轉去 FaaS(溢位)。把天花板壓低,利用率逼近滿載,但溢位變多;拉高則相反。整篇論文就是在這條曲線上找兩個答案:每個瞬間該把哪些 request 推去 FaaS,以及天花板長期該定在哪。

平均負載·/s
VM 利用率·%
溢位到 FaaS·%
合成的 sub-second 負載曲線;綠色是留在 VM 服務的量、赭色是冒出天花板被轉去 FaaS 的溢位。拖 C 把天花板上下移,讀 VM 利用率與溢位比例如何此消彼長——這正是快環(每個 request)與慢環(定天花板)分別要回答的問題。

合成的 sub-second 負載曲線;綠色是留在 VM 服務的量、赭色是冒出天花板被轉去 FaaS 的溢位

把 VM 容量天花板壓低,利用率逼近滿載但溢位到 FaaS 的請求變多;拉高則利用率掉、溢位少。守 SLO 靠 FaaS 吸走尖峰,省錢靠把天花板壓到剛好。

死線與帳單為什麼會共用一顆旋鈕

先講清楚為什麼這兩件事在傳統架構裡會綁在一起。摘要把既有做法歸成三類——reactive 與 proactive 的 autoscaler、純 serverless(FaaS)佈署、以及 VM/FaaS 的 hybrid 系統——並直接下判斷:它們在細粒度負載波動下,無法同時滿足嚴格 SLO、低成本與高利用率。三類各有各的破法。Reactive autoscaler 是看到負載升高才加機器,但以雲端常見的量級來說,開一台 VM 到 ready 動輒數十秒,等新機器起來,那個 sub-second 的尖峰早就過去、SLO 也早就破了。Proactive 靠預測,但細粒度的爆量本來就難預測準,猜低了破 SLO、猜高了又回到 over-provision。純 FaaS 把每個 request 都丟 serverless,彈性是有了,代價通常是每次呼叫都吃 per-invocation 溢價,還有 cold-start 帶來的延遲抖動,穩態流量用這種方式跑,帳單很難看。Hybrid 想兼顧,但多半仍把「守 SLO」與「省錢」綁在同一個 provisioning 決策上。

這幾種破法其實共享同一個病根,用控制的語言最好講:任何回饋控制迴路都有自己的反應週期,而它能壓下的擾動頻率上限,就卡在這個週期上。autoscaler 的迴路週期是「偵測到負載變化、做決策、把新 VM 開起來」,這一整段以前面提到的常見量級來說動輒數十秒;sub-second 的負載尖峰頻率遠高於這個上限,等於擾動比控制器快一個數量級,迴路根本追不上,只能在事後才反應。這不是把演算法調聰明就能解的,它是取樣定理等級的限制。想在這個頻段守住 SLO,唯一的路是有一個反應週期短到跟 request 同級的機制——這正是 Spandana 快環存在的理由。

還有一層物理逼著大家 over-provision:飽和點附近的延遲不是線性上升,而是急遽發散。利用率往 100% 逼近時,佇列等待時間往上翹成近乎垂直的一條曲線,最後那幾個百分點的利用率,要用暴增的尾延遲去換。守 SLO 的服務因此不敢把利用率推高,只能遠遠留一大塊 headroom,那塊 headroom 就是帳單上那條看不見的稅。Spandana 要拆的,正是這條「高利用率必然高尾延遲」的預設綁定。

VM 利用率 低 → → 高(逼近飽和) 相對 尾延遲 76-86% Spandana VM 利用率 佇列尾延遲發散 利用率 81% 相對尾延遲 ≈ 5.3×
單台 VM 佇列的示意曲線(非實測):利用率往飽和逼近時,尾延遲不是線性上升而是急遽發散——這正是守延遲服務不敢把利用率推高、只好 over-provision 的物理原因。赭色是 Spandana 實測的 76-86% 利用率區間;它敢站在這麼靠右的位置,是因為快環把會 miss SLO 的 overflow 轉去了 FaaS,尾延遲不必真的爬上去。拖曳赭點沿利用率軸移動,讀相對尾延遲怎麼隨飽和急升。

綁在一起的後果,就是那顆共用的旋鈕:把資源預算調大,尖峰有 headroom、SLO 守得住,但平時利用率低、錢燒掉;調小,帳單漂亮,但一遇尖峰就排隊、延遲爆掉、SLO 破。摘要用的字是「over-provision resources to protect SLOs, sacrificing utilization and cost efficiency」——保命的代價寫在利用率上。Spandana 認定這是一個 trade-off 而非物理定律,於是動手把旋鈕拆成兩顆。下面這張圖把「拆前」與「拆後」的資源長相並排——拖中間那條分隔線,左邊是 over-provision 的做法、右邊是 Spandana。

over-provision 三台 VM 大半閒置 Spandana 兩台 VM 壓高利用率 赭色=FaaS overflow band
示意圖:左邊 over-provision 用三台大半閒置的 VM 留 headroom 保 SLO;右邊 Spandana 用更少、卻壓到高利用率的 VM,尖峰交給頂上那條薄 FaaS overflow band。省下的成本,就是左圖那些空白格子。

示意圖:左邊 over-provision 用三台大半閒置的 VM 留 headroom 保 SLO;右邊 Spand…

傳統做法多開 VM 吸尖峰、利用率低;Spandana 把 VM 壓到高利用率,用薄薄的 FaaS overflow 兜尖峰。

快環——每台 VM 上的 per-request steering

拆出來的第一顆旋鈕,是負責守 SLO 的快環。摘要的描述很精確:「A lightweight controller colocated with each application VM enforces SLOs by steering each arriving request between the VM and FaaS.」三個字要圈起來。一是 colocated——controller 就跟 application 一起跑在同一台 VM 上,不是遠端一個中央排程器;決策在 request 自己的路徑上當場做,省掉一趟往返,因為那趟 round-trip 本身就會咬掉延遲預算。二是 each arriving request——決策粒度細到每一個進來的請求,這才對得上 sub-second 的抖動節奏。三是 lightweight——正因為它掛在每個 request 的熱路徑上,判斷必須夠便宜,重一點就變成新的延遲來源。

值得跟傳統 load balancer 分清楚:LB 是把 request 攤到多台同構的 VM 上,本質仍在同一個 VM 資源池裡分配;controller 的 steering 不是分配,而是替 overflow 換一種計算基座——留 VM 是一條路徑,轉 FaaS 是另一條彈性完全不同的路徑。整池 VM 都飽和時,LB 只能讓大家一起排隊;steering 在那一刻還有 FaaS 這條逃生門。差別就在,LB 的答案空間只有那幾台機器,controller 的答案空間多了一整個可即時擴張的 serverless 層。

還有一個常被忽略的點:controller 必須真的坐在 request 的資料路徑上,而不是一個在旁邊非同步觀察、事後才決定的 sidecar。因為 steering 的決定要在這個 request 被服務之前就下——留 VM 還是轉 FaaS,決定完才有地方送它。放旁邊事後算,等於決定慢了半拍,這半拍在 sub-second 的預算裡就是破 SLO 的距離。這也回頭解釋了為什麼它必須 lightweight:坐在資料路徑上的東西,每多花一微秒都直接記在每個 request 的延遲帳上。

steering 的規則本身是條件式的:「Requests that can meet the SLO stay on the VM; the remaining requests are forwarded to a stock FaaS layer such as AWS Lambda.」能在 SLO 內於 VM 完成的請求留下,接不住的那截轉去現成的 FaaS。這裡的關鍵不是「多開一台 VM」而是「換一條計算路徑」——當 VM 快滿、再收一個 request 就會排隊、排隊就會破延遲時,controller 不讓它排隊,直接把它送去彈性的 FaaS。排隊是延遲爆炸的引信,快環等於把引信拆掉:尖峰的 request 不在飽和的 VM 上等,而是瞬間流向可即時擴張的 serverless。SLO 因此在尖峰不破——這是快環唯一的職責,它完全不管成本。下面把兩顆旋鈕、三個角色攤開看。

Spandana 的兩個迴路、三個角色

Spandana——SLO 交給快環、成本交給慢環 快環 · per-VM controller colocated 在每台 VM;對 each arriving request steering:能守 SLO 留 VM,其餘轉 FaaS per-request FaaS overflow · stock AWS Lambda 彈性、按次計費的溢位水槽;只吃會 miss SLO 的那部分 overflow,不是全部流量 elastic 慢環 · resource allocator 計入 VM cost、FaaS cost、traffic volatility,定最省的 VM pool 尺寸,把 VM 推到高利用率 cost

click a role above

快環 · 職責邊界

能在 SLO 內於 VM 完成的 request 留下,其餘 forward 到 stock FaaS。決策在 request 自己的路徑上做、不繞中央排程器——那趟 round-trip 本身就會吃掉延遲預算。它只保證 SLO,完全不看帳單。時間尺度:每一個 request。

FaaS overflow · 職責邊界

彈性、瞬間可擴、按次計費,所以單位成本比穩態 VM 貴。它只吃「會 miss SLO 的那部分 overflow」而非全部流量;用現成 Lambda 代表不必自建 serverless infra,靠 commodity 就能兜底。

慢環 · 職責邊界

因為快環已用 FaaS 保證了 SLO,這層可以放手把 VM pool 推到高利用率、只追成本。它權衡 VM cost、FaaS cost 與 traffic volatility,算出最省的 provisioning。時間尺度:遠慢於 per-request。

有一個摘要沒有攤開的環節值得標記成推測:controller 到底怎麼判斷一個進來的 request「能不能在 VM 內守住 SLO」。摘要只寫了判斷的結果(能守住就留、否則轉走),沒寫判準。照這類系統的常見做法合理推想,這個判斷得靠一個便宜的本地估計——當下 VM 的佇列深度或負載、對照這個 request 還剩多少延遲預算——夠得上就留、來不及就轉。這個估計必須夠準又夠快:估得太保守會把太多本來 VM 接得住的量推去付 FaaS 溢價,估得太樂觀又會讓某些 request 排進飽和的 VM、破了 SLO。這一格屬於全文才有的機制細節,這裡只當推斷點出,不當摘要的斷言。

慢環——resource allocator 怎麼把 VM pool 調到最省

第二顆旋鈕負責省錢,而且擺明了跟第一顆用完全不同的節奏動。摘要說:「Spandana's resource allocator determines the most-efficient VM provisioning by accounting for VM cost, FaaS cost, and traffic volatility, allowing the VM pool to run at high utilization.」拆開來看它在權衡什麼。VM pool 開大,穩態計算便宜、溢位少,但養一堆機器的 VM cost 高;VM pool 縮小,養機器省了,但更多 request 冒出天花板、FaaS 帳單漲上來。這兩條成本一升一降,中間有一個總成本最低的甜蜜點,allocator 要找的就是它。traffic volatility 之所以進成本函式,是因為流量越爆、同樣的 pool 尺寸溢位越兇——波動性把甜蜜點往某一邊推。回到最上面那個互動工具:你拖 C 的時候,利用率與溢位比例的此消彼長,就是 allocator 在成本空間裡走的那條線。

真正優雅的地方在於「為什麼慢環可以慢」。它不需要對每個 request 反應,因為快環已經用 FaaS 兜底、把 SLO 這條硬約束扛住了。allocator 於是被解放出來,可以心無旁騖地把 VM 利用率往上推、只追成本,而不必擔心「推太高、尖峰一來就破 SLO」——那個風險已經被快環接走了。這就是 decoupling 的收穫:兩件事本來共用一顆旋鈕,是因為誰都不敢完全放掉 SLO 的保險;當快環把保險獨立扛下,慢環才敢把利用率的旋鈕轉到底。一個守約束、一個追目標,職責一分開,兩邊都能走到各自的極端而不互相牽制。

這個結構在控制工程裡有現成的名字:cascaded control(串級控制)。內迴路跑得快、負責即時排除擾動,外迴路跑得慢、負責把內迴路的 setpoint 調到最優。Spandana 幾乎是把這個範式搬到雲端資源上:快環是內迴路,用 FaaS 即時吸收負載擾動、把 SLO 這個受控量穩住;慢環是外迴路,慢慢把 VM pool 這個 setpoint 挪到成本最低處。串級控制之所以有效,關鍵就在兩個迴路的頻寬要分開——內快外慢、彼此不打架。Spandana 的 decouple 讀起來抽象,落到控制上其實是很經典的一招。

traffic volatility 這一項為什麼非進成本函式不可,值得單獨想。兩個服務就算平均流量一模一樣,波動大的那個在任何固定 VM pool 尺寸下都會溢位更多——因為溢位取決於尖峰有多高,而不是平均有多高。於是波動性直接搬動甜蜜點:越是尖銳爆量的流量,越划算把 pool 定小一點、讓更多量走 FaaS,因為為那些偶發尖峰常備 VM 太貴;越是平穩的流量,越該把量留在 VM。allocator 把波動性納進來,等於承認「拿平均值定價」會系統性地看錯這件事。

FaaS overflow 的代價——為什麼不乾脆全丟 FaaS

既然 FaaS 這麼好用、彈性又即時,為什麼不把所有流量都丟過去、VM 全部關掉?這正是摘要點名會敗下陣的「純 FaaS」路線。FaaS 的彈性不是免費的——它按次計費,單位成本比一台跑在穩態、利用率被壓高的 VM 貴;而且以 serverless 常見的行為來說,每次 invocation 都可能碰上 cold start,延遲的尾巴比常駐 VM 抖。把穩態那塊本來可以便宜跑的流量也丟 FaaS,等於用尖峰的價格買了平時的量,帳單自然難看。反過來,全留 VM 就是 over-provision,回到利用率低落的老問題。

Spandana 的位置刻意卡在兩個極端中間:穩態的、量大又可預期的那塊基載,留在高利用率的 VM 上便宜地跑;只有「冒出天花板、留在 VM 就會 miss SLO」的那截 overflow,才付 FaaS 的溢價去買即時彈性。摘要的「requests that can meet the SLO stay on the VM」講的就是這個分界。至於這條天花板該定多高、也就是願意把多少量推去付 FaaS 溢價、又保留多少量在 VM,正是慢環那個成本函式的輸出:當「再開一台 VM 的邊際成本」開始高於「把對應那截 overflow 丟 FaaS 的邊際成本」,就不值得再加 VM。還有一個容易被略過的工程紅利——摘要寫的是「a stock FaaS layer such as AWS Lambda」,用的是現成、commodity 的 serverless,不是自研的特製擴張層。這代表這套架構的溢位路徑靠公有雲既有的 Lambda 就能搭,導入門檻低得多。

把成本攤開看,更清楚 FaaS 為什麼只能當救火隊而非常駐。穩態那塊量大又可預期,用一台跑滿的 VM 分攤下來,每個 request 很便宜;同樣的量丟 FaaS,每一個都獨立計費、還可能各自吃一次 cold start,等於用零售價買批發量。反過來,尖峰那塊量少、來得又急又不可預期,為它常備 VM 就得長期養一堆閒置機器;這塊改用 FaaS,貴的是單價、省的是「不必為極少數尖峰時刻長期買單」。兩邊的交叉點——某截 overflow 到底該加一台 VM 還是丟 FaaS——正是慢環那個成本函式在解的東西。

76-86% 與 5-44% 到底說了什麼

論文用一句話報結果:「Spandana maintains strict SLO adherence, achieves 76-86% CPU utilization, and reduces cost by 5-44% over three SOTA baselines.」三個數字要分開讀,別糊在一起。先看 76-86% 的 CPU 利用率——對一個被延遲 SLO 綁住的服務,這是相當高的數字;這類服務為了留尖峰 headroom,利用率常被壓得低很多。它是一個區間,跨不同設定或 workload 落在 76% 到 86% 之間,而不是單一數字。再看 5-44% 的省成本,這個區間拉得很開,本身就是最誠實的訊號:對某些 baseline 或某些 workload 只省 5%,對另一些能省到 44%——省多省少高度取決於比的是誰、跑的是什麼流量。摘要沒有給平均值,也沒有在這句話裡點名那三個 SOTA baseline 或用的 workload,我就不替它編。

真正扛住整篇論證的,是三個數字前面那半句:strict SLO adherence。利用率衝到 76-86%、成本降 5-44%,都是在「SLO 嚴格守住」的前提下拿到的——重點從頭到尾不是拿 SLO 換成本,而是證明拆開之後兩者可以不再互斥。這也是為什麼摘要把 Spandana 定位成「decoupling SLO enforcement from cost optimization」而不是又一個更聰明的 autoscaler:它換的不是調參的手法,而是把問題本身切成兩塊的架構。至於快環確切的 admission 判準、慢環用什麼求解、對比的三個 baseline 是誰、跑的是哪些 trace——這些屬於全文的評測細節,摘要沒有攤開,本文也就守在摘要這個粒度上,不做超出證據的斷言。

一條 5% 到 44% 的區間,比一個漂亮的平均數誠實得多。它老實說出這類系統的真相:省多少,強烈依賴你原本用的是哪套 baseline、跑的是什麼形狀的流量。流量越尖、波動越大,over-provision 的浪費越兇,Spandana 能砍掉的空白就越多,數字自然靠近 44%;本來就平穩的服務,既有做法沒浪費多少,能省的空間也就窄,落在 5% 那一頭。看到寬區間別急著取中間值當代表,該問的是「我的 workload 長得像哪一端」。

數字直接取自摘要那一句評測結論;「意義」欄是把它讀精確,不是新增材料。
量測項Spandana 的數字精確意義
CPU 利用率76-86%嚴格守 SLO 的前提下,VM pool 實際被用掉的比例;是跨設定的區間,對延遲服務算高。
成本↓ 5-44%相對三個 SOTA baseline 的降幅;區間拉很開,代表省多少高度取決於比的對象與 workload。
SLOstrict adherence利用率與省錢都不以破 SLO 換來——這是全篇論證的地基。
對比基準3 SOTA三個 state-of-the-art 系統;摘要未點名,評測細節在全文,本文不臆測。
把一句話的評測結論攤成四行讀。省成本的 5-44% 之所以值得盯著看,正是那條區間的寬度——它在告訴你「贏多少」沒有單一答案。

如果你在公有雲上跑一個有延遲 SLO 的線上服務、又長期被「為了尖峰多開機器」的帳單困擾,這篇的價值不在那幾個百分比,而在它示範的一種切法:把「保命」與「省錢」當成兩個獨立問題,讓保命那半靠一個 per-request、能瞬間把 overflow 導向 commodity FaaS 的機制去扛,省錢那半才敢把常駐機群的利用率往上壓。它不必是 Spandana 這套實作——這個 decouple 的思路,對任何「怕破 SLO 而不敢提高利用率」的服務都適用。

落地這套東西,前提條件也要看清楚。它需要一個能被 request 路徑直接呼叫的 FaaS 供應商,論文舉的是 AWS Lambda,所以最順的場景是本來就跑在 AWS、且能接受把部分流量丟 Lambda 的服務。它也需要 application 能被拆成「在 VM 跑」與「在 FaaS 跑」兩種形態、且結果一致——無狀態或狀態外置的請求處理最合適,重度依賴本地狀態的就沒那麼直接。這些不是缺陷,而是把適用邊界劃清楚:它解的是「無狀態、延遲敏感、流量細粒度抖動」這一類服務的成本問題,不是所有服務的萬用解。

術語小抄——Spandana 的六個關鍵詞

桌面:游標停在術語上看定義 手機:定義直接列在下方

  • strict SLOService Level Objectives——服務對延遲等指標立下的嚴格承諾,破了就算失敗。整篇的張力就來自這條不可退讓的硬約束:既要守住它,又想省錢。
  • colocated controller與每台 application VM 跑在同一台機器上的 lightweight controller,不是遠端的中央排程器;決策就在 request 自己的路徑上當場做,省掉一趟會咬掉延遲預算的往返。
  • steeringcontroller 對每個進來的 request 下的判斷:能在 SLO 內於 VM 完成的留 VM,接不住的那截 forward 去 FaaS。是「換一條計算路徑」而不是「多開一台 VM」。
  • FaaS overflow把冒出 VM 天花板、留在 VM 就會 miss SLO 的那截 request,轉去現成的 serverless(如 AWS Lambda)吸收。彈性即時但按次計費,所以只吃 overflow、不吃全部流量。
  • traffic volatility流量的波動程度。就算平均值相同,波動越大的流量在同一個 VM pool 尺寸下溢位越兇;所以它是慢環成本函式的輸入之一,直接搬動最省的甜蜜點。
  • decouplingSpandana 的核心一招:把 SLO enforcement 與 cost optimization 拆成兩個獨立的控制問題——快環守死線、慢環追成本,各用最合適的時間尺度去解。
六個詞的定義都來自本文正文與論文摘要,不新增材料;把它們串起來,就是這套架構的縮圖:SLO 交給 colocated controller 的 per-request steering、用 FaaS overflow 兜底,成本才被 decoupling 出來獨立最佳化。

這套拆法解鎖的:把 SLO 當成不可退讓的硬約束、交給每台 VM 上的 per-request controller 用 FaaS 兜底,成本才被獨立地當成一個可以放手最佳化的目標——於是 VM pool 能被推到 76-86% 這種對延遲服務罕見的高利用率,而死線不必為此讓步。