1. 监控数据库性能的必要性
在咱们开发电商系统时,某个促销日凌晨突然出现数据库响应延迟。当时手忙脚乱地登录服务器查看日志,才发现是某个未优化的聚合查询拖垮了整个集群。这种惨痛经历让我意识到:主动监控数据库性能就像给系统装"心电图",能提前发现潜在风险。
2. 环境准备与基础配置
2.1 所需技术栈
- .NET 6+ 运行环境
- MongoDB.Driver 2.18+ 驱动
- MongoDB 5.0+ 数据库
2.2 连接数据库的正确姿势
// 创建MongoClient时启用性能监控
var settings = new MongoClientSettings {
Server = new MongoServerAddress("localhost", 27017),
ClusterConfigurator = cb => {
// 启用命令事件监听(性能监控的关键配置)
cb.Subscribe<CommandStartedEvent>(e => {
Console.WriteLine($"命令开始: {e.CommandName}");
});
cb.Subscribe<CommandSucceededEvent>(e => {
Console.WriteLine($"命令成功: {e.CommandName} 耗时 {e.Duration.TotalMilliseconds}ms");
});
}
};
var client = new MongoClient(settings);
var database = client.GetDatabase("shopDB");
3. 核心性能指标监控实现
3.1 实时慢查询捕获
// 设置慢查询阈值(单位:毫秒)
var profileFilter = new BsonDocument("millis", new BsonDocument("$gt", 100));
var options = new CreateCollectionOptions {
Capped = true,
MaxSize = 1024 * 1024 // 1MB容量
};
// 创建性能分析集合
database.CreateCollection("system.profile", options);
database.SetProfilingLevel(ProfilingLevel.All, 100);
// 实时监听慢查询
var profileCollection = database.GetCollection<BsonDocument>("system.profile");
var pipeline = new EmptyPipelineDefinition<BsonDocument>()
.Match("{ op: { $ne: 'command' }, millis: { $gt: 100 } }");
using var cursor = profileCollection.Watch(pipeline);
while (cursor.MoveNext())
{
foreach (var change in cursor.Current)
{
var query = change["command"]?.AsBsonDocument;
Console.WriteLine($"慢查询告警:{query}");
}
}
3.2 连接池健康检查
// 获取连接池状态
var server = client.Cluster.SelectServer(new SelectServerOptions());
var connectionPool = server.GetConnectionPool();
var poolStats = new BsonDocument {
{ "current", connectionPool.AvailableCount },
{ "inUse", connectionPool.UsedCount },
{ "maxSize", connectionPool.MaxConnectionPoolSize }
};
Console.WriteLine($"连接池状态:{poolStats}");
// 当连接数超过90%时触发告警
if ((double)poolStats["inUse"] / poolStats["maxSize"] > 0.9)
{
Console.WriteLine("⚠️ 连接池即将耗尽!");
}
4. 高级监控技巧
4.1 索引使用情况分析
var indexesCollection = database.GetCollection<BsonDocument>("products");
var indexes = await (await indexesCollection.Indexes.ListAsync()).ToListAsync();
foreach (var index in indexes)
{
var statsCommand = new BsonDocument {
{ "collStats", "products" },
{ "indexDetails", true }
};
var stats = await database.RunCommandAsync<BsonDocument>(statsCommand);
var indexStats = stats["indexDetails"][index["name"]];
Console.WriteLine($"索引 {index["name"]} 使用次数:{indexStats["accesses"]["ops"]}");
}
4.2 内存使用监控
var serverStatus = await database.RunCommandAsync<BsonDocument>(new BsonDocument {
{ "serverStatus", 1 },
{ "mem", 1 },
{ "wiredTiger", 1 }
});
var memoryUsage = new {
Resident = serverStatus["mem"]["resident"].AsInt32,
Virtual = serverStatus["mem"]["virtual"].AsInt32,
CacheUsage = serverStatus["wiredTiger"]["cache"]["bytes currently in cache"].AsInt64
};
Console.WriteLine($"内存使用:物理 {memoryUsage.Resident}MB / 虚拟 {memoryUsage.Virtual}MB");
Console.WriteLine($"缓存使用:{memoryUsage.CacheUsage / 1024 / 1024}MB");
5. 实战应用场景
5.1 秒杀场景优化
在某次秒杀活动中,我们通过实时监控发现某个商品详情的查询耗时突然从5ms飙升到200ms。经分析发现是未命中索引导致的全表扫描,及时添加复合索引后性能恢复。
5.2 连接池泄漏排查
某服务重启后持续出现连接超时,通过监控发现连接池使用率始终维持在100%。最终定位到某个未关闭的游标导致的连接泄漏,增加using
语句后问题解决。
6. 技术方案优缺点
优势:
- 深度集成现有C#系统
- 可自定义监控指标
- 实时性高(毫秒级响应)
不足:
- 数据可视化需要二次开发
- 长期存储需自行实现
- 可能影响生产性能(需谨慎配置)
7. 实施注意事项
- 监控采样频率建议设置在5-10秒
- 生产环境慎用全量命令监控
- 确保监控账号具有
clusterMonitor
权限 - 使用单独的监控数据库防止日志膨胀
- 设置合理的熔断机制避免监控影响业务
8. 总结与展望
通过MongoDB.Driver实现性能监控,我们就像给数据库装上了"听诊器"。虽然需要一定的开发成本,但获得的灵活性和深度集成优势是第三方工具无法比拟的。未来可结合Prometheus实现指标存储,或集成Grafana打造可视化看板。