You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

MongoDB C# Driver插入/更新时出现Thread static buffer占用错误求助

关于MongoDB C# Driver 2.20版本"Thread static buffer is already in use"偶现问题的分析与解决

问题描述

生产环境使用MongoDB C# Driver(版本2.20)插入或更新集合文档时,偶现(约1/100000概率)报错:
Thread static buffer is already in use. <--- Thread static buffer is already in use.
该问题仅在高负载或多线程场景下触发,覆盖.NET Framework及.NET Core 7的主应用与微服务环境。

简化代码片段

public IMongoCollection<TDocument> GetMongoDbCollection<TDocument>(string collectionName = null){
  IMongoCollection<TDocument> mongoCollection = null;
  try
  {
     string databaseAddress = Vault.Get("mongoDatabaseAddress"); 
     string userName = Vault.Get("mongoDbUserName");
     string password = Vault.Get("mongoDbPassword");
     MongoClient mongoClient = new MongoClient($"mongodb+srv://{userName}:{password}@{databaseAddress}/<dbname>?retryWrites=true&w=majority&serverSelectionTimeoutMS=10000");

     var database = mongoClient.GetDatabase("App");
     mongoCollection = database.GetCollection<TDocument>(collectionName);
  }
  catch (Exception ex)
  {
     LoggerClient.Error(ex);
  }
  return mongoCollection;
}

public void InsertTransactions(List<Transaction> transactions)
{
  try
  {
     var collection = this.GetMongoDbCollection<Transaction>(CurrentMongoCollection);
     // 编辑交易数据逻辑省略
     collection.InsertMany(encryptedTransactions);
  }
  catch (Exception ex)
  {
      LoggerClient.Error(ex);
  }
}

堆栈追踪信息

