System designDeep dive10 min

Edge computing

A CDN already has servers near every user; edge computing runs your code on them. Decisions that used to cross an ocean to the origin, such as redirects, token checks or A/B assignments, now happen a few milliseconds from the user. The catch is data: code at the edge that keeps calling a database far away can end up slower than code that never left the origin.

1 · The problem

A CDN brings files close to users, but every decision still crosses the ocean

A fashion store runs its application and database in Frankfurt and sells in 40 countries. Its CDN already serves images and scripts from servers near each shopper (Content delivery networks (CDNs)). But every request that needs a decision, such as "send this Australian shopper to the Australian store", still goes to Frankfurt.

From Sydney that is far. The great-circle distance to Frankfurt is about 16,500 km, and light in fiber costs about 1 ms of round trip per 100 km (Latency), so each round trip takes at least 165 ms, before any handshakes or the longer real cable routes. A redirect that the origin decides in a microsecond still costs the shopper that trip.

Edge computing runs code on the CDN's own servers, in the location that received the request. Cloudflare, for example, lists data centers in 348 cities, and runs its Workers code in the one closest to where a request arrived by default. The redirect is decided in Sydney; only requests that really need Frankfurt go there.

Decision in Frankfurt, at least
165 ms of round trip
Decision at a Sydney edge, about
5 ms of round trip

16,500 km at about 1 ms per 100 km is 165 ms before any handshake. An edge in the shopper's city is a few milliseconds away.

2 · The runtimes

Edge runtimes trade power for start-up speed and density

An edge location runs code for many customers on few machines, and may see a given customer's code only occasionally, so starting fast and staying small matter more than anything else. Cloudflare Workers runs code in V8 isolates, the same sandboxes a browser uses to keep web pages apart: many isolates share one runtime process, each with its own memory. Cloudflare's isolates start in about 5 ms, around a hundred times faster than a Node process, using an order of magnitude less memory.

The price is a narrower environment. AWS offers two edge options on its CDN, and their documented limits show the trade clearly:

Aspect

CloudFront Functions

Lambda@Edge

Runs for

Under a millisecond

Up to 30 seconds

Memory

2 MB

128 MB to 10 GB, by trigger

Code size

10 KB

50 MB

Network calls

No

Yes

Scale

Millions of requests a second

Up to 10,000 a second per region

Cloudflare's Workers sit between the two: 128 MB of memory, and CPU time per request limited to 10 ms on the free plan and up to 5 minutes on paid plans, with network calls allowed. Across all of them, the rule is the same: edge code should do little work per request, quickly, and keep no state of its own between requests, since an isolate can be evicted at any time.

3 · Good fits

The best edge work needs only the request itself

Work that can be decided from the request alone is ideal. AWS lists exactly these uses for its lightweight edge functions, and the fashion store has one of each:

  • Redirects and rewrites: send / from an Australian IP to /au/.
  • Request authorization: verify the signature on a JSON Web Token, rejecting bad requests before they cross the ocean (Authentication & authorization).
  • Header manipulation: add security headers to every response.
  • Cache key normalization: strip tracking parameters so equal pages share one cache entry, raising the hit rate.
Shopper in SydneyEdge function, Sydneyredirect, token checkRedirect or 401answered in SydneyEdge cache, Sydneypages, imagesOrigin, Frankfurtcart, orders, stockevery requestdecided herecacheableonly on a misscart, checkout

Most requests end in Sydney: answered by the function or the cache. Only work that needs the database makes the 165 ms-plus round trip.

A step further, the edge can assemble pages: fetch a cached product page and insert the shopper's country, currency or experiment group, so a mostly static page needn't come from the origin just because one part varies. Assigning experiment groups by hashing a user ID works well here, since it needs no data at all (Feature flags & configuration).

4 · The catch

Code at the edge that keeps calling a distant database gets slower

The store's developers move the cart page to the edge. The page needs three queries in sequence: the cart, then the prices for its items, then stock for those items. Each query from Sydney to the Frankfurt database is a full round trip:

Code in Sydney, 3 trips
495 ms
Code in Frankfurt
168 ms

At the edge: 3 × 165 ms. Next to the database: one 165 ms round trip from the shopper plus three local queries at about 1 ms each (assumed). Every sequential trip to distant data costs the full ocean crossing.

Moving computation toward the user only helps if the data it needs is there too. Otherwise the code belongs next to the data. Cloudflare's Smart Placement solves exactly this case: it watches a Worker's traffic and runs it near the back end it calls most, instead of near the user.

