---
title: "Kobako：Cold Start 原來能快 100 倍？"
date: 2026-06-17T00:00:00+08:00
publishDate: 2026-06-17T00:00:00+08:00
lastmod: 2026-06-15T21:40:29+08:00
tags: ["LLM","AI","經驗","Ruby","WebAssembly","Gem","效能"]
series: "kobako"
toc: true
permalink: "https://blog.aotoki.me/posts/2026/06/17/kobako-cold-start-100x-faster/"
language: "zh-tw"
---



[Kobako](https://github.com/elct9620/kobako) 是近期我針對 Ruby 生態系中，對 [Harness Engineering](https://blog.aotoki.me/tags/Harness-Engineering/) 支援所開發基於 WebAssembly 和 mruby 的沙盒（Sandbox）用來填補 AI 所撰寫的程式碼，沒有可以安全運行的環境。

關於 Kobako 的設計理念，我在 [上一篇文章](https://blog.aotoki.me/posts/2026/05/20/kobako-ruby-sandbox-for-ai/) 已經介紹過，這次想聊的是效能。在初期的版本中 Cold Start（冷啟動，通常指初次啟動）大概要花上 500 ms 左右，這遠比最佳實踐通常會抓 200 ms 回應來說慢的不少，即使 AI 通常接受更慢的回應，但這不是等待 LLM 回應，仍該用過去的 API 標準來看待。 

<!--more-->

## 預先編譯{#pre-compile}

WebAssembly 經過多年發展後，已經有很多新的技術跟規格，其中 `cwasm`（Wasmtime 把 `.wasm` 預先編譯後的產物）就是一種 AOT（Ahead-of-Time，預先編譯）的處理方式。

原因在於，我們編譯為 `wasm` 格式後，是針對 WebAssembly 的虛擬機器所設計，如果拿來跑 mruby 大致上就是在一個 WebAssembly 虛擬機器中，再啟動一個 mruby 虛擬機器，套了兩層在運作。

透過 `cwasm` 處理，會先在運行的環境直接編譯成當下環境 CPU 對應的機器碼，那就無限接近於把 WebAssembly 虛擬機器消除，只留下 mruby 虛擬機器的成本，啟動速度就從 500 ms 縮減到 5 ms 左右，因此 Cold Start 的時間馬上快上 100 倍。

簡單來說，Kobako 本身並沒有做太多處理，只是很單純的透過 WebAssembly 的標準，就極大的加速到跟一次簡單的 SQL 查詢差不多，對大部分應用幾乎等同無感。

> 今年 RubyKaigi 中 Matz 的新專案 [Spinel](https://github.com/matz/spinel) 正好就是一種 Ruby 的 AOT 編譯器，至於 `cwasm` 我則是第一次接觸到，畢竟過往都還停留在 `wasm` 的認識，這次跟 AI 協作意外學到新的概念。

## 預先偷跑{#pre-boot}

當在裝置上啟動過一次 Kobako 後，後續的 Cold Start 就會因為 AOT 從 500 ms 變成只要 5 ms 就能啟動完畢，那麼 `Kobako::Sandbox.new` 也能變快嗎？

原本的設計上，我們會把每個 `Kobako::Sandbox.new` 都獨立建立一個實例（Instance）並且在每次 `#run` 或者 `#eval` 時重新初始化 mruby 虛擬機器，確保可重用與乾淨隔離，但每多一個沙盒就會多佔用約 560 KB 的記憶體，對於希望「大量產生、刪除」的設計不太友善，當數量增加記憶體就會急劇消耗，而且還有一個初始化的時間約 130 µs 的成本在，即使這已經非常快。

Wasmtime 提供了一個叫做 [wizer](https://crates.io/crates/wasmtime-wizer) 的機制，我們可以預先把運行的記憶體準備好。這是因為每次啟動新的 mruby 虛擬機器時，對所有使用相同 `.wasm` 的 `Kobako::Sandbox` 是完全相同的記憶體，那麼預先把把 mruby 虛擬機器跑到啟動好的狀態存到 `.wasm` 中，未來啟動時就不需要再次去計算。

接下來搭配 Wasmtime 的 `InstancePre` 和 `Copy-on-Write` 兩個設計，就可以把啟動時間跟記憶體使用壓的更低。

- `InstancePre` - 把 Kobako 的 ABI（Application Binary Interface，應用程式二進位介面）先計算好，未來重新利用，不用每次都計算
- `Copy-on-Write` - 建立新的 `Kobako::Sandbox` 時，使用同一份 Baked 的 mruby 虛擬機器，不另外建立

透過這些處理，做一次 `Kobako::Sandbox.new` 的時間，就從 130 µs 降低到 30 µs 左右，記憶體使用從 560 KB 減少到 1 KB，因為不再需要每個沙盒都保存完整的記憶體，在有改變之前都會使用同一份基礎。

## 設計取捨{#design-decision}

原本在我的預期中，會透過消耗相對多的記憶體去換取更快的速度，但結果反而出乎我的預期，在速度跟記憶體使用上都得到很大的提升，更快地幫助我把專案推進到可以正式上線的等級。

尤其是這次用到的技術，很多都不是新技術，而是建構在已經被使用多年的機制。但透過 AI 的輔助，我很快的挖掘出這些技術，並且放置到恰當的位置。

這對軟體工程師這個職業的影響，依舊還是對應我們所熟知的衝擊，有經驗的工程師更有價值，原因就是「無條件接受」跟「有意識篩選」是兩件事情，後者是專業工程師的素養，在這次改版之前，我已經直覺的「可以用 Cache 重用」這樣的直覺判斷，先減少「每次都要等 500 ms」變成只等一次。

然而當整體功能完善後，考慮到每次啟動的時間跟佔用的記憶體，就讓我開始思考「還能更好嗎？」但受限於對 WebAssembly 技術不是熟悉的情境，透過 AI 大量搜集資料、探索，很快就確認 AOT、Bake 等技術是合理且有幫助的，分段處理（如果 AOT 不成立，做 Bake 大概也沒差異太大）一步一步推進來達到更好的成果。

我認為這在 AI 時代是很值得思考的問題，我們從 AI 身上拿到的「加速」是什麼？以 Kobako 的案例，整個專案極大的提升背後，是快速搜集資料，以及對軟體開發知識的熟悉得出適當的判斷。