MongoDB.Bson.BsonSerializationException:
   at MongoDB.Bson.Serialization.BsonClassMapSerializer`1.SerializeMember (MongoDB.Bson, Version=2.20.0.0, Culture=neutral, PublicKeyToken=null)
   at MongoDB.Bson.Serialization.BsonClassMapSerializer`1.SerializeClass (MongoDB.Bson, Version=2.20.0.0, Culture=neutral, PublicKeyToken=null)
   at MongoDB.Bson.Serialization.BsonClassMapSerializer`1.Serialize (MongoDB.Bson, Version=2.20.0.0, Culture=neutral, PublicKeyToken=null)
   at MongoDB.Bson.Serialization.Serializers.SerializerBase`1.MongoDB.Bson.Serialization.IBsonSerializer.Serialize (MongoDB.Bson, Version=2.20.0.0, Culture=neutral, PublicKeyToken=null)
   at MongoDB.Bson.Serialization.IBsonSerializerExtensions.Serialize (MongoDB.Bson, Version=2.20.0.0, Culture=neutral, PublicKeyToken=null)
   at MongoDB.Bson.Serialization.Serializers.BsonValueSerializerBase`1.Serialize (MongoDB.Bson, Version=2.20.0.0, Culture=neutral, PublicKeyToken=null)
   at MongoDB.Bson.Serialization.Serializers.SerializerBase`1.MongoDB.Bson.Serialization.IBsonSerializer.Serialize (MongoDB.Bson, Version=2.20.0.0, Culture=neutral, PublicKeyToken=null)
   at MongoDB.Bson.Serialization.IBsonSerializerExtensions.Serialize (MongoDB.Bson, Version=2.20.0.0, Culture=neutral, PublicKeyToken=null)
   at MongoDB.Bson.Serialization.Serializers.BsonValueSerializerBase`1.Serialize (MongoDB.Bson, Version=2.20.0.0, Culture=neutral, PublicKeyToken=null)
   at MongoDB.Driver.Core.Operations.BulkInsertOperation+InsertRequestSerializer.SerializeValue (MongoDB.Driver.Core, Version=2.20.0.0, Culture=neutral, PublicKeyToken=null)
   at MongoDB.Bson.Serialization.Serializers.SealedClassSerializerBase`1.Serialize (MongoDB.Bson, Version=2.20.0.0, Culture=neutral, PublicKeyToken=null)
   at MongoDB.Bson.Serialization.Serializers.SerializerBase`1.MongoDB.Bson.Serialization.IBsonSerializer.Serialize (MongoDB.Bson, Version=2.20.0.0, Culture=neutral, PublicKeyToken=null)
   at MongoDB.Driver.Core.WireProtocol.Messages.Encoders.BinaryEncoders.CommandMessageBinaryEncoder.WriteType1Section (MongoDB.Driver.Core, Version=2.20.0.0, Culture=neutral, PublicKeyToken=null)
   at MongoDB.Driver.Core.WireProtocol.Messages.Encoders.BinaryEncoders.CommandMessageBinaryEncoder.WriteSections (MongoDB.Driver.Core, Version=2.20.0.0, Culture=neutral, PublicKeyToken=null)
   at MongoDB.Driver.Core.WireProtocol.Messages.Encoders.BinaryEncoders.CommandMessageBinaryEncoder.WriteMessage (MongoDB.Driver.Core, Version=2.20.0.0, Culture=neutral, PublicKeyToken=null)
   at MongoDB.Driver.Core.WireProtocol.Messages.Encoders.BinaryEncoders.CommandRequestMessageBinaryEncoder.MongoDB.Driver.Core.WireProtocol.Messages.Encoders.IMessageEncoder.WriteMessage (MongoDB.Driver.Core, Version=2.20.0.0, Culture=neutral, PublicKeyToken=null)
   at MongoDB.Driver.Core.Connections.BinaryConnection+SendMessagesHelper.EncodeMessages (MongoDB.Driver.Core, Version=2.20.0.0, Culture=neutral, PublicKeyToken=null)
   at MongoDB.Driver.Core.Connections.BinaryConnection.SendMessages (MongoDB.Driver.Core, Version=2.20.0.0, Culture=neutral, PublicKeyToken=null)
   at MongoDB.Driver.Core.ConnectionPools.ExclusiveConnectionPool+PooledConnection.SendMessages (MongoDB.Driver.Core, Version=2.20.0.0, Culture=neutral, PublicKeyToken=null)
   at MongoDB.Driver.Core.ConnectionPools.ExclusiveConnectionPool+AcquiredConnection.SendMessages (MongoDB.Driver.Core, Version=2.20.0.0, Culture=neutral, PublicKeyToken=null)
   at MongoDB.Driver.Core.Connections.ConnectionExtensions.SendMessage (MongoDB.Driver.Core, Version=2.20.0.0, Culture=neutral, PublicKeyToken=null)
   at MongoDB.Driver.Core.WireProtocol.CommandUsingCommandMessageWireProtocol`1.Execute (MongoDB.Driver.Core, Version=2.20.0.0, Culture=neutral, PublicKeyToken=null)
   at MongoDB.Driver.Core.WireProtocol.CommandWireProtocol`1.Execute (MongoDB.Driver.Core, Version=2.20.0.0, Culture=neutral, PublicKeyToken=null)
   at MongoDB.Driver.Core.Servers.Server+ServerChannel.ExecuteProtocol (MongoDB.Driver.Core, Version=2.20.0.0, Culture=neutral, PublicKeyToken=null)
   at MongoDB.Driver.Core.Servers.Server+ServerChannel.Command (MongoDB.Driver.Core, Version=2.20.0.0, Culture=neutral, PublicKeyToken=null)
   at MongoDB.Driver.Core.Operations.RetryableWriteCommandOperationBase.ExecuteAttempt (MongoDB.Driver.Core, Version=2.20.0.0, Culture=neutral, PublicKeyToken=null)
   at MongoDB.Driver.Core.Operations.RetryableWriteOperationExecutor.Execute (MongoDB.Driver.Core, Version=2.20.0.0, Culture=neutral, PublicKeyToken=null)
   at MongoDB.Driver.Core.Operations.BulkUnmixedWriteOperationBase`1.ExecuteBatch (MongoDB.Driver.Core, Version=2.20.0.0, Culture=neutral, PublicKeyToken=null)
   at MongoDB.Driver.Core.Operations.BulkUnmixedWriteOperationBase`1.ExecuteBatches (MongoDB.Driver.Core, Version=2.20.0.0, Culture=neutral, PublicKeyToken=null)
   at MongoDB.Driver.Core.Operations.BulkUnmixedWriteOperationBase`1.Execute (MongoDB.Driver.Core, Version=2.20.0.0, Culture=neutral, PublicKeyToken=null)
   at MongoDB.Driver.Core.Operations.BulkMixedWriteOperation.ExecuteBatch (MongoDB.Driver.Core, Version=2.20.0.0, Culture=neutral, PublicKeyToken=null)
   at MongoDB.Driver.Core.Operations.BulkMixedWriteOperation.Execute (MongoDB.Driver.Core, Version=2.20.0.0, Culture=neutral, PublicKeyToken=null)
   at MongoDB.Driver.OperationExecutor.ExecuteWriteOperation (MongoDB.Driver, Version=2.20.0.0, Culture=neutral, PublicKeyToken=null)
   at MongoDB.Driver.MongoCollectionImpl`1.ExecuteWriteOperation (MongoDB.Driver, Version=2.20.0.0, Culture=neutral, PublicKeyToken=null)
   at MongoDB.Driver.MongoCollectionImpl`1.BulkWrite (MongoDB.Driver, Version=2.20.0.0, Culture=neutral, PublicKeyToken=null)
   at MongoDB.Driver.MongoCollectionImpl`1+<>c__DisplayClass28_0.<BulkWrite>b__0 (MongoDB.Driver, Version=2.20.0.0, Culture=neutral, PublicKeyToken=null)
   at MongoDB.Driver.MongoCollectionImpl`1.UsingImplicitSession (MongoDB.Driver, Version=2.20.0.0, Culture=neutral, PublicKeyToken=null)
   at MongoDB.Driver.MongoCollectionImpl`1.BulkWrite (MongoDB.Driver, Version=2.20.0.0, Culture=neutral, PublicKeyToken=null)
   at MongoDB.Driver.MongoCollectionBase`1.InsertOne (MongoDB.Driver, Version=2.20.0.0, Culture=neutral, PublicKeyToken=null)
   at MongoDB.Driver.MongoCollectionBase`1.InsertOne (MongoDB.Driver, Version=2.20.0.0, Culture=neutral, PublicKeyToken=null)
   at ObjectsStandard.Transaction.Save_CALL_ONLY_FROM_TICKET (ObjectsStandard, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null)
Inner exception System.InvalidOperationException handled at MongoDB.Bson.Serialization.BsonClassMapSerializer`1.SerializeMember:
   at MongoDB.Bson.IO.ThreadStaticBuffer.RentBuffer (MongoDB.Bson, Version=2.20.0.0, Culture=neutral, PublicKeyToken=null)
   at MongoDB.Bson.IO.ByteBufferStream.WriteCString (MongoDB.Bson, Version=2.20.0.0, Culture=neutral, PublicKeyToken=null)
   at MongoDB.Bson.IO.BsonBinaryWriter.WriteString (MongoDB.Bson, Version=2.20.0.0, Culture=neutral, PublicKeyToken=null)
   at MongoDB.Bson.Serialization.Serializers.StringSerializer.SerializeValue (MongoDB.Bson, Version=2.20.0.0, Culture=neutral, PublicKeyToken=null)
   at MongoDB.Bson.Serialization.Serializers.SealedClassSerializerBase`1.Serialize (MongoDB.Bson, Version=2.20.0.0, Culture=neutral, PublicKeyToken=null)
   at MongoDB.Bson.Serialization.Serializers.SerializerBase`1.MongoDB.Bson.Serialization.IBsonSerializer.Serialize (MongoDB.Bson, Version=2.20.0.0, Culture=neutral, PublicKeyToken=null)
   at MongoDB.Bson.Serialization.IBsonSerializerExtensions.Serialize (MongoDB.Bson, Version=2.20.0.0, Culture=neutral, PublicKeyToken=null)
   at MongoDB.Bson.Serialization.BsonClassMapSerializer`1.SerializeMember (MongoDB.Bson, Version=2.20.0.0, Culture=neutral, PublicKeyToken=null)

成因分析

  1. Driver内部缓冲区管理竞态:MongoDB Driver 2.20版本中的ThreadStaticBuffer组件存在线程内资源复用的竞态条件。ThreadStatic变量虽保证线程隔离,但当同一线程内出现嵌套Bson序列化(如异步上下文切换、线程池线程复用导致缓冲区未正确释放)时,会触发缓冲区重复租用的冲突。
  2. MongoClient频繁创建:代码中每次数据库操作都新建MongoClient实例,导致Driver内部资源(包括缓冲区管理组件)频繁创建销毁,加剧了线程资源竞争。MongoClient本身是线程安全的,应全局复用而非每次请求创建。

解决方案

1. 全局复用MongoClient实例

修改GetMongoDbCollection方法,将MongoClient改为单例模式,避免频繁初始化:

private static MongoClient _mongoClient;
private static readonly object _lockObj = new object();

public IMongoCollection<TDocument> GetMongoDbCollection<TDocument>(string collectionName = null){
  IMongoCollection<TDocument> mongoCollection = null;
  try
  {
     if (_mongoClient == null)
     {
        lock(_lockObj)
        {
           if (_mongoClient == null)
           {
              string databaseAddress = Vault.Get("mongoDatabaseAddress"); 
              string userName = Vault.Get("mongoDbUserName");
              string password = Vault.Get("mongoDbPassword");
              _mongoClient = new MongoClient($"mongodb+srv://{userName}:{password}@{databaseAddress}/<dbname>?retryWrites=true&w=majority&serverSelectionTimeoutMS=10000");
           }
        }
     }

     var database = _mongoClient.GetDatabase("App");
     mongoCollection = database.GetCollection<TDocument>(collectionName);
  }
  catch (Exception ex)
  {
     LoggerClient.Error(ex);
  }
  return mongoCollection;
}

2. 升级MongoDB C# Driver版本

该缓冲区管理问题在Driver 2.21及后续版本中已被官方修复,建议升级至最新稳定版本,从根源解决竞态问题。

3. 避免嵌套序列化操作

检查业务代码中是否存在同一线程内嵌套调用MongoDB操作的逻辑(如序列化文档成员时触发另一次数据库读写),此类嵌套易引发缓冲区冲突。若存在,调整为异步非阻塞逻辑或保证序列化操作的原子性。

4. 添加针对性重试机制

针对偶现的该错误,在业务代码中添加重试逻辑:当捕获到BsonSerializationException且内部异常为InvalidOperationException并包含"Thread static buffer is already in use"信息时,重试对应的数据库操作。

内容的提问来源于stack exchange,提问作者Ran Marciano

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 15:57:34