If you look across the vast landscape of AWS services through a lens of billing, a pattern begins to emerge.
There are of course the usual collection of billing jokes. You’re not charged for what you use, but for what you forget to turn off. Your AWS bill is a function of how many engineers you have, not how many customers you have.
But those are all customer experiences. For our purposes, let’s take a look at it from how AWS itself approaches setting pricing—and upon which dimensions they base their at times ridiculous pricing.
As Patrick “patio11” McKenzie once observed, “metered pricing is none of predictable, transparent, or fair“. Let’s dive in…
Virtually everything AWS will ever charge you for is on an axis of time.
No matter what the unit is, you’ll be charged for it over the course of a given duration. On one extreme, we have per-millisecond charges for Lambda functions. On the other, there are three year savings plan/reserved instance commitments.
Occasionally, contracts will stretch beyond this, as we discovered in our early days of AWS contract negotiation. But I can’t find a single item in the AWS billing universe that is a flat rate, “buy it once and own it forever” story other than physical devices (e.g., Deeps Composer/Racer/Lens, Storage Gateways, etc.), which themselves are tied to recurring monthly billing items.
This makes sense. The consumption-based billing model dictates that you don’t buy things once and then never pay again. Our staff works on the same principle; we don’t cut engineers a multi-million dollar check in return for a commitment to work at a company for the rest of their lives.
This is a pretty straightforward dimension. Combined with time, it encapsulates basically every storage service (or storage aspect of other services; DynamoDB, for example), ranging from tiny objects consisting of a few bytes all the way up to “GB/month stored on a Snowmobile.” This is invariably charged per-GB, which is a small blessing; we don’t have to do unit conversions to get to cost equivalence between services.
Of course, exactly where the 1000 vs. 1024 breakdown hits is a subject of some debate…
We also see aspects of this in terms of RAM. That’s often used as a quite reasonable dimension for things like Lambdas function or an aspect of how an EC2 instance is defined and sold.
There are some fascinating edge cases throughout the AWS billing universe.
One is Elastic MapReduce, or “EMR.” They charge a per-instance fee that varies on instance size. But they also make you pay the usual fee for the EC2 instance as well.
This has the function of making EMR clusters fantastically expensive compared to most other options; you’re paying for a job orchestrator to manage Hadoop in a way that scales with the size of your clusters. Obviously, people are paying this. But rarely are they doing so happily.
ECS takes a similar design pattern: EC2 instances under the ECS management layer. But in that scenario, ECS doesn’t charge you anything at all; it’s enough for that service to drive the adoption of other services.
The completely nuts
Sometimes, AWS’s approach to billing completely falls down well beyond what a human can fit in their head.
Take Elastic Load Balancer pricing as a prime example of this. You’re charged per load balancer hour (which makes sense) as well as per LCU-hour, which makes no sense whatsoever. An LCU, or “load balancer capacity unit” is the highest of four dimensions averaged over an hour. Those four dimensions are the number of new connections per second, the number of active connections per minute, the number of bytes processed in gigabytes, and the number of rule evaluations.
This, of course, means the answer to “how much will a load balancer cost me” is “nobody has any idea until you run your workload through one then blindly accept whatever AWS tells you.” This is rather obviously suboptimal.
A bunch of services—such as Kinesis, DynamoDB, Aurora, and more—like to charge based upon some underlying implementation measurement. Think “every 4K counts as a write” or “charging per IO operation without being clear on what counts as a single op.”
This is the only way that Timestream charges, which means you won’t have any idea what it costs to use the service until you try it out. This is exceedingly dicey for students looking to experiment with new services. “Am I about to wind up indebted for the next decade to a trillion-dollar company?” is a fair thing to be wary of.
There’s the “we hope you forgot about it” billing model, such as “try out an Amazon Workspace for a few days, decide it’s not for you, and fail to realize that you’ll be paying for an AWS Directory in perpetuity until you find it and shut it down” approach.
There’s also the “per connection hour as well as per subnet connected” approach that the AWS Client VPN takes.
And who can forget the surprise factor of “charge per gigabyte scanned with no way to determine in advance how large what you’re scanning is” approach favored by Cloudwatch Logs Insights?
When’s the last time you calculated out how many lines of code were in a pull request? If you’re puzzled by that question, you clearly aren’t using Amazon Code Guru because of course that’s how it charges you.
And I’ve already covered in some detail just how arcane data transfer pricing really is.
Fundamentally, the problem with most of these isn’t that the pricing model is inherently unfair; it’s that there’s no way to predict in advance just how much one of these services is going to cost you until after you test it to find out—occasionally to your own detriment. AWS has a legitimate interest here in ensuring that people aren’t abusing edge cases or corner cases of billing to game their system for free services. Regrettably, that interest is protected by some absolutely byzantine billing models.
Unfortunately, until AWS takes drastic measures to improve the billing experience for customers, this painful experience is going to continue to resonate with us all.
If you’re struggling to make sense of your AWS bill, give us a shout and we’ll help make the experience painless.