martyGale
martyGale

Reputation: 61

Unable to connect to a member of the replica set matching the read preference Primary

I have 3 mongodb nodes: primary, secondary and arbiter (version 2.4.9)

I have mongodb C# driver 1.8.3 I am using the following connection string:

connection string "mongodb://mongo2,mongo1,mongo3/?connect=replicaset&replicaset=myrs&readPreference=SecondaryPreferred"

When recording half case the driver throws an exception:

Unable to connect to a member of the replica set matching the read preference Primary

My code:

        var client = new MongoClient(connectionString);
        var server = client.GetServer();
        var database = server.GetDatabase(dbName);
        var collection = database.GetCollection<T>(collectionName);
        collection.Insert(newDoc);

What am I doing wrong?

Upvotes: 6

Views: 8125

Answers (4)

Vihana Kewalramani
Vihana Kewalramani

Reputation: 925

For me, few mongo server were crashed and hence I was seeing error. Please check your mongo db server connectivity

Upvotes: 0

Marvin Lacuna
Marvin Lacuna

Reputation: 1812

I know the post is already outdated, but I bumped into this issue last week and I was able to resolved the problem.

Few things you have to check:

  1. If your connection to mongodb is hosted in your connectionstrings.config, the & should be &amp; otherwise you would get an 'entity issue'.
  2. Don't forget to add the mongodb port 27017
  3. Use primaryPreffered over secondaryPreferred- this is if you want an application to read from the primary under normal circumstances, but to allow stale reads from secondaries when the primary is unavailable. This provides a “read-only mode” for your application during a failover. Using secondaryPreferred is a counter-indications. Know more from mongodb official documentation here.

  4. The obvious one is to check if the replica set is connected to each other, meaning there's an arbiter member, hence you would encounter that issue. I would like to bet if you only put the mongo1 and remove other replica set parameters, it would work perfectly.

  5. As what yaoxing mentioned, if you are using mongodb host/name make sure they are correct, further testing is to use MongoDB IP address instead of the host/name this still would work according to my testing.
  6. Mongodb parameters are case-sensitive, so better ensure you use replicaSet not replicaset as stated by lese.
  7. If you have an arbiter member, you don't have to include it on your connection.
  8. Furthermore, you can check this MongoDB configuration article. It also includes encryption just in case you want it, but overall if all the points were addressed you shouldn't have that problem.

Upvotes: 0

yaoxing
yaoxing

Reputation: 4183

I suspect it's because you provided wrong host names.

Here's one thing you should know, the available mongo instance list doesn't come from your connection string, it comes from the returned result of first available mongo instance. For example, when the driver communicates with instance mongo1, it gets a list of available instances, which you can get with the following command:

rs.status()

in my laptop it returns something like this:

{
    "set" : "rs0",
    "date" : ISODate("2014-01-27T06:43:11Z"),
    "myState" : 1,
    "members" : [
        {
            "_id" : 0,
            "name" : "YX-ARCH:27017",
            "health" : 1,
            "state" : 1,
            "stateStr" : "PRIMARY",
            "uptime" : 15894,
            "optime" : Timestamp(1390804960, 1),
            "optimeDate" : ISODate("2014-01-27T06:42:40Z"),
            "self" : true
        },
        {
            "_id" : 1,
            "name" : "YX-ARCH:27011",
            "health" : 1,
            "state" : 2,
            "stateStr" : "SECONDARY",
            "uptime" : 31,
            "optime" : Timestamp(1390804960, 1),
            "optimeDate" : ISODate("2014-01-27T06:42:40Z"),
            "lastHeartbeat" : ISODate("2014-01-27T06:43:10Z"),
            "lastHeartbeatRecv" : ISODate("2014-01-27T06:43:10Z"),
            "pingMs" : 0,
            "syncingTo" : "YX-ARCH:27017"
        }
    ],
    "ok" : 1
}

Which means there are 2 instances YX-ARCH:27017 (Primary) & YX-ARCH:27011 (Secondary).

Now the point is, these host names must be resolvable in your IIS server, because your driver will uses these addresses to connect to mongo instances.

Thus if the host name resolves to a internet IP, while your mongo service is only available for intranet, you'll never be able to connect to it. And you get the error above.

One more thing, it's not recommended to create a new instance of MongoClient each time. From the document you can know it's thread-safe class. And the MongoClient is added to the driver to manage replica set stuff. So in my opinion you should keep it a single instance object. Because each time you create a new instance, it tries to get replica set settings from one instance, which is not really a good thing for the efficiency.

Upvotes: 5

lese
lese

Reputation: 549

What am I doing wrong? 

I think you shouldn't declare the arbiter in the connection string. Arbiter is not really a node it don't hold any data, its task is to partecipate in the vote of the primary node(the one who takes the writes) of the replicaSet.

You did well to add the arbiter, because without it nodes(and votes) was even, and you would anyway be facing with some cases of connection failure. Anyway your problem is not related to this. Do you really need that connect=replicaset ?

I don't know much about C# , but i read that connection strings have the same format for all the official drivers, also this is an example in php :

    $m = new MongoClient("mongodb://mongo1:27017,mongo2:27018/?replicaSet=myrs&readPreference=secondary");

Are you testing eventual consistency? let me know what you think about it, i didnt had time to check it

don't know if its case-sensitive but watch out at the capital letter replicaSet=myrs

Upvotes: 0

Related Questions