The Bill Is a Table Too

The cost model of the bookshop's lakehouse, populated from the lab's own request and byte counts: what a commit costs, what a streaming writer costs a day, what compaction buys back, what the metadata file costs the catalog per load, and what the unreferenced files cost until they are cleaned. Then the operating model that owns each line, and the production review that puts the whole book on one page.

Chapter 2 counted the requests behind every operation on a one-table bookshop. Chapter 11 measured a streaming writer committing every five seconds. Put the two together.

  one commit (ch2):       7 requests   (1 PUT data, 2 PUT metadata, 2 GET metadata, 2 HEAD)
  one day at 5 s (ch11):  17,280 commits  x  7  =  120,960 requests, before a single query runs
  of which PUTs:          51,840   (priced at roughly ten times a GET)
  files left behind:      51,840 data files, 17,280 manifests, 17,280 manifest lists, 17,280 metadata files

That is the writer’s bill, per table, per day, on an idle platform — and none of it is a query. The same calculation connects the other measurements to a budget: multiply an operation’s footprint by how often the platform runs it, then apply the store’s price. The prices in this chapter are the published list prices of one large object store at the time of writing, and they are labelled as such. The book did not run against it. The counts are the lab’s, and they are the part that transfers.

Those costs need owners as well as estimates. The eight-line model below connects each expense to a measurement and a decision; the production review then checks who owns that decision and what evidence supports it.

The eight lines

LineWhat it countsWhere the number comes from
storagebytes on the store, referenced and notch9’s 171 MB of metadata copies; ch15’s twice-the-rows prefix
requestsPUT, GET, LIST, DELETE per operationch2’s table; ch8’s compaction; ch11’s commit rate
maintenance computeengine time for rewrites, expiry, cleanupch8’s seconds per rewrite; ch13’s pack at a second per table
query computeengine time per querych6’s medians; ch9’s planning share
transferbytes leaving the store’s regionthe load-table payload, times engines; replication, ch16
catalog servicerequests to the catalog and its payloadch9’s 560 KB per load; ch15’s forty-seven log lines per session
observabilitythe pack, the health table, the logsch13’s hourly pass
engineering timethe runbooks, the drills, the reviewsch14’s eight runbooks; ch16’s game day

The measurements below fill the model where the lab supplies a count or duration. Engineering time remains an explicit, unmeasured line.

Requests: the commit is the unit

Chapter 2’s table gave a one-row insert a fixed footprint of seven requests and a fifty-thousand-row insert thirteen. The cost of writing is the number of commits — not the number of rows. Chapter 11’s streaming writer is therefore the most expensive thing on the platform per byte, and the checkpoint interval is its price control.

Checkpoint intervalCommits per dayRequests per dayPUTs per dayFiles created per day
5 s17,280120,96051,84051,840 data + 51,840 metadata
30 s2,88020,1608,64017,280
5 min2882,0168641,728

At the published prices, PUTs at five thousandths of a cent per thousand and GETs at four ten-thousandths, the five-second row is about thirty cents a day in requests. The number that matters is not the thirty cents. It is the fifty-one thousand files, each of which every query has to open until chapter 8’s compaction folds them, and each of which chapter 9’s manifests reference until expiry. A writer at five seconds has to be paired with maintenance at chapter 11’s schedule — or the request bill moves from the writer to every reader.

Requests: what compaction buys back

Chapter 8’s numbers, on the streaming-shaped table.

  before compaction:  customer query 450 GETs, 2.4 MB;   day query 15 GETs
  compaction:         150 -> 30 files, 8.5 MB written, 30 PUTs, 1.0 s
  after:              customer query 100 GETs, 7.6 MB;   day query 3 GETs

The rewrite cost thirty PUTs and 8.5 MB of transfer within the region. Every customer query after it saves 350 GETs, every day query saves twelve. At the published prices the rewrite’s thirty PUTs cost about what one customer query’s 350 GETs cost, so in requests alone it pays for itself after the first query that follows it. The first draft of this sentence said two hundred queries; the cost model in the companion, run with the same numbers, said one — and the model was right. The byte column went the other way, tripling per customer query, and on a store that prices egress the calculation has a second term. Chapter 8’s return-on-cost rule is this arithmetic with the platform’s own query rate in it. A compaction that does not pay back inside its own schedule interval is scheduled too often.

Storage: the bytes nobody references

The storage bill includes objects a query never counts: old metadata copies, replaced data files and files retained by holds. These measurements put a size on each source.

  ch9:   601 metadata files, 171 MB, for a table whose data is under 1 MB;  500 of them orphans after retention was set
  ch15:  the curated orders prefix holds 120,150 rows of files for a 60,075-row table
  ch10:  a tag doubles a table's data storage through one compaction

Storage on a lakehouse is data, plus history, plus orphans, plus holds — and only the first is what a SELECT count(*) describes. The published storage price is a little over two cents per gigabyte-month. That makes none of this expensive at the bookshop’s size, and all of it expensive at a thousand times the bookshop, where the metadata-copy line alone is the size of a small table per table. The lines are bounded by chapter 10’s retention, chapter 9’s delete-after-commit, and chapter 14’s orphan cleanup. The health pack’s store-minus-metadata check is how the model knows what it is paying for.

Catalog service: the payload per load

Chapter 9 measured the load-table response at 560 KB for a table with six hundred snapshots and 12 KB after expiry. Chapter 15 measured one Spark session’s read as forty-seven catalog requests. Chapter 13’s pack makes nineteen metadata queries per table per pass.

  40 engines and dashboards x 1 load/minute x 560 KB  =  32 GB/day of catalog egress for one unexpired table
  the same table after expiry:                            0.7 GB/day
  the health pack, hourly, 1,000 tables:                  19,000 catalog requests/hour

A managed catalog prices requests and, sometimes, egress; a self-hosted one prices the machine and, chapter 3 found, the database behind it. Either way the payload is the lever, and the payload is the snapshot count — which is chapter 10’s retention policy expressed in bytes.

Compute: maintenance and queries

The maintenance compute line is the sum of the schedules. Chapter 8’s rewrites at a second per streaming-shaped table. Chapter 9’s manifest rewrites, chapter 10’s expiry, chapter 14’s cleanup. Chapter 13’s pack at a second per table per hour. On the bookshop’s few hundred tables it is minutes of one engine per hour. The query compute line is chapter 6’s and chapter 7’s medians times the query rate. The only thing this book can say about it in general is chapter 9’s finding: a query’s planning share is fixed by the manifest count and its execution share by the file count, so both maintenance lines reduce it.

Transfer: replication is a read of everything

Chapter 16 replicated 570 objects and 5.6 MB in 2.8 seconds. A replica region reads every byte the primary writes, once, plus every byte replication re-copies. For a copy that runs metadata-first that is nothing; for one that runs data-first it is the validation’s re-copy. At the published inter-region transfer price, two cents a gigabyte, the bookshop’s replica is cents a day. A platform’s is the same fraction of its write volume, and the write volume is the streaming writers’ fifty thousand files a day times their size.

The operating model: who owns each line

LineOwnerDecidesReviews with
requeststhe writer’s teamcheckpoint interval (ch11), commit batchingthe platform team, from ch13’s commit cadence
maintenancethe platform teamch8–10 schedules, ch11’s per-class schedulethe fleet score (ch8)
storagethe platform teamretention classes (ch10), cleanup (ch14)the store-minus-metadata check (ch13)
catalogthe platform teamretention, delete-after-commit (ch9), vending (ch15)load-table size per table
query computethe consumerslayout requests to the platform (ch6, ch7)interleaved medians
transferthe platform teamreplication order and interval (ch16)the game-day drill
observabilitythe platform teamthe pack, the rules, the classes (ch13)rule accuracy over the health table
engineering timeeveryonethe runbooks (ch14), the drills (ch16), this reviewthe post-incident list

