C# MongoDb Connect to Replica Set Issue - mongodb

According to the mongodb website, I should be able to connect to a replica set if I just give it one member from the replica set:
"The C# Driver is able to connect to a replica set even if the seed list is incomplete. It will find the primary server even if it is not in the seed list as long as at least one of the servers in the seed list responds (the response will contain the full replica set and the name of the current primary)." http://www.mongodb.org/display/DOCS/CSharp+Driver+Tutorial#CSharpDriverTutorial-Connectionstrings
However, I cannot get my driver to connect if I just give it a secondary member.
This is my current connection statement:
m_server = MongoServer.Create(new MongoServerSettings { ConnectionMode = ConnectionMode.ReplicaSet, Server = new MongoServerAddress(connection) });
The 'connection' variable is: mongodb://servername/?safe=true
I saw this: https://jira.mongodb.org/browse/CSHARP-500, and I did run rs.status(), and did use the correct server name. Any help is appreciated!

At this moment I’m learning MongoDB and I’ve being playing around replica set connections. I like to contribute with 2 ways that I have used to connect to the database that I found useful, if doesn’t help anyone, at least I will have a place to refer to in the future (I’m sure I’m going to need it at some point)
first:
var connString = "mongodb://localhost:27029,localhost:27027,localhost:27028?connect=replicaSet";
var client = new MongoClient(connString);
var db = client.GetDatabase("test");
second:
var settings = new MongoClientSettings
{
Servers = new[]
{
new MongoServerAddress("localhost", 27027),
new MongoServerAddress("localhost", 27028),
new MongoServerAddress("localhost", 27029)
},
ConnectionMode = ConnectionMode.Automatic,
ReplicaSetName = "m101",
WriteConcern = new WriteConcern(WriteConcern.WValue.Parse("3"),wTimeout:TimeSpan.Parse("10"))
};
var client = new MongoClient(settings);
The first, allows me to connect to the database through the servers specified in the list of server. This allows the driver to connect automatically to the new principal node in the replica set in the case of failure with the principal.
With the second, I send the list of servers in the replica set, the connection type. The name of the replica set, and the write concern configuration. With this settings, I’m forcing the driver to wait for an acknowledge of writing from the 3 servers in the replica set (WValue:3) and to wait at the most 10 seconds for the confirmation of writing.

So, the connection variable is a full connection string, not something to pass to MongoServerAddress. Also, you can specify the connection mode on the connection string as well. Try this:
connection = "mongodb://servername/?safe=true&connect=replicaset";
m_server = MongoServer.Create(connectionString);

Related

How to check MongoDB connection status in D?

As far as I understand from docs vibed have 2 was API for MongoDB
1. Low level
2. Hight level
Low level API have connection property, so I can connect to DB and check if connection is success with next code:
auto db = new MongoConnection("localhost", 27017);
db.connect;
if (db.connected == true)
writeln("Connected");
else
writeln("Can't connect to DB");
But all examples show that I need to use connect with Mongo with connectMongoDB class:
auto db = connectMongoDB("localhost").getDatabase("test");
but this class do not have connection status method.
Can I return from MongoConnection MongoClient type and use it's in my code. If I right understand all other methods need MongoClient to get basic operation.
Can I check connection status with connectMongoDB class?
Why try-catch block, do not avail? Even if I make an incorrect connectionString, I still can not get any error message.

Mongoose not reading from Mongo secondary database

I've implemented a replica set that I'm using globally. I have my master in Oregon, US and 4 secondaries. California and Virginia, Frankfurt and Sydney. I also have web servers in those same regions as well. Those web servers connect to mongo using mongoose:
var mongoose = require("mongoose");
var dbUrl = "mongodb://***.***.***.***:27017,***.***.***.***:27017,***.***.***.***:27017,***.***.***.***:27017,***.***.***.***:27017/exampleDb";
var dbOptions : {
"replSet": {
"rs_name": "exampleRepSet",
"readPreference": "ReadPreference.SECONDARY_PREFERRED",
"read_preference": "ReadPreference.SECONDARY_PREFERRED",
"w":0,
"slaveOk": true
}
}
mongoose.connect(dbUrl, dbOptions);
My problem is that my client's have higher latency to the database depending on how far away they are from the master. California get 40ms while Sydney gets 400ms. I don't understand why this is happening since they should be reading off of the secondary database in their region.
I understand that writes must be done to the primary but even if I perform a find then shouldn't it be done on the regional secondary and return pretty quick?
I realize there are some redundant options in that config but I'm getting desperate. I've also tried the option "ReadPreference.NEAREST" to no avail.
Try using the following options:
var mongoose = require("mongoose");
var dbUrl = "mongodb://***.***.***.***:27017,***.***.***.***:27017,***.***.***.***:27017,***.***.***.***:27017,***.***.***.***:27017/exampleDb";
mongoose.connect(dbUrl, {
server: {
readPreference: "nearest",
strategy: "ping"
},
replset: {
rs_name: "exampleRepSet",
readPreference: "nearest",
strategy: "ping"
}
});
Whilst the documentation specifies ping as the default strategy, it seems Mongoose mandates that you specify one when you use readPreference.
Also note that secondaryPreferred is not the same thing as nearest. secondaryPreferred prefers reads off of secondary members (as the name suggests) regardless of network latency, where nearest prioritizes reads to the member with the lowest amount of network latency.
Short of a misconfiguration in your replica set, make sure your primary is online and reachable - by default Mongoose will refuse to use a secondary if the primary is offline.
Edit
Try setting the read preference on the connection string itself with mongodb://connection/db/?readPreference=secondary and not in the dbOptions. I can't find anything in the node-mongodb-native that says a read preference can be added to the replset config. http://mongodb.github.io/node-mongodb-native/2.0/api/ReplSet.html
Old Answer
You may need to set the setting to nearest and not secondary preferred. http://docs.mongodb.org/manual/reference/read-preference/#nearest
dbOptions.db = {
readPreference: "secondaryPreferred",
};
This worked for me

