DAX 和 DynamoDB 一致性模型 - Amazon DynamoDB

本文為英文版的機器翻譯版本,如內容有任何歧義或不一致之處,概以英文版為準。

DAX 和 DynamoDB 一致性模型

Amazon DynamoDB Accelerator (DAX) 是一種寫入式快取服務,旨在簡化將快取新增至 DynamoDB 資料表的程序。由於 與 DynamoDB 分開DAX運作,因此請務必了解 DAX和 DynamoDB 的一致性模型,以確保您的應用程式如預期般運作。

在許多使用案例中,您的應用程式使用 的方式DAX會影響DAX叢集內資料的一致性,以及 DAX和 DynamoDB 之間的資料一致性。

DAX 叢集節點之間的一致性

若要達到應用程式的高可用性,建議您使用至少三個節點來佈建 DAX 叢集。然後將這些節點置放到區域中的多個可用區域內。

DAX 叢集執行時,會複寫叢集中所有節點之間的資料 (假設您已佈建超過一個節點)。請考慮使用 DAX 執行成功 UpdateItem 的應用程式。此動作會使用新的值修改主要節點中的項目快取。該值接著會複寫到叢集中的所有其他節點。這項複寫最終會一致,而且通常不需要一秒就能完成。

在此情況下,根據每個用戶端所存取的節點,兩個用戶端可能會讀取相同 DAX 叢集中的相同索引鍵,但收到不同的值。在叢集中的所有節點之間完全複寫更新時,這些節點將會一致。(此行為與 DynamoDB 的最終一致性質相似。)

如果您要建置使用 DAX 的應用程式,則應該設計該應用程式,使其容忍最終一致資料。

DAX 項目快取行為

每個DAX叢集都有兩個不同的快取:項目快取和查詢快取。如需詳細資訊,請參閱DAX:運作方式

本節會解決讀取和寫入 DAX 項目快取的一致性隱憂。

讀取一致性

使用 DynamoDB,GetItem 操作預設會執行最終一致讀取。假設您搭配 DynamoDB 用戶端使用 UpdateItem。若您接著立即嘗試讀取相同項目,您可能會看到資料顯示的是更新前的內容。這是因為所有 DynamoDB 儲存體位置之間的傳播延遲。通常可在幾秒內達到一致性。因此若您重試讀取,您可能會看到更新後的項目。

當您搭配 DAX 用戶端使用 GetItem 時,操作 (在此案例中為最終一致讀取) 會以以下方式繼續。

工作流程圖,顯示加上編號的更新項目步驟。
  1. DAX 用戶端發出 GetItem 請求。DAX 嘗試從項目快取讀取請求的項目。如果項目位於快取中 (「快取命中」),則 DAX 會將其傳回應用程式。

  2. 如果項目無法使用 (快取遺漏), 會針對 DynamoDB DAX執行最終一致的GetItem操作。

  3. DynamoDB 會傳回請求的項目,並將其DAX存放在項目快取中。

  4. DAX 將項目傳回應用程式。

  5. (未顯示) 如果 DAX 叢集包含超過一個節點,則會將項目複寫至叢集中的所有其他節點。

項目會保留在DAX項目快取中,取決於存留時間 (TTL) 設定和快取最近最少使用的 (LRU) 演算法。如需詳細資訊,請參閱DAX:運作方式

不過,在此期間, DAX不會從 DynamoDB 重新讀取項目。如果其他人使用 DynamoDB 用戶端更新項目,DAX並完全略過,則使用DAX用戶端的GetItem請求會產生與使用 DynamoDB 用戶端的相同GetItem請求不同的結果。在此案例中, DAX和 DynamoDB 會保留相同索引鍵的不一致值,直到DAX項目TTL的 過期為止。

如果應用程式修改基礎 DynamoDB 資料表中的資料,繞過 DAX,應用程式需要預測和容忍可能發生的資料不一致。

注意

除了 GetItem,DAX 用戶端還支援 BatchGetItem 請求。基本上 BatchGetItem 是一或多個 GetItem 請求的包裝函式,因此 DAX 會將每個請求視為個別的 GetItem 操作。