The ownership rule is the one chapter 13 found for alerts: a line is owned by whoever can change the number. The writer’s team owns requests because they own the checkpoint interval. The platform owns storage because it owns retention. A line with two owners is a line nobody reduces.

The production review

The production review fits on one page per platform. Each row links a decision to its evidence and the artifact that implements it, so the review can distinguish an operating policy from an intention.

DecisionChapterArtifactStatus for the bookshop
object store: conditional writes, request pricing understood2the request tableSeaweedFS; ch2’s table
catalog: which, and what it refuses3the catalog decision recordPolaris, Postgres-backed; the fixture retired (ch8, ch11)
conflict classes and isolation levels per table4the conflict matrixserializable on orders; snapshot on events
engine certification5the generated matrix90 cells; PyIceberg on v3 views flagged
table design per workload6, 7the worksheet; the skew SQLorders bucketed by customer (ch7)
compaction policy8the decision tree; the fleet scorebinpack, scoped, partial progress; by checkpoint count for upserts
metadata and statistics9the planning-latency probemanifest cache on; stats for Trino
retention classes10the policy templatehot / audit / dev
streaming tables11the schedule; the runbook5 s checkpoints on events; savepoints single-use
change data12the convergence testlanding + curated per source
table health13the SQL pack; the health tablehourly; classes declared
incidents14eight runbooksrehearsed on the lab
authorisation15the policy test suitevending everywhere; Trino behind access control
disaster recovery16the game-day scriptcold replica catalog; metadata-first replication
managed or not17the operating-model matrixself-hosted, reviewed yearly
cost18this modelthe eight lines, populated

Launch approval is every row having an artifact that exists, a status that was measured rather than asserted, and an owner from the table above. The bookshop’s page has one open row — chapter 5’s Kafka Connect sink — and one row that is judgment rather than measurement, chapter 17’s. A platform is ready when its page reads like that: every number traceable to a run, every gap named.

SLOs, from the numbers

The service levels the review commits to, each one a metric chapter 13’s pack or a writer’s dashboard already produces.

SLOTargetSource
freshness, streaming tablescheckpoint interval + 1ch11, ch13
convergence time, change dataone checkpointch12’s test
commit successevery checkpoint completes; restores countedch11’s REST counts
planning latencymetadata requests per query flatch9’s probe
load-table payloadunder 64 KB per tablech9, ch13
files per partitionunder a threshold set from the fleet’s p90ch13
recovery timeregistration loop under an hour for the fleetch16’s 50 ms per table
recovery pointthe replication intervalch16

What was not run

Every price in this chapter is a published list price for one store, not a measured bill, and the book says so at each use. Engineering time was not measured at all — it is the line the review exists to make visible. And the query-rate multipliers are the bookshop’s assumptions, which is the one input the model cannot take from the lab.

Exercises

1. Price your writers. For each streaming table, take its checkpoint interval from the snapshot cadence in the health table. Compute commits, requests and files per day with the seven-request footprint. Sort by files per day.

Show answer

The top of the list is the table whose compaction schedule matters most, and usually the one whose checkpoint interval was set for latency nobody asked for. Doubling its interval halves every number in the row and costs the consumer the same seconds of freshness, which chapter 13’s freshness SLO will say whether anyone notices.

2. Price your history. For each table, take the metadata-file size from the health table and multiply by the number of engines that load it per day.

Show answer

The largest product is the table whose retention class is wrong, not the table with the most data. Expiry on that one table changes the catalog line more than any other single action, and the health table records the size before and after.

Final thoughts

The bill turned out to be a table like any other. Eight rows, each one a number this book had already measured, multiplied by a rate the platform chooses and a price the store publishes. The writer’s checkpoint interval was the largest lever and the least visible one. The metadata file was the second. The storage that the table does not count was the line that no query ever showed. Each has an owner, because each has exactly one number that changes it.

The appendix is the format’s next version, as it stood when this edition was written, and which of its promises the pinned release already keeps.

Next: Appendix A: Version Four Is a Number, Not a Format

Comments