Creating a MongoDB Replica Set Service in DreamFactory

I'm trying to create a Service using a MongoDB Replica Set. MongoDB's docs says here that the connection string format has to be
mongodb://[username:password#]host1[:port1][,host2[:port2],...[,hostN[:portN]]][/[database][?options]]
So, my connection string is something like
mongodb://IP1:PORT1,IP2:PORT2,IP3:PORT3/DATABASE?replicaSet=REPLICA_SET_NAME
But when I try to explore the service, I'm not getting any data, collection or schema and I noticed that DreamFactory created another database called "DATABASE?replicaSet=REPLICA_SET_NAME". I tried to just remove these options "replicaSet=REPLICA_SET_NAME" to see what happens and then I'm getting this error while I explore:
{
"error": [
{
"context": null,
"message": "Failed to list resources for this service.\nIP1:PORT1: not master and slaveOk=false",
"code": 500
}
]
}
If I keep trying to explore the same REST Endpoint (for instance, /rest/API-NAME?names_only=true&include_schemas=true), then I eventually get the correct response. It seems that it tries with a different ip and port every time I make the request.
I also noticed that if I just leave the primary server and remove the options from the connection string, then it works fine. But this is pointless, because I'm losing the whole replica set point.
I even tried to set a lookup key with the name "replicaSet" equals to REPLICA_SET_NAME, but it didn't work either.
How can I use MongoDB replica sets with DreamFactory?
This may not be the solution to your problem but I have few observations.
Techically, your connection string are fine. But what I have found in DreamFactory is, they don't seem to allow options with the connection string. They seem to allow only authentication and database name in connection string. It is considering "DATABASE?replicaSet=REPLICA_SET_NAME" as the database name because they only allow database name in the URI.
This is info box text below the text field to enter the connection string in DreamFactory - "The connection string can include authentication credentials as well as database name. If they contain special characters, please enter them below."
Looks like they meant, "only authentication credentials as well as database name."
When you remove the option "replicaSet=REPLICA_SET_NAME", then you get the desired database name. But since you have replicaset nodes in connection, it will pick one server from them and connect to it. If it connects to primary node things work well as you can read and write to primary node. If it happens to chooses a node that is not primary then you have "Failed to list resources for this service.\nIP1:PORT1: not master and slaveOk=false" error.
The only condition when this should work is -
1. You connect only to the primary node, just to avoid connecting to secondaries.
2. you pass only the database name, just to escape messing up the database name
That's why it works when you just leave the primary server and also remove the options from connection string.

How to use Cashbah MongoDB connections?

Note: I realise there is a similar question on SO but it talks about an old version of Casbah, plus, the behaviour explained in the answer is not what I see!
I was under the impression that Casbah's MongoClient handled connection pooling. However, doing lsof on my process I see a big and growing number of mongodb connections, which makes me doubt this pooling actually exists.
Basically, this is what I'm doing:
class MongodbDataStore {
val mongoClient = MongoClient("host",27017)("database")
var getObject1(): Object1 = {
val collection = mongoClient("object1Collection")
...
}
var getObject2(): Object2 = {
val collection = mongoClient("object2Collection")
...
}
}
So, I never close MongoClient.
Should I be closing it after every query? Implement my own pooling? What then?
Thank you
Casbah is a wrapper around the MongoDB Java client, so the connection is actually managed by it.
According to the Java driver documentation (http://docs.mongodb.org/ecosystem/drivers/java-concurrency/) :
If you are using in a web serving environment, for example, you should
create a single MongoClient instance, and you can use it in every
request. The MongoClient object maintains an internal pool of
connections to the database (default maximum pool size of 100). For
every request to the DB (find, insert, etc) the Java thread will
obtain a connection from the pool, execute the operation, and release
the connection. This means the connection (socket) used may be
different each time.
By the way, that's what I've experienced in production. I did not see any problem with this.

Do I need to specify all the host for replica Set in Mongoose, Express-session-mongo and mongolian?

I have MongoDB replica Set as:
Host1: 10.10.10.1:27017
Host2: 10.10.10.1:27018
Host3: 10.10.10.2:27017
Host4: 10.10.10.2:27018
When I set the connection (e.g. IN Mongoose), I have to do this:
mongoose.connectSet('mongodb://10.10.10.1:271017/mydb,
mongodb://10.10.10.1:27018/mydb,
mongodb://10.10.10.2:27107/mydb, mognodb://10.10.10.27108/mydb);
can I just do this?
mongoose.connectSet('mongodb://10.10.10.1/mydb, mongodb://10.10.10.2/mydb');
How about express-session-mongo and mongolian? how to set up the connection to replica set?
Why I have to define all the host names? shouldn't the driver know all the primary and secondary and keep the lookup table, instead of manually define it during setting up the connection?
so the mongodb driver that is used by mongoose will find all members of the replicaset if you have at least one member in the original set. This is due to each member in a replicaset knowing about all the other members. But the more servers you know about the better as it makes it more likely to find a server in case your only passed in server is down.