入門閱讀時間 3 分鐘

何時該用 DynamoDB(以及何時不該)

對於它所擅長的工作負載,DynamoDB 是一個出色的資料庫;對於其餘的,它令人沮喪。決定性的問題 不是「它能不能擴充套件到 web 級?」—— 而是「我是否提前知道我的訪問模式,而且它們是基於鍵的嗎?」 把這點搞對,DynamoDB 會在任意規模下給你個位數毫秒的讀取;搞錯了,你就會永遠跟它缺乏 join 和 即席查詢的事實較勁。

何時該使用 DynamoDB?

當你的訪問模式已知、基於鍵且吞吐量高,並且希望在任意規模下獲得可預測的個位數毫秒延遲、無需管理任何伺服器時,選擇 DynamoDB。如果你需要即席查詢、複雜 join 或全資料集分析,或者資料量小且查詢形態還在不斷變化,則應避開它。

  • 在以下情況用 DynamoDB:你的訪問模式已知、基於鍵、且高流量 —— 而你想要在任意規模下都 可預測的延遲,且無伺服器要管。
  • 在以下情況避開它:你需要即席查詢、豐富的 join,或對整個資料集做分析;或者資料量小而查詢 形態又不斷變化。
  • 核心取捨:DynamoDB 要你提前為查詢做設計;作為回報,它在你增長時永不變慢。
  • 它不是換了套語法的關係型資料庫 —— 把它當關系型來建模是痛苦的頭號來源。

偏向 DynamoDB 的訊號

當下面這些大多成立時,DynamoDB 大放異彩:

  • 你提前知道訪問模式。 你能列出應用發起的確切查詢(「按 id 取一個使用者」、「列出某使用者的 訂單,最新優先」),而且它們不會隨意變。DynamoDB 就是圍繞這些查詢建模的。
  • 訪問是基於鍵的。 你按已知的分割區索引鍵查詢項,而不是為任意屬性組合做掃描。
  • 規模與可預測延遲很重要。 無論表裡裝的是一千個項還是十億個項,DynamoDB 都交付 穩定的個位數毫秒 效能。
  • 你想要零營運負擔。 沒有例項、沒有故障轉移、沒有 vacuum —— 它完全託管,並能按需縮容 到零。
  • 寫入吞吐量高而尖峰。 事件日誌、IoT 遙測、會話/購物車狀態、排行榜 —— 帶有清晰鍵的、 以追加為主的工作負載。

反對它的訊號

在以下情況轉向關係型資料庫(或搜尋/分析引擎):

  • 你的查詢是即席的。 分析師按任意列切分資料,或需求每週都變。這時 SQL 的靈活性勝出; DynamoDB 則需要為每個模式建一個新索引。
  • 你需要在整個資料集上做真正的 join 和聚合。 報表、商業智慧、「按地區按月彙總收入」—— 那是 OLAP/關係型的活兒。(對著實時表提一次性問題則是另一回事——DynoTable 的 SQL Workbench 會在用戶端對 DynamoDB 執行 JOINGROUP BY 和聚合;真正該放到別處的是常態化的 BI 工作負載。)
  • 資料集小且低流量。 一個安靜的管理後臺裡幾千行資料,從 DynamoDB 的規模裡得不到好處, 反而失去了 SQL 的便利。
  • 你還無法預測訪問模式。 早期產品仍在摸索形態?一個你能自由重新查詢的關係型 schema 在 模式穩定下來之前更寬容。
否,即席 / 多變否,小且安靜新的工作負載訪問模式已知且基於鍵?關係型資料庫需要跨資料集的 join / 分析?高規模或尖峰寫入?DynamoDB

DynamoDB 與其他資料庫的對比

「該用 DynamoDB 還是 X?」通常只是同一個問題換了身衣服:X 能不能讓我把訪問模式的決定往後推,而我要為此付出什麼代價? DynamoDB 正是那個拒絕讓你往後推的選項。下面每一組對比都圍繞這一個取捨展開,而不是功能清單。

關係型:PostgreSQL、RDS 與 Aurora

這才是真正的分岔口,也是最多團隊走錯的那個。關係型資料庫允許你在拿到資料之後再寫查詢。DynamoDB 不行 —— 表的形態在第一個項寫入之前,就已經被查詢決定了。

當查詢形態還在變動、當你需要跨整個資料集做 join 或聚合、或者資料量小到規模根本不是你的問題時,選關係型。當訪問模式已經定型且基於鍵,而你希望它在十億個項時的代價和一千個項時一樣時,選 DynamoDB。

RDS 和 Aurora 並不改變這筆賬 —— 它們是託管的關係型引擎,因此既繼承了 SQL 的靈活性,也繼承了它的擴充套件模型。它們改變的是營運層面的對比:有了 Aurora Serverless,DynamoDB「沒有伺服器要管」這個論點就弱了很多,決策於是乾淨地落回訪問模式上。Aurora 擴充套件的是計算;DynamoDB 直接取消了這個概念。

文件型:MongoDB 與 DocumentDB

兩者都儲存類 JSON 的文件,所以遠看像是可以和 DynamoDB 互換。其實不然。MongoDB 能為任意欄位建索引並對其執行即席查詢;DynamoDB 給你的只有分割區索引鍵、排序索引鍵,以及你事先宣告好的那些索引。

這讓 MongoDB 更適合仍在演進的查詢形態,而 DynamoDB 更適合高流量下已知的查詢形態。DocumentDB 處在同一條線的 AWS 一側 —— 它相容 MongoDB API,所以把它看作「MongoDB 的靈活性,加上 AWS 的營運模型」,並且完全按上面那條「靈活性對可預測性」的軸來和 DynamoDB 比較。

