Hermes Wiki

Cell-Based Architecture

Concept

Most scaling strategies grow a system by making a shared backend bigger — more replicas behind one load balancer, one larger database, one global control plane. That works for throughput but does nothing for blast radius: when the shared thing fails, everyone fails. Cell-based architecture attacks the blast-radius problem instead of the throughput problem.

A cell is a complete, self-contained instance of the system — its own compute, storage, caches, and supporting services — that serves only a subset of the total workload (a slice of tenants, users, or partitions). The full system is a collection of near-identical cell replicas sitting behind a thin routing layer (the "cell router" or mapping layer) whose only job is to deterministically map each request to its home cell. A request enters, is routed to one cell, and is served entirely within that cell. Crucially, cells do not share state with each other — that isolation is the whole point.

The payoff is fault isolation by construction: a failure caused by a poison-pill request, a bad deploy, a corrupted cache, a hot tenant, or a wiped database is contained to the single cell that experienced it. If you have 10 cells of equal size, any single-cell failure caps the blast radius at ~10% of the workload instead of 100%. It also shrinks recovery: restoring one cell's database (10% of the data) is far faster than restoring the whole fleet's.

The routing layer must be kept dumb and highly available — it's the one shared component, so it should do as little as possible (a simple, well-tested mapping from a partition key to a cell ID), because any logic or state there re-introduces the shared-fate failure mode the cells were meant to eliminate.

Tradeoffs

Approach Blast radius Operational cost Notes
Single scaled backend 100% — one failure hits everyone Lowest — one thing to run Simplest until the first fleet-wide incident
Cell-based (N cells) ~1/N — failure contained to one cell Higher — N copies to deploy, observe, patch; harder cross-cell queries Blast radius is a design parameter you tune via cell count/size
Sharding alone Data partitioned, but often shared control plane / routing / deploy Moderate Sharding splits data; cells split the entire stack including failure domains

The core cost is operational multiplication: every deploy, migration, observability dashboard, and on-call runbook now runs across N cells, and progressive rollout (deploy to one cell, watch, then fan out) becomes mandatory rather than optional. You also lose easy cross-cell operations — anything that needs to span cells (a global report, a cross-tenant join) fights the isolation the design bought you. Cell-based architecture is a deliberate trade of operational complexity for containment; it earns its keep only when a fleet-wide outage is expensive enough to justify running many copies.

Cell size is itself a tradeoff: smaller cells mean smaller blast radius but more cells to operate and more routing overhead; larger cells are cheaper to run but each failure hurts more. There's also a maximum safe cell size — a cell should be small enough that you've actually load-tested it to its limit, so you know it won't hit an untested scaling cliff.

When to use / when not to

  • Use when a fleet-wide outage is unacceptable — high-availability control planes, payment systems, identity services, multi-tenant SaaS where one tenant must never take down the rest.
  • Use when you already have a natural partition key (tenant ID, account ID, region) that cleanly maps requests to cells without cross-cell chatter.
  • Strong fit when combined with shuffle sharding at the routing layer to further reduce the chance that any two customers share the exact same set of failure domains.
  • Don't adopt it early — for a small system with one team and modest availability targets, N copies of everything is pure overhead that slows you down without a blast-radius problem worth solving yet.
  • Poor fit for workloads dominated by cross-partition operations (global aggregations, cross-tenant transactions) — the isolation that makes cells safe makes those operations expensive or impossible.

Common pitfall

Putting state or non-trivial logic in the routing layer. The moment the router holds shared state (a global session store, a shared rate-limit counter, dynamic per-request business logic), it becomes a shared failure domain — and now a bug or overload there takes down every cell at once, exactly the fleet-wide outage the architecture was built to prevent. The router must stay a thin, stateless, aggressively-tested mapping function; anything richer belongs inside a cell. A close second pitfall is letting cells quietly develop cross-cell dependencies over time (one cell calling another's database "just this once"), which erodes the isolation guarantee until a supposedly-contained failure cascades across cells.

Engineering Lens

Cell-based architecture is where "blast radius" stops being a slogan and becomes a tunable design parameter: the Principal-level move is being able to state, quantitatively, that a single failure caps at 1/N of the workload by construction — not by hoping a bug stays contained. In an architecture review it reframes the availability conversation from "how do we prevent all failures" (impossible) to "when a failure happens, how much of the system does it take with it, and can we prove that bound." That framing is exactly what regulated Fintech and Capital Markets platforms need: an auditor or risk committee asking "what's the maximum customer impact of a single component failure" gets a designed, defensible number instead of a shrug. It's the same fault-isolation instinct as the bulkhead pattern, scaled up from within-a-service resource pools to entire independent stacks.

Sources

Hermes Wiki