简体   繁体   中英

Is it safe to create multiple instances of MongoClient by using the same connection string each time?

I'm trying to better understand this documentation concerning how to reuse instances of MongoClient .

We create MongoClient instances by passing the connection string in the constructor, this is the reference to the constructor overload we call .

The official documentation states the following (emphasis are mine):

However, multiple MongoClient instances created with the same settings will utilize the same connection pools underneath . Unfortunately, certain types of settings are not able to be compared for equality. For instance, the ClusterConfigurator property is a delegate and only its address is known for comparison. If you wish to construct multiple MongoClients, ensure that your delegates are all using the same address if the intent is to share connection pools.

What I'm trying to understand is whether calling new MongoClient("mongodb://some-server.net:27017/foo") multiple times will use the same pool of connections or not (notice that the connection string passed to the constructor is exactly the same at each constructor call).

I performed a few tests where by using the mongo shell I monitored the number of connections by using the command db.serverStatus().connections . I didn't see any difference in the number of connections by switching from a single static instance of MongoClient to multiple instances created .

My intuition is that when using the constructor overload taking a string the problem highlighted in the documentation is not triggered (of course this is only true if the connection string is the same each time the constructor is called). The warning related to MongoClientSettings described in the docs is probably triggered only when using the constructor overload taking an instance of MongoClientSettings .

Just for reference this is my test code:

  class Program
  {
    static readonly string[] names = { "Enrico", "Luca", "Mario" };
    static readonly MongoClient client;
    static readonly IMongoDatabase database;
    static readonly IMongoCollection<BsonDocument> collection;

    static Program()
    {
      client = new MongoClient("mongodb://localhost:27017");
      database = client.GetDatabase("test-connections");
      collection = database.GetCollection<BsonDocument>("people");
    }

    static async Task Main(string[] args)
    {
      var tasks = Enumerable
        .Range(1, 2_000_000)
        .AsParallel()
        .Select(_ => WriteDocument());

      await Task.WhenAll(tasks).ConfigureAwait(false);

      Console.WriteLine("All done");

      Console.ReadLine();
    }

    static async Task WriteDocument()
    {
      //var client = new MongoClient("mongodb://localhost:27017");
      //var database = client.GetDatabase("test-connections");
      //var collection = database.GetCollection<BsonDocument>("people");
      var randomIndex = RandomGenerator.Instance.Next(0, names.Length);
      var randomName = names[randomIndex];
      var document = new BsonDocument("name", randomName);
      await collection.InsertOneAsync(document).ConfigureAwait(false);
    }
  }

Does anyone know how the connection pool reuse works in the C# MongoDb driver ?

UPDATE 30th June 2019

Starting from the comments in the answer (thanks to Haytam for his contribution) I investigated the code of the mongodb C# driver and it seems that given a connection string the same connection pool is reused each time.

Here you can see that all the overloads of MongoClient constructor call the overload taking the MongoClientSetting as parameter .

At this line you can see how given an instance of MongoClientSetting a corresponding instance of ICluster is obtained from the default ClusterRegistry instance.

The classes implementing ICluster are MultiServerCluster and SingleServerCluster . These classes basically maintain the connection pool as you can see by looking in the source code (they do that by using instances of the Server class).

In order to verify that two identical connection strings lead to two identical ICluster instances I added the following code in a unit test (in order to run this unit test you must add that directly to the source code of the mongodb C# driver, because it uses the internal method ToClusterKey ):

  var url1 = new MongoUrl("mongodb://localhost:27017/test");
  var settings1 = MongoClientSettings.FromUrl(url1);
  var clusterKey1 = settings1.ToClusterKey();

  var url2 = new MongoUrl("mongodb://localhost:27017/test");
  var settings2 = MongoClientSettings.FromUrl(url2);
  var clusterKey2 = settings2.ToClusterKey();

  var equals = clusterKey1.Equals(clusterKey2);
  Console.WriteLine(equals);

  var subject = new ClusterRegistry();
  var cluster1 = subject.GetOrCreateCluster(clusterKey1);
  var cluster2 = subject.GetOrCreateCluster(clusterKey2);

  var sameCluster = cluster1.Equals(cluster2);
  Console.WriteLine(sameCluster);

If you run this tests you will see that both equals and sameCluster are true .

In order to verify that different connection strings lead to different instances of ICluster you can run the following unit test where the second connection string has been modified by specifying a custom connection timeout (the default connection timeout is 30 seconds):

  const string connString1 = "mongodb://localhost:27017/test";
  var settings1 = MongoClientSettings.FromConnectionString(connString1);
  var clusterKey1 = settings1.ToClusterKey();

  const string connString2 = "mongodb://localhost:27017/test?connectTimeoutMS=15000";
  var settings2 = MongoClientSettings.FromConnectionString(connString2);
  var clusterKey2 = settings2.ToClusterKey();

  var equals = clusterKey1.Equals(clusterKey2);
  Console.WriteLine(equals);

  var subject = new ClusterRegistry();
  var cluster1 = subject.GetOrCreateCluster(clusterKey1);
  var cluster2 = subject.GetOrCreateCluster(clusterKey2);

  var sameCluster = cluster1.Equals(cluster2);
  Console.WriteLine(sameCluster);

If you run this tests you will see that both equals and sameCluster are false .

To put a long story short:

you can safely instantiate multiple instances of MongoClient if you use the exact same connection string each time, because all of them will share the same pool of connections and you won't kill your database server

All the constructors end up creating a settings object:

MongoClient(string connectionString) calls MongoClient(MongoUrl url) which calls MongoClient(MongoClientSettings settings) .

See the source code here: https://github.com/mongodb/mongo-csharp-driver/blob/master/src/MongoDB.Driver/MongoClient.cs#L105

The line 79 _cluster = ClusterRegistry.Instance.GetOrCreateCluster(_settings.ToClusterKey()); is the one responsable for knowing that you're using the same settings and will use the same cluster, which I guess uses the same connection pool.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM