資料庫設計的旅程,始於對 商業領域(Domain) 的深刻理解,途經對工具的理性選擇,最終落實於對效能與彈性的精巧平衡。它是一個 商業邏輯思維實現 的沉默英雄。在初期可能不被注意,但在系統面對巨大流量和複雜需求的壓力時,其堅實的架構將決定系統的成敗。這份遠見與戰略思維,正是資料庫設計從 「技術應用」 昇華為 「設計藝術」 的關鍵。
成功的資料庫設計,是一場在「商業需求」、「技術現實」與「未來變化」之間,不斷權衡與取捨的戰略藝術。
在進行資料庫技術選型時,我們就必須做好 需求解析的工作。某種程度上,身為一個架構師與工程師,商業領域(Domain)的理解程度上一定會且 要 比其他人來得更加深刻。 系統的 核心價值 是什麼? 資料的樣貌是什麼? 系統最常對資料做什麼? 系統規模的未來曲線如何成長?
我們必須要有個深刻理解脈絡與工具,好進行 需求解析
=> 技術選型
=> Schema 設計
資料庫設計的哲學,就是一場從抽象到具體的旅程,這也是 DDD 最重要、最核心的概念:
我們在一開始時,必須先忘掉技術,成為偵探與心理學家,我們必須深入理解「商業故事」,找出系統中的 核心主角 (Entities) 、他們之間的 關係 (Relationships)、 會發生的故事 (Operations),以及必須遵守的 規則 (Constraints)。
我們在這個階段,必須
忘掉技術,專注於「商業邏輯」與「資料故事」
我們需求解析階段花的時間越多,後面返工的機率就越低。一個模糊的藍圖,只會蓋出一棟搖搖欲墜的危樓。
以之前所說的分層租戶-Netflix 為例
在串流影視平台的設計開始前,可以先按照以下順序逐步釐清我們抽象的 商業實現邏輯概念
使用者 (User)
、影視作品 (VideoContent)
、工作室 (Studio)
、版權合約 (License)
。這些就是我們未來資料庫裡的主要「名詞」。category
來進行概念上的區分了。tag
的原因是:category
代表的是一種本質性、互斥的分類,一個作品要嘛是電影,要嘛是連續劇,這個分類決定了它的基本資料結構(例如連續劇有季、集的概念,電影則沒有)。而 tag
(標籤) 是一種描述性、非互斥的屬性,一部電影可以同時有「科幻」、「動作」、「奧斯卡得獎」等多個標籤。在需求解析階段,分清「本質分類」與「描述標籤」至關重要。使用者
觀看 (WATCHES) 影視作品
,也可以 評分 (RATES) 它。影視作品
由某個 工作室
製作 (PRODUCED_BY)。影視作品
在特定 地理區域 (Region)
的播放權,受一份 版權合約
約束 (LICENSED_UNDER)。使用者
可以有多個 使用者設定檔 (Profile)
,例如家庭共享帳號下的「爸爸」、「媽媽」、「小孩」。再用這個邏輯思路來進行兩個情境復驗 Uber Eats 與 TSMC 晶圓工廠 IoT
用戶 (User)
:下訂單的顧客。餐廳 (Restaurant)
:提供餐點的商家。外送員 (Courier)
:負責運送餐點的合作夥伴。訂單 (Order)
:一次完整的交易紀錄,是連接所有主角的關鍵。餐點 (MenuItem)
:菜單上的具體品項。菜系 (Cuisine)
:如「日式」、「義式」、「速食」等分類。支付方式 (PaymentMethod)
:如信用卡、Apple Pay。用戶
可以下多筆 (PLACES) 訂單
。訂單
只能屬於一個 (BELONGS_TO) 用戶
,並且 來自一家 (ORDERED_FROM) 餐廳
。訂單
包含多個 (CONTAINS) 餐點
。訂單
在特定階段會被 指派給 (ASSIGNED_TO) 一位 外送員
。餐廳
提供多種 (SERVES) 餐點
,並 屬於一種或多種 (SPECIALIZES_IN) 菜系
。用戶
可以有多種 (HAS_PAYMENT_METHOD) 支付方式
。外送員
位置的即時追蹤。這是地圖上移動的點,對延遲極度敏感。用戶
瀏覽附近餐廳列表、滑動菜單、搜尋特定餐點。用戶
查詢進行中訂單的狀態(已接單、準備中、外送中)。用戶
提交 訂單
。這是系統在用餐尖峰時段的寫入瓶頸。用戶
給予 餐廳
或 餐點
評分。用戶
將某家 餐廳
加入收藏。餐廳
更新菜單、價格或營業時間。用戶
新增或刪除 支付方式
。用戶
只能看到在其外送範圍內的 餐廳
。用戶
只能向正在營業的 餐廳
下訂單。訂單
的成立與 支付
的成功必須是原子操作;支付失敗,訂單就不能成立。狀態
(例如「外送員已取餐」)的更新,必須能即時地被 用戶
和 餐廳
兩方看到。訂單
在同一時間只能被一位 外送員
配送。我們首先要深入理解晶圓製造的「商業故事」,釐清數據背後的物理意義
機台 (Machine)
:如蝕刻機、曝光機,是數據產生的源頭。感測器 (Sensor)
:安裝在機台上的具體測量單元,如溫度計、壓力計。晶圓 (Wafer)
:正在被加工的產品,每一片都有獨一無二的 ID。批次 (Lot/Batch)
:一組一起加工的晶圓,共享相同的製程參數。製程參數 (Recipe)
:一套指令,定義了機台在處理某個批次時的設定值。維運人員 (Operator)
:負責監控與操作機台的人。機台
上安裝了多個 感測器
。機台
在特定時間正在處理某一個 批次
中的某一片 晶圓
。批次
的加工過程遵循一套 製程參數
。維運人員
。超高頻寫入 (Ultra High-Frequency Write):數萬個 感測器
以毫秒為單位,持續不斷地將測量數據(溫度、壓力、震動)寫入系統。 這是系統最主要的負載。
高頻讀取 (High-Frequency Read):
維運人員
的儀表板需要以秒級更新,顯示最近幾分鐘的關鍵參數曲線。批次
參數(如溫度)偏離 製程參數 設定的範圍,必須在秒內觸發警報。中頻讀取 (Medium-Frequency Read):
批次
在某個 機台
上的完整加工歷史數據,以分析良率下降的原因。查詢範圍通常是數小時到數天。低頻讀取 (Low-Frequency Read):
數據完整性:任何 感測器
的數據都不能遺失,因為單一數據點的遺失可能導致整個批次的良率分析失敗。
時間精確性:所有數據必須帶有精確到毫秒的時間戳,且順序絕不能錯亂。時間是這個領域最重要的維度。
數據保留策略:出於品質追溯和合規要求,原始數據可能需要被保留數年之久。
低延遲警報:異常發生時,從數據產生到觸發警報的總延遲必須控制在秒級以內。
我們對於 需求解析 (建築藍圖) 有個概念如下
初步釐清需求後,接下來的重要節點是 技術選型
理論上來說,當需求的覆蓋率在已知的討論環節中(詳見<商業邏輯的轉化發>)已經盡可能地趨近 80%,這已經很接近我們的初步具體化系統,也符合 80/20 權衡法則的策略區分,我們應該會有一個概念:
我會在這個 會發生的故事 (Operations)
下,因為 必須遵守的規則 (Constraints)
,建置對應的資料庫設計
在這時候有一個分析工具叫做 鑽石模型
這是一種抽象的決策藝術,幫助我們在四個關鍵切面之間進行權衡,打磨出最佳設計,四個面向分別是 : 業務邏輯、資料特性、應用模式、系統規模
鑽石模型的精髓在於,它強調這些維度是交互影響的。一個好的設計,不會只看單一切面,而是會綜合評估,在看似衝突的需求中找到那個精妙的平衡點。例如,為了應對「海量規模」(維度四),我們可能會在「業務邏輯」(維度一)上放寬對即時一致性的要求。
我們可以根據在一開始 會發生的故事 (Operations)
中依據 核心主角 (Entities)
的 會發生的故事 (Operations)
特性進行技術上的選擇,而常見的特性如下
資料變更頻率:
資料量級規模:
一致性需求:
查詢模式:
災難恢復:
這次我們換個順序,從 **晶圓 IoT 會發生的故事 (Operations)
** 開始說起。
- 超高頻寫入 (Ultra High-Frequency Write):
- 數萬個
感測器
以毫秒為單位,持續不斷地將測量數據(溫度、壓力、震動)寫入系統。 這是系統最主要的負載。- 高頻讀取 (High-Frequency Read):
- 即時監控:
維運人員
的儀表板需要以秒級更新,顯示最近幾分鐘的關鍵參數曲線。- 即時警報:系統需要持續掃描傳入的數據,一旦某個
批次
參數(如溫度)偏離 製程參數 設定的範圍,必須在秒內觸發警報。- 中頻讀取 (Medium-Frequency Read):
- 良率分析:品管工程師需要查詢某個
批次
在某個機台
上的完整加工歷史數據,以分析良率下降的原因。查詢範圍通常是數小時到數天。- 低頻讀取 (Low-Frequency Read):
- 趨勢分析與模型訓練:研發工程師需要分析過去數年的數據,以優化 製程參數 或訓練預測性維護的機器學習模型。查詢範圍極大,但對即時性要求不高
從需求解析中我們看到,數據的價值和存取模式與其「年齡」高度相關。這是一個 「冷熱資料分層」 與 「CQRS」 混合應用場景。
S3
提供近乎無限且成本極低的儲存空間。AWS Glue
負責將數據從 Timestream 或直接從 IoT 來源轉換為適合分析的 Parquet
格式。Amazon Athena
讓工程師可以直接用標準 SQL 對儲存在 S3 上的海量數據進行 ad-hoc 查詢,而無需管理任何伺服器。從上面的需求解析我們能清楚看到,Netflix 不是一個單一的系統,而是一個由多個不同需求的「子宇宙」組成的聯邦。強行用一種資料庫解決所有問題,就像只用一種螺絲起子去組裝一整台電腦,是注定會失敗的。因此,我們必須採用「多語言持久化 (Polyglot Persistence)」的策略。
- 高頻讀取:
- 使用者瀏覽目錄、搜尋影片、觀看影片。這是系統 最主要的流量來源 ,對 延遲極度敏感。
- 中頻寫入:
- 系統記錄使用者的觀看歷史、更新看到一半的影片時間戳、儲存用戶的評分。
- 低頻寫入:
- 內容團隊上傳新的影視作品、更新作品的封面或簡介、設定新的版權合約。
影視目錄、搜尋與個人化推薦 (元數據 Domain)
MongoDB
用來儲存影視作品的詳細元數據,其彈性的 Schema 非常適合應對多變的內容屬性。OpenSearch
則用來建立搜尋索引,提供高效能的關鍵字搜尋、分類篩選與聚合分析。推薦引擎的關係數據也可以部分儲存在圖資料庫 Neptune
中。使用者觀看歷史與狀態 (行為日誌 Domain)
DynamoDB
的鍵值模型非常適合以 UserID
為分區鍵,VideoID
或 Timestamp
為排序鍵的設計,能提供近乎無限的擴展性與低延遲的讀寫。用戶帳號、訂閱與支付 (交易 Domain)
PostgreSQL
的事務能力和成熟的生態系,是處理金融相關數據、確保帳務準確無誤的不二之選。
- 超高頻讀取/更新 (Real-time Streaming):
外送員
位置的即時追蹤。這是地圖上移動的點,對延遲極度敏感。- 高頻讀取 (Read-Heavy):
用戶
瀏覽附近餐廳列表、滑動菜單、搜尋特定餐點。用戶
查詢進行中訂單的狀態(已接單、準備中、外送中)。- 高頻寫入 (Write-Heavy):
用戶
提交訂單
。這是系統在用餐尖峰時段的寫入瓶頸。- 中頻寫入 (Medium-Write):
用戶
給予餐廳
或餐點
評分。用戶
將某家餐廳
加入收藏。- 低頻寫入 (Low-Write):
餐廳
更新菜單、價格或營業時間。用戶
新增或刪除支付方式
。
需求解析清楚地告訴我們,Uber Eats 的業務是由多個特性迥異的「界定上下文 (Bounded Context)」組成的。
order_id
進行快速讀寫,並能輕鬆應對流量洪峰,實現水平擴展。flowchart TD
A[系統需求分析] --> B{工作負載類型?}
B -->|OLTP 交易型| C{一致性需求?}
B -->|OLAP 分析型| D{資料模型?}
B -->|搜尋型| E[OpenSearch + CloudFront]
B -->|時間序列| F[Timestream + Redis]
B -->|圖形關係| G[Neptune + Redis]
C -->|強一致性| H{資料模型?}
C -->|最終一致性| I{資料模型?}
H -->|關聯式| J[RDS PostgreSQL<br/>+ ElastiCache Redis<br/>+ Multi-AZ]
H -->|文件型| K[DocumentDB<br/>+ DAX<br/>+ Cross-Region]
I -->|文件型| L[DynamoDB<br/>+ DAX<br/>+ Global Tables]
I -->|鍵值對| M[ElastiCache<br/>+ Cross-AZ<br/>+ Backup]
D -->|列式存儲| N[Redshift<br/>+ Spectrum<br/>+ S3 Data Lake]
D -->|文件分析| O[EMR + S3<br/>+ Glue<br/>+ Athena]
E --> P[成本效益分析]
F --> P
G --> P
J --> P
K --> P
L --> P
M --> P
N --> P
O --> P
P --> Q{預算範圍?}
Q -->|< $1000/月| R[基礎配置]
Q -->|$1000-5000/月| S[標準配置]
Q -->|> $5000/月| T[企業配置]
R --> U[最終架構建議]
S --> U
T --> U
graph LR
subgraph "決策維度"
A1[工作負載<br/>OLTP/OLAP/Search/Graph]
A2[一致性需求<br/>Strong/Eventual/Causal]
A3[資料模型<br/>Relational/Document/KV]
A4[規模需求<br/>GB/TB/PB級別]
end
subgraph "AWS 服務選型"
B1[RDS PostgreSQL<br/>關聯式OLTP<br/>強一致性]
B2[DynamoDB<br/>NoSQL OLTP<br/>最終一致性]
B3[Redshift<br/>列式OLAP<br/>分析查詢]
B4[Neptune<br/>圖資料庫<br/>關係查詢]
B5[OpenSearch<br/>全文搜尋<br/>日誌分析]
B6[Timestream<br/>時間序列<br/>IoT監控]
end
subgraph "快取策略"
C1[ElastiCache Redis<br/>毫秒級快取]
C2[DAX<br/>DynamoDB加速]
C3[CloudFront<br/>邊緣快取]
end
subgraph "災難恢復"
D1[Multi-AZ<br/>高可用性]
D2[Global Tables<br/>跨區域複製]
D3[Cross-Region<br/>災難恢復]
end
A1 --> B1
A1 --> B2
A1 --> B3
A2 --> B1
A2 --> B2
A3 --> B4
A4 --> B5
A4 --> B6
B1 --> C1
B2 --> C2
B3 --> C3
B4 --> C1
B5 --> C3
B6 --> C1
B1 --> D1
B2 --> D2
B3 --> D3
B4 --> D3
B5 --> D3
B6 --> D3
quadrantChart
title "AWS 資料庫服務的成本效能象限"
x-axis "低成本" --> "高成本"
y-axis "低效能" --> "高效能"
quadrant-1 "高效能高成本"
quadrant-2 "高效能低成本"
quadrant-3 "低效能低成本"
quadrant-4 "低效能高成本"
"RDS PostgreSQL": [0.7, 0.8]
"DynamoDB": [0.5, 0.9]
"ElastiCache": [0.8, 0.95]
"Redshift": [0.6, 0.7]
"Neptune": [0.75, 0.6]
"OpenSearch": [0.4, 0.65]
"Timestream": [0.3, 0.7]
"S3": [0.1, 0.3]
"DocumentDB": [0.65, 0.7]
我們的探討始於一個根本性的問題:什麼是資料? 結論是,資料並非單純且客觀的靜態屬性,而是 「在 特定上下文 中,由特定需求驅動的 行為 所產生的 影響 ,再經由多重視角詮釋後的記錄」。
需求( require ) => 行為(conduct) => 影響(effect)
這個認知是理解所有現代資料庫策略的基石,它解釋了為何不存在萬能的資料庫,並直接導向了 CQRS
、微服務
與 事件溯源
等架構的誕生。
基於上述哲學,我們深入解析了八種應對不同業務挑戰的核心策略,每種策略都是為了解決特定情境下的矛盾而生:
最後,我們將所有策略置於一個統一的設計框架下:
需求解析 -> 技術選型 -> Schema
設計 的流程,確保每一個技術決策都有堅實的業務邏輯支撐。總而言之,我們一同了解了資料庫設計從單純的技術應用,昇華為一門在 「商業需求」
、「技術現實」
與 「未來變化」
之間不斷尋求最佳平衡點的戰略藝術。一個卓越的架構師,如同經驗豐富的主廚,會為不同的菜餚(業務場景)挑選最合適的廚具(設計策略),最終烹調出穩定、高效且具彈性的系統盛宴。
拖了這麼久也非常不好意思,但由於資料庫的設計影響到了整個系統最基礎的根源,不得不再這邊稍微講的沒那麼模糊一點,實際上每一個核心設計策略都對應了一個資料庫設計生態系,本身就是一個宏大的學問。
明天我們將會來點輕鬆的,簡單的聊聊Git版本控制策略。