DynamoDB 熱分區:如何找到並修復它們
DynamoDB 將你的資料分佈在許多實體分割區上,每個分割區都有自己的吞吐量的切片。 熱分區是指一個鍵吸引更多的讀取或寫入的資料超出了其切片所能提供的服務 - 因此請求該關鍵節流閥,而其餘的桌子閒置。
什麼是DynamoDB熱分區?
DynamoDB 熱分區是指一個 吸收的讀取或寫入遠遠超過其吞吐量切片可以服務的數量,因此在表的其餘部分閒置時對該鍵進行請求。原因是密鑰設計——名人物品、低基數密鑰、今天的日期——而不是表大小。治癒方法是傳播寫入。
- 原因是鍵設計,而不是表大小。 一個集中流量——名人用戶、DynamoDB 標誌、今天的日期——就是陷阱。
- 自適應容量有所幫助,但它不是解決辦法。 DynamoDB 重新平衡熱量自動,但單一項目或單一密鑰仍然可以超過分區可以服務。
- 解決辦法是傳播寫入。 將熵加入金鑰(寫入分片)或將熱讀路徑移至更好的分散式存取模式。
- 來自 SQL,這沒有等效項。 關係表沒有的概念「一行的索引值太受歡迎」—DynamoDB 的扁平吞吐量-每鍵模型確實如此。
為什麼分區存在
DynamoDB 是 2007 年亞馬遜 Dynamo 紙的生產繼承者,該紙交易了用於分區、水平擴展的單節點 SQL 模型。數據被分片透過跨實體儲存節點的分區鍵的雜湊。
每個分區保存有限數量的資料並提供有限數量的服務吞吐量。 AWS 記錄了每個 3,000 RCU 和 1,000 WCU 的硬上限分區,每秒 — 預先配置和按需的軟上限相同 ZZ保留0ZZ (AWS — partition behavior)。計費模式不會提高物理上限;它只會改變表級支出的方式是計量的。使用 pricing calculator 用於表級成本和貢獻者見解,以查看是否受到限制分區限制與表格限制。
那個天花板就是整個故事。你的表的 吞吐量是總和跨所有分區。一個鍵的項目集合從一個分區開始,並且 split-for heat 可以將其跨越多個排序鍵邊界 — 除非表具有 LSI 或排序鍵不斷增加,將其固定為 1。
為陷阱命名:一鍵堆積的流量
只有當你的存取均勻分佈在金鑰之間時,吞吐量才會均勻共用。當一個鍵獲得不成比例的流量時,它會單獨進行節流,而表的整體容量未使用。
經典熱鍵形狀:
- 名人物品-每個人都會閱讀的一個使用者、產品或租戶。
- 低基數分區鍵 —
status、country、type。很少有明顯的值意味著很少的分區可以完成所有工作。 - 時間段密鑰 —
PK = "2026-06-23"。今天的每一篇文章都會鍛鍊一個分區;昨天的天氣永遠寒冷。
來自SQL,這些都不重要。流行值的 B 樹索引是很好。在DynamoDB中,流行的值是物理放置的單位,所以受歡迎程度成為吞吐量懸崖。
一個有效的例子:名人排行榜
假設你經營全球遊戲排行榜。分數存在於一個表格中,其鍵值如下:
PK = "BOARD#global"
SK = "PLAYER#<playerId>"
Reads依分數搶前N;每次之後寫入玩家的 currentScore
比賽。全域板中的每一行共享一個分區鍵 - BOARD#global
- 因此每次讀取和寫入都會發生在單一分割區上。
加上一個擁有 200 萬現場觀眾的主播,向他們的刷新按鈕發送垃圾郵件自己的排名,並且該分區突破了 3,000 個讀取單元。你得到
ProvisionedThroughputExceededException 在全球板上,而其他所有表中的板閒置。
腳槍是 BOARD#global 崩潰:你將單一邏輯板建模為單一實體鑰匙。
傳播寫入:對密鑰進行分片
解決方法是製造基數。向分區附加分片後綴 鍵,以便一個邏輯板在 N 個實體分區上扇出:
PK = "BOARD#global#<shard>" -- shard = playerId mod 10
SK = "PLAYER#<playerId>"
寫入現在分散在十個分區而不是一個分區 — 寫入量的十倍淨空。成本:讀取整個棋盤必須命中所有十個分片並合併,因為沒有單一 Query 跨越分片邊界。你用閱讀的簡單性來換取寫分佈。
親自看看差異。將單一重複鍵貼到視覺化工具中下面,每個寫入都會落在一個儲存桶中-熱分區。加入分片後綴
(BOARD#global#0 … #9) 並且相同的寫入均勻地散開:
這是一個直覺教學哈希,而不是 DynamoDB 真正的內部哈希 — 真正的函數和分區邊界是 AWS 內部。讀作「甚至傳播 vs 傾斜”,而不是作為對密鑰落在哪個物理分區的預測。
AWS 將此稱為寫分片,並專門推薦它用於高速、低基數鍵(AWS)。
這與背後的本能是一樣的 single-table design — 你為存取模式,而不是資料「自然」放置的方式。
讓適應力完成簡單的部分
DynamoDB 提供自適應容量,在 re:Invent 2018 的議程「Amazon DynamoDB Under the Hood」(DAT401)中介紹過。它會持續把一張表的吞吐量重新分配到正在吃熱量的分割區上,並把一個持續發熱的鍵隔離到它自己的分割區(鍵級隔離,AWS — bursting & adaptive capacity)。
它即時而且免費——但它受物理定律的限制(自適應容量是怎麼運作的)。自適應容量能在鍵之間搬運熱量,split-for-heat 甚至能在排序鍵邊界上切開一個發熱的項集合。每個分割區的上限只在這幾種情況下絕對:單個發熱的項、一個不斷遞增的排序鍵,或者一張帶 LSI 的表——那裡名人鍵照樣會被限流。分片是確定性的解法;split-for-heat 又慢又看運氣,所以別等它。
一旦你看到繁忙鍵上的節流閥,決策路徑:
大多數熱分區都會解決“對鍵進行分片”或“讓自適應容量吸收它」——圖表就是你所在的分支。
重新設計之前先診斷一下
你無法修復你看不到的東西。節流顯示為
ProvisionedThroughputExceededException(已配置)或作為
ThrottledRequests、ReadThrottleEvents/WriteThrottleEvents 和
ReadThrottleEventsForKeyRange/WriteThrottleEventsForKeyRange — 的特定於分區限制的計數 — 在 CloudWatch 中(AWS — CloudWatch metrics)。
再配上 CloudWatch Contributor Insights for DynamoDB,它會直接把你被訪問最多的鍵排名——按名字確認一個名人鍵的最快方式(AWS — Contributor Insights)。而如果你根本還不確定熱鍵是不是原因——DynamoDB 會因為四種不同的理由限流——那就從限流指南開始,讓指標說出你真正撞上的是哪個上限。
當你測試分片讀取路徑時,你將手動建構每個分片的 KeyConditionExpression。生成那些沒有拼字錯誤的
DynamoDB Expression Builder — 它發出每個分片的精確 PK = :pk AND begins_with(SK, :sk) 形狀。
要避開的陷阱
- 不斷增加的排序鍵。 單調排序鍵(時間戳記、序列 number)強制每個新寫入到一個項目集合的同一端,並且 split-for-heat 也無濟於事——集合的上限仍然是 1,000 個寫入單元。將熵加入排序鍵或對分區鍵進行分片。
- 不必要地對讀取密集的路徑進行分片。 如果讀取占主導地位並且該項目是小,通常是快取或具有更好分佈密鑰的 GSI 擊敗分片的分散-聚集讀取成本。
- 將熱分區與慢速
Scan混淆。Scan很慢,因為它閱讀一切;由於一個按鍵超載,熱分區會受到限制。不同的問題 - 請參閱 Query vs Scan。
後續步驟
繪製分片鍵的草圖,然後根據真實資料證明讀取路徑。建構每個分片的條件 DynamoDB Expression Builder,和 download DynoTable 在你自己的桌子上運行它們並觀察哪些隔間實際上會帶走熱量。