寫入一致性

DAX 是一種寫入快取,可簡化DAX項目快取與基礎 DynamoDB 資料表保持一致的程序。

DAX 用戶端支援與 DynamoDB (PutItemUpdateItemDeleteItemBatchWriteItem和 ) 相同的寫入API操作TransactWriteItems。當您將這些操作與DAX用戶端搭配使用時,項目會在 DAX和 DynamoDB 中修改。 會DAX更新其項目快取中的項目,無論這些項目TTL的值為何。

例如,假設您從 DAX 用戶端發出 GetItem 請求,從 ProductCatalog 資料表讀取項目。(分割區索引鍵是 Id;沒有排序索引鍵。) 您擷取了 Id101 的項目。該項目QuantityOnHand的值為 42。 會將項目DAX存放在具有特定 的項目快取中TTL。在此範例中,假設 TTL為 10 分鐘。然後,在 3 分鐘後,另一個應用程式使用 DAX 用戶端來更新相同的項目;因此,該項目的 QuantityOnHand 值現在是 41。假設未再次更新項目,則在下個 10 分鐘期間,任何後續讀取相同的項目都會傳回已快取的 QuantityOnHand 值 (41)。

DAX 程序如何寫入

DAX 適用於需要高效能讀取的應用程式。作為寫入快取, 會同步DAX將您的寫入傳遞至 DynamoDB,然後自動和非同步複寫產生的更新到叢集中所有節點的項目快取。您不需要管理快取失效邏輯,因為 DAX 會為您自動進行處理。

DAX 支援下列寫入操作:PutItemUpdateItemDeleteItemBatchWriteItemTransactWriteItems

當您將 PutItemUpdateItemDeleteItemBatchWriteItem 請求傳送至 DAX 時,會執行下列作業:

  • DAX 會將請求傳送至 DynamoDB。

  • DynamoDB 會回應 DAX,確認寫入成功。

  • DAX 將項目寫入至其項目快取。

  • DAX 將成功傳回給申請者。

當您將 TransactWriteItems 請求傳送至 DAX 時,會執行下列作業:

  • DAX 會將請求傳送至 DynamoDB。

  • DynamoDB 會回應 DAX,確認交易已完成。

  • DAX 將成功傳回給申請者。

  • 在背景中,DAX 會對 TransactWriteItems 請求中的每個項目進行 TransactGetItems 請求,以將項目存放在項目快取。TransactGetItems 會用來確保可序列化隔離

如果寫入 DynamoDB 因任何原因失敗,包括限流,項目不會快取在 中DAX。故障異常會傳回給申請者。這可確保資料不會寫入DAX快取,除非第一次成功寫入 DynamoDB。

注意

每個對 DAX 進行的寫入都會改變項目快取的狀態。但是,寫入項目快取不會影響查詢快取。(DAX 項目快取和查詢快取的用途不同,並且會各自獨立操作。)

DAX 查詢快取行為

DAX 會快取從 Query 獲得的結果,並在其查詢快取中進行 Scan 請求。但是,這些結果完全不會影響項目快取。當您的應用程式向 發出 QueryScan請求時DAX,結果集會儲存在查詢快取中,而不是項目快取中。您無法執行 Scan 操作來「預熱」項目快取,因為項目快取和查詢快取是不同的實體。

的一致性 query-update-query

項目快取的更新或基礎 DynamoDB 資料表的更新不會讓查詢快取中所存放的結果失效,或對其進行修改。

為了說明,請考慮以下情況。應用程式正在使用 DocumentRevisions 資料表,該資料表具有分割區索引鍵 DocId 和排序索引鍵 RevisionNumber

  1. ​客戶端對 DocId 101 和所有 RevisionNumber​ 大於或等於 5​ 的項目發出 Query。DAX​ 會將結果集存放在查詢快取,並將結果集傳回使用者。

  2. 用戶端針對 RevisionNumber20DocId 101 發出 PutItem 請求。

  3. 用戶端發出與步驟 1 所述相同的 Query (DocId 101 以及 RevisionNumber >= 5)。

