【发布时间】:2021-05-11 14:30:56
【问题描述】:
我正在尝试使用 C# 驱动程序 (v2.11.6) 上的 BulkWrite 将大约 150k 更新推送到 Mongo 数据库(在 Windows 上运行的 v 4.2.9,具有两个节点的阶段副本),看起来这是不可能的。该项目是.Net Framework 4.7.2。
Mongo c# 驱动程序文档很糟糕,但不知何故,在论坛和大量谷歌搜索下,我终于能够find a way 如何使用批处理运行大约 150k 更新,类似这样(对于 SO 稍微简化了一点):
client = new MongoClient(connString);
database = client.GetDatabase(db);
// Build all the updates
List<UpdateOneModel<GroupEntry>> updates = new List<UpdateOneModel<GroupEntry>>();
foreach (GroupEntry groupEntry in stats)
{
FilterDefinition<GroupEntry> filter = Builders<GroupEntry>.Filter.Eq(e => e.Key, groupEntry.Key);
UpdateDefinitionBuilder<GroupEntry> update = Builders<GroupEntry>.Update;
var groupEntrySubUpdates = new List<UpdateDefinition<GroupEntry>>();
if (groupEntry.Value.Clicks != 0)
groupEntrySubUpdates.Add(update.Inc(u => u.Value.Clicks, groupEntry.Value.Clicks));
if (groupEntry.Value.Position != 0)
groupEntrySubUpdates.Add(update.Set(u => u.Value.Position, groupEntry.Value.Position));
UpdateOneModel<GroupEntry> groupEntryUpdate = new UpdateOneModel<GroupEntry>(filter, update.Combine(updates));
groupEntryUpdate.IsUpsert = true;
updates.Add(groupEntryUpdate);
}
// Now BulkWrite them in transaction to make sure data are consistent
IClientSessionHandle session = client.StartSession();
session.StartTransaction();
IMongoCollection<GroupEntry> collection = database.GetCollection<GroupEntry>(collectionName);
// Following line FAILS after some time
BulkWriteResult<GroupEntry> bulkWriteResult = collection.BulkWrite(session, updates);
if (!bulkWriteResult.IsAcknowledged)
throw new Exception("Mongo BulkWrite is not acknowledged!");
session.CommitTransaction();
问题是我不断收到以下异常:
{
"operationTime":Timestamp(1612737199,
1),
"ok":0.0,
"errmsg":"Exec error resulting in state FAILURE :: caused by :: operation was interrupted",
"code":262,
"codeName":"ExceededTimeLimit",
"$clusterTime":{
"clusterTime":Timestamp(1612737199,
1),
"signature":{
"hash":new BinData(0,
"ljcwS5Gf2JBpEu/OgPFbvRqclLw="")",
"keyId":"NumberLong(""6890288652832735234"")"
}
}
}
有人知道吗? Mongo c# 驱动程序文档完全没用。看起来我应该以某种方式设置属性 $maxTimeMS,但在 BulkInsert 上是不可能的。我试过了:
- 重新启动和重建
- MongoDriver 的不同版本
- 为 MongoClient 和会话上的所有“超时”属性设置更大的超时
- 为 BulkWrite 创建更小的批次(每批次最多 1000 个项目)。在 50-100 次更新后失败。
- 在无用的 Mongo docs 和 Mongo JIRA 上花费数小时
到目前为止还没有运气。有趣的是,相同的方法适用于 .Net CORE 3.1 上的 c# 驱动程序 2.10.3(是的,我尝试过),即使批量更大(大约 300k 更新)。
我错过了什么?
编辑:
我尝试根据 dododo 的 cmets 将 maxCommitTime 设置为 25 分钟,如下所示:
IClientSessionHandle session = client.StartSession(new ClientSessionOptions()
{
DefaultTransactionOptions = new TransactionOptions(new Optional<ReadConcern>(ReadConcern.Default),
new Optional<ReadPreference>(ReadPreference.Primary),
new Optional<WriteConcern>(WriteConcern.Acknowledged),
new Optional<TimeSpan?>(TimeSpan.FromMinutes(25)))
});
现在在执行提交时会引发异常:NoSuchTransaction - 事务 1 已中止。。我们检查了 MongoDB 日志文件,并在其中发现了新的错误:
在会话中使用 txnNumber 1 中止交易 09ea7755-7148-43e8-83d8-8bf58c211bda 因为它已经运行了 长于 'transactionLifetimeLimitSeconds
基于docs,默认为 60 秒。所以我们将它设置为 5 分钟,现在它可以工作了。
所以,谢谢你 dododo 为我指明了正确的方向。
无论如何,如果 Mongo 团队更好地描述错误并在基本 CRUD 操作之上编写文档,那就太好了。
【问题讨论】:
-
这是一个服务器错误(不是 .NET 驱动程序),看起来
maxTimeMS仅适用于游标。我怀疑这是一种事务行为,而不是批量操作本身,所以大概,您的操作在没有会话的情况下工作。如果是这样,请尝试在事务选项中设置maxCommitTime -
that the same approach works on c# driver 2.10.3 on .Net CORE 3.1- 这看起来很可疑,你能再尝试一下吗?就像在 2.10.3 和 2.11.6 的 net framework 和 net core 中再次检查相同的数据库版本、具有相同索引的相同数据结构/记录? -
即使您抨击文档,您仍然应该包含您在其中找到的相关信息。
-
dododo 我尝试了您的建议并相应地更新了问题。谢谢。关于 .Net Core 3.1 - 我无法执行您的建议(stage/prod env),但根据分辨率,看起来生产速度足以在 60 秒内完成每笔交易。这就是它在那里工作的原因。 D. DM:我添加了指向描述这种方法的页面的链接。
-
现在可以正常工作了。所以再次感谢你渡渡鸟。
标签: c# mongodb timeout bulk bulkupdate