Section 5: What Must Survive, What Can Be Forgotten - Data Modeling
Executive Summary: Section 4's calls create about a dozen kinds of state, and the modeling move that matters is sorting them into two bins. Durable truth (accounts, functions, immutable versions, aliases, code chunks, accepted async events, billing) lives in replicated stores and is never lost. Soft state (which sandboxes exist, which are idle, who holds a lease) lives in memory and is rebuilt from the workers in seconds. We partition metadata by account, the async queue by function, and placement by function version, and we make versions and code content-addressed and immutable so that no cache on the hot path ever needs invalidating.
The interviewer taps the PublishVersion and Invoke calls still on the board from Section 4: "Every one of these writes something somewhere. What's in the tables, and where do the tables live?"
"Before the schema, one sorting question: if this disappeared right now, would a customer lose something they can't get back? That splits the platform in two and decides nearly every storage choice."
The Entities
accounts (account_id PK, cell_id, concurrency_limit = 1000, unreserved_floor)
functions (account_id, function_name, latest_config {runtime, handler, memory,
timeout, env_ciphertext, role}, latest_code_digest) -- "$LATEST", mutable
versions (account_id, function_name, version_no, -- immutable once published
code_digest, runtime, handler, memory_mb, timeout_s,
env_ciphertext, role, config_hash)
aliases (account_id, function_name, alias_name,
routing [{version_no, weight}]) -- a pointer, 1 or 2 targets
concurrency_config (account_id, function_name, reserved,
provisioned [{qualifier, count}])
event_invoke_config (account_id, function_name, qualifier, max_retries = 2,
max_event_age_s <= 21600, on_failure_destination)
event_source_maps (mapping_id, account_id, function_qualifier, source_arn,
batch_size, checkpoint {shard -> sequence},
state: enabled|disabled|failing)
code_manifests (code_digest PK, [chunk_hash...], size) -- content-addressed
code_chunks (chunk_hash PK, encrypted_blob, key_ref) -- content-addressed
async_events (event_id, function_qualifier, payload <= 256 KB,
attempt, next_attempt_at, first_accepted_at)
idempotency_keys (account_id, function_name, idempotency_key PK, event_id,
expires_at = accepted + 6 h)
billing_rollups (account_id, function_version, memory_mb, minute,
invocations, billed_ms) -- 1 ms increments
sandboxes (SOFT) (sandbox_id, host_id, az, function_version, state,
lease_holder, lease_expires_at, last_used_at)
Here is Tidewater in those rows. checkout-api has a functions row holding whatever was last uploaded, and a versions row for version 42: Node.js 22, 1,024 MB, the digest of a 25 MB zip, and encrypted env vars. Alias live holds [{42, 1.0}]. During Section 4's canary it held [{42, 0.90}, {43, 0.10}]. concurrency_config carries the provisioned 3,000 that gets warmed at 08:55. thumbnail-maker's event_invoke_config says 2 retries, 6 h max age, and a dead-letter queue as the on-failure destination.
Three details carry more weight than they look:
- A version is a frozen tuple. Code digest plus every setting that changes behaviour, hashed into
config_hash. Nothing about version 42 can change after publish, which is why rollback is just repointinglive, and why provisioned concurrency targets a version or alias, never$LATEST. - An alias holds no data of its own. It is a pointer with at most two weighted targets. Alias moves are the main thing the config change stream carries.
- An async event carries
first_accepted_at, not justattempt. The 6 h max age is measured from acceptance. A throttled event can be retried many times, but it can never outlive its age limit.
Sign in to continue reading
The rest of this lesson is available with a free account. Signing in with Google or Microsoft is free.
Sign in to read the full lesson