進階閱讀時間 3 分鐘

DynamoDB 請求路由如何運作

你送出的每次讀取或寫入,都先打到一支無狀態的請求路由器艦隊。 一個路由器對你的分區鍵做雜湊、把雜湊對應到擁有那個鍵資料的 儲存節點,並把請求轉發到那裡。那一跳就是為什麼一次查鍵 無論資料表握有一千個項目或十億個都花一樣的成本。

DynamoDB 的請求路由是如何運作的?

DynamoDB 將每個請求透過一支無狀態的請求路由器艦隊進行路由,艦隊對你的分區鍵做雜湊、將雜湊對應到擁有該分區的單一儲存節點,再把讀取或寫入請求轉發到那裡。路由是鍵雜湊的純函式,因此無論資料表持有一千個項目或十億個,一次查詢的成本都相同。

  • 請求路由器是大門口。 它是一支無狀態的艦隊,接下你的 請求、對分區鍵做雜湊,並把它路由到持有那個分區的儲存節點—— 不掃描、不需要整張資料表的知識。
  • 分區鍵決定一切。 路由是分區鍵雜湊的純函式。 同一個鍵、同一個節點、每次都一樣——所以 GetItem 是 O(1),不是 O(資料表大小)。
  • 一個主、兩個從。 一次寫入落在分區的主節點上, 由它在耐久之前跨可用區複製到兩個從節點。
  • 壞鍵打敗這個設計。 一個低基數或「熱」的分區鍵把 流量漏斗到一個節點——路由沒問題,你的鍵才是問題。

從路由所解決的問題開始

從 SQL 過來,你想像一個查詢規劃器:它讀統計、挑一個索引, 也許掃描。成本隨它碰到多少資料而擴張。那個模型不適合 一個必須在任何規模下都以個位數毫秒回答的鍵值儲存。

DynamoDB 的答案是把單一項目查找變成一個直接定址,而不是一個 搜尋。分區鍵不是你篩選的一欄——它是一個雜湊 函式的輸入,這個函式算出 資料實體上住在哪裡。沒有統計、沒有規劃器。

那是你脫離關聯式思考時所接受的交易:你放棄 臨時查詢的彈性,換來常數時間的定址。

認識請求路由器

當一個請求抵達,它不會直接去到儲存。它打到一個請求 路由器——一支無狀態、水平擴展、罩住整個服務的艦隊。 (AWS re:Invent「DynamoDB Deep Dive」講座描述了這支前端艦隊。

路由器做三件事,而且自己不持有任何資料:

  • 對 IAM 認證並授權 這個請求。
  • 對分區鍵做雜湊 來找到擁有它的分區。
  • 轉發 請求到那個分區的儲存節點。

因為路由器是無狀態的,服務在負載下會增加更多路由器。它們 沒有一個是瓶頸、沒有一個是單點故障——這正是 2007 年 Amazon Dynamo 論文 圍繞著建造原始系統的同一個性質。

跟著一次讀取穿過路由器

拿一張給無人機隊的遙測資料表。項目由 DroneId(分區 鍵)和 ReadingTs(排序鍵)作鍵,屬性像是 BatteryPctAltitudeM

你要某一台無人機的最新一筆讀數:

PK = "DRONE#A19F"
SK begins_with "2026-06-23"

這是路由器拿它做的事。下方的引言由上到下追蹤這個 請求——把它讀成一個向下的流。

用戶端:GetItemPK = DRONE#A19F請求路由器(無狀態艦隊)Hash(DRONE#A19F) 鍵空間槽位把槽位對應 擁有該鍵的分區那個分區的主節點讀取項目DRONE#A19F

路由器對 DRONE#A19F 做雜湊、把它對應到擁有那個鍵的分區,並 把讀取轉發到那個分區的主儲存節點,由它回傳項目。

關鍵洞見:雜湊指向資料表所擁有的眾多分區中的 一個。 路由器從不看其他分區,所以增加無人機——和分區—— 不會讓這次查找變慢。

知道一個分區實際上是什麼

一個分區 是一個儲存與吞吐量的單位。每個都被封頂(大約 10 GB 和一片固定的讀寫容量),而 DynamoDB 在一個分區 長過任一上限時分裂它。每個有給定分區鍵的項目都住在 同一個分區上,這就是讓一個跨單一分區鍵的 Query 便宜的原因。

每個分區被複製到散布在多個可用區的三個儲存節點:一個和兩個

節點角色處理它能服務的一致性
所有寫入;強一致讀取強(看見它自己最新的寫入)
最終一致讀取;故障切換最終(可能落後主節點)

一次寫入去到主節點,由它在確認耐久性之前複製到從節點。一次 強一致讀取被路由到主節點,這樣它反映最新的寫入。一次 最終一致讀取可能由一個還沒跟上的從節點服務——半價、可能過期。

點名地雷:一個熱分區鍵

路由只和你的分區鍵一樣好。雜湊把鍵均勻分散,所以如果 你的鍵有高基數和均勻的流量,負載就分散到所有 節點。破壞任一性質,你就得到一個熱分區

假設你把那份遙測改用 Region 而不是 DroneId 作鍵。現在每台在 us-east-1 的無人機都共用一個分區鍵——所以它們每一次讀取和寫入都 雜湊到 同一個 節點。路由器把它的工作做得完美;你只是 把整支隊伍漏斗到單一分區的容量上。

你沒辦法看著路由器挑節點,但你 可以 設計路由良好的鍵。 當你在運算式建構器裡建立一個鍵條件時, 你放在 PK = … 左邊的分區鍵,正是路由器會去雜湊的 那個值——讓那個值保持高基數,正是讓讀取待在不同節點上的關鍵。

這如何連回你的存取模式

請求路由是讓單一資料表設計 規則不容妥協的那個機制:你圍繞分區鍵建模,因為分區鍵 就是 那個位址。這也是為什麼一個 Query 勝過一個 Scan—— 一個 Query 透過路由器打到一個分區,而一個 Scan 是依序走遍每個 分區。

次要索引拿到它們自己的分區和它們自己的路由:一個 GSI 由它自己的分區鍵路由,獨立於 基底資料表的,這就是為什麼一個 GSI 可以在資料表不熱時也變熱。

後續步驟

設計路由到許多節點、而不是一個節點的鍵。在 運算式建構器裡勾勒那個 PK = … 條件,看看究竟哪個值 被雜湊,然後下載 DynoTable對著你 自己的資料表跑那些查詢,並看著哪些分區鍵實際扛著你的流量。

已更新