Hermes Wiki

Serverless (FaaS) Architecture

Concept

Serverless — more precisely Function-as-a-Service (FaaS), since "serverless" also covers managed databases and object storage that have nothing to do with functions — is a compute model where the provider owns everything below the function boundary: no server to patch, no process to keep alive, no capacity to pre-provision. Code is packaged as small, stateless functions triggered by events (an HTTP request, a queue message, a file landing in object storage, a cron tick), and the platform allocates an execution environment per invocation, runs the function, and tears it down. Billing follows the same shape: pay per invocation and per millisecond of actual execution, not for idle capacity sitting between requests.

The architectural consequence is that a serverless application is decomposed into many small, independently-deployed, independently-scaled units glued together by managed event sources (API Gateway, SQS, EventBridge, S3 notifications) rather than a single long-running process handling routing internally. Each function scales to zero when idle and scales out near-instantly under burst load — the provider is doing the capacity planning a traditional autoscaling group would otherwise need tuned.

The defining operational wrinkle is the cold start: when no warm execution environment exists for a function, the platform has to provision one — download the code, initialize the runtime, run any module-level initialization — before the first line of handler code executes. As of 2026, Node.js and Python cold starts on AWS Lambda are typically under 200ms and Java cold starts (with SnapStart, which resumes from a pre-initialized JVM snapshot rather than booting cold) are also under 200ms, both roughly 20-30% faster than they were in 2024 — but a cold start is still a real, user-visible latency spike compared to an always-warm process, and the single biggest lever for reducing it remains keeping the deployment package small, since every extra megabyte the platform has to load adds to that first-invocation latency.

Tradeoffs

Approach Idle cost Scaling Latency consistency Operational burden
Traditional servers / VMs (always-on) Pay for provisioned capacity even at zero traffic Manual or autoscaling-group-based, minutes to react Consistent — no cold start Highest — patching, capacity planning, OS-level ops
Containers (ECS/Fargate, Kubernetes) Pay for running tasks; can scale to a small baseline, rarely true zero Faster than VMs, still not instant; good for sustained high throughput Consistent once warm; container-level cold starts are smaller but not zero Moderate — image builds, orchestration config, still some infra ops
Serverless / FaaS True scale-to-zero — pay only per invocation Near-instant scale-out, provider-managed Inconsistent — cold starts on infrequently-hit functions Lowest — no server or cluster to manage, but new debugging/observability tooling required
FaaS + Provisioned Concurrency Pay for the pre-warmed capacity whether it's used or not Eliminates cold starts for the provisioned slice; overflow beyond it still cold-starts Consistent for the provisioned portion Adds a capacity-sizing decision back into a model whose whole point was avoiding that

The real tradeoff isn't "serverless is cheaper" in the abstract — for a spiky or low-volume workload it is, since idle time costs nothing; for a sustained high-throughput workload, per-invocation billing can end up costing more than a comparably-sized always-on container fleet. AWS's own guidance frames Lambda as the right default for event-driven and spiky workloads under roughly 50M requests/month, with ECS Fargate preferred for sustained high throughput or when Lambda's hard 15-minute execution timeout is itself a constraint.

When to use / when not to

  • Use for event-driven, bursty, or unpredictable-traffic workloads — webhook handlers, image/file processing triggered by uploads, glue code between managed services, scheduled batch jobs — where idle-cost savings and zero-ops scaling outweigh cold-start latency.
  • Use at fan-out/glue points in an event-driven architecture where each function does one narrow thing and the event bus (not the function) owns the routing logic.
  • Don't use for long-running processes, heavy sustained computation, or workloads with strict low-latency requirements on every request (real-time chat backends, mobile gaming servers) — hard runtime/memory limits and cold-start variance work against both.
  • Don't reach for it reflexively for a steady, predictable, high-throughput service — a container or VM fleet sized to known load is often both cheaper and operationally simpler to reason about (traditional APM/debugging tooling works out of the box, unlike serverless-specific observability).
  • Weigh vendor lock-in honestly: business logic itself is usually portable, but the integration layer — event source bindings, provider SDK calls, IAM/permission models, deployment configuration — is not, and migrating off a provider's FaaS platform later is a real cost, not a hypothetical one.

Common pitfall

Treating "serverless" as synonymous with "no cost/ops tradeoffs" and defaulting to it for every service, then discovering later that a handful of high-traffic functions are now costing more per month than the equivalent container would have — or that provisioned concurrency was quietly added to fix cold-start complaints and, in doing so, reintroduced the exact idle-capacity cost the architecture was chosen to avoid.

Engineering Lens

The design-review question worth asking isn't "should this be serverless" as a blanket policy — it's "what's this function's traffic shape, and does scale-to-zero billing or cold-start latency dominate the cost/latency budget for it." A payment-webhook handler that fires a few thousand times a day is an easy serverless call; a request-path function sitting in the critical path of every user-facing page load, hit millions of times a day, is a much closer call that deserves the provisioned-concurrency-cost-vs-container math done explicitly rather than assumed. Mixing both patterns within one system, function-by-function, based on each one's actual traffic shape — rather than picking one compute model for the whole architecture — is usually the stronger answer.

Sources

Hermes Wiki