{
    "componentChunkName": "component---src-templates-mdx-content-page-js",
    "path": "/dynamodb-paper/",
    "result": {"data":{"mdx":{"body":"var _excluded = [\"components\"];\n\nfunction _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }\n\nfunction _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; }\n\nfunction _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }\n\n/* @jsxRuntime classic */\n\n/* @jsx mdx */\nvar _frontmatter = {\n  \"path\": \"/dynamodb-paper/\",\n  \"publishedDate\": \"2026-10-23\",\n  \"updatedDate\": \"2026-10-23\",\n  \"metaTitle\": \"DynamoDB Paper Explained: Architecture and Dynamo\",\n  \"metaDescription\": \"Compare the DynamoDB and Dynamo papers: replication, admission control, durability, failure recovery, and what their designs mean for your tables.\",\n  \"title\": \"The DynamoDB paper explained, and how it differs from Dynamo\",\n  \"authorName\": \"Rafal Wilinski\",\n  \"authorLink\": \"https://x.com/rafalwilinski\",\n  \"authorImage\": \"/images/authors/rafal-wilinski.jpg\",\n  \"image\": \"/images/posts/dynamodb-paper/social.png\"\n};\nvar layoutProps = {\n  _frontmatter: _frontmatter\n};\nvar MDXLayout = \"wrapper\";\nreturn function MDXContent(_ref) {\n  var components = _ref.components,\n      props = _objectWithoutProperties(_ref, _excluded);\n\n  return mdx(MDXLayout, _extends({}, layoutProps, props, {\n    components: components,\n    mdxType: \"MDXLayout\"\n  }), mdx(\"p\", null, \"The \", mdx(\"strong\", {\n    parentName: \"p\"\n  }, \"DynamoDB paper\"), \" describes Amazon's managed, multi-tenant database service; the \", mdx(\"strong\", {\n    parentName: \"p\"\n  }, \"Dynamo paper\"), \" describes its earlier, internally operated key-value store. DynamoDB uses leader-based replication with Multi-Paxos, while Dynamo accepts writes through a leaderless design that can leave conflicting versions for applications to reconcile. Read the \", mdx(\"a\", {\n    parentName: \"p\",\n    \"href\": \"https://www.usenix.org/system/files/atc22-elhemali.pdf#page=3\"\n  }, \"DynamoDB paper, sections 2 and 3\"), \", for the service's architecture, and the \", mdx(\"a\", {\n    parentName: \"p\",\n    \"href\": \"https://www.allthingsdistributed.com/files/amazon-dynamo-sosp2007.pdf#page=6\"\n  }, \"Dynamo paper, sections 4.4 through 4.6\"), \", for the original availability tradeoffs.\"), mdx(\"h2\", null, \"Which Amazon DynamoDB paper should you read?\"), mdx(\"table\", null, mdx(\"thead\", {\n    parentName: \"table\"\n  }, mdx(\"tr\", {\n    parentName: \"thead\"\n  }, mdx(\"th\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"Paper\"), mdx(\"th\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"What it describes\"), mdx(\"th\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"What a practitioner gets from it\"))), mdx(\"tbody\", {\n    parentName: \"table\"\n  }, mdx(\"tr\", {\n    parentName: \"tbody\"\n  }, mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, mdx(\"strong\", {\n    parentName: \"td\"\n  }, \"Amazon DynamoDB: A Scalable, Predictably Performant, and Fully Managed NoSQL Database Service\"), \", Elhemali et al., USENIX ATC 2022\"), mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"The AWS service and its operational evolution\"), mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"Why capacity management changed, how replication works, and how AWS protects durability and availability\")), mdx(\"tr\", {\n    parentName: \"tbody\"\n  }, mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, mdx(\"strong\", {\n    parentName: \"td\"\n  }, \"Dynamo: Amazon's Highly Available Key-value Store\"), \", DeCandia et al., SOSP 2007\"), mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"The earlier internal Amazon storage system\"), mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"Consistent hashing, version conflicts, configurable quorums, and repair after failures\")))), mdx(\"p\", null, \"The publication details and originals are available from \", mdx(\"a\", {\n    parentName: \"p\",\n    \"href\": \"https://www.usenix.org/conference/atc22/presentation/elhemali\"\n  }, \"USENIX\"), \" and the \", mdx(\"a\", {\n    parentName: \"p\",\n    \"href\": \"https://www.allthingsdistributed.com/files/amazon-dynamo-sosp2007.pdf\"\n  }, \"Dynamo PDF\"), \". Below, \", mdx(\"strong\", {\n    parentName: \"p\"\n  }, \"DynamoDB paper\"), \" and \", mdx(\"strong\", {\n    parentName: \"p\"\n  }, \"Dynamo paper\"), \" refer to these respective publications. Section citations identify historical design claims; the final section separates subsequently documented features.\"), mdx(\"p\", null, \"If the service itself is new to you, start with \", mdx(\"a\", {\n    parentName: \"p\",\n    \"href\": \"/what-is-dynamodb/\"\n  }, \"what DynamoDB is\"), \". The papers explain the machinery behind that API, but they are not substitutes for the current API contract.\"), mdx(\"h2\", null, \"Why DynamoDB was built after Dynamo and SimpleDB\"), mdx(\"p\", null, \"The DynamoDB paper's history is partly about removing work from application teams. Dynamo delivered high availability, but each team operated its own installation. Developers needed database expertise even when their application only needed a key-value store.\"), mdx(\"p\", null, \"SimpleDB offered a managed service and removed that operational burden. Its storage and throughput ceilings still forced applications to divide data among tables. Indexing every attribute also made write and query latency harder to predict. DynamoDB combined managed operations and a richer table model with automatic partitioning and predictable access paths. The authors describe a new architecture, rather than a hosted deployment of Dynamo. \", mdx(\"a\", {\n    parentName: \"p\",\n    \"href\": \"https://www.usenix.org/system/files/atc22-elhemali.pdf#page=3\"\n  }, \"DynamoDB paper, \\xA72.\")), mdx(\"p\", null, \"This explains an otherwise puzzling design choice: DynamoDB deliberately limits the work performed by ordinary keyed requests. It can distribute that work without allowing arbitrary query complexity to dictate latency. You choose the access paths through primary keys and indexes; the service manages their placement and capacity.\"), mdx(\"h2\", null, \"How does DynamoDB's architecture work?\"), mdx(\"h3\", null, \"A request router finds the partition and its replicas\"), mdx(\"p\", null, \"A partition-key value passes through an internal hash function. That result, together with the sort key where present, identifies the item's position in the table's key space. A physical partition owns a contiguous, disjoint portion of that space. Its replicas form a \", mdx(\"strong\", {\n    parentName: \"p\"\n  }, \"replication group\"), \" across Availability Zones.\"), mdx(\"p\", null, \"Request routers authenticate and authorize calls, find the relevant partition, and send data operations to storage nodes. Each storage node hosts replicas belonging to multiple partitions and customers. The autoadmin service manages fleet health, partition replacement, scaling, and control-plane operations such as creating resources. \", mdx(\"a\", {\n    parentName: \"p\",\n    \"href\": \"https://www.usenix.org/system/files/atc22-elhemali.pdf#page=4\"\n  }, \"DynamoDB paper, \\xA73.\")), mdx(\"p\", null, mdx(\"img\", {\n    parentName: \"p\",\n    \"src\": \"/images/posts/dynamodb-paper/dynamodb-architecture.svg\",\n    \"alt\": \"DynamoDB routes writes to a partition leader across Availability Zones, looks up routing metadata through MemDS, and can add a log-only replica during recovery.\"\n  })), mdx(\"p\", null, \"The diagram combines the request path in \\xA73 with metadata availability in \\xA76.6. It shows a normal storage group plus a recovery mechanism, not a requirement that every partition always has an extra log replica.\"), mdx(\"h3\", null, \"Multi-Paxos orders writes; the leader serves strong reads\"), mdx(\"p\", null, \"The group uses Multi-Paxos for consensus and leader election. The leader maintains its role through a renewable lease. It creates a write-ahead log record for each write and sends that record to peers. The request succeeds after a quorum has persisted the record in its local logs. The normal write quorum described by the paper is \", mdx(\"strong\", {\n    parentName: \"p\"\n  }, \"two of three replicas in different Availability Zones\"), \". \", mdx(\"a\", {\n    parentName: \"p\",\n    \"href\": \"https://www.usenix.org/system/files/atc22-elhemali.pdf#page=10\"\n  }, \"DynamoDB paper, \\xA7\\xA73 and 6.1.\")), mdx(\"p\", null, \"Only the leader serves writes and strongly consistent reads. Eventually consistent reads can use a storage replica that may not yet reflect the latest committed write. After an unplanned leader change, the new leader waits for the old lease to expire before serving writes or strong reads. That rule prevents competing leaders from serving incompatible histories. \", mdx(\"a\", {\n    parentName: \"p\",\n    \"href\": \"https://www.usenix.org/system/files/atc22-elhemali.pdf#page=5\"\n  }, \"DynamoDB paper, \\xA73.\")), mdx(\"p\", null, \"There is a leader \", mdx(\"strong\", {\n    parentName: \"p\"\n  }, \"per partition\"), \", not a single leader for the whole table. Adding partitions therefore adds independently replicated units of work.\"), mdx(\"h3\", null, \"A storage replica and a log replica have different jobs\"), mdx(\"p\", null, \"A storage replica holds both a B-tree containing item data and a write-ahead log. A \", mdx(\"strong\", {\n    parentName: \"p\"\n  }, \"log replica\"), \" retains recent log entries without the B-tree. It participates in replication as a Paxos acceptor, but it cannot answer item reads from a B-tree it does not have.\"), mdx(\"p\", null, \"When a storage replica fails, copying its entire state takes longer than copying its recent log. Adding a log replica quickly protects new writes while full storage recovery proceeds. This separates the urgent task of restoring log redundancy from the larger task of rebuilding queryable storage. \", mdx(\"a\", {\n    parentName: \"p\",\n    \"href\": \"https://www.usenix.org/system/files/atc22-elhemali.pdf#page=8\"\n  }, \"DynamoDB paper, \\xA7\\xA73, 5.1 and 6.1.\")), mdx(\"h3\", null, \"MemDS makes metadata traffic predictable\"), mdx(\"p\", null, \"Originally, a router cached the partition map for an entire table. A warm cache made metadata traffic small, but a cold router needed expensive lookups. Expanding the router fleet could therefore overload the metadata service at the moment the system needed more capacity.\"), mdx(\"p\", null, \"The replacement is \", mdx(\"strong\", {\n    parentName: \"p\"\n  }, \"MemDS\"), \", an in-memory distributed metadata store sized to handle the full request rate. It uses a Perkle tree, combining Patricia-tree lookup properties with Merkle-tree hashing. Routers fetch the partition information relevant to a key instead of downloading a whole table map.\"), mdx(\"p\", null, \"Crucially, a router cache hit still triggers an asynchronous MemDS refresh. Metadata work continues when caches are warm, so losing cache effectiveness does not create the same sudden load multiplier. Storage nodes remain authoritative for partition membership and push changes to MemDS. A storage node contacted using stale metadata can return updated membership or an error that causes another lookup. \", mdx(\"a\", {\n    parentName: \"p\",\n    \"href\": \"https://www.usenix.org/system/files/atc22-elhemali.pdf#page=11\"\n  }, \"DynamoDB paper, \\xA76.6.\")), mdx(\"h2\", null, \"How admission control evolved from provisioned to on-demand\"), mdx(\"p\", null, \"Admission control decides whether the system can accept a request without overloading storage or interfering with another tenant. The central lesson of the DynamoDB paper is that \", mdx(\"strong\", {\n    parentName: \"p\"\n  }, \"table capacity and physical partition placement should not be coupled too tightly\"), \".\"), mdx(\"p\", null, mdx(\"img\", {\n    parentName: \"p\",\n    \"src\": \"/images/posts/dynamodb-paper/admission-control-evolution.svg\",\n    \"alt\": \"Admission control evolved from provisioned partition allocations through bursting and adaptive capacity to table-wide admission, consumption-based placement and splitting, and on-demand tables.\"\n  })), mdx(\"p\", null, \"The dated milestones are DynamoDB's \", mdx(\"strong\", {\n    parentName: \"p\"\n  }, \"2012\"), \" launch, \", mdx(\"strong\", {\n    parentName: \"p\"\n  }, \"2016\"), \" adaptive capacity, and \", mdx(\"strong\", {\n    parentName: \"p\"\n  }, \"2018\"), \" on-demand tables, from the DynamoDB paper's \\xA72 and Figure 1. The other steps follow \\xA74's design progression; the paper does not assign each an individual launch date.\"), mdx(\"h3\", null, \"Provisioned capacity initially became fixed partition allocations\"), mdx(\"p\", null, \"The original implementation divided a table's provisioned capacity among partitions and enforced it on storage nodes. This made tenant isolation straightforward, but assumed traffic would be distributed reasonably evenly.\"), mdx(\"p\", null, \"The paper's example illustrates that allocation. These are \", mdx(\"strong\", {\n    parentName: \"p\"\n  }, \"historical allocation examples\"), \", not a formula for estimating today's partition count. \", mdx(\"a\", {\n    parentName: \"p\",\n    \"href\": \"https://www.usenix.org/system/files/atc22-elhemali.pdf#page=6\"\n  }, \"DynamoDB paper, \\xA74.\")), mdx(\"table\", null, mdx(\"thead\", {\n    parentName: \"table\"\n  }, mdx(\"tr\", {\n    parentName: \"thead\"\n  }, mdx(\"th\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"Table provisioned throughput\"), mdx(\"th\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"Partitions in the example\"), mdx(\"th\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"Allocation per partition\"))), mdx(\"tbody\", {\n    parentName: \"table\"\n  }, mdx(\"tr\", {\n    parentName: \"tbody\"\n  }, mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"3,200 WCU\"), mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"4\"), mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"800 WCU\")), mdx(\"tr\", {\n    parentName: \"tbody\"\n  }, mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"3,600 WCU\"), mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"4\"), mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"900 WCU\")), mdx(\"tr\", {\n    parentName: \"tbody\"\n  }, mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"6,000 WCU\"), mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"8, after splitting\"), mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"750 WCU\")))), mdx(\"p\", null, \"A size-driven split could also divide an allocation even when most traffic remained on the same hot data. The table gained storage distribution while its busy portion lost usable throughput. The authors call this \", mdx(\"strong\", {\n    parentName: \"p\"\n  }, \"throughput dilution\"), \". Customers could encounter throttling despite having enough total table capacity.\"), mdx(\"h3\", null, \"Bursting borrowed unused capacity for short spikes\"), mdx(\"p\", null, \"Bursting let a partition spend previously unused capacity, subject to spare throughput on its storage node. The paper describes retaining unused capacity for up to \", mdx(\"strong\", {\n    parentName: \"p\"\n  }, \"300 seconds\"), \". Partition allocation, burst allowance, and node capacity were tracked with token buckets; bursting writes also needed to account for peer replicas' node capacity. \", mdx(\"a\", {\n    parentName: \"p\",\n    \"href\": \"https://www.usenix.org/system/files/atc22-elhemali.pdf#page=6\"\n  }, \"DynamoDB paper, \\xA74.1.1.\")), mdx(\"p\", null, \"This helped temporary spikes. It did not make a busy partition independent of the node hosting it, and it did not provide an unlimited reserve for sustained traffic.\"), mdx(\"h3\", null, \"Adaptive capacity reacted to sustained imbalance\"), mdx(\"p\", null, \"The next mechanism monitored provisioned and consumed capacity. When partitions throttled while the table stayed within its provisioned throughput, the system boosted their allocations. Autoadmin could move boosted partitions to nodes with sufficient resources.\"), mdx(\"p\", null, \"That improved skewed workloads, but the mechanism reacted after throttling had already appeared. The user still experienced an interruption before the control loop corrected placement or allocation. \", mdx(\"a\", {\n    parentName: \"p\",\n    \"href\": \"https://www.usenix.org/system/files/atc22-elhemali.pdf#page=7\"\n  }, \"DynamoDB paper, \\xA74.1.2.\")), mdx(\"h3\", null, \"Global admission control moved the table budget to routers\"), mdx(\"p\", null, \"Global admission control, or \", mdx(\"strong\", {\n    parentName: \"p\"\n  }, \"GAC\"), \", tracks consumption across the table. Each request router keeps local tokens and periodically obtains more from GAC. It can make an admission decision locally without a synchronous GAC round trip for every request.\"), mdx(\"p\", null, \"This lets uneven traffic use the table's budget without being trapped behind an arbitrary equal allocation to each partition. Partition token buckets still exist as a protective limit on storage-node resource use. Here, \", mdx(\"strong\", {\n    parentName: \"p\"\n  }, \"global means across the table's request routers\"), \", not cross-Region global tables. \", mdx(\"a\", {\n    parentName: \"p\",\n    \"href\": \"https://www.usenix.org/system/files/atc22-elhemali.pdf#page=7\"\n  }, \"DynamoDB paper, \\xA74.2.\")), mdx(\"p\", null, \"The paper describes GAC replacing the earlier adaptive-capacity mechanism. Current AWS documentation still uses \", mdx(\"em\", {\n    parentName: \"p\"\n  }, \"adaptive capacity\"), \" for automatic handling of uneven workloads. Do not interpret the historical implementation change as the removal of that customer-facing capability. \", mdx(\"a\", {\n    parentName: \"p\",\n    \"href\": \"https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/bp-partition-key-design.html\"\n  }, \"AWS partition-key design guidance.\")), mdx(\"h3\", null, \"Placement and splitting began following consumption\"), mdx(\"p\", null, \"Looser partition allocations require better management of shared nodes. Storage nodes monitor consumption and storage usage; autoadmin moves candidate replicas away from overloaded nodes. That protects tenants when multiple colocated workloads become busy together. \", mdx(\"a\", {\n    parentName: \"p\",\n    \"href\": \"https://www.usenix.org/system/files/atc22-elhemali.pdf#page=7\"\n  }, \"DynamoDB paper, \\xA74.3.\")), mdx(\"p\", null, \"Splitting also became sensitive to actual traffic. The system chooses a split point using observed access distribution, instead of simply cutting the key range in the middle. A single hot item cannot be divided this way. Sequential access that continually moves to the newest part of a range may also gain nothing, so the service detects patterns where a split would be ineffective. \", mdx(\"a\", {\n    parentName: \"p\",\n    \"href\": \"https://www.usenix.org/system/files/atc22-elhemali.pdf#page=8\"\n  }, \"DynamoDB paper, \\xA74.4.\")), mdx(\"h3\", null, \"On-demand combined those mechanisms into a capacity mode\"), mdx(\"p\", null, \"On-demand removes the customer's need to forecast provisioned capacity. Consumption-based placement, splitting, and GAC supply the underlying controls. The paper says the service immediately accommodates up to \", mdx(\"strong\", {\n    parentName: \"p\"\n  }, \"double the previous peak\"), \", then allocates additional capacity as traffic grows. That is a scaling behavior, not a promise that every possible instantaneous jump succeeds. \", mdx(\"a\", {\n    parentName: \"p\",\n    \"href\": \"https://www.usenix.org/system/files/atc22-elhemali.pdf#page=8\"\n  }, \"DynamoDB paper, \\xA74.5.\")), mdx(\"p\", null, \"For current mode selection, pre-warming, and scaling behavior, see \", mdx(\"a\", {\n    parentName: \"p\",\n    \"href\": \"/dynamodb-on-demand-vs-provisioned-scaling/\"\n  }, \"on-demand versus provisioned scaling\"), \".\"), mdx(\"h2\", null, \"How DynamoDB protects durability and correctness\"), mdx(\"p\", null, \"Replication is only the first layer. Identical replicas can all contain the same software-induced error, and hardware can silently corrupt bytes. The paper describes checks at several independent boundaries.\"), mdx(\"table\", null, mdx(\"thead\", {\n    parentName: \"table\"\n  }, mdx(\"tr\", {\n    parentName: \"thead\"\n  }, mdx(\"th\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"Protection\"), mdx(\"th\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"What it detects or protects against\"), mdx(\"th\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"Paper section\"))), mdx(\"tbody\", {\n    parentName: \"table\"\n  }, mdx(\"tr\", {\n    parentName: \"tbody\"\n  }, mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"Replicated write-ahead logs and fast addition of log replicas\"), mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"Loss of a storage node and reduced redundancy for recent writes\"), mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, mdx(\"a\", {\n    parentName: \"td\",\n    \"href\": \"https://www.usenix.org/system/files/atc22-elhemali.pdf#page=8\"\n  }, \"\\xA75.1\"))), mdx(\"tr\", {\n    parentName: \"tbody\"\n  }, mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"Periodic log archival to S3\"), mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"Dependence on the live storage replicas alone\"), mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, mdx(\"a\", {\n    parentName: \"td\",\n    \"href\": \"https://www.usenix.org/system/files/atc22-elhemali.pdf#page=8\"\n  }, \"\\xA75.1\"))), mdx(\"tr\", {\n    parentName: \"tbody\"\n  }, mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"Checksums on messages, log entries, files, and uploads\"), mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"Silent corruption during storage, transformation, or transfer\"), mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, mdx(\"a\", {\n    parentName: \"td\",\n    \"href\": \"https://www.usenix.org/system/files/atc22-elhemali.pdf#page=9\"\n  }, \"\\xA75.2\"))), mdx(\"tr\", {\n    parentName: \"tbody\"\n  }, mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"Archive manifests and log-sequence checks\"), mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"Wrong table or partition data, missing log entries, inconsistent uploads\"), mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, mdx(\"a\", {\n    parentName: \"td\",\n    \"href\": \"https://www.usenix.org/system/files/atc22-elhemali.pdf#page=9\"\n  }, \"\\xA75.2\"))), mdx(\"tr\", {\n    parentName: \"tbody\"\n  }, mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"Continuous scrubbing and reconstruction from archived logs\"), mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"Differences between live replicas, or between live state and independently reconstructed state\"), mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, mdx(\"a\", {\n    parentName: \"td\",\n    \"href\": \"https://www.usenix.org/system/files/atc22-elhemali.pdf#page=9\"\n  }, \"\\xA75.3\"))), mdx(\"tr\", {\n    parentName: \"tbody\"\n  }, mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"TLA+ specifications, model checking, stress and failure-injection tests\"), mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"Replication and control-plane mistakes, including rare interleavings\"), mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, mdx(\"a\", {\n    parentName: \"td\",\n    \"href\": \"https://www.usenix.org/system/files/atc22-elhemali.pdf#page=9\"\n  }, \"\\xA75.4\"))))), mdx(\"p\", null, mdx(\"strong\", {\n    parentName: \"p\"\n  }, \"S3 archival is not the synchronous write-acknowledgment step.\"), \" A successful write depends on the replication group's persisted log quorum; logs are archived periodically. Keeping those stages separate explains why recent, unarchived logs need fast redundancy repair.\"), mdx(\"p\", null, \"Continuous verification is especially valuable because it checks whether independent ways of deriving the same state agree. A checksum can detect changed bytes; rebuilding from history can expose a deeper discrepancy in how current state was produced.\"), mdx(\"p\", null, \"Formal verification adds another layer. The authors model-check changes to the replication protocol and also apply formal methods to other components. This is evidence of systematic correctness work, not a claim that every line of the service has been mathematically proved bug-free.\"), mdx(\"p\", null, \"Durability also differs from recovery after a valid but unwanted operation. Your application can successfully delete the wrong data, and replication will preserve that deletion. The paper describes backups and point-in-time restores built from archived logs and snapshots. Configure and test \", mdx(\"a\", {\n    parentName: \"p\",\n    \"href\": \"/dynamodb-backup-and-restore/\"\n  }, \"backup and restore\"), \" for that separate failure mode. \", mdx(\"a\", {\n    parentName: \"p\",\n    \"href\": \"https://www.usenix.org/system/files/atc22-elhemali.pdf#page=9\"\n  }, \"DynamoDB paper, \\xA75.5.\")), mdx(\"h2\", null, \"How DynamoDB stays available during failures and deployments\"), mdx(\"h3\", null, \"Failure detection must avoid unnecessary elections\"), mdx(\"p\", null, \"Write availability requires a healthy leader and a write quorum. Strong-read availability also depends on the leader. A \", mdx(\"strong\", {\n    parentName: \"p\"\n  }, \"gray failure\"), \" occurs when components disagree about reachability: a follower may lose contact with a leader that other replicas can still reach.\"), mdx(\"p\", null, \"Immediately electing a replacement in that situation can disrupt an otherwise functioning group. A follower proposing failover first asks peers whether they can still communicate with the leader; a healthy response causes it to abandon that attempt. This reduces false-positive elections. \", mdx(\"a\", {\n    parentName: \"p\",\n    \"href\": \"https://www.usenix.org/system/files/atc22-elhemali.pdf#page=10\"\n  }, \"DynamoDB paper, \\xA7\\xA76.1 and 6.2.\")), mdx(\"h3\", null, \"Availability is measured from outside the storage fleet too\"), mdx(\"p\", null, \"Server-side success rates cannot reveal every problem a caller sees. The service monitors table and service availability, metrics supplied by internal Amazon clients, and canary applications that call public endpoints from each Availability Zone. Those different vantage points help expose network failures that healthy storage nodes alone would miss. \", mdx(\"a\", {\n    parentName: \"p\",\n    \"href\": \"https://www.usenix.org/system/files/atc22-elhemali.pdf#page=10\"\n  }, \"DynamoDB paper, \\xA76.3.\")), mdx(\"p\", null, \"Use the \", mdx(\"a\", {\n    parentName: \"p\",\n    \"href\": \"/dynamodb-sla/\"\n  }, \"DynamoDB SLA guide\"), \" for the current contractual definition and credit conditions. The paper's monitoring discussion is an engineering description, not a latency guarantee or an unconditional availability promise.\"), mdx(\"h3\", null, \"Safe deployment includes rollback and mixed versions\"), mdx(\"p\", null, \"The authors test upgrades, downgrades, and the state left after rollback. For protocol changes, they first deploy software able to read the new format, then enable writing that format. Small initial deployment groups and automated rollback limit the impact of regressions.\"), mdx(\"p\", null, \"Planned storage-node updates also relinquish leadership explicitly, avoiding the lease-expiry wait required after an unexpected failure. \", mdx(\"a\", {\n    parentName: \"p\",\n    \"href\": \"https://www.usenix.org/system/files/atc22-elhemali.pdf#page=11\"\n  }, \"DynamoDB paper, \\xA76.4.\")), mdx(\"h3\", null, \"Dependency failures should not stop all existing traffic\"), mdx(\"p\", null, \"Routers cache IAM and KMS results and refresh them asynchronously. During an impairment, cached results can sustain previously established operations for a predetermined period. A request reaching a router without the needed cached state can still be affected. This is a bounded resilience mechanism, not permission to bypass authentication. Together with MemDS, it illustrates the paper's preference for predictable dependency load. \", mdx(\"a\", {\n    parentName: \"p\",\n    \"href\": \"https://www.usenix.org/system/files/atc22-elhemali.pdf#page=11\"\n  }, \"DynamoDB paper, \\xA7\\xA76.5 and 6.6.\")), mdx(\"h2\", null, \"What do the published performance results establish?\"), mdx(\"p\", null, \"The DynamoDB paper's \\xA77 tests YCSB workload A, \", mdx(\"strong\", {\n    parentName: \"p\"\n  }, \"50% reads and 50% updates\"), \", and workload B, \", mdx(\"strong\", {\n    parentName: \"p\"\n  }, \"95% reads and 5% updates\"), \". Both use uniformly distributed keys and \", mdx(\"strong\", {\n    parentName: \"p\"\n  }, \"900-byte items\"), \". Tests run against production DynamoDB in Northern Virginia, scaling from \", mdx(\"strong\", {\n    parentName: \"p\"\n  }, \"100,000 to 1 million total operations per second\"), \" and reporting \", mdx(\"strong\", {\n    parentName: \"p\"\n  }, \"50th- and 99th-percentile\"), \" latency. The graphs show broadly stable read and write latency as aggregate throughput increases. \", mdx(\"a\", {\n    parentName: \"p\",\n    \"href\": \"https://www.usenix.org/system/files/atc22-elhemali.pdf#page=12\"\n  }, \"DynamoDB paper, \\xA77 and Figures 5 and 6.\")), mdx(\"p\", null, \"That supports a specific conclusion: the tested distributed workloads scaled without a corresponding increase in latency. It does not establish a maximum for a hot item, a guarantee for large payloads, or the behavior of your application's retries and network path.\"), mdx(\"p\", null, \"The abstract separately reports a peak of \", mdx(\"strong\", {\n    parentName: \"p\"\n  }, \"89.2 million requests per second\"), \" from Amazon systems during \", mdx(\"strong\", {\n    parentName: \"p\"\n  }, \"Prime Day 2021\"), \". That is aggregate production activity, not a single-table benchmark. \", mdx(\"a\", {\n    parentName: \"p\",\n    \"href\": \"https://www.usenix.org/system/files/atc22-elhemali.pdf#page=2\"\n  }, \"DynamoDB paper, abstract.\")), mdx(\"p\", null, \"The engineering lesson running through \\xA7\\xA71 and 8 is predictability: partition placement, admission control, verification, and deployment procedures all support the same customer-visible goal. For your own load test, reproduce key skew and item sizes, not just total request volume.\"), mdx(\"h2\", null, \"How did the original Dynamo paper's design work?\"), mdx(\"h3\", null, \"Consistent hashing chooses a preference list\"), mdx(\"p\", null, \"Dynamo maps keys into a circular hash space and walks clockwise to find storage nodes. Virtual nodes assign multiple positions to a physical host, helping distribute ownership and accommodate unequal hardware. A key's \", mdx(\"strong\", {\n    parentName: \"p\"\n  }, \"preference list\"), \" contains distinct physical nodes, skipping repeated positions belonging to the same host, and includes fallback candidates beyond the intended replica set. \", mdx(\"a\", {\n    parentName: \"p\",\n    \"href\": \"https://www.allthingsdistributed.com/files/amazon-dynamo-sosp2007.pdf#page=6\"\n  }, \"Dynamo paper, \\xA7\\xA74.2 and 4.3.\")), mdx(\"p\", null, \"The paper also records an evolution beyond the simplest ring sketch: partition boundaries were decoupled from placement, making movement and archival easier. A ring diagram explains ownership; it does not capture every later partition-management detail. \", mdx(\"a\", {\n    parentName: \"p\",\n    \"href\": \"https://www.allthingsdistributed.com/files/amazon-dynamo-sosp2007.pdf#page=12\"\n  }, \"Dynamo paper, \\xA76.2.\")), mdx(\"p\", null, mdx(\"img\", {\n    parentName: \"p\",\n    \"src\": \"/images/posts/dynamodb-paper/dynamo-vs-dynamodb-replication.svg\",\n    \"alt\": \"Dynamo replicates a key to clockwise preference-list nodes, while DynamoDB sends writes through a leader inside the key's partition replication group.\"\n  })), mdx(\"h3\", null, \"Leaderless does not mean coordinator-free\"), mdx(\"p\", null, \"A coordinator handles each Dynamo request, gathers replica responses, and returns a result. It is not a permanently elected leader with exclusive authority over writes. The implementation allows different eligible nodes to coordinate writes, including choosing a node that responded quickly to a preceding read. \", mdx(\"a\", {\n    parentName: \"p\",\n    \"href\": \"https://www.allthingsdistributed.com/files/amazon-dynamo-sosp2007.pdf#page=7\"\n  }, \"Dynamo paper, \\xA7\\xA74.5 and 5.\")), mdx(\"p\", null, mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"N\"), \" is the replication factor, \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"R\"), \" the required read responses, and \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"W\"), \" the required write acknowledgments. The paper discusses \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"R + W > N\"), \" as quorum-like behavior. \", mdx(\"strong\", {\n    parentName: \"p\"\n  }, \"That inequality alone does not make this Dynamo design strongly consistent\"), \": its failure handling permits different reachable replica sets, and its version model explicitly permits concurrent histories. \", mdx(\"a\", {\n    parentName: \"p\",\n    \"href\": \"https://www.allthingsdistributed.com/files/amazon-dynamo-sosp2007.pdf#page=7\"\n  }, \"Dynamo paper, \\xA7\\xA74.4 through 4.6.\")), mdx(\"h3\", null, \"Vector clocks detect causality, not the correct business answer\"), mdx(\"p\", null, \"Each object version carries a vector clock containing node counters. If one version causally descends from another, the older version can be discarded. Concurrent versions have no such ordering, so reads may return multiple versions and an opaque context. The application reconciles them and writes back using that context.\"), mdx(\"p\", null, \"For a shopping cart, merging contents can preserve additions made during disconnected updates. It can also resurrect something another update removed. The vector clock detects the conflict; it cannot decide the intended cart contents. \", mdx(\"a\", {\n    parentName: \"p\",\n    \"href\": \"https://www.allthingsdistributed.com/files/amazon-dynamo-sosp2007.pdf#page=6\"\n  }, \"Dynamo paper, \\xA74.4.\")), mdx(\"h3\", null, \"Sloppy quorum and hinted handoff favor continued writes\"), mdx(\"p\", null, \"When intended replicas are unreachable, Dynamo uses healthy nodes further down the preference list. A substitute stores a \", mdx(\"strong\", {\n    parentName: \"p\"\n  }, \"hint\"), \" identifying the intended recipient, then transfers the data when that recipient recovers. This is hinted handoff.\"), mdx(\"p\", null, \"The price is that reads and writes need not contact the same replica set during a failure. Applications accept that uncertainty in exchange for continued operation when strict membership would prevent progress. \", mdx(\"a\", {\n    parentName: \"p\",\n    \"href\": \"https://www.allthingsdistributed.com/files/amazon-dynamo-sosp2007.pdf#page=8\"\n  }, \"Dynamo paper, \\xA74.6.\")), mdx(\"h3\", null, \"Merkle trees, read repair, and gossip repair divergence\"), mdx(\"p\", null, \"Merkle trees summarize key ranges with hashes. Replicas compare summaries, descend into differing branches, and synchronize only the affected data. Read repair provides another opportunity to update stale replicas after collecting responses. Gossip spreads membership and token ownership; explicit joins and removals distinguish permanent membership changes from temporary unreachability. Failure detection for request routing can be local rather than requiring universal agreement that a host failed. \", mdx(\"a\", {\n    parentName: \"p\",\n    \"href\": \"https://www.allthingsdistributed.com/files/amazon-dynamo-sosp2007.pdf#page=8\"\n  }, \"Dynamo paper, \\xA7\\xA74.7, 4.8 and 5.\")), mdx(\"p\", null, \"Dynamo also had admission control, but \\xA76.5 describes protecting foreground requests from background repair and handoff work. That is a different problem from allocating a managed table's purchased throughput among tenants and partitions.\"), mdx(\"h2\", null, \"Dynamo vs DynamoDB: what actually changed?\"), mdx(\"table\", null, mdx(\"thead\", {\n    parentName: \"table\"\n  }, mdx(\"tr\", {\n    parentName: \"thead\"\n  }, mdx(\"th\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"Concern\"), mdx(\"th\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"Dynamo paper\"), mdx(\"th\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"DynamoDB paper\"))), mdx(\"tbody\", {\n    parentName: \"table\"\n  }, mdx(\"tr\", {\n    parentName: \"tbody\"\n  }, mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"Operating model\"), mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"Internal, separately operated service instances\"), mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"Fully managed, multi-tenant cloud service\")), mdx(\"tr\", {\n    parentName: \"tbody\"\n  }, mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"Placement and replication\"), mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"Consistent-hash preference lists select replica hosts\"), mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"Partition key ranges are backed by replication groups\")), mdx(\"tr\", {\n    parentName: \"tbody\"\n  }, mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"Write coordination\"), mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"Per-request coordinator; concurrent histories possible\"), mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"Elected partition leader and Multi-Paxos\")), mdx(\"tr\", {\n    parentName: \"tbody\"\n  }, mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"Read contract\"), mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"Versioned, eventually consistent objects\"), mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"Strong or eventual reads from table data\")), mdx(\"tr\", {\n    parentName: \"tbody\"\n  }, mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"Conflict handling\"), mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"Vector clocks and application or timestamp reconciliation\"), mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"Ordered writes within a partition; no sibling-version reconciliation API\")), mdx(\"tr\", {\n    parentName: \"tbody\"\n  }, mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"Failure response\"), mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"Sloppy quorums, hinted handoff, read repair, anti-entropy\"), mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"Quorum replication, leader failover, log replicas, storage repair\")), mdx(\"tr\", {\n    parentName: \"tbody\"\n  }, mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"Developer controls\"), mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"Tune replica and quorum settings\"), mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"Choose keys, capacity mode, indexes, and supported consistency options\")), mdx(\"tr\", {\n    parentName: \"tbody\"\n  }, mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"Data interface\"), mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"Opaque key-value objects\"), mdx(\"td\", {\n    parentName: \"tr\",\n    \"align\": null\n  }, \"Items with attributes, indexes, conditional operations, and transactions\")))), mdx(\"p\", null, \"Sources: \", mdx(\"a\", {\n    parentName: \"p\",\n    \"href\": \"https://www.allthingsdistributed.com/files/amazon-dynamo-sosp2007.pdf\"\n  }, \"Dynamo paper, \\xA7\\xA72, 4, 5 and 6\"), \", and \", mdx(\"a\", {\n    parentName: \"p\",\n    \"href\": \"https://www.usenix.org/system/files/atc22-elhemali.pdf\"\n  }, \"DynamoDB paper, \\xA7\\xA72, 3, 4 and 6\"), \". This compares the papers' designs. Cross-Region replication is a separate consistency boundary discussed below.\"), mdx(\"p\", null, \"Marc Brooker's \", mdx(\"a\", {\n    parentName: \"p\",\n    \"href\": \"https://brooker.co.za/blog/2025/08/15/dynamo-dynamodb-dsql.html\"\n  }, \"comparison of Dynamo, DynamoDB, and Aurora DSQL\"), \" reinforces the distinction: DynamoDB's replica groups and ordered writes spare applications much of Dynamo's version-reconciliation burden. Strong consistency and high operational availability can coexist when failures leave a functioning quorum.\"), mdx(\"h2\", null, \"What should DynamoDB users do with this knowledge?\"), mdx(\"p\", null, mdx(\"strong\", {\n    parentName: \"p\"\n  }, \"Design for traffic distribution.\"), \" Many distinct keys help only if requests actually reach them. A workload dominated by an aggregate counter can remain constrained even in a large table. Review \", mdx(\"a\", {\n    parentName: \"p\",\n    \"href\": \"/dynamodb-partition-key/\"\n  }, \"partition-key design\"), \" against real access patterns, and investigate \", mdx(\"a\", {\n    parentName: \"p\",\n    \"href\": \"/dynamodb-hot-partitions/\"\n  }, \"hot partitions\"), \" when throttling persists despite spare table capacity.\"), mdx(\"p\", null, mdx(\"strong\", {\n    parentName: \"p\"\n  }, \"Keep partition limits separate from table capacity.\"), \" Current AWS guidance specifies \", mdx(\"strong\", {\n    parentName: \"p\"\n  }, \"3,000 read units and 1,000 write units per second per partition\"), \", in both capacity modes. Item size and read consistency determine the request count those units support. On-demand automates capacity management; it does not let an indivisible hot item consume unlimited throughput. \", mdx(\"a\", {\n    parentName: \"p\",\n    \"href\": \"https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/bp-partition-key-design.html\"\n  }, \"AWS partition-key design, throughput limits\"), \". The \", mdx(\"a\", {\n    parentName: \"p\",\n    \"href\": \"/dynamodb-limits/\"\n  }, \"DynamoDB limits reference\"), \" distinguishes physical limits from adjustable quotas.\"), mdx(\"p\", null, mdx(\"strong\", {\n    parentName: \"p\"\n  }, \"Choose consistency for the operation.\"), \" \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"ConsistentRead: true\"), \" on supported table or local-secondary-index reads requests the current committed state. Global secondary indexes do not support that option. An eventually consistent read returning older data does not imply that the preceding acknowledged write was nondurable. Read the \", mdx(\"a\", {\n    parentName: \"p\",\n    \"href\": \"/dynamodb-read-consistency/\"\n  }, \"consistency guide\"), \" and \", mdx(\"a\", {\n    parentName: \"p\",\n    \"href\": \"https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/HowItWorks.ReadConsistency.html\"\n  }, \"AWS read-consistency contract\"), \" before relying on read-after-write behavior.\"), mdx(\"p\", null, mdx(\"strong\", {\n    parentName: \"p\"\n  }, \"Treat predictable latency as a workload property to validate.\"), \" Admission control protects accepted work from overload, but your application still sees throttling, retry delays, and network latency. Measure those separately. A fast successful-request metric can coexist with a slow user operation that retried repeatedly.\"), mdx(\"h2\", null, \"What has changed since the DynamoDB paper?\"), mdx(\"p\", null, \"Current documentation adds capabilities beyond the paper's snapshot. These are public features, not evidence that a particular internal protocol has changed.\"), mdx(\"ul\", null, mdx(\"li\", {\n    parentName: \"ul\"\n  }, mdx(\"strong\", {\n    parentName: \"li\"\n  }, \"Warm throughput and configurable on-demand maximums.\"), \" You can inspect instantly supportable throughput and pay to pre-warm for an expected spike. Separately, maximum-throughput settings constrain on-demand usage on a best-effort basis; burst capacity can exceed the target. \", mdx(\"a\", {\n    parentName: \"li\",\n    \"href\": \"https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/warm-throughput.html\"\n  }, \"Warm throughput\"), \" and \", mdx(\"a\", {\n    parentName: \"li\",\n    \"href\": \"https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/on-demand-capacity-mode-max-throughput.html\"\n  }, \"on-demand maximum throughput\"), \".\"), mdx(\"li\", {\n    parentName: \"ul\"\n  }, mdx(\"strong\", {\n    parentName: \"li\"\n  }, \"More precise throttling diagnostics.\"), \" \", mdx(\"inlineCode\", {\n    parentName: \"li\"\n  }, \"ThrottlingReasons\"), \" identifies the affected table or index and distinguishes partition, provisioned, service-quota, and configured-maximum causes. A \", mdx(\"inlineCode\", {\n    parentName: \"li\"\n  }, \"KeyRangeThroughputExceeded\"), \" reason directs investigation toward workload distribution. See \", mdx(\"a\", {\n    parentName: \"li\",\n    \"href\": \"https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_ThrottlingReason.html\"\n  }, \"AWS ThrottlingReason\"), \" and the \", mdx(\"a\", {\n    parentName: \"li\",\n    \"href\": \"/dynamodb-throttling/\"\n  }, \"throttling guide\"), \".\"), mdx(\"li\", {\n    parentName: \"ul\"\n  }, mdx(\"strong\", {\n    parentName: \"li\"\n  }, \"Multi-Region strong consistency.\"), \" Global tables support both eventual and strong consistency modes. The strong mode synchronously replicates writes across Regions before success; the eventual mode retains asynchronous replication and conflict reconciliation. The regional replication group drawn above is not a complete diagram of either cross-Region mode. \", mdx(\"a\", {\n    parentName: \"li\",\n    \"href\": \"https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/HowItWorks.ReadConsistency.html#HowItWorks.ReadConsistency.GlobalTables\"\n  }, \"AWS global-table read consistency\"), \" and \", mdx(\"a\", {\n    parentName: \"li\",\n    \"href\": \"/dynamodb-global-tables/\"\n  }, \"global tables\"), \" explain the distinction.\")), mdx(\"p\", null, \"The enduring practitioner lesson is to use the papers to explain behavior, then use current documentation to establish the guarantee your application can rely on.\"), mdx(FAQ, {\n    questions: [{\n      question: \"What is the DynamoDB paper?\",\n      answer: \"It is Amazon DynamoDB: A Scalable, Predictably Performant, and Fully Managed NoSQL Database Service, published at USENIX ATC. It describes the managed service's architecture, admission-control evolution, durability mechanisms, availability engineering, and scaling experiments.\"\n    }, {\n      question: \"Is DynamoDB the same database as Dynamo?\",\n      answer: \"No. Dynamo is an earlier internal key-value store using version reconciliation and leaderless replication. DynamoDB is a managed, multi-tenant service whose paper describes leader-based replication with Multi-Paxos.\"\n    }, {\n      question: \"Does DynamoDB use Paxos or consistent hashing?\",\n      answer: \"These solve different problems. DynamoDB hashes partition keys to locate data, while Multi-Paxos orders replication within a partition's replica group; the DynamoDB paper describes both in section 3.\"\n    }, {\n      question: \"Does DynamoDB use vector clocks?\",\n      answer: \"The Dynamo paper uses vector clocks to identify causally related and concurrent object versions. The DynamoDB paper describes leader-based replication instead, and DynamoDB's item API does not ask applications to reconcile sibling versions using vector clocks.\"\n    }, {\n      question: \"Why can an on-demand DynamoDB table still throttle?\",\n      answer: \"On-demand manages capacity automatically, but physical partition capacity, service quotas, scaling readiness, and configured maximum throughput still matter. A single hot item cannot be divided across partitions to remove its throughput limit.\"\n    }, {\n      question: \"Do DynamoDB writes wait for S3?\",\n      answer: \"The paper describes acknowledgment after a quorum persists the write-ahead log record on replicas. Log archival to S3 happens periodically and is a separate durability mechanism; see sections 3 and 5.1 of the DynamoDB paper.\"\n    }],\n    mdxType: \"FAQ\"\n  }));\n}\n;\nMDXContent.isMDXComponent = true;","frontmatter":{"publishedDate":"2026-10-23","updatedDate":"2026-10-23","path":"/dynamodb-paper/","metaTitle":"DynamoDB Paper Explained: Architecture and Dynamo","metaDescription":"Compare the DynamoDB and Dynamo papers: replication, admission control, durability, failure recovery, and what their designs mean for your tables.","title":"The DynamoDB paper explained, and how it differs from Dynamo","authorName":"Rafal Wilinski","authorLink":"https://x.com/rafalwilinski","authorImage":"/images/authors/rafal-wilinski.jpg","image":"/images/posts/dynamodb-paper/social.png"}}},"pageContext":{}},
    "staticQueryHashes": ["3649515864"]}