Module O-8·28 min read

Cost per request and per tenant as design metrics, the egress bandwidth tax, spot and reserved capacity, storage tiering — and when scaling out is just buying past a design flaw.

JJS
Written by Jatin Jain Saraf · Senior Software Engineer

Module O-8 — FinOps: Cost Architecture

What this module covers: Cost as a design constraint with the same standing as latency — because the architecture determines the bill and finance can only report it. Unit economics, since total spend is unactionable and cost per request or per tenant is not, plus the attribution work that makes those numbers exist at all. The egress tax, which has appeared as a warning in six earlier modules and gets its accounting here. The cost model and the single best lever for each resource class, including two line items that are routinely large and rarely understood — provisioned IOPS and NAT gateway data processing. Then the architectural levers ordered by size, ending on the question this course has been building towards: when is scaling out just buying your way past a design flaw, and what is the test that tells you. Finally governance that works — tagging enforced by policy, anomaly detection on daily spend, cost estimates in pull requests — and the honesty about trade-offs, including that premature cost optimisation has exactly the same shape as premature performance optimisation.


The Architecture Determines the Bill

A finance team can report spend, allocate it, and ask questions about it. It cannot change it, because almost every line on a cloud invoice is the direct consequence of a design decision made months earlier: where the data lives, how many round trips a request makes, whether a cache exists, what the retention policy is, how the keys are distributed.

Which means cost is an engineering property, and it deserves the same treatment as latency:

A system that costs three times more per request than it needs to is a defect, with the same status as one that is three times slower than it needs to be.

Not a moral failing and not an emergency — a measurable, attributable, fixable property. And like latency, it is cheap to influence at design time and expensive to retrofit.

Analogy: a building's running costs. Once the walls are up, the facilities manager can adjust the thermostat, negotiate the electricity tariff and turn lights off at night — worth doing, and bounded. The decisions that actually set the bill were made on paper: the insulation, the glazing, the orientation, whether the plant room is sized for the load. Nobody blames the facilities manager for a poorly-insulated building, and nobody expects them to fix it. The architect could have, for almost nothing, at the time.


Unit Economics: Total Spend Is Unactionable

"We spent £180,000 last month" supports no decision. Every useful cost conversation is about a unit:

UnitAnswers
Cost per request (per service)is this endpoint's implementation efficient?
Cost per tenantwhich customers are unprofitable?
Cost per order / per active userdo we make money at this price?
Cost per GB ingested / per million eventsis this pipeline's design sane?

Three things follow from expressing cost this way.

Efficiency becomes trackable. Total spend rises with growth, which hides everything. Cost per request rising means the system is getting less efficient, and that is a signal you can act on. A deploy that doubles cost per request should be as visible as one that doubles p99 latency — and in most organisations it is not visible at all.

Gross margin becomes visible per plan. If cost per tenant on the £29 tier is £41, you are selling at a loss, and only unit economics reveals it. The distribution is usually extreme: a small number of tenants consume a large share of the cost, which is Module P-8's noisy-neighbour problem with prices attached, and Module P-18's per-tenant limits are what convert an unbounded cost into a bounded one.

And it requires attribution work, which is the part that must be set up in advance:

  • Mandatory tagging enforced by policy as code (Module O-3): owner, service, environment, cost centre. Untagged resources are unattributable, and a resource created untagged is very rarely tagged later.
  • Per-tenant metering for the usage that dominates — requests, storage, tokens, egress — which is the usage_events table from Module P-18 doing double duty.
  • A shared-cost allocation rule. A shared database or cluster serves everyone, and allocating it by headcount is arbitrary; allocate by measured usage (queries, bytes, CPU-seconds) even approximately, because an approximate measurement drives better decisions than an arbitrary split.

The Egress Tax

Six earlier modules flagged data transfer as a cost. Here is the accounting.

Ingress is generally free; egress is priced, and the price rises with distance:

text

The asymmetry is architectural rather than incidental. It means:

  • "Just point it at the other region's database" costs a cross-region round trip and a per-gigabyte charge on every query, forever (Module A-9).
  • Replicating every write to N regions is charged N−1 times, which is why Module A-14's rule — replicate the inputs and derive the outputs locally — is a cost decision as much as an architectural one. Replicating 240,000 derived timeline writes per second across regions is a very large bill for data you could compute.
  • Chatty service-to-service traffic across zones is billed per gigabyte, which makes topology-aware routing (Module A-5) a cost control and not merely a latency optimisation.
  • Serving object storage directly to users instead of through a CDN pays origin egress rates on every byte, every time (Module A-11).
  • Shipping all observability data to one central region moves a continuous, high-volume stream across a priced boundary (Modules O-1, A-9) — and the same pipeline is a residency problem, which is a rare case where the cheap fix and the compliant fix coincide.

And the mitigation nobody does first: measure egress by source. Most teams cannot say which service or which flow generates their data-transfer charges, which makes the line item unattackable. Cost-and-usage data broken down by transfer type is the prerequisite; after that the levers are a CDN, compression, zone-local routing, private endpoints, and deriving rather than replicating.


Cost Model and Best Lever, per Resource Class

Compute.

LeverTypical savingApplies to
Right-sizing (measure, then shrink)20–50%almost everything — most instances are over-provisioned
ARM instance families20–40%anything that compiles/runs on ARM, which is now most things
Spot / preemptible60–90%interruptible work: transcoding (A-11), batch, CI, embeddings (A-12)
Reserved / committed use30–60%your predictable baseline
Autoscalingvariesremoving idle at off-peak

Spot capacity is the largest single discount available and it requires the engineering from Module P-19: checkpointing so a reclaimed instance costs one chunk rather than the whole job, and idempotency so a retried chunk is harmless. Transcoding is the canonical fit.

The idle problem deserves naming separately, because several earlier modules created it: a GPU costs the same whether it is inferring or not (Module A-12), a warm standby costs the same whether it is failing over or not (Module O-7), and a provisioned database replica costs full price at 2% utilisation. For these, utilisation is the only lever, and the honest comparison against a per-request managed service is a utilisation calculation rather than a preference.

Serverless versus provisioned has a computable crossover: per-invocation pricing wins decisively on spiky and low-volume workloads and loses badly on steady high volume. It is worth actually computing rather than arguing about, and the answer changes as a workload matures — which is a reason to keep the compute layer replaceable.

Storage. Tiering with the traps from Module A-11 (retrieval charges, minimum storage durations, per-object transition fees, minimum billable object sizes — so tier large cold objects and leave small ones alone). Then the three quiet accumulations:

  • Snapshot and volume sprawl — orphaned snapshots, and PersistentVolumeClaims deliberately retained when a StatefulSet scales down (Module O-3). Nobody deletes these because nobody owns them.
  • Log retention, which is frequently the largest observability line item and grows with traffic and with every developer who adds a log line (Module O-1).
  • "Keep everything forever" as a default, which is a decision made by omission and is also a compliance liability (Module O-9).

Sign in to keep reading

The rest of this module is free — sign in with Google to unlock it and track your progress.

Sign in & Register

Discussion

0

Join the discussion

Loading comments...

© 2026 Jatin Jain Saraf (JJS). All rights reserved.