在此案例中,步驟 3 發出的 Query 快取結果集會和步驟 1 快取的結果集完全相同。原因是,DAX 不會根據對個別項目的更新,使 QueryScan 結果集無效。步驟 2 PutItem的操作只會在 TTL 的 Query過期時反映在DAX查詢快取中。

您的應用程式應考慮查詢快取TTL的值,以及應用程式在查詢快取和項目快取之間可容忍不一致結果的時間長度。

強烈一致和交易讀取

若要執行強烈一致的 GetItemQueryBatchGetItemScan請求,請將 ConsistentRead參數設定為 true。 會將強烈一致的讀取請求DAX傳遞給 DynamoDB。當 收到來自 DynamoDB 的回應時, 會將結果DAX傳回給用戶端,但不會快取結果。 DAX 無法自行提供強烈一致的讀取,因為它不會與 DynamoDB 緊密耦合。基於此原因,任何從 DAX 進行的後續讀取都必須是最終一致讀取。任何後續的強烈一致讀取都必須傳遞至 DynamoDB。

DAX 處理TransactGetItems請求的方式與其處理強烈一致讀取的方式相同。 會將所有TransactGetItems請求DAX傳遞給 DynamoDB。收到來自 DynamoDB 的回應時, 會將結果DAX傳回給用戶端,但不會快取結果。

負快取

在項目快取和查詢快取中,DAX 都支援負快取項目。當DAX在基礎 DynamoDB 資料表中找不到請求的項目時,會發生負快取項目。DAX 會快取空的結果,並將該結果傳回使用者,而不是產生錯誤。

例如,假設應用程式將 GetItem 請求傳送至 DAX 叢集,而 DAX 項目快取中沒有相符項目。這會導致 從基礎 DynamoDB 資料表DAX讀取對應的項目。如果項目不存在於 DynamoDB 中, 會將空白項目DAX存放在其項目快取中,並將空白項目傳回給應用程式。現在假設應用程式傳送對同一個項目的另一個 GetItem 請求,DAX 會找到項目快取中的空項目,並將它立即傳回應用程式。​ 它完全不會參考 DynamoDB。

負快取項目會保留在DAX項目快取中,直到其項目TTL過期、LRU叫用,或使用 PutItemUpdateItem或 修改項目為止DeleteItem

DAX 查詢快取會以類似的方式處理負快取結果。如果應用程式執行 QueryScan,且DAX查詢快取不包含快取的結果, 會將請求DAX傳送至 DynamoDB。如果結果集中沒有相符項目,則 DAX 會將空結果集存放至查詢快取,並將空結果集傳回應用程式。後續 QueryScan請求會產生相同的 (空白) 結果集,直到該結果集TTL的 已過期為止。

寫入策略

DAX 的全部寫入行為適用於許多應用程式模式。但是,有些應用程式模式不適用全部寫入模式。

針對對延遲相當敏感的應用程式,全部寫入 DAX 會造成額外的網路躍點。因此,寫入 DAX 比直接寫入 DynamoDB 慢一點。若您的應用程式對寫入延遲相當敏感,您可以透過改為直接寫入 DynamoDB 來降低延遲。如需詳細資訊,請參閱繞過式寫入

針對寫入密集應用程式 (例如,執行大量資料載入的應用程式),您可能會不想要透過 DAX 寫入所有資料,因為應用程式只會讀取該資料的極小部分。當您透過 寫入大量資料時DAX,它必須調用其LRU演算法,以在快取中留出空間,以便讀取新項目。這會降低 DAX 做為讀取快取的有效性。

當您將項目寫入 DAX 時,項目快取狀態會變更,以容納新的項目 (例如,DAX 可能需要移出項目快取中較舊的資料,以清出空間來放置新項目)。新項目會保留在項目快取中,取決於快取的LRU演算法和快取TTL的設定。只要項目仍在項目快取中, DAX就不會從 DynamoDB 重新讀取項目。