So split the work. The edge handles what needs only the request, and passes everything else to code running beside the database, ideally in one call that does all three queries there. Or bring some data to the edge, which the next section is about.

5 · Data at the edge

Edge data stores are either eventually consistent or in one place

Edge platforms offer data stores, and they make the trade-offs of distributed data very visible (Consistency models):

Store

How it works

Good for

Not for

Workers KV

Central storage, cached in each location after first read

Read-heavy data: redirects, settings, feature rules

Counters, stock, anything needing the latest value

Durable Objects

One instance per name, single-threaded, with strongly consistent storage

Coordination: one cart, one room, one rate counter

Data read heavily from everywhere at once

Origin database

Your usual database, far away

Orders, payments, stock

Low-latency reads from far away

Workers KV is fast to read because it is cached, which also makes it eventually consistent. A change is usually visible at once in the location where it was made, but other locations may keep serving their cached copy for up to 60 seconds or more. Even a lookup that found nothing is cached, so a newly created key can stay "missing" elsewhere for the same time:

Fine for a banner, wrong for a price the store must honor. Anything that must be current at the moment of purchase belongs in a strongly consistent store.

Durable Objects take the opposite trade. Each object has a globally unique name and lives in one place, created close to where it was first requested, with storage of up to 10 GB that is strongly consistent and transactional. Requests from anywhere reach that one instance, which handles them one at a time. A shopper's cart as one object is consistent and fast for that shopper; a single global stock counter as one object would make every shopper in the world wait in one line.

6 · Global deploys

Code that runs everywhere also fails everywhere

Edge platforms push new code to every location within seconds, which is part of their appeal. It is also the risk. On July 2, 2019, Cloudflare deployed a new web application firewall rule containing a regular expression that backtracked enormously. It exhausted the CPU that serves HTTP traffic on every core handling it, across its network worldwide, and took down its proxying, CDN and firewall for 27 minutes.

Cloudflare's own list of causes included that a non-emergency rule change could go globally into production without a staged rollout, and that rolling back took too long. The lessons carry over to any edge code:

  • Stage edge deploys like any other release: a few locations, then more (Deployment strategies).
  • Keep CPU limits per request, so one bad change can't take a whole machine.
  • Keep a fast way back, tested, and a way to reach your own systems when the edge is down.
  • Watch per-location metrics, since a problem may start in one place.

Lesson

What it would have changed on July 2, 2019

Stage edge deploys

The bad rule reaches a few locations first, not the whole network

CPU limits per request

The runaway expression can't exhaust a whole machine

A fast, tested way back

The outage ends well before 27 minutes

Per-location metrics

The CPU spike shows at the first location to get the rule

7 · In practice

Put logic at the edge only when its data is there too

Fashion store task

Where it runs

Why

Country redirect, security headers

Edge function

Needs only the request

Token check

Edge function

Rejects bad requests before the ocean

Product pages with local currency

Edge, from cache plus a small insert

Mostly static

Feature rules, banners

Edge, from an eventually consistent store

Read often, changed rarely

Cart, checkout, stock

Next to the database

Several queries; must be current

For the store, the checklist:

  • Count round trips to data before moving code to the edge; one distant query per request is the most an edge function should make.
  • Keep edge code small and stateless, within CPU and memory limits.
  • Use eventually consistent edge stores for what can be a minute stale, and a single-owner or origin store for what can't.
  • Place code near its data when it must make several calls.
  • Stage edge deploys and keep a tested rollback.

Check yourself

5 questions

1. Why does running a cart page at a Sydney edge location make it slower when the database is in Frankfurt?
2. Which task is the best fit for a sub-millisecond edge function with no network access?
3. The store ends a sale by setting sale = off in Workers KV. What may shoppers in Sydney see?
4. Why would one Durable Object holding a single global stock counter be a poor design?
5. What made Cloudflare's 2019 rule change an outage across its whole network?

Takeaways

Remember this

  • Edge computing runs code in CDN locations near users, saving the round trip to the origin for decisions that need only the request.
  • Edge runtimes such as V8 isolates start in milliseconds and use little memory, in exchange for tight limits on CPU, memory and state.
  • Redirects, token checks, headers, cache keys and page assembly suit the edge; work that makes several calls to distant data doesn't.
  • Edge data stores are either eventually consistent caches, fine for read-mostly settings, or single-owner objects with strong consistency in one place.
  • Edge deploys reach every location at once, so stage them and keep CPU limits and a fast rollback.