Choosing a DynamoDB Capacity Mode

    By Jamie Kelly, Head of AWS Technology - UK

    Jamie Kelly

    In this blog post, I’m going to look at DynamoDB capacity modes and when you might choose one over the other. To start, I’ll introduce DynamoDB at a high level, then I’ll go through the two capacity modes and how they work, before finishing off with a few worked examples to give you an idea of how the bill would look in various situations.

    what is dynamodb?

    Taking the headline description straight from the AWS DynamoDB Landing Page, DynamoDB is marketed as:

    A fast, flexible NoSQL database service for single-digit millisecond performance at any scale.

    Let's break that down into a few constituent parts:

    • Fast: It can serve requests as fast as a few milliseconds (and if you use DynamoDB Accelerator, microseconds).
    • Flexible NoSQL: It's a NoSQL database which can provide flexibility of design. To be clear, this doesn't mean you don't have to design how you use it, but that's a post for another day.
    • Database Service: It's a managed service offered by AWS. No servers to manage, no administration, no patching, etc.
    • Performance At Any Scale: Fast is great. But if your database is going to slow down the bigger it gets, you'll have problems. Thankfully, the design of DynamoDB avoids this. It's rapid at any scale and can actually get faster as it grows.

    This is sounding pretty neat at this stage, so what does an item stored in DynamoDB look like? If you were to grab an item out of DynamoDB and expose it as JSON, it could look like this:

    {

        "Author": "John Grisham",

        "Title": "The Rainmaker",

        "Formats": {

            "Hardcover": "J4SUKVGU",

            "Paperback": "D7YF4FCX"

        },

        "Category": "Suspense"

    }

    DynamoDB Capacity Modes

    DynamoDB provides two capacity modes, each with its own pricing model:

    • Provisioned Capacity
    • On-Demand Capacity.

    The right mode for you will depend on the workload and access characteristics. We're going to dive into each of these modes and see how they are priced. The right mode is largely going to come down to how much it costs you to run. So let's go ahead and dig a little deeper into each of these modes and see how they are charged.

    Provisioned Capacity

    Provisioned Capacity is a reservation of throughput, measured in Write Capacity Units (WCUs) and Read Capacity Units (RCUs). These capacity units determine the number and size of requests that you can make on the table per second before the DynamoDB service will start to throttle access to that table. With Provisioned Capacity mode, you specify the capacity you want and get billed for that capacity. It's not a flat capacity though, you can set autoscaling rules that allow you to have the available reserved capacity dynamically changed, which can save you money if your workload is predictable enough for it to be viable. In this mode, you are billed by reserved WCUs and RCUs, so how are they calculated exactly?

    WCUs are the easier of the two to calculate, 1 WCU = 1 Write Request up to 1KB in size per second. For example:

    • 5 writes of 1KB per second = 5 WCUs
    • 5 writes of 2KB per second = 10 WCUs
    • 1 write of 5KB per second = 5 WCUs

    RCUs are a little bit more complex, due to there being three different types of read request that you can issue. DynamoDB is eventually consistent as a system, however, you can request a strongly consistent read or even a transactional read. These do, however, come with a pricing penalty, so you should really question whether or not you absolutely require anything more than eventual consistency — many workloads do not, in my experience. The breakdown of read request pricing is: 

    • 0.5 RCU = 1 Read Request up to 4KB in size per Second (Eventually Consistent)
    • 1 RCU = 1 Read Request up to 4KB in size per Second (Strongly Consistent)
    • 2 RCUs = 1 Read Request up to 4KB in size per Second (Transactional)

    If you have mixed usage of request types, this can make estimating your pricing a bit tricky, as you now have to estimate volume for each type of request to calculate your estimated cost. Now I’ll give a few examples, with a bit more detail for each this time. I'll use ‘chunk’ to refer to the number of 4KB sections of data charged for. Remember, this will always be rounded up, so 4KB = 1 chunk, 5KB = 2 chunks, 8KB = 2 chunks:

    • 6 eventually consistent reads of 4KB per second = 3 RCUs
        6 (reads per second) * 0.5 (eventually consistent) * 1 (chunk of data)
    • 6 eventually consistent reads of 1KB per second = 3 RCUs
        6 (reads per second) * 0.5 (eventually consistent) * 1 (chunk of data still)
    • 6 eventually consistent reads of 5KB per second = 6 RCUs
        6 (reads per second) * 0.5 (eventually consistent) * 2 (chunks of data, the first 4KB being chunk one, the final KB is rounded up as the next chunk)
    • 2 strongly consistent reads of 8KB per second = 4 RCUs
        2 (reads per second) * 1 (strongly consistent) * 2 (chunks of data)
    • 1 transactional read of 5KB per second = 4 RCUs
        1 (reads per second) * 2 (eventually consistent) * 2 (chunks of data)

    At this point in time, the provisioned capacity mode pricing in eu-west-2 (London) is $0.000772 per WCU per hour, and $0.0001544 per RCU per hour. We’ll be using these later for making our cost estimates.

    On-demand

    On-demand is the pay per request mode and it is measured in Write Request Units (WRUs) and Read Request Units (RRUs). These work in a similar fashion to WCUs and RCUs, but as there is no capacity to set, the pricing model deals in request units instead of capacity units. For the capacity side of the equation, DynamoDB will scale to whatever capacity you need as requests ramp up - the starting capacity is 2,000 WRUs per second and 6,000 RRUs per second. Unless you scale over double your currently assigned capacity in a short amount of time, you won't get throttled. As you're paying per request, you don't have to think about capacity scaling and AWS takes care of it for you automatically. In looking at how WRUs and RRUs are calculated, you might notice some similarities to the provisioned capacity units:

    • 1 WRU = 1 Write Request up to 1KB in size
    • 0.5 RRU = 1 Read Request up to 4KB in size (Eventually Consistent)
    • 1 RRU = 1 Read Request up to 4KB in size (Strongly Consistent)
    • 2 RRUs = 1 Read Request up to 4KB in size (Transactional)

    Taking a one second snapshot of the same examples used previously, some familiar numbers come up:

    • 6 eventually consistent reads of 4KB = 3 RRUs
    • 6 eventually consistent reads of 1KB = 3 RRUs
    • 6 eventually consistent reads of 5KB = 6 RRUs
    • 2 strongly consistent reads of 8KB = 4 RRUs
    • 1 transactional read of 5KB = 4 RRUs

    In On-demand mode, the "per-hour" aspect of the pricing that Provisioned Capacity uses no longer applies. Instead, it charges a flat amount per request and in eu-west-2 (London) that comes in at $0.0000014846 per WRU and $0.000000297 per RRU. These unit rates are lower than the WCU and RCU costs, but it's important to remember that those are per hour. In an hour, if we were maxing out 1WCU and 1 RCU, we'd have made:

    `60 * 60 = 3,600` read and write requests each

    So how do they stack up? As mentioned earlier, that depends on your workload!

    Worked Examples

    So we have some details on how the two modes charge, both in the units used and the cost per unit, but how might that come out in a cost comparison across different hypothetical workloads? Let's explore two different examples and see how the modes compete. In these examples we'll use 730 hours as a typical month. We're also going to give headroom for up to 10% extra traffic so we can sleep at night, knowing we aren't constantly running a system on the edge.

    For a recap on the pricing we're using:

    • 1 WCU = $0.000772 per hour
    • 1 RCU = $0.0001544 per hour
    • 1 WRU = $0.0000014846
    • 1 RRU = $0.000000297
    Scenario 1: Consistent Load

    In this scenario, we have a well-known workload that is chugging away at much the same rate, 24/7. It's dealing with items that are a max of 1KB in size, and the system will make roughly 100 writes per second and around 8,000 eventually consistent reads per second throughout the month. How will our bill look in each mode?

    If we use Provisioned Capacity mode for the month, we will need to provision for 110 WCUs and 8,800 RCUs to cover the load plus the 10% headroom.

    This comes to:

    110 * 730 * $0.000772 = $62.00 for the WCUs

    8,800 * 730 * $0.0001544 = $991.87 for the RCUs

    $62 + $992 = $1,054 total for the month

    On-demand, we'll be paying for about:

    100 * 60 * 60 * 730 = 262,800,000 write requests

    8,000 * 60 * 60 * 730 = 21,024,000,000 read requests

    Multiplying that by the pricing above and we get $390.16 for the writes, and $6244.13 for the reads, for a grand total of $6,635 for the month.

    The clear winner for consistent loads is using Provisioned Capacity, with On-demand being more than six times as expensive! Whilst this example focuses on a consistent load 24/7 (rare in my experience), for the easier calculations, similar conclusions will be arrived at for any loads that are predictable with relatively smooth scaling, as DynamoDB allows you to automatically scale the provisioned capacity based on usage as required. If your workload has a predictable load pattern without major spikes, Provisioned Capacity is evidently the way to go.

    Scenario 2: Daily Spike

    For the second scenario, we're looking at a workload that has low usage during most of the day but gets hit hard for a random hour of the day. This scenario simulates those more unpredictable spiky workloads, where you can't accurately predict how much capacity you need or aren't sure when you'll suddenly need more. In this scenario, we will have the same 1KB items, but this time we'll have ~100 writes per second and ~8,000 eventually consistent reads per second for just half an hour at a random point per day, and 1 write and 80 reads per second for the rest of the day.

    Using Provisioned Capacity, we need to provision for the max load, as we have no idea when it'll hit and autoscaling won't be able to scale up in time, leading to throttling and a loss of service. As such, we need to provision the same capacity as the previous example, coming to a monthly cost of $1,054.

    However, for On-demand mode, we're paying per request. For the busy half hour, we're paying for:

    100 * 60 * 30 = 180,000 writes

    8,000 * 60 * 30 = 14,400,000 reads

    For the rest of the day it's:

    1 * 60 * 60 * 23.5 = 84,600 writes

    80 * 60 * 60 * 23.5 = 6,768,000 reads

    To align with the 730-hour assumption we'll get the total day's writes (264,600) and reads (21,168,000), divide by 24 and multiply back out by the 730, giving us a monthly total of 8,048,250 writes in the month and 643,860,000 reads. This will cost a total of $11.95 + $191.23 = $204 for the month.

    In this example we can see a dramatic saving by using On-demand mode to account for the unknown levels of traffic.

    ddb

    Above: Example cost savings on a low usage table (~30k request units per day)

    Wrap-up

    As we have seen, DynamoDB has two different capacity modes that allow you to choose the most efficient option for your workload. In general, the Provisioned Capacity mode will be best suited to workloads with a known traffic profile with a smooth-scaling curve. On-demand is best for spiky workloads or workloads that can be unpredictable. If you're unsure, do the maths and you can work out which is likely to pay off whilst being able to serve your users without throttling issues. For a new workload that needs to be able to run but for which you can't work out the required provisioned capacity, I'd suggest starting in On-demand mode and switching to Provisioned Capacity when you have had time to reflect on the usage data — it's all in CloudWatch. Thankfully, DynamoDB makes it easy to switch between the two!