中階閱讀時間 3 分鐘

DynamoDB 分區鍵如何運作

你的分區鍵不是一欄——它是一個位址。DynamoDB 對那個鍵做雜湊, 而雜湊決定哪台實體機器儲存這個項目。鍵挑得好,負載就分散; 挑得差,就有一台伺服器扛下所有壓力。

DynamoDB 分區鍵是如何運作的?

DynamoDB 會將你的分區鍵丟進一個內部雜湊函式,而那個雜湊決定哪個實體分區儲存該項目。鍵不像 SQL 欄位那樣被排序或建立索引——它是一個位址。選一個高基數的鍵,負載就分散到多個分區;選一個低基數的鍵,單一分區就扛下所有壓力。

  • 鍵是被雜湊的,不是被排序的。 DynamoDB 把你的分區鍵丟進一個 內部雜湊來選擇分區。兩個相鄰的值在磁碟上落得天差地遠。
  • 一個分區是一個真實的儲存單位。 每個約上限在 10 GB、3,000 讀取單位/秒、1,000 寫入單位/秒。你的流量被你的鍵 分散到的分區數量除掉。
  • 熱鍵是地雷。 把大多數請求漏斗到單一分區鍵值,你就會在那個 分區上節流,而資料表其餘部分卻閒置。
  • 高基數鍵勝出。 你擁有越多各不相同、均勻命中的鍵值, 就有越多分區吸收負載。

從鍵實際在做什麼開始

從 SQL 過來,主鍵是一個排序、有索引的欄,你在它上面 JOINORDER BY。在 DynamoDB 裡,分區鍵(有時叫雜湊鍵)做的是 另一件事:它決定 擺放位置

DynamoDB 把分區鍵餵進一個內部雜湊函式。輸出對應到 一個鍵空間,而鍵空間被切成許多範圍——每個範圍由一個 實體分區擁有。那個分區是某個真實節點上的真實儲存。

所以分區鍵回答一個問題:哪台機器握有這個項目? 排序鍵(如果你有的話)只在那台機器 之內 排序項目。它 在擺放位置上不起作用。

跟著一次寫入穿過雜湊

假設你經營一個吃進裝置讀數的 SaaS。你的資料表 SensorReadings 用 分區鍵 deviceId 和排序鍵 readingTs。你為 deviceId = "vac-7741" 寫入一筆讀數。

這是那次寫入走的路徑——從你的鍵到它落腳的磁碟:

鍵空間切片PutItemdeviceId = 'vac-7741'對分區鍵做雜湊雜湊對應到鍵空間中的一點哪個範圍擁有它?分區 P2項目已儲存, readingTs 排序

vac-7741 的寫入被雜湊到鍵空間裡的一點,那一點落在 P2 的範圍裡,於是項目落腳在 P2——在那裡依 readingTs 排序。

要內化的東西是:"vac-7741""vac-7742" 只差一個字元, 但它們的雜湊毫無關聯。它們幾乎肯定住在不同的 分區上。在分區鍵空間裡沒有「附近」這回事。

這是 DynamoDB 從原始設計繼承來的一致性雜湊概念—— 2007 年的 Amazon Dynamo 論文(「Dynamo: Amazon's Highly Available Key-value Store」)正是藉由雜湊把鍵分散到各節點,讓沒有任何單一節點變成 瓶頸。

尊重分區的硬性上限

一個實體分區是有限的。根據 AWS DynamoDB 開發人員指南,每個約 最多容納:

上限每分區
儲存~10 GB
讀取吞吐量3,000 讀取單位/秒
寫入吞吐量1,000 寫入單位/秒

當一個分區填過 10 GB,或你預配的吞吐量需要更多空間時, DynamoDB 會分裂它——鍵空間範圍被劃分,項目重新分布 到更多分區上。這是自動的;你不會觸發它。

要注意的點:分裂是依項目的 雜湊 來分散。如果每個熱請求都鎖定 單一分區鍵值,分裂幫不上忙——那些流量仍然全部雜湊 到同一個點。你沒辦法把單一鍵的負載分裂到多個分區上。

點名這個陷阱:熱分區

熱分區 是經典的地雷。當一個分區鍵值(或極少數一組) 吸走不成比例的流量份額時,它就發生。

具體的失敗:你把 SensorReadings 換成一個分區鍵 region, 值像是 "us-east""eu-west"。三個區域意味著三個鍵值意味著—— 頂多——三個分區在做真正的工作。用讀取猛轟 "us-east",它就會 在 3,000 RCU 節流,而資料表的總預配容量卻閒置著。

DynamoDB 的自適應容量緩和了這個——它能把未使用的吞吐量 挪向繁忙的分區,並把單一極熱的鍵隔離到它自己的 分區。AWS 在 re:Invent「Advanced Design Patterns for DynamoDB」深度講座裡詳細說明過。但自適應容量買到的是時間,不是 豁免:它無法細分單一個別鍵的負載。為分散而設計;別倚賴 那張安全網。

選一個高基數的鍵

修法是基數——各不相同鍵值的數量,以及流量 命中它們有多均勻。

  • 低基數regionstatustrue/false):分區少、 流量集中、你很早就節流。
  • 高基數deviceIduserId、一個訂單 ID):許多值雜湊 到許多分區,負載分散,餘裕增長。

從 SQL 過來,你會樂於為一欄 status 建索引並在它上面篩選。當作 DynamoDB 的分區鍵那就是個陷阱——它沒法分散。把低基數 屬性留作篩選條件、或留作次要索引的排序鍵, 絕不要當成決定擺放位置的那個東西。

當一個天生不錯的鍵仍然偏斜時——少數幾個鯨魚租戶的流量 超過其餘——加一個後綴把一個邏輯值扇散到 N 個分區,例如 tenantId#3 用於一條分片的寫入路徑。你在讀取時再重新聚合。

要在你的鍵分散後鎖定一個分區 之內 的項目,你會在排序鍵上寫 一個 KeyConditionExpression。你可以在 DynamoDB 運算式建構器 裡對著你自己的 schema 組一個,再把它接進 程式碼:

deviceId = "vac-7741" AND readingTs BETWEEN "2026-06-01" AND "2026-06-30"

那會從單一分區讀出一台裝置的六月區間——一個 Query,不是 Scan。分區鍵釘住機器;排序鍵 條件收窄資料列。

陷阱與後續步驟

  • 別依在 SQL 裡讀起來順不順來挑鍵。 依它 分散 得如何來挑。 基數第一,查詢方便第二。
  • 別以為資料表的總容量就是你每個鍵能用的。 吞吐量是 每分區的;一個熱值可能在資料表看起來閒置時就把你節流。
  • 別跟分裂硬碰。 它是自動且雜湊驅動的——你的工作是給它 足夠多各不相同的鍵去分散。

一旦你的鍵乾淨地分散開,下一個決定是如何在一個分區 之內 安排項目——參見單一資料表設計——以及何時 一個次要索引才是某個第二存取模式的 正確工具。

下載 DynoTable瀏覽你真實的分區與鍵 分布,並在一個熱鍵半夜呼叫你之前先發現它。

已更新