System Design (High-Level Design) Module 13 – Architecture styles at scale
Serverless and edge computing: when they fit
How functions as a service and edge code run, their limits on concurrency, duration and state, and how cold starts and connection storms are handled.
What you will learn
- Compute how many execution environments a function needs from its request rate and duration
- Choose a fix for cold starts from its cost and the latency objective
- Predict how a traffic burst meets a function's scaling limits, and keep it from failing requests
- Size the database connections a function needs, with and without a pooler
- Decide what runs at the edge, and give every piece of shared state a single owner
Before you start
What you’ll learn · Before you start
What you will learn
- Compute how many execution environments a function needs from its request rate and duration
- Choose a fix for cold starts from its cost and the latency objective
- Predict how a traffic burst meets a function's scaling limits, and keep it from failing requests
- Size the database connections a function needs, with and without a pooler
- Decide what runs at the edge, and give every piece of shared state a single owner
Before you start
On this page
An API that answers 2,000 requests a second in 120 ms keeps 240 copies of its code busy on a serverless platform, and 4,000 if a slow dependency stretches each request to 2 seconds. Serverless functions run your code in response to a request or an event, in short-lived environments that the provider creates and scales, and you pay for the time they run. Edge computing runs small pieces of code at a content delivery network’s locations near users, before a request travels to your region.
Both take servers off your list of worries and add limits instead. A serverless function usually handles one request per environment at a time, runs for at most 15 minutes per invocation on AWS Lambda, sometimes starts cold, and keeps nothing between invocations you can count on. Use functions for spiky, event-driven work, use edge computing for quick decisions about the request itself, such as redirects and token checks, and give every piece of state one home outside both.
How functions run, and what the edge adds
For each request in flight, a Lambda function in its default mode gets its own execution environment: The isolated runtime a function platform creates to run one copy of a function's code. It handles one request at a time and may be kept and reused for later requests., so the number of environments it needs is the request rate times the request duration (Lambda concurrency). That is how the slow dependency above turns 240 environments into 4,000, four times the default account limit of 1,000 per Region, and the rest fail with a throttling error. Step through that arithmetic:
The drawing shows the whole scene; its 5 steps are listed below.
Every step as text
- Requests arrive. Two thousand requests arrive every second, and each takes 120 ms. Every request in flight gets an execution environment of its own, which handles one request at a time.
- Rate times duration. On average 2,000 × 0.12 = 240 requests are in flight at any moment, so the function holds 240 environments, the request rate times the request duration.
- A slow dependency. A dependency slows down and every request now takes 2 seconds. The same traffic keeps 2,000 × 2 = 4,000 requests in flight, so it needs 4,000 environments.
- The account's limit. The account allows 1,000 concurrent executions per Region by default, for all its functions together, so this function can hold at most 1,000.
- Throttled. 1,000 environments at 2 seconds each finish 500 requests a second, so three in four requests fail with a throttling error. Nothing broke; a slow dependency multiplied the environments the traffic needs.
Edge code lives with tighter limits: CloudFront Functions run in under a millisecond with 2 MB of memory and no network access, while Lambda@Edge may call other services and run for up to 30 seconds (edge functions compared). The picture shows where each kind of code sits:
Edge code near the user, functions and state in one region
Text description of the diagram
A user's request first reaches an edge location a few milliseconds away. There an edge function handles redirects, token checks and cache keys, and an edge cache answers what it can. On a cache miss the request travels to one region, tens of milliseconds or more away. There functions handle requests, one request per execution environment at a time. They send their queries through a connection pooler, which keeps only a few connections open to the database. Slow work goes from the functions to a queue, and worker functions take it from the queue later.
| Criterion | Containers or VMs | Regional functions | Edge functions |
|---|---|---|---|
| Runs | All the time | Per request or event | Per request, near the user |
| Scales | As you configure | By itself, up to quotas | By itself |
| Longest run | No limit | 15 minutes on AWS Lambda | Under a millisecond to 30 seconds |
| State between requests | Memory and disk you manage | None you can count on | None; read-mostly data at most |
| You pay for | Capacity, used or not | Requests and running time | Requests and running time |
| When to choose | Steady load, long work, open connections | Spiky, event-driven, short work | Quick decisions about the request itself |
What the rest of this lesson works through, one line each:
- Cold starts: a new environment runs its setup code before it answers, so lighter setup shortens each one.
- Snapshots: new environments resume from a snapshot of one already set up.
- Provisioned concurrency: environments kept ready, for a charge, so requests up to that number start warm.
- A queue in front: requests wait instead of failing while the function adds environments.
- Reserved concurrency: a cap and a guarantee of environments for one function.
- Connection poolers: each environment holds its own database connection, so a burst can exhaust the database’s connections. A pooler lets thousands share a few.
- Single-writer objects: one owner per key that applies updates one at a time.
The AWS documentation says cold starts typically occur in under 1 % of invocations and take from under 100 ms to over a second. The model below shows what that does to the tail when the handler alone takes 40 ms at the median:
"""Latency of a function when some invocations start cold.
A warm invocation runs only the handler; a cold one first creates the execution environment and runs the
initialisation code. The AWS Lambda documentation says cold starts typically occur in under 1 % of
invocations and take from under 100 ms to over 1 second. The durations below are assumptions inside that range:
- handler: median 40 ms, p99 about 130 ms (lognormal);
- extra time of a cold start: median 600 ms, p99 about 1,900 ms (lognormal)."""
import math
import random
import statistics
random.seed(11)
REQUESTS = 200_000
def handler_ms():
return random.lognormvariate(math.log(40), 0.5)
def cold_extra_ms():
return random.lognormvariate(math.log(600), 0.5)
def latencies(cold_share):
return [handler_ms() + (cold_extra_ms() if random.random() < cold_share else 0.0) for _ in range(REQUESTS)]
print("cold starts p50 ms p95 ms p99 ms p99.9 ms")
for share in (0.0, 0.001, 0.01, 0.05):
q = statistics.quantiles(latencies(share), n=1000)
print(f"{share:>10.1%} {q[499]:>10.0f} {q[949]:>8.0f} {q[989]:>8.0f} {q[998]:>10.0f}") Output
cold starts p50 ms p95 ms p99 ms p99.9 ms
0.0% 40 91 128 191
0.1% 40 91 129 275
1.0% 40 96 230 1206
5.0% 41 212 958 1707
Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 cold_start_model.py
Runs on this device, in your browser. The first run downloads Python (about 13.5 MB), which is kept for the next runs.
Your run, in this browser
At 1 % the median does not move, but the p99 (99th percentile): The latency within which 99 % of requests finish, so the slowest 1 % take longer. Tail latency is read from such high percentiles, because an average hides the slowest requests. More in “Latency, throughput and percentiles” goes from 128 ms to 230 ms and the p99.9 passes a second. Cold starts are a tail problem, and a busy service’s users meet its tail every day.
Checkpoint
Check: One environment per request in flight
Cold starts live in the tail; fix them cheapest first Pro: opens with a Pro, Premium or Ultimate pass
In this part:
- Bursts hit two limits, and a queue turns refusals into a wait
- Connections run out before the database’s CPU does
- Shared state needs one writer, or updates are lost
- Edge code pays off only when it answers without the region
- Practise: twelve workloads, sorted
- Interview questions
- What is a cold start in serverless computing, and when does it happen?
- A function-based API passed its load test, but at launch the PostgreSQL database began refusing connections within a minute while its CPU stayed at 30 %. Explain what happened and how you would fix it, with numbers.
- During a flash sale, traffic to an order function jumps from 300 to 8,000 requests a second, each taking 400 ms, and a third of the requests fail with status 429 for the first half-minute. Why, and what would you change before the next sale?
- Product wants two numbers on every product page, served by edge code in 40 cities: "people viewing now" and "items left in stock". Design both, and explain why they need different designs.
- Key takeaways
5 diagrams · 3 runnable examples (JavaScript, Python) · 3 interview answers · about 38 minutes
Opening this part with your pass…
This part opens with any MySmartCoPilot pass.
- Pro pass · 1 week₹79$2.99
- 30 days₹179$5.99
- 1 year₹1,699$45
One payment; a pass never renews. The price shown is the total you pay: no fees or charges are added at checkout.
Passes can’t be bought right now, so this part can’t be opened at the moment. The free part above stands on its own. If you have a pass, enter your licence key.
It also opens every other in-depth part in Learn and every Pro tool. Sales are final, except where the law gives you a right to withdraw, for example in the EU and the UK (refund policy).
Terms in this lesson
- cold start
- The extra time an invocation takes when no warm execution environment is ready: the platform must create one, load the code and run the setup code before the handler runs.
- execution environment
- The isolated runtime a function platform creates to run one copy of a function's code. It handles one request at a time and may be kept and reused for later requests.
- provisioned concurrency
- Execution environments that a function platform sets up in advance and keeps ready, so requests up to that number meet no cold start. Keeping them adds a charge.
- reserved concurrency
- A number of execution environments set aside for one function: no other function can use them, and the function can never use more.
- single writer
- One owner for each key, such as a counter or a stock level, that applies the updates for that key one at a time, so concurrent updates cannot overwrite each other.
References
- Understanding Lambda function scaling (AWS Lambda Developer Guide) (Amazon Web Services)
- Lambda scaling behavior (AWS Lambda Developer Guide) (Amazon Web Services)
- Lambda quotas (AWS Lambda Developer Guide) (Amazon Web Services)
- Understanding the Lambda execution environment lifecycle (AWS Lambda Developer Guide) (Amazon Web Services)
- Improving startup performance with Lambda SnapStart (AWS Lambda Developer Guide) (Amazon Web Services)
- Amazon RDS Proxy (Amazon RDS User Guide) (Amazon Web Services)
- Differences between CloudFront Functions and Lambda@Edge (Amazon CloudFront Developer Guide) (Amazon Web Services)
- Amazon CloudFront KeyValueStore (Amazon CloudFront Developer Guide) (Amazon Web Services)
- Durable entities (Azure Durable Task documentation) (Microsoft)
- PostgreSQL 18 documentation: Connection settings (max_connections) (The PostgreSQL Global Development Group)
Related tools
Report a problem with this lesson
Kept only in this browser. Your Learn progress