寬列型:Cassandra

Cassandra 是 DynamoDB 在架構上最近的親戚:分割區索引鍵、聚簇鍵,以及同樣那條硬道理 —— 糟糕的分割區索引鍵是一個你無法靠加索引繞開的設計缺陷。如果你在兩者之間做選擇,決定因素很少是資料模型 —— 而是誰來營運它,以及你怎麼付錢。Cassandra 要你自己營運(或者買託管服務);DynamoDB 則是你直接消費。Amazon Keyspaces 是託管版 Cassandra 的折中地帶。

正因為模型如此接近,本站的建模指導大多可以遷移過去:單表設計中關於分割區索引鍵和訪問模式的那套推理,幾乎可以逐行套用到 Cassandra 上。

記憶體型:Redis

這並不是一個真正的二選一。Redis 以記憶體為先,為亞毫秒級訪問那些丟了也能重建的資料而最佳化;DynamoDB 則預設持久。生產環境裡常見的答案是兩者都要 —— DynamoDB 作為權威資料來源,Redis(或者 DAX,也就是 DynamoDB 自己的讀穿透快取)擋在熱鍵前面。

只有當資料確實是短暫的時候,才單獨選 Redis:限流計數器、短生命週期的會話、可以重新算出來的排行榜。

搜尋型:Elasticsearch 與 OpenSearch

這同樣不是一個二選一,而且理由比 Redis 那節更直白:DynamoDB 根本沒有全文搜尋。 Query 只能按鍵相等以及一小組排序索引鍵條件來匹配。帶 FilterExpressionScan 會讀取每一個項,然後把其中大部分丟掉 —— 那是一次外掛了篩選條件的全表遍歷,不是搜尋,而且你付的是讀取的項的錢,而不是返回的項的錢。這裡沒有相關性排序,沒有分析器,沒有模糊匹配,也沒有分面。

所以問題從來不是「DynamoDB 還是搜尋引擎」,而是「這個工作負載需不需要搜尋?如果需要,誰來喂這個索引?」標準形態是兩者都要:DynamoDB 作為權威資料來源,旁邊跟一個搜尋叢集,由 DynamoDB Streams 把每一次變更送進索引。這買來了真正的搜尋,代價是你要多營運一套系統,還要接受一個與表最終一致的索引。

OpenSearch 和 Elasticsearch 是同一個決定。 OpenSearch 是 AWS 從 Elasticsearch 分叉出來的版本,2021 年因 Elastic 的許可證變更在 7.10 處分道揚鑣,此後兩者漸行漸遠。但這些差異都不影響這裡的問題 —— 對於「搜尋該不該放在 DynamoDB 之外」,它們的表現完全一致。在兩者之間做選擇,看的是許可、託管方式和你想營運哪個託管服務,而不是任何和 DynamoDB 有關的因素。

只有當搜尋確實就是產品本身時,才把搜尋引擎當作主儲存 —— 日誌分析,或者主要訪問模式就是自由文字的商品目錄。即便如此,大多數團隊仍會在它後面保留一個持久化儲存,因為搜尋索引是一個派生檢視,你必須能夠重建它。

資料模型對比掩蓋掉的成本維度

上面每一組對比談的都是資料模型,但賬單上的意外通常是結構性的:關係型引擎按你預置的容量計費,DynamoDB 按你執行的操作計費。這讓 DynamoDB 對尖峰和空閒的工作負載很便宜,對持續掃描則很昂貴 —— 同一個工作負載可以在一個引擎上大獲全勝,在另一個上慘敗,中間連一行程式碼都不用改。

人們漏掉的那個倍數是索引。在關係型引擎上,多一個索引的代價是儲存加上一點寫入延遲;在 DynamoDB 上,每一個次要索引都意味著對投影的屬性做一次完整的額外寫入。我們在索引指南裡按三種寫入量把這筆賬算了出來 —— 一個 GSI 讓寫入賬單翻倍,兩個則變成三倍。在你倒向任何一邊之前,先用定價計算器給你真實的讀/寫組合建個模。

在投入前算清成本

DynamoDB 的定價跟隨讀取、寫入和儲存 —— 而非例項小時 —— 所以它對尖峰和無伺服器工作負載很便宜, 對持續的大量掃描則可能昂貴。在投入之前用 DynamoDB 定價計算器給你真實的讀/寫組合建模;一個技術上 看似合適的工作負載,在成本上也應該算得過來。

一旦你判定它合適

工作就轉向建模了。DynamoDB 獎勵那些把表圍繞查詢來設計的做法 —— 見如何在 DynamoDB 中建模資料單表設計——以及明確的 何時不該採用單表設計

在 DynoTable 的條目網格中瀏覽一張有資料的 DynamoDB 表。
在 DynoTable 的條目網格中瀏覽一張有資料的 DynamoDB 表。

陷阱與後續步驟

  • 別把 DynamoDB 當關系型資料庫來建模 —— 在讀取時 join 的規範化表,正是它懲罰得最狠的 反模式。
  • 別拿它做分析 —— 把它和一個分析儲存搭配(或匯出到一個),用於報表,而不是去掃描。
  • 不確定訪問模式?再等等。 在你瞭解自己的查詢之前就採用 DynamoDB,是選了那個唯一要求你 必須先了解查詢的資料庫。
  • 相關: Query 與 Scan 展示了「基於鍵的訪問」究竟為你買到了什麼。

想在把應用押上去之前先探索一張 DynamoDB 表嗎?下載 DynoTable,直接連到你的資料——它的 SQL Workbench 能執行那些 DynamoDB 自己不肯跑的臨時 JOIN 和聚合。

已更新