Cloud Infrastructure · Cost Engineering
Billing Units and Why a Cloud Bill Is an Estimate
How usage records become invoice lines: instance-hours, the GB-month integral, minimum billing increments, and the order in which discounts are applied.
A cloud invoice is not a measurement of what a workload consumed. It is the output of applying a price list to a stream of usage records, and each of those records was produced by a meter attached to a resource rather than by anything that observed the application. The distinction matters because the two ends of that chain use different units, count different things, and round at different points. A workload can halve its work and see the bill move by a tenth, or keep its work constant and see the bill double, and neither result is a billing error.
Every meter reports a unit, not a quantity of work
A compute meter reports time during which an instance was allocated, in units of seconds or hours. It does not report CPU instructions retired, memory touched, or requests served. A storage meter reports the time-integral of bytes held. A request meter reports a count of operations by class. A network meter reports bytes crossing a named boundary in a named direction. Each of these is a proxy for work, and each proxy is chosen because it is cheap to measure at the hypervisor or the service front end.
Granularity is a separate decision from unit. Compute is commonly metered per second but billed with a minimum: a short-lived instance may be charged for a full minute even if it existed for four seconds. That minimum is not an accounting convenience. It exists because instance start and stop involve real work at the control plane, and a workload that creates and destroys instances thousands of times per hour would otherwise consume scheduling capacity without contributing revenue. The practical consequence is a floor on the cost of any instance, which changes the shape of the cost curve for bursty workloads: below the minimum interval, cost is proportional to the number of instance starts rather than to their duration.
Storage meters work differently, because the quantity being measured is a stock rather than a flow. A provider does not know how many bytes were stored; it knows how many bytes were stored at each moment it sampled, and it integrates. This is why storage billing is expressed in GB-months and why the number is fractional. A volume of 100 GB that exists for the first fifteen days of a 30-day month and is then deleted does not consume 100 GB-months. It consumes the area under the curve, divided by the width of the month.
The GB-month is an integral, and the month is a convention
The arithmetic follows from the definition. Storage cost equals the integral of bytes over time, scaled by a price per byte per unit time. Providers publish that price per GB-month, so the conversion factor is the number of hours the provider treats as one month. The average calendar month is 730 hours: 365 days times 24 hours divided by 12. Using 730 makes the annual total exact and makes every month identical for billing purposes, at the cost of a discrepancy of a few percent against February or July.
Writing the computation out makes the rounding visible:
HOURS_PER_MONTH = 730.0
def gb_months(samples):
"""samples: ascending list of (hour_index, gigabytes_held)."""
area = 0.0
for (t0, gb), (t1, _) in zip(samples, samples[1:]):
area += gb * (t1 - t0) # step function: value holds until next sample
return area / HOURS_PER_MONTH
# 100 GB held for 360 hours, then deleted
print(round(gb_months([(0, 100.0), (360, 0.0)]), 2)) # 49.32
The step-function assumption is the first place an estimate diverges from reality. Bytes usually arrive continuously, and sampling every hour underestimates a spike that begins and ends between samples. Providers that bill on a per-second or per-minute average narrow that window, but never close it. The second divergence is the deletion at hour 360: the sample at 360 reports zero, and the interval before it is charged in full, so a deletion that happens just after a sample is charged for the whole preceding interval. The error is bounded by one sampling interval and is always in the provider’s favour.
Discounts are applied after usage is priced
An invoice is not the sum of usage records multiplied by list prices. The order of operations runs roughly: usage is priced at list, commitment instruments are matched against eligible usage and replace the list price with a discounted one, credits and free-tier allowances are subtracted, and tax is applied to the remainder. Each step can only be reconstructed with the rules that governed it at the time, which is why an invoice total generally cannot be recomputed from the exported usage records alone.
Two properties of that sequence produce most of the confusion in cost analysis. First, discounts attach to usage rather than to resources, so the effective price of a specific instance depends on what else ran in the account during the same hour. Second, allowances are usually consumed in a fixed order, so the marginal cost of the first unit of a service in a month is zero and the marginal cost of the ten-thousandth is list price. An average price computed across the month therefore describes the past and not the next decision, a gap that becomes acute when capacity is added incrementally. The distinction between average and marginal price is treated at length in allocating shared cost to a unit of work.
Tiered pricing adds a second nonlinearity. When a service prices the first tranche of usage differently from later tranches, the bill is a piecewise-linear function of the quantity, and the marginal price at the current operating point is what matters for a decision to add or remove load. Reports that show only totals hide the operating point entirely.
Why the number on the dashboard is an estimate
Three mechanisms keep a running cost estimate from matching the eventual invoice.
The first is lag. Usage records are emitted by many independent services, and the aggregate is assembled as they arrive. A resource created in the last hours of a period may be billed in the next one. Cost dashboards that sum records therefore under-report recent activity, and the gap grows with the rate of change in the account. A cost figure is most trustworthy exactly when nothing is changing, which is when it is least useful.
The second is unmeasured dimensions. Egress bytes, request counts, and cross-zone transfers are metered at boundaries that a workload does not see. An application that issues one request and receives a large response is charged for the response bytes, and an application that reads from a replicated store may be charged for inter-zone traffic it never explicitly initiated. These appear in the invoice as separate line items, and they are the usual explanation for a bill that exceeds a resource-based estimate. The structure of those boundaries is the subject of egress boundaries and which bytes are billed.
The third is that prices are not constant. List prices change, regional prices differ, and the discount instruments in force during a period may not be the ones in force when the estimate was produced. An estimate computed from a stored price table drifts silently.
What the model implies for forecasting
Because the units are allocations and integrals rather than work performed, a cost forecast is a forecast about provisioning decisions and traffic volume, not about efficiency. The two inputs that dominate are the number and size of resources held over time, and the volume of billable traffic crossing metered boundaries. Both are step functions with long plateaus, which is why cost responds slowly to changes in application behaviour and immediately to changes in configuration.
This also sets the limit of what any cost model can claim. A model that reproduces last month’s invoice to within a few percent has demonstrated that its price table and its usage extraction are consistent with the provider’s; it has not demonstrated that the underlying attribution is meaningful. Attribution error and pricing error look identical in a total, and separating them requires reconciling at the level of individual line items, where minimum increments and minimum storage durations are visible as their own charges. Those durations are the subject of storage lifecycle transitions and minimum durations, and they are a common source of a bill that exceeds the naive per-gigabyte calculation.
References
- The Datacenter as a Computer: An Introduction to the Design of Warehouse-Scale Machines — Barroso and Hoelzle, Morgan and Claypool
- The Cost of a Cloud: Research Problems in Data Center Networks — Greenberg, Hamilton, Jain, and Kandula, ACM SIGCOMM Computer Communication Review 2009
- Amazon S3 pricing — Amazon Web Services