Function-as-a-service platforms promise that code runs only when needed and scales without effort. The price of that convenience is that an environment for the code does not always exist at the moment a request arrives. If none is available, the platform has to create one before it can run the function, and that extra time is called a cold start. Most requests hit an environment that is already warm and complete quickly, so averages look healthy. The slow requests are the ones that bring in a new environment, and because they are rarer, they are easy to overlook in monitoring that reports only mean latency. Users, however, experience them as occasional, unexplained pauses. A page that loads instantly nine times and stalls on the tenth feels broken, even though the dashboard reports a healthy average. That mismatch between what monitoring shows and what people feel is the real difficulty of the cold start problem.

What triggers a cold start?

A cold start occurs whenever the platform needs a fresh execution environment. This happens on the first invocation after a deployment, after a period of inactivity during which idle environments are reclaimed, and whenever concurrent demand exceeds the number of warm environments, so the platform scales out. Each new environment goes through a sequence of steps. The platform allocates resources and starts an isolated sandbox, downloads and unpacks the function code, starts the language runtime and runs any initialisation code the function contains, such as loading libraries or opening connections. Only then can it process the request. A burst of traffic can therefore produce many cold starts at once, just when responsiveness matters most.

Advertisement

Why do some functions suffer more than others?

The size of the delay depends heavily on choices the developer makes. Runtimes with heavier startup costs, such as those that load a large virtual machine and many classes, generally take longer than lightweight ones. Large deployment packages take longer to download and unpack. Initialisation code that connects to databases, loads configuration or builds large objects runs on every cold start. Memory allocation can also matter, since on many platforms it is tied to the share of processor power a function receives. For chains of functions that call one another, the delays accumulate, so a workflow with several steps can see cold starts compound into a noticeable total.

Strategies to reduce the impact

Mitigations fall into two groups. The first reduces the cost of each start, by trimming dependencies, shipping smaller packages, deferring heavy initialisation until it is needed and choosing a runtime suited to latency-sensitive work. Some platforms offer snapshot features that restore a pre-initialised environment, which can shorten startup for slower runtimes. The second group reduces how often starts happen on the critical path, by keeping a number of environments ready through provisioned concurrency or scheduled warm-up requests, with the extra cost that implies. Neither approach removes the problem entirely, so latency-critical designs also use timeouts, caching and asynchronous patterns that tolerate an occasional slow start.

Why it matters

Serverless is attractive because it removes capacity planning, but it moves some performance questions into the platform's behaviour. Cold starts are the clearest example. Teams that measure tail latency, understand what triggers new environments and decide deliberately how much warm capacity to pay for avoid the unpleasant surprise of a service that is quick in testing and sluggish for real users at the worst moments.

Average latency tells you how the platform usually behaves. Cold starts live in the part of the chart the average hides.

Sources

  1. AWS Lambda: Understanding the execution environment lifecycle