【问题标题】:MongoDB BulkWrite ExceededTimeLimit error in .Net.Net 中的 MongoDB BulkWrite ExceededTimeLimit 错误
【发布时间】: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


【解决方案1】:

正如dododo所说,这个错误是服务器关闭事务的表现,因为它比transactionLifetimeLimitSeconds花费的时间更长,默认为60秒。所以需要做两件事:

  1. 将参数transactionLifetimeLimitSeconds设置为60秒以上
  2. ma​​xCommitTime 设置为更高的值。我找不到默认值,所以我将其设置为 10 分钟(与 transactionLifetimeLimitSeconds 相同)。在开始会话时设置它(见问题)。

无论如何,这方面的文档都丢失了,并且错误本身具有误导性。所以我希望它可以帮助任何需要处理这个问题的人。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2022-11-18
    • 2019-12-06
    • 2021-04-25
    • 1970-01-01
    • 1970-01-01
    • 2021-12-23
    • 1970-01-01
    • 2021-07-06
    相关资源
    最近更新 更多