最佳绩效实践
使用此信息可将最佳实践应用于在 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.大型跳过()操作
问题:
// 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 |
|
|
增大磁盘尺寸,提高 IOPS |
| 活动连接数 |
|
|
规模规划或优化连接池 |
| 复制延迟 |
|
|
调查并根据需要扩大规模 |
| 高速缓存命中率 | < 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%
最佳做法摘要
| 区域 | 建议 |
|---|---|
| 索引 | 定期检查并删除未使用的索引 |
| Monitoring | 配置 CPU、内存、磁盘和复制滞后警报 |
| 容量规划 | 将磁盘使用率保持在 80% 以下,并主动进行扩展 |
| 查询设计 | 在开发过程中使用解释计划 |
| 缩放 | 在饱和之前主动扩大规模 |
| 连接池 (connection pooling) | 使用连接池,避免按请求连接 |
| 阅读偏好 | 使用辅助设备处理读取繁重的工作负载 |
| 写下关注 | 兼顾耐用性和性能需求 |
| 模式设计 | 避免无界数组和过度嵌入 |
| 备份规划 | 安排在人流量较少的时段 |
| 网络 | 为 IBM Cloud 工作负载使用专用端点 |
| 安全性 | 定期轮换证书并使用 IP 允许列表 |
| 文档 | 记录基准指标和正常模式 |
| 测试 | 首先在非生产环境中测试性能变化 |
| 支持 | 在联系技术支持之前收集诊断信息 |