MongoDB C# 2.0 TimeoutException

12
我们最近将我们的Web应用程序升级到了MongoDB C# Driver 2.0并部署到生产环境。在一定负载以下,应用程序可以正常运行。一旦生产服务器上的负载超过一定限制,应用程序的CPU立即降至0,在约30秒后,会记录下这个异常信息多次:
System.TimeoutException message: A timeout occured after 30000ms selecting a server using CompositeServerSelector{ Selectors = ReadPreferenceServerSelector{ ReadPreference = { Mode = Primary, TagSets = System.Collections.Generic.List`1[MongoDB.Driver.TagSet] } }, LatencyLimitingServerSelector{ AllowedLatencyRange = 00:00:00.0150000 } }. Client view of cluster state is { ClusterId : "1", Type : "Standalone", State : "Disconnected", Servers : [{ ServerId: "{ ClusterId : 1, EndPoint : "Unspecified/10.4.0.113:27017" }", EndPoint: "Unspecified/10.4.0.113:27017", State: "Disconnected", Type: "Unknown" }] }.
stack trace:
at MongoDB.Driver.Core.Clusters.Cluster.ThrowTimeoutException(IServerSelector selector, ClusterDescription description)
at MongoDB.Driver.Core.Clusters.Cluster.<WaitForDescriptionChangedAsync>d__18.MoveNext()
--- End of stack trace
我们正在使用一个单例的MongoClient对象,它是这样初始化的:
private static object _syncRoot = new object();

private static MongoClient _client;
private static IMongoDatabase _database;

private IMongoDatabase GetDatabase()
{
    ...

    if (_client == null)
    {
        lock (_syncRoot)
        {
            if (_client == null)
            {
                _client = new MongoClient(
                    new MongoClientSettings
                    {
                        Server = new MongoServerAddress(host, port),
                        Credentials = new[] { credentials },
                    });

                _database = _client.GetDatabase("proddb");
                return _database;
            }
        }
    }
    return _database;
}

public IMongoCollection<T> GetCollection<T>(string name)
{
    return GetDatabase().GetCollection<T>(name);
}

典型的数据库调用代码如下:

public async Task<MongoItem> GetById(string id)
{
    var collection = _connectionManager.GetCollection<MongoItem>("items");
    var fdb = new FilterDefinitionBuilder<MongoItem>();
    var f = fdb.Eq(mi => mi.Id, id);
    return await collection.Find(f).FirstOrDefaultAsync();
}

我们该如何发现原因并解决这个问题?


3
这需要进行更多的诊断。你能否在jira.mongodb.org下的CSHARP项目中提交一个工单?我可以告诉你,这个异常告诉我们,我们已经无法连接到服务器。发生了某些使我们失去连接的事件。因此,我想看一下服务器的日志(似乎你只有一个以独立模式运行的服务器)。 - Craig Wilson
我在我的ASP.NET MVC应用程序中每次都遇到相同的超时异常,但是使用相同的库从控制台应用程序中,我从未看到过它。 - Tyler Jensen
你解决了错误吗? - RPDeshaies
1
不行 :( 我们已经回到了1.1驱动程序。考虑在未来再试一次。 - Serhat Ozgel
这是很久以前的事情了,但在驱动程序升级后我遇到了同样的问题。使用单例模式,在负载下才会出现问题。1.x 版本多年来没有问题,但是在 2.11 版本中,在高峰期间突然出现了一堆超时错误日志(重试通常可以解决)。 - Chris Lukic
4个回答

6
这篇文章可能会有所帮助:

我已经弄清楚了。 这个JIRA票据中有详细信息。

实际上,我们区分了连接独立服务器和直接连接到副本集成员,后者相对不常见。不幸的是,MongoLab的单节点设置实际上是一个单节点副本集,这使我们不信任它。您可以通过在连接字符串末尾添加?connect=replicaSet来解决此问题。它将强制驱动程序进入副本集模式,一切都将正常工作。

鉴于此,我们将重新考虑CSHARP-1160。非常感谢您的报告,请让我知道在连接字符串中添加?connect=replicaSet是否有效。


这是一个一直发生并且与mongolab相关的情况,因为mongolab将单节点视为副本集。我们托管自己的mongodb,我们遇到的问题不是“无法连接到mongodb”,而是仅在负载过重时出现的问题。 - Serhat Ozgel
这就是解决我的问题的方法!谢谢! - Paul Lemke

2

我之前使用司机版本v2.2.4时遇到了同样的问题。升级到v2.3.0后,该问题似乎已经得到解决。


2
这个问题涉及到 CSHARP-1435CSHARP-1515CSHARP-1538 的错误报告,很可能已经在最近的 C# MongoDB 驱动程序中得到了修复。
这个问题可能与读取返回的文档数量超过单个批次适合的数量有关。source 因此,可能的解决方案是:
  • Make sure your MongoDB is up and running.source
  • Check MongoDB logs for any additional details.
  • If connecting to group of mongod processes (see: replication), add ?connect=replicaSet to your connection string. For example:

    mongodb://db1.example.net:27017,db2.example.net:2500/?replicaSet=test&connectTimeoutMS=300000
    

    Example ConnectionStrings.config file:

    <connectionStrings>
          <add name="MongoDB" connectionString="mongodb://10.0.80.231:27017,10.0.108.31:27017/?replicaSet=groupname&amp;connectTimeoutMS=600000&amp;socketTimeoutMS=600000" />
          <add name="RedisCache" connectionString="www-redis.foo.cache.amazonaws.com:6379" />
          <add name="SqlConnection" connectionString="server=api.foo.eu-west-1.rds.amazonaws.com;database=foo;uid=sqlvpc;pwd=somepass;" providerName="System.Data.SqlClient"  />
    </connectionStrings>
    

    Related: CSHARP-1160, How to include ampersand in connection string?

    If above won't work, check: C# MongoDB Driver Ignores timeout options.

  • Try upgrading MongoDB.Driver as per above bug reports.

  • Try increasing connect and socket timeouts.

    Either by appending ?connectTimeoutMS=60000&socketTimeoutMS=60000 to your connection string. See: mongoDB Connection String Options.

    Alternatively changing settings in your code (e.g. connecttimeout, maxpoolsize, waitQueueSize and waitQueueTimeout). See the example here.

  • Check connection string whether you're including the database properly.source
  • Increasing a delay between each query in case of rapid calls to MongoDB.source
请同时检查MongoDB C#/.NET驱动程序的MongoDB兼容性

C#/.NET Driver Version, MongoDB C#/.NET driver compatibility


0

当我在使用MongoLab的免费(2.6版本)沙盒时,我遇到了同样的问题,但当我开始使用付费集群后,超时问题就消失了。

我本来想说,我认为问题是只支持MongoDB 3.0+版本(因为我找到了一些文档说了这个,并且我发誓我通过MongoLab进行了3.0升级过程),但当我去搜索文档时,现在它说支持2.6版本,而我的付费MongoLab数据库仍然显示为2.6.9版本。

我想我可能有点疯了,但至少我的代码现在可以工作了!


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接