績效的最佳做法
使用此資訊將最佳實作應用於您在 IBM Cloud 上執行的 Databases for MongoDB 部署。
效能疑難排解流程圖
使用流程圖來決定如何排除效能故障,以及下一步要採取的步驟。
┌─────────────────────────────────┐
│ Performance issue detected │
└────────────┬────────────────────┘
│
▼
┌─────────────────────────────────┐
│ Check IBM Cloud Monitoring │
│ - CPU > 80%? │
│ - Memory > 80%? │
│ - Disk latency high? │
└────────────┬────────────────────┘
│
┌────┴────┐
│ YES │
▼ │
┌──────────────┐ │
│ Scale │ │
│ resources │ │
└──────────────┘ │
│ NO
▼
┌─────────────────────┐
│ Check slow queries │
│ db.system.profile │
└─────────┬───────────┘
│
┌────┴────┐
│ Found? │
▼ │
┌─────────┐ │
│ Optimize│ │
│ queries │ │
│ & indexes│ │
└─────────┘ │
│ NO
▼
┌────────────────┐
│ Check Locks │
│ currentOp() │
└────────┬───────┘
│
┌────┴────┐
│ Locked? │
▼ │
┌─────────┐ │
│ Kill or │ │
│ optimize│ │
└─────────┘ │
│ NO
▼
┌────────────────┐
│ Check cache │
│ hit ratio │
└────────┬───────┘
│
┌────┴────┐
│ < 95%? │
▼ │
┌─────────┐ │
│ Scale │ │
│ memory │ │
└─────────┘ │
│ NO
▼
┌────────────────┐
│ Check │
│ replication │
└────────┬───────┘
│
┌────┴────┐
│ Lagging?│
▼ │
┌─────────┐ │
│ Scale │ │
│ or fix │ │
└─────────┘ │
│ NO
▼
┌────────────────┐
│ Contact IBM │
│ Support │
└────────────────┘
常見的反模式
避免這些導致效能問題的常見錯誤。
查詢反模式
1.遺失索引
問題:
// No index on 'email' field
db.users.find({ email: "user@example.com" })
解決方案:
// Create index
db.users.createIndex({ email: 1 })
2.低效的 regex 查詢
問題:
// Case-insensitive regex without index
db.users.find({ name: /john/i })
解決方案:
// Use text index or exact match
db.users.createIndex({ name: "text" })
db.users.find({ $text: { $search: "john" } })
3.大型 skip() 作業
問題:
// Skipping thousands of documents
db.collection.find().skip(10000).limit(10)
解決方案:
// Use range queries with indexed field
db.collection.find({ _id: { $gt: lastSeenId } }).limit(10)
4.選擇不必要的欄位
問題:
// Fetching entire documents
db.users.find({ status: "active" })
解決方案:
// Use projection
db.users.find({ status: "active" }, { name: 1, email: 1 })
5.低效的聚合管道
問題:
// $match after $lookup
db.orders.aggregate([
{ $lookup: { ... } },
{ $match: { status: "completed" } }
])
解決方案:
// $match first to reduce documents
db.orders.aggregate([
{ $match: { status: "completed" } },
{ $lookup: { ... } }
])
模式設計問題
1.無界陣列
問題:
// Array grows indefinitely
{
userId: 123,
activities: [/* thousands of items */]
}
解決方案:
// Use separate collection or bucketing
{
userId: 123,
month: "2024-01",
activities: [/* limited items */]
}
2.過度嵌入
問題:
// Deeply nested documents
{
user: {
profile: {
settings: {
preferences: {
// many levels deep
}
}
}
}
}
解決方案:
// Flatten or use references
{
userId: 123,
profileId: 456
}
3.大型文件
問題:
// Documents approaching 16MB limit
{
data: "very large string...",
attachments: [/* large binary data */]
}
解決方案:
// Store large data separately (GridFS or object storage)
{
dataRef: "s3://bucket/key",
attachments: [{ ref: "gridfs://id" }]
}
連線管理錯誤
1.未使用連線池
問題:
// Creating new connection per request
app.get('/api/users', async (req, res) => {
const client = await MongoClient.connect(uri);
// ...
await client.close();
});
解決方案:
// Reuse connection pool
const client = new MongoClient(uri, { maxPoolSize: 50 });
await client.connect();
app.get('/api/users', async (req, res) => {
const db = client.db();
// ...
});
2.不關閉游標
問題:
// Cursor left open
const cursor = db.collection.find();
// Never closed
解決方案:
// Always close cursors
const cursor = db.collection.find();
try {
await cursor.forEach(doc => { /* process */ });
} finally {
await cursor.close();
}
3.連接太多
問題:
// One connection per user session
const connections = new Map();
users.forEach(user => {
connections.set(user.id, new MongoClient(uri));
});
解決方案:
// Share connection pool across application
const client = new MongoClient(uri);
// All users share the same pool
索引陷阱
1.太多索引
問題:
// Index on every field
db.collection.createIndex({ field1: 1 })
db.collection.createIndex({ field2: 1 })
db.collection.createIndex({ field3: 1 })
// ... 20+ indexes
影響: 減慢寫入速度並增加儲存空間。
解決方案: 只保留必要的索引,並使用複合索引。
2.複合索引中索引順序錯誤
問題:
// Query: { status: "active", createdAt: { $gt: date } }
// Index: { createdAt: 1, status: 1 } // Wrong order
解決方案:
// Correct order: equality first, range second
db.collection.createIndex({ status: 1, createdAt: 1 })
3.不使用涵蓋查詢
問題:
// Index exists but query not covered
db.users.createIndex({ email: 1 })
db.users.find({ email: "user@example.com" }, { name: 1, email: 1 })
// Still fetches documents
解決方案:
// Include all projected fields in index
db.users.createIndex({ email: 1, name: 1 })
db.users.find({ email: "user@example.com" }, { name: 1, email: 1, _id: 0 })
附錄:度量臨界值
關鍵績效指標的建議臨界值。
| 度量 | 警告臨界值 | 嚴重臨界值 | 建議動作 |
|---|---|---|---|
| CPU 使用率 |
|
|
縮放 CPU 核心 |
| 記憶體使用率 |
|
|
縮放記憶體分配 |
| 磁碟使用率 |
|
|
擴充磁碟空間 |
| 磁碟 IOPS | 限值的 80 |
|
增加磁碟大小以獲得更多 IOPS |
| 作用中連線 | 限值的 80 |
|
規模規劃或最佳化連線池 |
| 抄寫延遲 |
|
|
調查並視需要調整規模 |
| 快取命中率 | < 95% | < 90% | 擴充記憶體或最佳化查詢 |
| 查詢執行時間 |
|
|
最佳化查詢和索引 |
| 鎖定等待時間 |
|
|
最佳化作業並終止長時間執行的查詢 |
| 尋頁錯失數 |
|
|
刻度記憶 |
| 網路延遲 |
|
|
檢查網路設定 |
| 備份持續時間 |
|
|
考慮擴充或最佳化 |
監測頻率建議
| 度量種類 | 檢查頻率 | 保留期間 |
|---|---|---|
| 資源使用率 | 每 1 分鐘 | 30 天 |
| 查詢效能 | 每 5 分鐘 | 14 天 |
| 抄寫狀態 | 每 1 分鐘 | 30 天 |
| 連線統計資料 | 每 5 分鐘 | 14 天 |
| 備份狀態 | 每隔 1 小時 | 90 天 |
| 磁碟成長 | 每隔 1 小時 | 90 天 |
警報設定範例
CPU 警報
Condition: CPU > 80% for 10 consecutive minutes
Action: Send notification to ops team
Escalation: Page on-call if > 90% for 15 minutes
記憶體警示
Condition: Memory > 85% for 15 consecutive minutes
Action: Send notification to ops team
Escalation: Auto-scale if > 95% for 10 minutes
複製滯後警示
Condition: Lag > 10 seconds
Action: Send notification immediately
Escalation: Page on-call if > 60 seconds
磁碟空間警示
Condition: Disk > 80%
Action: Send notification to ops team
Escalation: Create incident if > 90%
最佳實務摘要
| 範疇 | 建議 |
|---|---|
| 檢索 | 定期檢視並移除未使用的索引 |
| 監視 | 設定 CPU、記憶體、磁碟和複製滯後警示 |
| 容量規劃 | 將磁碟使用率維持在 80% 以下,並主動進行擴充 |
| 查詢設計 | 在開發過程中使用解釋計劃 |
| 調整 | 在飽和之前主動調整規模 |
| 連線儲存區 (connection pooling) | 使用連線池並避免每次要求連線 |
| 閱讀偏好 | 針對讀取繁重的工作負載使用副檔 |
| 書面關注 | 平衡耐用性與效能需求 |
| 模式設計 | 避免無界陣列和過度嵌入 |
| 備份規劃 | 安排在低流量時段 |
| 網路 | IBM Cloud 工作負載使用專用端點 |
| 安全 | 定期輪換憑證,並使用 IP 允許列表 |
| 文件 | 記錄基線指標和正常模式 |
| 測試 | 先在非生產階段測試效能變更 |
| 支援 | 聯絡支援人員前先收集診斷資料 |