Part 5: Demystifying Savings Plans
Breaking down Purchasing and Amortization
My name is Christopher Harris, and I am a maintainer on the FinOps FOCUS project. I’ve built cost management products at Datadog and CloudHealth (Broadcom) over the past 8 years, and I’m excited to share some of what I have learned with you.
Savings Plans offer incredible discounts (up to 72%!) in return for contractually obligated spending over a 1-year or 3-year term. AWS introduced Savings Plans in 2019 to help customers flexibly manage commitments across aggregate spend as an alternative to Reserved Instances that match against granular resources or operations.
AWS offers 3 types of Savings Plans across different services:
- Compute Savings Plan (≤ 66% savings) covering EC2, Fargate (ECS, EKS), Lambda
- EC2 Savings Plan (≤ 72% savings)
- SageMaker (≤ 64% savings)
Purchasing
To begin, customers must select a term, hourly commitment, and payment option to purchase a Savings Plan.
Term
A Savings Plan term spans either 1 year (8,760 hours or 31,536,000 seconds) or 3 years (26,280 hours or 94,608,000 seconds). Each second of a Savings Plan can match an eligible resource or set of operations within a term.
Hourly Commitment
An hourly commitment is a monetary value that a customer agrees to spend on eligible services for each term-hour. Additionally, EC2 savings plans also require an Instance Family (i.e. r6, m5, etc.) and a Region (i.e. us-east-1, etc.).
Payment Option
Lastly, Savings Plans require a selecting a payment option that defines whether AWS receives payment before and/or during the term:
- All Upfront: Pay now (# of term hours * hourly commitment)
- Partial Upfront: Pay 1/2 now (0.5 * # of term hours * hourly commitment)
- No Upfront: Pay nothing now.
Amortization
For the rest of this article, we’ll consider an AWS account with 1 Compute Savings Plan (1 year, Partial Upfront, $0.269 Hourly Commitment) and 1 EC2 VM Instance (m5.2xlarge, us-east-1, Linux/Unix)
There is never an inherent link between a specific Savings Plan and a specific resource or set of operations. AWS applies a bin-packing heuristic that matches against eligible, running infrastructure to guarantee the most efficient utilization of commitments on the customer’s behalf.
Savings Plans
Customers wanting to apply a Savings Plan to cover the entire cost of this EC2 VM instance can commit to 1 Compute Savings Plan for the total discounted cost. This means that if a customer wants to perfectly match this EC2 VM instance’s cost with 1 Savings Plan, they need to commit to the hourly discounted rate when purchasing.
For example, while this EC2 VM instance’s on-demand rate is $0.384, a customer purchasing this Compute Savings Plan to fully cover this instance needs to commit to the discounted rate, $0.269 per hour.
The annual total cost of this Compute Saving Plan with an hourly commitment of $0.269 is $2,356.44 ($0.269 per hour * 8,760 hours).
After a Savings Plan is purchased, AWS distributes the Savings Plan’s pre-committed upfront and/or recurring fees across each second of an eligible, running EC2 instance over the Saving Plan’s term. This is amortization. If the hourly commitment is not fully utilized, the Savings Plan can be further applied to additional, eligible, and running resources.
In the example below, the left side of the vertical line shows a list of committed spend per hour for all 8,760 hours of our Compute Savings. The right side of the line shows how our 1 EC2 VM instance was amortized across various instance states: running → green, stopped → orange, terminated → red.
For each hour, here’s what happened:
- Hours 1–3 → 1 EC2 VM ran and amortized 3 SP hours ($0.807).
- Hours 4–6 → 1 EC2 VM was stopped and 3 SP hours were wasted ($0.807).
- Hours 7–8 → 1 EC2 VM ran and amortized 2 SP hours ($0.538).
- Hours 9–8756 → (not shown) 1 EC2 VM ran and amortized 8,748 SP hours ($2353.212).
- Hour 8,757–8,758 → 1 EC2 VM ran and amortized 2 SP hours ($0.538).
- Hours 8,759–8,760 → 1 EC2 VM was terminated and 2 SP hours were wasted ($0.538).
As a result, our Compute Savings Plan amortized 8,755 of 8,760 hours resulting in a 99.94% utilization rate, 29.91% savings against its on-demand rate, and $1.345 accrued waste.
Compute Savings Plan Total Cost: ($0.269/hour * 8,760 running hours) = $2356.44
On-Demand Cost: $0.384 per hour * 8,755 running hours = $3361.92
Utilization Rate:
8,755 (fully) utilized hours / 8,760 committed hours * 100 = 99.94%
Total Savings: (1 - $2356.44 / $3361.92) * 100 = 29.91%
Accrued Waste: $0.269 * 5 hours = $1.345
Amortization within the CUR
There are 4 Charge Types (lineItem/LineItemType) associated with Savings Plans within the CUR:
- SavingsPlanUpfrontFee → The amount paid upfront at the beginning of the Savings Plan’s term for All Upfront or Partial Upfront Savings Plan.
- SavingsPlanRecurringFee → The amount paid monthly across the Savings Plan’s term ($0 for an All Upfront Savings Plan).
- SavingsPlanCoveredUsage → The amortized, discounted rate applied to an eligible resource or operation during the usage period.
- SavingsPlanNegation → The product SKU adjustment that cancels out on-demand, accrual costs.
Below is the same diagram as above, but with red and blue annotations denoting how each Savings Plan charge type applies to either Purchasing or Usage, respectively.
SavingsPlanUpfrontFee
Since the Compute Savings Plan chosen is configured with a Partial Upfront payment option, a single SavingsPlanUpfrontFee row is created at the beginning of the Savings Plan’s term.
Below is an abbreviated CUR showing 1 row at the time of purchase for half (Partial Upfront) of the committed amount across the 1-year term.
+-------------------------+-------------------------+------------------------+-------------------------------------------------------+
| lineItem/UsageStartDate | lineItem/LineItemType | lineItem/UnblendedCost | savingsPlan/SavingsPlanARN |
+-------------------------+-------------------------+------------------------+-------------------------------------------------------+
| 20230101T00:00:00Z | SavingsPlanUpfrontFee | 1178.22 | arn:aws:savingsplans::123456789101:savingsplan/abc123 |
+-------------------------+-------------------------+------------------------+-------------------------------------------------------+
$0.269 per hour * 8760 hours * 0.5 = $1178.22
SavingsPlanRecurringFee
All yellow boxes within the red annotation in the above diagram represent the Savings Plan’s unutilized spending. The CUR tracks the Savings Plan’s utilization under a row with a SavingsPlanRecurringFee charge type, and this row repeats at the selected CUR granularity (i.e. hourly, daily, monthly).
The abbreviated CUR below shows the Savings Plan’s utilization at the hourly granularity for all hours shown in the diagram above. Wasted hours show a $0 savingsPlan/UsedCommitment of a $0.269 potential amortized commitment for each hour while fully utilized hours show $0.269 under savingsPlan/UsedCommitment.
+-------------------------+-------------------------+----------------------------+-----------------------------------+-------------------------------------------------------+
| lineItem/UsageStartDate | lineItem/LineItemType | savingsPlan/UsedCommitment | savingsPlan/TotalCommitmentToDate | savingsPlan/SavingsPlanARN |
+-------------------------+-------------------------+----------------------------+-----------------------------------+-------------------------------------------------------+
| 20230101T00:00:00Z | SavingsPlanRecurringFee | 0.269 | 0.269 | arn:aws:savingsplans::123456789101:savingsplan/abc123 |
| 20230101T01:00:00Z | SavingsPlanRecurringFee | 0.269 | 0.269 | arn:aws:savingsplans::123456789101:savingsplan/abc123 |
| 20230101T02:00:00Z | SavingsPlanRecurringFee | 0.269 | 0.269 | arn:aws:savingsplans::123456789101:savingsplan/abc123 |
| 20230101T03:00:00Z | SavingsPlanRecurringFee | 0.0 | 0.269 | arn:aws:savingsplans::123456789101:savingsplan/abc123 |
| 20230101T04:00:00Z | SavingsPlanRecurringFee | 0.0 | 0.269 | arn:aws:savingsplans::123456789101:savingsplan/abc123 |
| 20230101T05:00:00Z | SavingsPlanRecurringFee | 0.0 | 0.269 | arn:aws:savingsplans::123456789101:savingsplan/abc123 |
| 20230101T06:00:00Z | SavingsPlanRecurringFee | 0.269 | 0.269 | arn:aws:savingsplans::123456789101:savingsplan/abc123 |
| 20230101T07:00:00Z | SavingsPlanRecurringFee | 0.269 | 0.269 | arn:aws:savingsplans::123456789101:savingsplan/abc123 |
| ... <8,748 hours> ... | SavingsPlanRecurringFee | 2353.212 | 2353.212 | arn:aws:savingsplans::123456789101:savingsplan/abc123 |
| 20231231T08:00:00Z | SavingsPlanRecurringFee | 0.269 | 0.269 | arn:aws:savingsplans::123456789101:savingsplan/abc123 |
| 20231231T09:00:00Z | SavingsPlanRecurringFee | 0.269 | 0.269 | arn:aws:savingsplans::123456789101:savingsplan/abc123 |
| 20231231T10:00:00Z | SavingsPlanRecurringFee | 0.0 | 0.269 | arn:aws:savingsplans::123456789101:savingsplan/abc123 |
| 20231231T11:00:00Z | SavingsPlanRecurringFee | 0.0 | 0.269 | arn:aws:savingsplans::123456789101:savingsplan/abc123 |
+-------------------------+-------------------------+----------------------------+-----------------------------------+-------------------------------------------------------+
Jan 1 03:00-05:00: $200.136 - $199.329 = $0.807 SP hourly commitment wasted
...
Dec 31 10:00-11:00: $200.136 - $199.598 = $0.538 SP hourly commitment wasted
Total Commitment Wasted: $0.807 + $0.538 = $1.345
Total Commitment Used: $2,356.44 - $1.345 = $2,355.095
Commitment Utilization: $2,355.095 / $2,356.44 * 100 = 99.94%
A Savings Plan’s utilization can be queried as (Athena):
SELECT
YEAR(bill_billing_period_start_date) AS year,
MONTH(bill_billing_period_start_date) AS month,
(
SUM(savings_plan_used_commitment) /
SUM(savings_plan_total_commitment_to_date) * 100
) AS utilization_rate
FROM
<cur>
WHERE
line_item_line_item_type = 'SavingsPlanRecurringFee'
GROUP BY
1,2
ORDER BY
1,2
SavingsPlanCoveredUsage & SavingsPlanNegation
All green boxes within the blue annotation denote where the Compute Savings Plan is amortized across the running EC2 VM instance. Instead of paying the on-demand rate of $0.384 per hour, the discounted rate ($0.269 per hour) from the Compute Savings Plan is amortized for each hour and the customer effectively saves 29.91% off the list price.
When calculating the (net) amortized cost for a SavingsPlanCoveredUsage charge type, the savingsPlan/EffectiveCost (or savingsPlan/NetEffectiveCost) is used instead of the lineItem/UnblendedCost (or lineItem/NetUnblendedCost).
For more information, see my first article around calculating cost measures.
While the accrued cost (lineItem/UnblendedCost or lineItem/NetUnblendedCost) is provided so customers can determine how much was saved hourly, this value double-counts the accrual cost for all Savings Plans’ amortization. To mitigate this issue, AWS also provides a SavingsPlanNegation charge type to offset this cost.
The abbreviated CUR below shows how each charge type is represented. Unlike SavingsPlanRecurringFee rows, SavingsPlanCoveredUsage and SavingsPlanNegation rows only exist when amortization occurs.
+-------------------------+-------------------------+----------------------------+-----------------------------------+-------------------------------------------------------+
| lineItem/UsageStartDate | lineItem/LineItemType | lineItem/UnblendedCost | savingsPlan/EffectiveCost | savingsPlan/SavingsPlanARN |
+-------------------------+-------------------------+----------------------------+-----------------------------------+-------------------------------------------------------+
| 20230101T00:00:00Z | SavingsPlanCoveredUsage | 0.384 | 0.269 | arn:aws:savingsplans::123456789101:savingsplan/abc123 |
| 20230101T00:00:00Z | SavingsPlanNegation | -0.384 | 0.0 | arn:aws:savingsplans::123456789101:savingsplan/abc123 |
| 20230101T01:00:00Z | SavingsPlanCoveredUsage | 0.384 | 0.269 | arn:aws:savingsplans::123456789101:savingsplan/abc123 |
| 20230101T01:00:00Z | SavingsPlanNegation | -0.384 | 0.0 | arn:aws:savingsplans::123456789101:savingsplan/abc123 |
| 20230101T02:00:00Z | SavingsPlanCoveredUsage | 0.384 | 0.269 | arn:aws:savingsplans::123456789101:savingsplan/abc123 |
| 20230101T02:00:00Z | SavingsPlanNegation | -0.384 | 0.0 | arn:aws:savingsplans::123456789101:savingsplan/abc123 |
| 20230101T06:00:00Z | SavingsPlanCoveredUsage | 0.384 | 0.269 | arn:aws:savingsplans::123456789101:savingsplan/abc123 |
| 20230101T06:00:00Z | SavingsPlanNegation | -0.384 | 0.0 | arn:aws:savingsplans::123456789101:savingsplan/abc123 |
| 20230101T07:00:00Z | SavingsPlanCoveredUsage | 0.384 | 0.269 | arn:aws:savingsplans::123456789101:savingsplan/abc123 |
| 20230101T07:00:00Z | SavingsPlanNegation | -0.384 | 0.0 | arn:aws:savingsplans::123456789101:savingsplan/abc123 |
| ... 8,748 hours ... | SavingsPlanCoveredUsage | 3359.232 | 2353.212 | arn:aws:savingsplans::123456789101:savingsplan/abc123 |
| ... 8,748 hours ... | SavingsPlanNegation | -3359.232 | 0.0 | arn:aws:savingsplans::123456789101:savingsplan/abc123 |
| 20231231T08:00:00Z | SavingsPlanCoveredUsage | 0.384 | 0.269 | arn:aws:savingsplans::123456789101:savingsplan/abc123 |
| 20231231T08:00:00Z | SavingsPlanNegation | -0.384 | 0.0 | arn:aws:savingsplans::123456789101:savingsplan/abc123 |
| 20231231T09:00:00Z | SavingsPlanCoveredUsage | 0.384 | 0.269 | arn:aws:savingsplans::123456789101:savingsplan/abc123 |
| 20231231T09:00:00Z | SavingsPlanNegation | -0.384 | 0.0 | arn:aws:savingsplans::123456789101:savingsplan/abc123 |
+-------------------------+-------------------------+----------------------------+-----------------------------------+-------------------------------------------------------+
8,760 hours 0.0 2355.095
Hopefully, this article clarifies some of the complexities Savings Plans are purchased and amortized within the CUR. Please feel free to comment with any questions or for additional clarification.
Check out my other stories about Understanding the AWS CUR.