Serverless cold start는 isolated execution environment 하나를 만드는 operation으로 줄여 설명하기 쉽습니다. Sandbox가 1ms보다 빠르게 fork되면 문제가 끝난 것처럼 보입니다. Ant Group의 운영 measurement는 그렇지 않음을 보여 줍니다. Request는 scheduler와 node gateway를 지나 high-level 및 low-level runtime을 통과하고, kernel resource를 확보하며, network stack과 security policy를 초기화하고, language runtime과 dependency를 load한 뒤 user code를 실행하고 instance를 정리합니다.
연구 환경에는 unique function 5만 개가 넘고 하루 call은 약 1억 건이었습니다. Function 절반 이상은 cold-start probability가 0.75를 넘었고 35% 이상은 모든 invocation이 cold였습니다. Aggregate traffic에서는 일부 popular function에 request가 집중돼 hot request가 많았습니다. Infrequent function을 모두 warm하게 유지하면 idle instance에 memory를 쓰므로 체계은 hot container를 1분만 보관했습니다[1].
Catalyzer는 favorable condition에서 secure VM-process를 1ms 미만에 fork했습니다. 그래도 end-to-end cold start는 수백 ms에서 수 초였습니다. AFaaS는 한 stage를 빠르게 만들면 다른 stage가 드러난다는 observation에서 출발합니다. Runtime control-path overhead, sustained concurrency의 resource contention, user-code initialization 세 gap을 다룹니다.
Optimized fork 뒤에 남은 control path
OCI-compatible container stack은 containerd, shim, low-level runtime을 분리합니다. High-level process가 RPC를 보내고 runtime binary를 load하며 argument를 준비하고 seed에 fork를 요청한 뒤 sandbox를 activate합니다. Modular interface는 여러 container type을 지원하지만 measured Catalyzer path에서는 18ms에서 25ms가 걸렸습니다. Sandbox creation을 최적화한 뒤 cold-start time의 약 30%에서 40%였습니다.
AFaaS는 specialized fork runtime interface(FRI)를 도입합니다. Containerd plug-in이 long-lived low-level runtime을 직접 호출하고 function instance 사이에서 invariant한 work를 seed preparation으로 옮깁니다. Repeated process 및 binary setup을 function call과 prepared state로 바꿉니다. 대신 OCI generality 일부를 포기하고 FaaS-specific lifecycle을 선택합니다.
Specialization이 타당하려면 boundary를 audit할 수 있어야 합니다. 어떤 OCI semantics를 생략했는지, invocation마다 어떤 field가 달라질 수 있는지, containerd와 plug-in, sandbox upgrade를 어떻게 조정하는지 알아야 합니다. 같은 general interface를 더 빠르게 구현한 것이 아니라 일부 flexibility가 필요 없다고 선언해 latency를 줄였습니다.
Kernel setup을 shared bottleneck으로 만드는 concurrency
Sequential 소규모 benchmark는 많은 instance가 함께 시작할 때의 lock과 allocation path를 가립니다. Virtual Ethernet pair, cgroup, namespace, network state, seccomp filter 생성은 host-kernel structure에서 contention을 일으킬 수 있습니다. Catalyzer는 sustained execution 중 cache miss와 global lock contention 때문에 setup이 fast path에서 slow path로 옮겨가며 throughput이 떨어졌습니다.
AFaaS는 resource를 pool 가능한 object와 inherited state로 나눕니다. Veth device를 pre-allocate하고 cgroup을 recycle합니다. User code isolation은 guest OS 안에서 이뤄지므로 seed와 child가 selected network 및 IPC namespace를 share할 수 있습니다. Network structure는 seed에 준비할 common piece와 address 및 backend device 같은 per-instance identity로 나눕니다. Seccomp rule은 request 전에 parse 및 compile해 작은 installation step만 남깁니다.