全部寫入

DAX 項目快取會實作全部寫入政策。如需詳細資訊,請參閱DAX 程序如何寫入

當您撰寫項目時, DAX會確保快取的項目與 DynamoDB 中存在的項目同步。針對在寫入項目之後需要立即重新讀取項目的應用程式,這十分有用。不過,如果其他應用程式直接寫入 DynamoDB 資料表,項目快取中的DAX項目將不再與 DynamoDB 同步。

為了示範,請考慮正在使用 ProductCatalog 資料表的兩位使用者 (Alice 和 Bob)。Alice 使用 存取資料表DAX,但 Bob 直接略過DAX和存取 DynamoDB 中的資料表。

工作流程圖表顯示使用者 Alice 和 Bob 如何使用 DAX和 DynamoDB 存取資料表的編號步驟。
  1. Alice 會更新ProductCatalog資料表中的項目。 會將請求DAX轉送至 DynamoDB,更新成功。 DAX然後將項目寫入其項目快取,並傳回成功回應給 Alice。從這個時間點開始,除非最後從快取中移出項目,否則任何從 DAX 讀取項目的使用者都會看到具有 Alice 更新的項目。

  2. 稍後,Bob 更新了 Alice 寫入的相同 ProductCatalog 項目。不過,Bob 會直接在 DynamoDB 中更新項目。 DAX 不會自動重新整理其項目快取,以回應透過 DynamoDB 的更新。因此,DAX 使用者將不會看到 Bob 的更新。

  3. Alice 再次從 DAX 中讀取項目。該項目位於項目快取中,因此 會將其DAX傳回 Alice,而不存取 DynamoDB 資料表。

在此情況下,Alice 和 Bob 會看到相同 ProductCatalog 項目的不同呈現。除非 DAX 從項目快取中移出項目,或另一位使用者使用 DAX 再次更新相同的項目,否則就會是這種情況。

繞過式寫入

如果您的應用程式需要寫入大量資料 (例如大量資料載入),繞過資料DAX並將其直接寫入 DynamoDB 可能很合理。這種「繞過式寫入」策略可減少延遲。但是,項目快取將不會和 DynamoDB 中的資料保持同步。

如果您決定使用繞過式寫入策略,請記住,只要應用程式使用 DAX 用戶端讀取資料,DAX 就會填入其項目快取。這在某些情況下十分有益,因為它確定只會快取最常讀取的資料 (與最常寫入的資料相反)。

例如,請考慮想要使用 DAX 處理不同資料表 (GameScores 資料表) 的使用者 (Charlie)。GameScores 的分割區索引鍵是 UserId;因此,所有 Charlie 的分數都會有相同的 UserId

工作流程圖表顯示 Charlie 如何使用 與 DynamoDB 資料表搭配使用的編號步驟DAX。
  1. Charlie 想要擷取其所有的分數,因此他傳送 Query 至 DAX。假設此查詢之前尚未發出, 會將查詢DAX轉送至 DynamoDB 進行處理。它會將結果存放在 DAX 查詢快取中,然後將結果傳回給 Charlie。除非移出結果集,否則結果集仍然會位於查詢快取中。

  2. 現在假設 Charlie 玩 Meteor Blasters 遊戲,並得到高分。Charlie 將 UpdateItem 請求傳送至 DynamoDB,修改 GameScores 資料表中的項目。

  3. 最後,Charlie 決定重新執行他稍早發出的 Query 來從 GameScores 擷取他的所有資料。在結果中,Charlie 看不到他在 Meteor Blasters 中的高分。原因是查詢結果來自查詢快取,而不是項目快取。兩個快取彼此獨立,因此其中一個快取中的變更不會影響另一個快取。

DAX 不會重新整理查詢快取中具有來自 DynamoDB 最新資料的結果集。查詢快取中的每個結果集,其狀態都會是執行 QueryScan 操作時的狀態。因此,Charlie 的 Query 結果不會反映其 PutItem 操作。除非 DAX 從查詢快取中移出結果集,否則就會是這種情況。