Support Desk: Keeping MongoDB Live

Rocco at the Support Desk

We've noticed that a number of customers are not making the best use of the high availability features of Compose's MongoDB deployments. As these features can see you through maintenance without downtime, we thought it was time for a refresher on how they work. So here's the speed guide to Replica Sets.

What are Replica Sets?

Replica sets are a group of MongoDB servers configured to be replicas of each other. At Compose, we have two visible servers in our replica set, a primary server and a secondary server which is a replica of the primary.

What happens when one of them goes offline?

If the primary goes offline, the secondary adopts the role of primary and takes on its responsibilities. If the secondary goes offline, it doesn't affect the primary and it will be updated when it comes back online.

Doesn't that mean I'd have to switch servers?

Yes it does, if you've only told your applications about the primary server.

How do I tell them I have a replica set?

There are the older methods which involve custom calls for each driver or the more modern and preferred technique of using the MongoDB URI. You use a Replica Set MongoDB URI to identify your databases. Here's a URL for a single database:

mongodb://user:password@c128.lamppost.1.mongolayer.com:10128/demonstratum  

This means the server is on c128.lamppost.1.mongolayer.com, port 10128. If this server went offline, there's no information as to where to look for a server which was secondary but which would be stepping up to the primary role. Now, here's a Replica Set URI

mongodb://user:password@c128.lamppost.1.mongolayer.com:10128,c47.lamppost.8.mongolayer.com:10047/demonstratum?replicaSet=set-549413b59277061139006d47  

Now, as well as the server on c128, we list its secondary on c47.lampost.8.mongolayer.com, port 10047. We also add on ?replicaSet=set-549413b59277061139006d47 which is the auto-generated name of the replica set. Now, when a replica set aware driver uses this URI, it can work out where to find a secondary being promoted and connect to that.

Are the drivers I use replica set aware?

If the driver accepts connections in the form of the MongoDB URI then it should be replica set aware. If it does not, consult the driver's documentation for how it supports replica sets.

Will I need to change any code?

The hand over to a new primary is not instant and can take up to sixty seconds. During that time, write operations will fail as the replica set is in read-only mode. For that reason, wrap your database write operations with code to retry after a brief wait, or discard the operation if your application design allows for that.

What about the Mongo shell?

Well spotted. The Mongo shell takes a host name and a port rather than a MongoDB URI. If you wanted to connect to the replica set about you'd run

mongo demonstratum -host set-549413b59277061139006d47/c128.lamppost.1.mongolayer.com:10128,c47.lamppost.8.mongolayer.com:10047 -u user -p password  

The database name is given, but the -host argument now specifies the replica set name, followed by a slash and then the list of hosts and ports. When connected, the db.isMaster() command can give information about replica set, the primary and which host you are currently talking to.

Can you tell me more about connecting with specific drivers?

C

The C Driver supports creating connections with the replica set URI as an advanced connection.

Java

Use the MongoClient class's MongoClientURI consuming constructor to connect with a replica set URI.

Node.js

For the native driver, use the MongoClient.connect method and use a replica set URI. If you are using Mongoose then use Mongoose.createConnection with a replica set URI.

PHP

Again, the PHP drivers MongoClient supports connections with a replica set URI. More details are available.

Python

The PyMongo driver also has a MongoClient class which supports replica set URIs. There's also a guide to high availability in the documentation covering how to handle failover and using MongoReplicaSetClient.

Ruby

Ruby developers can use the MongoClient.from_uri class method to pass a Replica Set URI to the official Ruby driver. Mongoid 3 and 4 both take a URI as a parameter in the config/mongoid.yml file.

Go

The mgo Go driver is the only one significantly different from other drivers. A connection is made using Dial with a replica set URI. Technically the replset parameter doesn't need to be present as the mgo driver auto-discovers the replica set cluster, but it does no harm if it is present.