Pooling은 free capacity가 아닙니다. 보고한 configuration은 veth device 1,000개와 cgroup 600개를 준비했습니다. Pool은 고갈될 수 있고 refill은 noisy neighbor가 될 수 있습니다. 원문은 serial pool preparation도 다른 workload와 contend할 수 있다고 설명합니다. Low-water mark, preparation rate limit, fallback latency, maintenance work와 user traffic 사이 isolation이 필요합니다.
Sharing에는 threat model도 필요합니다. 이 구조에서 host network namespace 공유가 가능한 이유는 secure container의 guest OS 안에서 isolation하기 때문입니다. Ordinary process-container design에 그대로 적용할 수 없습니다. Reused device는 재배정 전에 old connection을 닫아야 하고 inherited memory가 다른 tenant function state를 노출해서도 안 됩니다.
Application work를 앞당기는 seed tree
Language와 framework initialization은 short function보다 오래 걸릴 수 있습니다. Python 또는 Node.js load, library import, code compile, framework configuration parse가 handler execution을 넘을 수 있습니다. Guest OS만 가진 seed는 VM setup을 피하지만 application work를 남깁니다. 모든 function seed를 두면 latency는 줄지만 memory를 쓰고 warm 상태 관리가 어렵습니다.
AFaaS는 hierarchy를 사용합니다. Level 0은 guest OS, level 1 child는 language runtime을 initialize합니다. Level 2 child는 function framework, dependency, compiled user code를 더합니다. Copy-on-write로 descendant가 ancestor의 physical page를 share합니다. Exact function seed가 없으면 closest language 또는 root seed에서 fork해 남은 initialization만 수행합니다.
Hierarchy는 hot-or-cold binary choice를 graded reuse로 바꿉니다. Popular function은 level-2 seed를 둘 수 있고 long tail은 language state를 공유합니다. Shared component가 큰 function에서 controlled measurement의 seed memory는 Catalyzer 대비 28.11%에서 84.91% 줄었습니다. Production seed size는 initialized code에 따라 6.9MB에서 135.03MB였습니다.
AFaaS는 extended page table도 prefill합니다. Forked VM-process는 physical page를 share하지만 guest-to-host mapping을 다시 만들며 fault할 수 있습니다. Seed EPT를 복사하고 last directory level을 read-only로 두어 read-side VM exit를 줄입니다. Copy-on-write memory sharing이 그 memory에 접근할 translation structure까지 자동으로 공유하는 것은 아닙니다.
Fork가 복제하는 dangerous state
Fork는 useful code page보다 많은 것을 복제합니다. Buffered 난수-number state는 child가 repeated value를 만들게 할 수 있습니다. Open socket, identifier, timer, credential, cached process assumption도 cloning 뒤 invalid할 수 있습니다. AFaaS는 long-lived connection을 끊고 unique state를 다시 initialize합니다. Buffered get난수() path가 child 사이에서 난수 sequence를 반복할 수 있었던 사례를 원문이 설명합니다.
이는 performance detail이 아니라 correctness와 security gate입니다. Runtime 및 library upgrade마다 shareable, copy-on-write, per-instance로 분류할 새로운 state가 생길 수 있습니다. Seed catalog에는 open descriptor, entropy source, network state, JIT cache, after-fork hook manifest가 필요합니다. 첫 response 하나만 test하면 여러 child 사이 correlation을 놓칩니다.
Early destruction도 가정이 있습니다. AFaaS는 unified handler가 return하면 function이 끝났다고 보고 guest를 pause하며 TCP session을 끊고 full language-runtime shutdown을 기다리지 않고 resource를 회수합니다. Durable effect가 remote service를 통하는 stateless function에는 맞습니다. Background work, buffered local write, asynchronous finalizer를 contract 밖에 남기는 handler에는 안전하지 않습니다.
Short function과 long function을 나눈 평가
Short function에서 AFaaS는 Catalyzer-only configuration 대비 average latency를 3.76배에서 6.68배, P99 latency를 6.31배에서 11.74배 개선했습니다. Expensive initialization function은 function-specific seed의 이익이 더 커 average speedup 4.09배에서 31.48배, P99 speedup 6.19배에서 34.51배였습니다. Long-running handler는 execution이 response를 지배해 average improvement가 1.05배에서 1.14배였습니다.
Concurrency 1에서 24까지 JavaScript benchmark의 AFaaS end-to-end latency는 16.34ms에서 39.56ms였습니다. Catalyzer alone은 51.32ms에서 117.92ms였습니다. 그 안의 AFaaS cold-start work는 6.97ms에서 14.55ms, Catalyzer는 38.39ms에서 74.05ms였습니다. Selected secure-container setup에서 Kata와 gVisor는 더 느렸습니다.
Production measurement는 representative Node.js function 8개를 하루 동안 봤습니다. End-to-end speedup은 1.80배에서 8.14배였고 startup latency는 5.45ms에서 9.41ms였습니다. System은 18개월 넘게 배포됐습니다. One-machine benchmark보다 강한 evidence지만 CataOnly comparison은 simultaneous 운영 A/B가 아니라 matched hardware와 mocked peer response를 사용했습니다.
Workload context를 함께 봐야 합니다. Ant Group에서는 request의 80% 이상이 user execution을 221ms 안에 끝냈습니다. Multi-second function이 많은 체계에서는 10ms startup 감소가 user-visible latency에서 차지하는 비율이 작습니다. 반대로 매우 짧은 handler를 쓰는 latency-sensitive API에는 control-path millisecond가 모두 보입니다.
운영에 남은 한계
Seed 하나는 fork를 serialize하므로 매우 높은 concurrency에는 같은 seed replica 여러 개가 필요할 수 있습니다. Repeated creation 및 destruction은 bpf_jit_limit leak과 연관된 seccomp installation failure를 만들었습니다. Co-located workload는 pooled object를 assign 또는 recycle할 때 필요한 cgroup lock을 여전히 잡을 수 있습니다. Optimized path는 bottleneck을 줄이지 shared host state를 없애지는 않습니다.
Function-specific seed가 너무 많으면 memory pressure가 늘고 page가 disk로 나가 assumed startup latency를 무너뜨립니다. Admission은 invocation probability, saved initialization time, seed size, parent contention을 함께 봐야 합니다. 최적 seed set은 demand와 library 버전에 따라 바뀝니다.
AFaaS의 재사용할 lesson은 scaling request부터 response까지 cold start를 측정하는 것입니다. Fast fork는 그 path 안의 한 mechanism입니다. Interface specialization은 control work를 줄이고 pool은 burst 밖으로 contended allocation을 옮기며 hierarchical seed는 language 및 function initialization을 demand 이전으로 옮깁니다. 각 technique은 compatibility, reserved resource, preparation work, memory 중 다른 budget에서 latency를 빌립니다.
Production release에서는 sustained concurrency의 end-to-end percentile, pool depletion behavior, uniqueness reinitialization, seed provenance, memory pressure, fallback path, cross-tenant isolation을 확인해야 합니다. Sub-millisecond cloning은 surrounding contract가 whole request를 millisecond range에 유지할 때 의미가 있습니다.
출처와 저작권 안내
이 글은 Silicon & Systems가 작성한 편집 분석으로, 운영 design과 measurement, limitation을 우리 표현으로 다시 썼습니다. 원문의 문장, 표, 도판은 재수록하지 않았고 도판은 이 글을 위해 새로 만들었습니다. 전체 논문은 USENIX OSDI 2025 발표 페이지에서 확인할 수 있습니다. 저작권은 저자에게 있습니다. 2025.