iT邦幫忙

2026 iThome 鐵人賽

DAY 21
0

[Day 21] Sandbox Scaling:Rewrite 不夠,就換 Bigger Sandbox

上一篇處理的是 Sandbox Adaptive Execution。

遇到 OOM 時,不是直接換更大的 sandbox,而是先調整 execution strategy:

OOM
→ Rewrite
→ Retry

但如果 rewrite 之後還是超過 memory limit 呢?

這時才需要 scale up。

Case:Ward Hierarchical Clustering

這次讓 Agent 在 sandbox 裡:

Generate 16,000 random 2-D points, run Ward hierarchical clustering on all of them, cut the tree into 5 clusters, and return the cluster sizes.

一開始拿到的是 1 GB sandbox。

Agent 寫好 clustering.py 後執行,第一次 OOM:

  • Peak Memory:992 MB / 1024 MB
  • Run Time:1.3 秒

Agent 沒有馬上換 bigger sandbox,而是先 rewrite code。

第二次執行還是 OOM:

  • Peak Memory:1013 MB / 1024 MB
  • Run Time:2.2 秒

也就是:

1 GB Sandbox
→ OOM
→ Rewrite
→ OOM again

兩次 execution 都已經碰到 1 GB memory limit,這時才進入 scale up。

從 1 GB 搬到 4 GB

這裡不是直接 resize 原本的 sandbox。

目前這個 Daytona setup 上,我用的是 replace:

1 GB Sandbox
      ↓
Create 4 GB Sandbox
      ↓
Install Packages
      ↓
Copy Work Folder
      ↓
Switch
      ↓
Delete Old Sandbox
      ↓
Retry

實際 timeline 可以直接看到整個過程:

從第二次 OOM 開始:

  • Create 4 GB sandbox:11.7 秒
  • Install packages:7.6 秒
  • Copy work folder:4.2 秒
  • 整個 moving phase:約 23 秒

這次 work folder 只有 6 KB,主要時間其實花在建立新的 sandbox 和準備 environment。

切換完成後,conversation 開始使用新的 4 GB sandbox,舊的 1 GB sandbox 才會被刪掉。

接著原本失敗的 code step 在新的 sandbox 上重新執行:

這次成功了:

  • Peak Memory:2118 MB / 4096 MB
  • Run Time:10.2 秒
  • CPU Time:9.9 秒

最後 Agent 正常完成 clustering,回傳 5 個 cluster 的大小。

完整流程就是:

1 GB
→ OOM
→ Rewrite
→ OOM again
→ Move to 4 GB
→ Retry
→ Success

Conversation 不需要綁死 Sandbox

這也是前面把 Conversation 和 Sandbox 分開的原因。

對 Agent 來說,它做的還是:

execute("python3 /home/daytona/clustering.py")

但底下實際使用的 execution resource 可以從:

Conversation
→ 1 GB Sandbox

切成:

Conversation
→ 4 GB Sandbox

Agent 不需要自己處理 create、copy、switch、delete。

這些都是 sandbox layer 的工作。

為什麼不是一 OOM 就 Scale Up?

這個 case 也剛好接回 Day 20。

Day 20 的 recovery path 是:

OOM
→ Understand the bottleneck
→ Rewrite
→ Retry

因為很多 OOM 可以透過 execution strategy 解決。

但這次 rewrite 之後仍然用了 1013 MB / 1024 MB,第二次一樣被 kill。

這時才往下一層走:

Rewrite still fails
→ Bigger Sandbox

也就是 scale up 是 recovery path 的下一步,不是看到 OOM 的第一個反應。

Scale Up 期間,兩個 Sandbox 會同時存在

Replace 還有一個 capacity 問題。

新的 sandbox ready 之前,舊的不能先刪掉。

所以 migration 中間會短暫同時存在:

Old Sandbox   1 GB
New Sandbox   4 GB

單一 conversation 在這個階段暫時需要 5 GB memory capacity。

因此 scheduler 在建立 bigger sandbox 前,不只要確認還有沒有 sandbox slot,也要確認 total memory budget 放不放得下。

這也接回 Day 19:

Sandbox scheduling 不能只算 sandbox 數量,也要算 memory。

從 Load Page 看 Scaling

Load page 上可以更直接看到這次 execution 的差異。

Conversation 3 前兩次 execution:

step 1
→ 992 MB
→ OOM

rewrite 1
→ 1013 MB
→ OOM

換到 4 GB sandbox 後:

step 3
→ 2118 MB
→ Success

這也確認了這次不是單純「差一點點 memory」。

成功執行實際用了超過 2 GB,原本的 1 GB sandbox 確實不夠。

Resize vs Replace

最直接的做法看起來會是:

1 GB
→ resize
→ 4 GB

但目前這個 Daytona account / API setup 沒有直接對 running sandbox 做 resize。

所以目前採用:

Create Bigger
→ Copy
→ Switch
→ Delete Old

因為 Agent 操作的是 LazySandbox,上層不需要跟著 provider lifecycle 改變。

Sandbox 換了,但 conversation 還是同一個 conversation。

Scaling 也有成本

這次整個 conversation 大致可以分成:

1 GB Sandbox   ~22s
Moving         ~23s
4 GB Sandbox   ~18s

光 moving 就花了大約 23 秒。

所以 bigger sandbox 不適合變成每次 OOM 的預設解法。

其中比較明顯可以再優化的是 environment preparation。

這次新的 sandbox 還需要重新安裝:

pyarrow
polars
plotly
duckdb
scikit-learn

如果之後改成 prebuilt snapshot,常用 packages 已經準備好,就可以少掉這段 startup cost。

Sandbox Scaling

到這裡,execution recovery path 變成:

Execute
  ↓
OOM
  ↓
Rewrite Execution Strategy
  ↓
Still OOM
  ↓
Create Bigger Sandbox
  ↓
Move Working State
  ↓
Retry

Day 20 處理的是 code 怎麼調整。

這篇處理的是 code 調整還不夠時,Sandbox 怎麼跟著 workload scale up。


上一篇
[Day 20] Sandbox Adaptive Execution:動態調整執行策略
系列文
AaaS from Scratch: 從一次性定義,到規模化分析 共 21 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言