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)
成因分析
- Driver内部缓冲区管理竞态:MongoDB Driver 2.20版本中的
ThreadStaticBuffer组件存在线程内资源复用的竞态条件。ThreadStatic变量虽保证线程隔离,但当同一线程内出现嵌套Bson序列化(如异步上下文切换、线程池线程复用导致缓冲区未正确释放)时,会触发缓冲区重复租用的冲突。 - 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
相关产品推荐
相关产品推荐

